diff options
author | Mark Wielaard <mark@gcc.gnu.org> | 2006-05-18 17:29:21 +0000 |
---|---|---|
committer | Mark Wielaard <mark@gcc.gnu.org> | 2006-05-18 17:29:21 +0000 |
commit | 4f9533c7722fa07511a94d005227961f4a4dec23 (patch) | |
tree | 9f9c470de62ee62fba1331a396450d728d2b1fad /libjava/classpath/javax | |
parent | eaec4980e139903ae9b274d1abcf3a13946603a8 (diff) | |
download | gcc-4f9533c7722fa07511a94d005227961f4a4dec23.tar.gz |
Imported GNU Classpath 0.90
Imported GNU Classpath 0.90
* scripts/makemake.tcl: LocaleData.java moved to gnu/java/locale.
* sources.am: Regenerated.
* gcj/javaprims.h: Regenerated.
* Makefile.in: Regenerated.
* gcj/Makefile.in: Regenerated.
* include/Makefile.in: Regenerated.
* testsuite/Makefile.in: Regenerated.
* gnu/java/lang/VMInstrumentationImpl.java: New override.
* gnu/java/net/local/LocalSocketImpl.java: Likewise.
* gnu/classpath/jdwp/VMMethod.java: Likewise.
* gnu/classpath/jdwp/VMVirtualMachine.java: Update to latest
interface.
* java/lang/Thread.java: Add UncaughtExceptionHandler.
* java/lang/reflect/Method.java: Implements GenericDeclaration and
isSynthetic(),
* java/lang/reflect/Field.java: Likewise.
* java/lang/reflect/Constructor.java
* java/lang/Class.java: Implements Type, GenericDeclaration,
getSimpleName() and getEnclosing*() methods.
* java/lang/Class.h: Add new public methods.
* java/lang/Math.java: Add signum(), ulp() and log10().
* java/lang/natMath.cc (log10): New function.
* java/security/VMSecureRandom.java: New override.
* java/util/logging/Logger.java: Updated to latest classpath
version.
* java/util/logging/LogManager.java: New override.
From-SVN: r113887
Diffstat (limited to 'libjava/classpath/javax')
265 files changed, 22092 insertions, 8123 deletions
diff --git a/libjava/classpath/javax/accessibility/AccessibleAction.java b/libjava/classpath/javax/accessibility/AccessibleAction.java index 2ca683e45eb..a7cf05e4a04 100644 --- a/libjava/classpath/javax/accessibility/AccessibleAction.java +++ b/libjava/classpath/javax/accessibility/AccessibleAction.java @@ -55,6 +55,28 @@ package javax.accessibility; */ public interface AccessibleAction { + + /** + * The name of an action which decrements a value. + * + * @since 1.5 + */ + static final String DECREMENT = "decrement"; + + /** + * The name of an action which increments a value. + * + * @since 1.5 + */ + static final String INCREMENT = "increment"; + + /** + * The name of an action which toggles the expansion of a tree node. + * + * @since 1.5 + */ + static final String TOGGLE_EXPAND = "toggle expand"; + /** * Get the number possible actions for this object, with the zeroth * representing the default action. diff --git a/libjava/classpath/javax/accessibility/AccessibleAttributeSequence.java b/libjava/classpath/javax/accessibility/AccessibleAttributeSequence.java new file mode 100644 index 00000000000..5ee50e5d787 --- /dev/null +++ b/libjava/classpath/javax/accessibility/AccessibleAttributeSequence.java @@ -0,0 +1,71 @@ +/* AccessibleAttributeSequence.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.accessibility; + +import javax.swing.text.AttributeSet; + +/** + * This is a convenience class that represents an accessible + * attribute sequence. + * @since 1.5 + */ +public class AccessibleAttributeSequence +{ + /** + * The attributes of the text. + */ + public AttributeSet attributes; + + /** + * The starting index. + */ + public int startIndex; + + /** + * The ending index. + */ + public int endIndex; + + /** + * Create a new instance. + */ + public AccessibleAttributeSequence() + { + } +} diff --git a/libjava/classpath/javax/accessibility/AccessibleContext.java b/libjava/classpath/javax/accessibility/AccessibleContext.java index 536deac0dcd..972f4feae92 100644 --- a/libjava/classpath/javax/accessibility/AccessibleContext.java +++ b/libjava/classpath/javax/accessibility/AccessibleContext.java @@ -249,6 +249,35 @@ public abstract class AccessibleContext = "AccessibleHypertextOffset"; /** + * Constant used when a component's bounds have changed. The old and + * new bounds are given in the event. + * @since 1.5 + */ + public static final String ACCESSIBLE_COMPONENT_BOUNDS_CHANGED + = "accessibleComponentBoundsChanged"; + + /** + * Constant used when the state of child objects changes. The old + * value in the event is always null, and the new value is the component + * whose children have changed. + * @since 1.5 + */ + public static final String ACCESSIBLE_INVALIDATE_CHILDREN + = "accessibleInvalidateChildren"; + + /** + * Constant used when the attributes of some text have changed. + * On insertion, the old value is null and the new value is an + * {@link AccessibleAttributeSequence} describing the insertion. + * On deletion, the old value is an {@link AccessibleAttributeSequence} + * and the new value is null. For replacement, both the old + * and new values are {@link AccessibleAttributeSequence} objects. + * @since 1.5 + */ + public static final String ACCESSIBLE_TEXT_ATTRIBUTES_CHANGED + = "accessibleTextAttributesChanged"; + + /** * The accessible parent of this object. * * @see #getAccessibleParent() @@ -540,14 +569,15 @@ public abstract class AccessibleContext /** * Get any supported accessible relation set. The default implementation - * returns null. + * returns an empty AccessibleRelationSet. + * + * @return the supported relation set, or <code>null</code> * - * @return the supported relation set, or null * @see AccessibleRelationSet */ public AccessibleRelationSet getAccessibleRelationSet() { - return null; + return new AccessibleRelationSet(); } /** diff --git a/libjava/classpath/javax/accessibility/AccessibleExtendedText.java b/libjava/classpath/javax/accessibility/AccessibleExtendedText.java new file mode 100644 index 00000000000..f40fa0fd2dc --- /dev/null +++ b/libjava/classpath/javax/accessibility/AccessibleExtendedText.java @@ -0,0 +1,108 @@ +/* AccessibleExtendedText.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.accessibility; + +import java.awt.Rectangle; + +/** + * This interface provides extended text functionality, similar + * to AccessibleText. + * @see AccessibleText + * @since 1.5 + */ +public interface AccessibleExtendedText +{ + /** + * This constant indicates that the retrieved text should be a + * complete line. + */ + int LINE = 4; + + /** + * This constant indicates that the retrieved text should consist + * of a run with identical attributes. + */ + int ATTRIBUTE_RUN = 5; + + /** + * Determines the bounding box of some text held by this object. + * @param start the starting index + * @param end the ending index + * @return the bounding box + * @see AccessibleText#getCharacterBounds(int) + */ + Rectangle getTextBounds(int start, int end); + + /** + * Return a range of text from the underlying object. + * @param start the starting index + * @param end the ending index + */ + String getTextRange(int start, int end); + + /** + * Return a text sequence from the underlying object. The part + * parameter describes the type of sequence to return; it is one + * of the constants from {@link AccessibleText} or from this + * class. + * @param part the type of the sequence to return + * @param index start of the sequence + */ + AccessibleTextSequence getTextSequenceAfter(int part, int index); + + /** + * Return a text sequence from the underlying object. The part + * parameter describes the type of sequence to return; it is one + * of the constants from {@link AccessibleText} or from this + * class. + * @param part the type of the sequence to return + * @param index start of the sequence + */ + AccessibleTextSequence getTextSequenceAt(int part, int index); + + /** + * Return a text sequence from the underlying object. The part + * parameter describes the type of sequence to return; it is one + * of the constants from {@link AccessibleText} or from this + * class. + * @param part the type of the sequence to return + * @param index end of the sequence + */ + AccessibleTextSequence getTextSequenceBefore(int part, int index); +} diff --git a/libjava/classpath/javax/accessibility/AccessibleRelation.java b/libjava/classpath/javax/accessibility/AccessibleRelation.java index fae69efc4f2..3d515fd5765 100644 --- a/libjava/classpath/javax/accessibility/AccessibleRelation.java +++ b/libjava/classpath/javax/accessibility/AccessibleRelation.java @@ -61,7 +61,7 @@ public class AccessibleRelation extends AccessibleBundle * @see #LABELED_BY * @see #MEMBER_OF */ - public static final String LABEL_FOR = "labelFor"; + public static final String LABEL_FOR; /** * Indicates the object is labeled by other objects. @@ -72,7 +72,7 @@ public class AccessibleRelation extends AccessibleBundle * @see #LABEL_FOR * @see #MEMBER_OF */ - public static final String LABELED_BY = "labeledBy"; + public static final String LABELED_BY; /** * Indicates an object is a member of a group of target objects. @@ -83,7 +83,7 @@ public class AccessibleRelation extends AccessibleBundle * @see #LABEL_FOR * @see #LABELED_BY */ - public static final String MEMBER_OF = "memberOf"; + public static final String MEMBER_OF; /** * Indicates an object is a controller for other objects. @@ -94,7 +94,7 @@ public class AccessibleRelation extends AccessibleBundle * @see #LABELED_BY * @see #MEMBER_OF */ - public static final String CONTROLLER_FOR = "controllerFor"; + public static final String CONTROLLER_FOR; /** * Indicates an object is controlled by other objects. @@ -105,7 +105,7 @@ public class AccessibleRelation extends AccessibleBundle * @see #LABELED_BY * @see #MEMBER_OF */ - public static final String CONTROLLED_BY = "controlledBy"; + public static final String CONTROLLED_BY; /** Indicates that the label target group has changed. */ public static final String LABEL_FOR_PROPERTY = "labelForProperty"; @@ -122,8 +122,104 @@ public class AccessibleRelation extends AccessibleBundle /** Indicates that the controlling objects have changed. */ public static final String CONTROLLED_BY_PROPERTY = "controlledByProperty"; + /** + * Indicates that an object is a child of another object. + * @since 1.5 + */ + public static final String CHILD_NODE_OF = "childNodeOf"; + + /** + * Indicates that the ancestry relationship has changed. + * @since 1.5 + */ + public static final String CHILD_NODE_OF_PROPERTY = "childNodeOfProperty"; + + /** + * Indicates that an object is embedded by another object. + * @since 1.5 + */ + public static final String EMBEDDED_BY = "embeddedBy"; + + /** + * Indicates that the {@link #EMBEDDED_BY} property changed. + * @since 1.5 + */ + public static final String EMBEDDED_BY_PROPERTY = "embeddedByProperty"; + + /** + * Indicates that an object embeds another object. + * @since 1.5 + */ + public static final String EMBEDS = "embeds"; + + /** + * Indicates that the {@link #EMBEDS} property changed. + * @since 1.5 + */ + public static final String EMBEDS_PROPERTY = "embedsProperty"; + + /** + * Indicates that one object directly follows another object, + * as in a paragraph flow. + * @since 1.5 + */ + public static final String FLOWS_FROM = "flowsFrom"; + + /** + * Indicates that the {@link #FLOWS_FROM} property changed. + * @since 1.5 + */ + public static final String FLOWS_FROM_PROPERTY = "flowsFromProperty"; + + /** + * Indicates that one object comes directly before another object, + * as in a paragraph flow. + * @since 1.5 + */ + public static final String FLOWS_TO = "flowsTo"; + + /** + * Indicates that the {@link #FLOWS_TO} property changed. + * @since 1.5 + */ + public static final String FLOWS_TO_PROPERTY = "flowsToProperty"; + + /** + * Indicates that one object is a parent window of another object. + * @since 1.5 + */ + public static final String PARENT_WINDOW_OF = "parentWindowOf"; + + /** + * Indicates that the {@link #PARENT_WINDOW_OF} property changed. + * @since 1.5 + */ + public static final String PARENT_WINDOW_OF_PROPERTY = "parentWindowOfProperty"; + + /** + * Indicates that one object is a subwindow of another object. + * @since 1.5 + */ + public static final String SUBWINDOW_OF = "subwindowOf"; + + /** + * Indicates that the {@link #SUBWINDOW_OF} property changed. + * @since 1.5 + */ + public static final String SUBWINDOW_OF_PROPERTY = "subwindowOfProperty"; + /** An empty set of targets. */ private static final Object[] EMPTY_TARGETS = { }; + + static + { + // not constants in JDK + LABEL_FOR = "labelFor"; + LABELED_BY = "labeledBy"; + MEMBER_OF = "memberOf"; + CONTROLLER_FOR = "controllerFor"; + CONTROLLED_BY = "controlledBy"; + } /** * The related objects. diff --git a/libjava/classpath/javax/accessibility/AccessibleRole.java b/libjava/classpath/javax/accessibility/AccessibleRole.java index f386ad0e93f..a5396f147f5 100644 --- a/libjava/classpath/javax/accessibility/AccessibleRole.java +++ b/libjava/classpath/javax/accessibility/AccessibleRole.java @@ -467,6 +467,56 @@ public class AccessibleRole extends AccessibleBundle = new AccessibleRole("groupbox"); /** + * A formula for creating a value. + * + * @since 1.5 + */ + public static final AccessibleRole EDITBAR + = new AccessibleRole("editbar"); + + /** + * A text-based footer. + * + * @since 1.5 + */ + public static final AccessibleRole FOOTER + = new AccessibleRole("footer"); + + /** + * A text-based header. + * + * @since 1.5 + */ + public static final AccessibleRole HEADER + = new AccessibleRole("header"); + + + /** + * A text-based paragraph. + * + * @since 1.5 + */ + public static final AccessibleRole PARAGRAPH + = new AccessibleRole("paragraph"); + + /** + * Represents the current level of progress on a particular task. + * + * @since 1.5 + */ + public static final AccessibleRole PROGRESS_MONITOR + = new AccessibleRole("progress monitor"); + + /** + * A ruler is a method of measuring the distance between two + * points. + * + * @since 1.5 + */ + public static final AccessibleRole RULER + = new AccessibleRole("ruler"); + + /** * Create a new constant with a locale independent key. Follow the example, * keep the constructor private and make public constants instead. * diff --git a/libjava/classpath/javax/accessibility/AccessibleState.java b/libjava/classpath/javax/accessibility/AccessibleState.java index a630354b0a6..e4d00bd70b8 100644 --- a/libjava/classpath/javax/accessibility/AccessibleState.java +++ b/libjava/classpath/javax/accessibility/AccessibleState.java @@ -177,6 +177,28 @@ public class AccessibleState extends AccessibleBundle = new AccessibleState("iconified"); /** + * Indicates that the state of this particular object is + * indeterminate. This commonly occurs when an object is incapable + * of representing the state by a single value. + * + * @since 1.5 + */ + public static final AccessibleState INDETERMINATE + = new AccessibleState("indeterminate"); + + /** + * Indicates that this particular object manages a number of + * subcomponents. This is a common property of structures such as + * trees and tables, which have a number of sub-elements such as + * rows and columns. The subcomponents should be left to the + * object, and not managed by the application. + * + * @since 1.5 + */ + public static final AccessibleState MANAGES_DESCENDANTS + = new AccessibleState("manages descendants"); + + /** * Indicates that something must be done in the current object before * interaction is allowed on other windows, usually for dialogs. * @@ -250,6 +272,15 @@ public class AccessibleState extends AccessibleBundle = new AccessibleState("showing"); /** + * Indicates that this particular object is truncated when displayed + * visually. + * + * @since 1.5 + */ + public static final AccessibleState TRUNCATED + = new AccessibleState("truncated"); + + /** * Indicates that this object intends to be visible. However, if its * parent is invisible, this object is as well. * diff --git a/libjava/classpath/javax/accessibility/AccessibleStreamable.java b/libjava/classpath/javax/accessibility/AccessibleStreamable.java new file mode 100644 index 00000000000..cbeedf783f7 --- /dev/null +++ b/libjava/classpath/javax/accessibility/AccessibleStreamable.java @@ -0,0 +1,62 @@ +/* AccessibleStreamable.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.accessibility; + +import java.awt.datatransfer.DataFlavor; +import java.io.InputStream; + +/** + * This interface represents a streamable accessible object. + * @since 1.5 + */ +public interface AccessibleStreamable +{ + /** + * Return an array of the data flavors supported by this object. + */ + DataFlavor[] getMimeTypes(); + + /** + * Return an input stream that yields the contents of this object, + * using the given data flavor. If the given data flavor cannot + * be used, returns null. + * @param flavor the data flavor + */ + InputStream getStream(DataFlavor flavor); +} diff --git a/libjava/classpath/javax/accessibility/AccessibleText.java b/libjava/classpath/javax/accessibility/AccessibleText.java index 88aee1495c7..be5f45c7e7c 100644 --- a/libjava/classpath/javax/accessibility/AccessibleText.java +++ b/libjava/classpath/javax/accessibility/AccessibleText.java @@ -92,7 +92,7 @@ public interface AccessibleText * Given a point in the coordinate system of this object, return the * 0-based index of the character at that point, or -1 if there is none. * - * @param p the point to look at + * @param point the point to look at * @return the character index, or -1 */ int getIndexAtPoint(Point point); diff --git a/libjava/classpath/javax/accessibility/AccessibleTextSequence.java b/libjava/classpath/javax/accessibility/AccessibleTextSequence.java new file mode 100644 index 00000000000..88fa4c2b880 --- /dev/null +++ b/libjava/classpath/javax/accessibility/AccessibleTextSequence.java @@ -0,0 +1,68 @@ +/* AccessibleTextSequence.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.accessibility; + +/** + * This is a convenience class that encapsulates a String and a range. + * @since 1.5 + */ +public class AccessibleTextSequence +{ + /** + * The text of the sequence. + */ + public String text; + + /** + * The starting index. + */ + public int startIndex; + + /** + * The ending index. + */ + public int endIndex; + + /** + * Create a new instance. + */ + public AccessibleTextSequence() + { + } +} diff --git a/libjava/classpath/javax/crypto/Cipher.java b/libjava/classpath/javax/crypto/Cipher.java index b9dee74d51a..1f68ea60528 100644 --- a/libjava/classpath/javax/crypto/Cipher.java +++ b/libjava/classpath/javax/crypto/Cipher.java @@ -1,5 +1,5 @@ /* Cipher.java -- Interface to a cryptographic cipher. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,6 +40,9 @@ package javax.crypto; import gnu.java.security.Engine; +import java.nio.ByteBuffer; +import java.nio.ReadOnlyBufferException; + import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -496,7 +499,6 @@ public class Cipher { throw new IllegalStateException("neither encrypting nor decrypting"); } - state = INITIAL_STATE; return cipherSpi.engineDoFinal(input, inputOffset, inputLength); } @@ -532,7 +534,6 @@ public class Cipher { throw new IllegalStateException("neither encrypting nor decrypting"); } - state = INITIAL_STATE; return cipherSpi.engineDoFinal(new byte[0], 0, 0, output, outputOffset); } @@ -576,7 +577,6 @@ public class Cipher { throw new IllegalStateException("neither encrypting nor decrypting"); } - state = INITIAL_STATE; return cipherSpi.engineDoFinal(input, inputOffset, inputLength, output, outputOffset); } @@ -590,6 +590,43 @@ public class Cipher } /** + * Finishes a multi-part transformation with, or completely + * transforms, a byte buffer, and stores the result into the output + * buffer. + * + * @param input The input buffer. + * @param output The output buffer. + * @return The number of bytes stored into the output buffer. + * @throws IllegalArgumentException If the input and output buffers + * are the same object. + * @throws IllegalStateException If this cipher was not initialized + * for encryption or decryption. + * @throws ReadOnlyBufferException If the output buffer is not + * writable. + * @throws IllegalBlockSizeException If this cipher requires a total + * input that is a multiple of its block size to complete this + * transformation. + * @throws ShortBufferException If the output buffer is not large + * enough to hold the transformed bytes. + * @throws BadPaddingException If the cipher is a block cipher with + * a padding scheme, and the decrypted bytes do not end with a + * valid padding. + * @since 1.5 + */ + public final int doFinal (ByteBuffer input, ByteBuffer output) + throws ReadOnlyBufferException, ShortBufferException, + BadPaddingException, IllegalBlockSizeException + { + if (input == output) + throw new IllegalArgumentException + ("input and output buffers cannot be the same"); + if (state != ENCRYPT_MODE && state != DECRYPT_MODE) + throw new IllegalStateException + ("not initialized for encrypting or decrypting"); + return cipherSpi.engineDoFinal (input, output); + } + + /** * Returns the size an output buffer needs to be if this cipher is * updated with a number of bytes. * @@ -672,11 +709,11 @@ public class Cipher */ public final void init(int opmode, Key key) throws InvalidKeyException { - state = opmode; if (cipherSpi != null) { cipherSpi.engineInit(opmode, key, new SecureRandom()); } + state = opmode; } /** @@ -791,11 +828,11 @@ public class Cipher public final void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { - state = opmode; if (cipherSpi != null) { cipherSpi.engineInit(opmode, key, random); } + state = opmode; } /** @@ -890,11 +927,11 @@ public class Cipher SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - state = opmode; if (cipherSpi != null) { cipherSpi.engineInit(opmode, key, params, random); } + state = opmode; } /** @@ -925,11 +962,11 @@ public class Cipher SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - state = opmode; if (cipherSpi != null) { cipherSpi.engineInit(opmode, key, params, random); } + state = opmode; } /** @@ -1068,6 +1105,35 @@ public class Cipher } /** + * Continue a multi-part transformation on a byte buffer, storing + * the transformed bytes into another buffer. + * + * @param input The input buffer. + * @param output The output buffer. + * @return The number of bytes stored in <i>output</i>. + * @throws IllegalArgumentException If the two buffers are the same + * object. + * @throws IllegalStateException If this cipher was not initialized + * for encrypting or decrypting. + * @throws ReadOnlyBufferException If the output buffer is not + * writable. + * @throws ShortBufferException If the output buffer does not have + * enough available space for the transformed bytes. + * @since 1.5 + */ + public final int update (ByteBuffer input, ByteBuffer output) + throws ReadOnlyBufferException, ShortBufferException + { + if (input == output) + throw new IllegalArgumentException + ("input and output buffers must be different"); + if (state != ENCRYPT_MODE && state != DECRYPT_MODE) + throw new IllegalStateException + ("not initialized for encryption or decryption"); + return cipherSpi.engineUpdate (input, output); + } + + /** * Wrap a key. * * @param key The key to wrap. diff --git a/libjava/classpath/javax/crypto/CipherSpi.java b/libjava/classpath/javax/crypto/CipherSpi.java index a51a3aed69b..194c1dabf45 100644 --- a/libjava/classpath/javax/crypto/CipherSpi.java +++ b/libjava/classpath/javax/crypto/CipherSpi.java @@ -1,5 +1,5 @@ /* CipherSpi.java -- The cipher service provider interface. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.crypto; +import java.nio.ByteBuffer; + import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -179,6 +181,31 @@ public abstract class CipherSpi throws IllegalBlockSizeException, BadPaddingException, ShortBufferException; /** + * @since 1.5 + */ + protected int engineDoFinal (ByteBuffer input, ByteBuffer output) + throws BadPaddingException, IllegalBlockSizeException, + ShortBufferException + { + int total = 0; + byte[] inbuf = new byte[256]; + while (input.hasRemaining ()) + { + int in = Math.min (inbuf.length, input.remaining ()); + input.get (inbuf, 0, in); + byte[] outbuf = new byte[engineGetOutputSize (in)]; + int out = 0; + if (input.hasRemaining ()) // i.e., we have more 'update' calls + out = engineUpdate (inbuf, 0, in, outbuf, 0); + else + out = engineDoFinal (inbuf, 0, in, outbuf, 0); + output.put (outbuf, 0, out); + total += out; + } + return total; + } + + /** * Returns the block size of the underlying cipher. * * @return The block size. @@ -380,6 +407,26 @@ public abstract class CipherSpi throws ShortBufferException; /** + * @since 1.5 + */ + protected int engineUpdate (ByteBuffer input, ByteBuffer output) + throws ShortBufferException + { + int total = 0; + byte[] inbuf = new byte[256]; + while (input.hasRemaining ()) + { + int in = Math.min (inbuf.length, input.remaining ()); + input.get (inbuf, 0, in); + byte[] outbuf = new byte[engineGetOutputSize (in)]; + int out = engineUpdate (inbuf, 0, in, outbuf, 0); + output.put (outbuf, 0, out); + total += out; + } + return total; + } + + /** * <p>Wrap a key.</p> * * <p>For compatibility this method is not declared diff --git a/libjava/classpath/javax/crypto/KeyGenerator.java b/libjava/classpath/javax/crypto/KeyGenerator.java index c3f4cee9f5c..e824c64522e 100644 --- a/libjava/classpath/javax/crypto/KeyGenerator.java +++ b/libjava/classpath/javax/crypto/KeyGenerator.java @@ -160,9 +160,11 @@ public class KeyGenerator { try { - return new KeyGenerator((KeyGeneratorSpi) + KeyGenerator instance = new KeyGenerator((KeyGeneratorSpi) Engine.getInstance(SERVICE, algorithm, provider), provider, algorithm); + instance.init(new SecureRandom()); + return instance; } catch (InvocationTargetException ite) { diff --git a/libjava/classpath/javax/imageio/ImageIO.java b/libjava/classpath/javax/imageio/ImageIO.java index 3ea7e858544..b2304a78304 100644 --- a/libjava/classpath/javax/imageio/ImageIO.java +++ b/libjava/classpath/javax/imageio/ImageIO.java @@ -1016,7 +1016,7 @@ public final class ImageIO * The image data will be cached in the current cache directory if * caching is enabled. * - * @param input an object to which to write image data + * @param output an object to which to write image data * * @return an ImageOutputStream that can send data to output, or * null diff --git a/libjava/classpath/javax/imageio/ImageWriteParam.java b/libjava/classpath/javax/imageio/ImageWriteParam.java index 1979957fef1..4d8efc37a74 100644 --- a/libjava/classpath/javax/imageio/ImageWriteParam.java +++ b/libjava/classpath/javax/imageio/ImageWriteParam.java @@ -103,7 +103,7 @@ public class ImageWriteParam extends IIOParam protected float compressionQuality; /** - * Contains the name of the available compression types. + * Contains the name of the current compression type. */ protected String compressionType; diff --git a/libjava/classpath/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java b/libjava/classpath/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java new file mode 100644 index 00000000000..c0567be7830 --- /dev/null +++ b/libjava/classpath/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java @@ -0,0 +1,280 @@ +/* JPEGHuffmanTable.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.imageio.plugins.jpeg; + +/** + * The JPEGHuffmanTable class represents a Huffman table read from a + * JPEG image file. The standard JPEG AC and DC chrominance and + * luminance values are provided as static fields. + */ +public class JPEGHuffmanTable +{ + /** + * Huffman code lengths. + */ + private short[] lengths; + + /** + * Huffman values. + */ + private short[] values; + + // The private constructors are used for these final fields to avoid + // unnecessary copying. + /** + * The standard JPEG AC chrominance Huffman table. + */ + public static final JPEGHuffmanTable StdACChrominance = + new JPEGHuffmanTable(new short[] { 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, + 4, 4, 0, 1, 2, 0x77 }, + new short[] { 0x00, 0x01, 0x02, 0x03, 0x11, + 0x04, 0x05, 0x21, 0x31, 0x06, + 0x12, 0x41, 0x51, 0x07, 0x61, + 0x71, 0x13, 0x22, 0x32, 0x81, + 0x08, 0x14, 0x42, 0x91, 0xa1, + 0xb1, 0xc1, 0x09, 0x23, 0x33, + 0x52, 0xf0, 0x15, 0x62, 0x72, + 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, + 0x19, 0x1a, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59, 0x5a, 0x63, + 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, + 0x82, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x92, + 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, + 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, + 0xd7, 0xd8, 0xd9, 0xda, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xf2, 0xf3, + 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }, false); + + /** + * The standard JPEG AC luminance Huffman table. + */ + public static final JPEGHuffmanTable StdACLuminance = + new JPEGHuffmanTable(new short[] { 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, + 4, 4, 0, 0, 1, 0x7d }, + new short[] { 0x01, 0x02, 0x03, 0x00, 0x04, + 0x11, 0x05, 0x12, 0x21, 0x31, + 0x41, 0x06, 0x13, 0x51, 0x61, + 0x07, 0x22, 0x71, 0x14, 0x32, + 0x81, 0x91, 0xa1, 0x08, 0x23, + 0x42, 0xb1, 0xc1, 0x15, 0x52, + 0xd1, 0xf0, 0x24, 0x33, 0x62, + 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, + 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x63, 0x64, + 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x79, 0x7a, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8a, 0x92, 0x93, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, + 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, + 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xd2, 0xd3, + 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xe1, 0xe2, 0xe3, + 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, + 0xe9, 0xea, 0xf1, 0xf2, 0xf3, + 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }, false); + + /** + * The standard JPEG DC chrominance Huffman table. + */ + public static final JPEGHuffmanTable StdDCChrominance = + new JPEGHuffmanTable(new short[] { 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0 }, + new short[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11 }, false); + + /** + * The standard JPEG DC luminance Huffman table. + */ + public static final JPEGHuffmanTable StdDCLuminance = + new JPEGHuffmanTable(new short[] { 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0 }, + new short[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11 }, false); + + /** + * Construct and initialize a Huffman table. Copies are created of + * the array arguments. lengths[index] stores the number of Huffman + * values with Huffman codes of length index + 1. The values array + * stores the Huffman values in order of increasing code length. + * + * @param lengths an array of Huffman code lengths + * @param values a sorted array of Huffman values + * @throws IllegalArgumentException if either parameter is null, if + * lengths.length > 16 or values.length > 256, if any value in + * length or values is negative, or if the parameters do not + * describe a valid Huffman table + */ + public JPEGHuffmanTable(short[] lengths, short[] values) + { + // Create copies of the lengths and values arguments. + this(checkLengths(lengths), checkValues(values, lengths), true); + } + + /** + * Private constructor that avoids unnecessary copying and argument + * checking. + * + * @param lengths an array of Huffman code lengths + * @param values a sorted array of Huffman values + * @param copy true if copies should be created of the given arrays + */ + private JPEGHuffmanTable(short[] lengths, short[] values, boolean copy) + { + this.lengths = copy ? (short[]) lengths.clone() : lengths; + this.values = copy ? (short[]) values.clone() : values; + } + + private static short[] checkLengths(short[] lengths) + { + if (lengths == null || lengths.length > 16) + throw new IllegalArgumentException("invalid length array"); + + for (int i = 0; i < lengths.length; i++) + { + if (lengths[i] < 0) + throw new IllegalArgumentException("negative length"); + } + + int sum = 0; + for (int i = 0; i < lengths.length; i++) + { + if (lengths[i] > ((1 << (i + 1)) - 1)) + throw new IllegalArgumentException("invalid number of codes" + + " for code length " + (i + 1)); + sum += lengths[i]; + } + + return lengths; + } + + private static short[] checkValues(short[] values, short[] lengths) + { + if (values == null || values.length > 256) + throw new IllegalArgumentException("invalid values array"); + + for (int i = 0; i < values.length; i++) + { + if (values[i] < 0) + throw new IllegalArgumentException("negative value"); + } + // lengths is known-valid by this point. + int sum = 0; + for (int i = 0; i < lengths.length; i++) + sum += lengths[i]; + + if (values.length != sum) + throw new IllegalArgumentException("invalid number of values" + + " for number of codes"); + + return values; + } + + /** + * Retrieve a copy of the array of Huffman code lengths. If the + * returned array is called lengthcount, there are + * lengthcount[index] codes of length index + 1. + * + * @return a copy of the array of Huffman code lengths + */ + public short[] getLengths() + { + return (short[]) lengths.clone(); + } + + /** + * Retrieve a copy of the array of Huffman values, sorted in order + * of increasing code length. + * + * @return a copy of the array of Huffman values + */ + public short[] getValues() + { + return (short[]) values.clone(); + } + + /** + * Create a string representation of this JPEG Huffman table. + * + * @return a string representation of this JPEG Huffman table. + */ + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + buffer.append("JPEGHuffmanTable:\nlengths:"); + + for (int i = 0; i < lengths.length; i++) + buffer.append(" " + lengths[i]); + + buffer.append("\nvalues:"); + + for (int i = 0; i < values.length; i++) + buffer.append(" " + values[i]); + + return buffer.toString(); + } +} diff --git a/libjava/classpath/javax/imageio/plugins/jpeg/JPEGImageReadParam.java b/libjava/classpath/javax/imageio/plugins/jpeg/JPEGImageReadParam.java new file mode 100644 index 00000000000..b570922f99a --- /dev/null +++ b/libjava/classpath/javax/imageio/plugins/jpeg/JPEGImageReadParam.java @@ -0,0 +1,161 @@ +/* JPEGImageReadParam.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.imageio.plugins.jpeg; + +import javax.imageio.ImageReadParam; + +/** + * The JPEGImageReadParam class is only used to set JPEG decoding + * tables for streams that do not provide their own tables. If a + * stream does not provide tables and a custom JPEGImageReadParam is + * not provided, then the standard JPEG tables are used from the + * JPEGQTable and JPEGHuffmanTable classes. If a stream does provide + * decoding tables then JPEGImageReadParam will be ignored. + * JPEGImageReadParam cannot be used to retrieve the tables from a + * stream. Instead, use IIOMetadata for this purpose. + * + * A JPEGImageReadParam instance is retrieved from the built-in JPEG + * ImageReader using the getDefaultImageReadParam method. + */ +public class JPEGImageReadParam + extends ImageReadParam +{ + private JPEGQTable[] qTables; + private JPEGHuffmanTable[] DCHuffmanTables; + private JPEGHuffmanTable[] ACHuffmanTables; + + /** + * Construct a JPEGImageReadParam. + */ + public JPEGImageReadParam() + { + super(); + } + + /** + * Check if the decoding tables are set. + * + * @return true if the decoding tables are set, false otherwise + */ + public boolean areTablesSet() + { + // If qTables is not null then all tables are set. + return (qTables != null); + } + + /** + * Set the quantization and Huffman tables that will be used to + * decode the stream. Copies are created of the array arguments. + * The number of Huffman tables must be the same in both Huffman + * table arrays. No argument may be null and no array may be longer + * than four elements. + * + * @param qTables JPEG quantization tables + * @param DCHuffmanTables JPEG DC Huffman tables + * @param ACHuffmanTables JPEG AC Huffman tables + * + * @throws IllegalArgumentException if any argument is null, if any + * of the arrays are longer than four elements, or if the Huffman + * table arrays do not have the same number of elements + */ + public void setDecodeTables(JPEGQTable[] qTables, + JPEGHuffmanTable[] DCHuffmanTables, + JPEGHuffmanTable[] ACHuffmanTables) + { + if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) + throw new IllegalArgumentException("null argument"); + + if (qTables.length > 4 || DCHuffmanTables.length > 4 + || ACHuffmanTables.length > 4) + throw new IllegalArgumentException("argument has too many elements"); + + if (DCHuffmanTables.length != ACHuffmanTables.length) + throw new IllegalArgumentException("Huffman table arrays differ in length"); + + // Do a shallow copy. JPEGQTable's data is not directly + // modifyable since JPEGQTable.getTable returns a copy. Therefore + // it is safe to have multiple references to a single JPEGQTable. + // Likewise for JPEGHuffmanTable. + this.qTables = (JPEGQTable[]) qTables.clone(); + this.DCHuffmanTables = (JPEGHuffmanTable[]) DCHuffmanTables.clone(); + this.ACHuffmanTables = (JPEGHuffmanTable[]) ACHuffmanTables.clone(); + } + + /** + * Clear the quantization and Huffman decoding tables. + */ + public void unsetDecodeTables() + { + qTables = null; + DCHuffmanTables = null; + ACHuffmanTables = null; + } + + /** + * Retrieve the quantization tables. + * + * @returns an array of JPEG quantization tables + */ + public JPEGQTable[] getQTables() + { + return qTables == null ? qTables : (JPEGQTable[]) qTables.clone(); + } + + /** + * Retrieve the DC Huffman tables. + * + * @return an array of JPEG DC Huffman tables + */ + public JPEGHuffmanTable[] getDCHuffmanTables() + { + return DCHuffmanTables == null ? DCHuffmanTables + : (JPEGHuffmanTable[]) DCHuffmanTables.clone(); + } + + /** + * Retrieve the AC Huffman tables. + * + * @return an array of JPEG AC Huffman tables + */ + public JPEGHuffmanTable[] getACHuffmanTables() + { + return ACHuffmanTables == null ? ACHuffmanTables + : (JPEGHuffmanTable[]) ACHuffmanTables.clone(); + } +} diff --git a/libjava/classpath/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java b/libjava/classpath/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java new file mode 100644 index 00000000000..1e7989e82db --- /dev/null +++ b/libjava/classpath/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java @@ -0,0 +1,293 @@ +/* JPEGImageWriteParam.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.imageio.plugins.jpeg; + +import java.util.Locale; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import javax.imageio.ImageWriteParam; + +/** + * The JPEGImageWriteParam class can be used to specify tables and + * settings used in the JPEG encoding process. Encoding tables are + * taken from the metadata associated with the output stream, and + * failing that (if the metadata tables are null) from an instance of + * JPEGImageWriteParam. The default metadata uses the standard JPEG + * tables from the JPEGQTable and JPEGHuffmanTable classes. Non-null + * metadata tables override JPEGImageWriteParam tables. Compression + * settings range from 1.0, best compression, through 0.75, default + * compression, to 0.0, worst compression. + * + * A JPEGImageWriteParam instance is retrieved from the built-in JPEG + * ImageWriter using the getDefaultImageWriteParam method. + */ +public class JPEGImageWriteParam + extends ImageWriteParam +{ + private JPEGQTable[] qTables; + private JPEGHuffmanTable[] DCHuffmanTables; + private JPEGHuffmanTable[] ACHuffmanTables; + private boolean optimize; + private String[] compressionQualityDescriptions; + private float[] compressionQualityValues; + + /** + * Localized messages are stored in separate files. + */ + private ResourceBundle messages; + + /** + * Construct a JPEGImageWriteParam with the following state: tiling + * is not supported, progressive mode is supported, initial + * progressive mode is MODE_DISABLED, compression is supported, one + * compression type named "JPEG" is supported and the default + * compression quality is 0.75f. Compression type names and + * compression quality descriptions are localized to the given + * locale. + * + * @param locale the locale used for message localization + */ + public JPEGImageWriteParam(Locale locale) + { + super(locale); + + // Get localized compression type and compression quality + // description strings for the given locale. + messages = PropertyResourceBundle.getBundle + ("javax/imageio/plugins/jpeg/MessagesBundle", locale); + + // Initialize inherited ImageWriter fields. + canWriteTiles = false; + canWriteProgressive = true; + progressiveMode = MODE_DISABLED; + canWriteCompressed = true; + compressionTypes = new String[] + { + messages.getString("compression.types.jpeg") + }; + compressionType = compressionTypes[0]; + compressionQuality = 0.75f; + } + + /** + * Reset the compression quality to 0.75f. + */ + public void unsetCompression() + { + compressionQuality = 0.75f; + } + + /** + * Check if compression algorithm is lossless. JPEGImageWriteParam + * overrides this ImageWriteParam method to always return false + * since JPEG compression is inherently lossy. + * + * @return false + */ + public boolean isCompressionLossless() + { + return false; + } + + /** + * Retrieve an array of compression quality descriptions. These + * messages are localized using the locale provided upon + * construction. Each compression quality description in the + * returned array corresponds to the compression quality value at + * the same index in the array returned by + * getCompressionQualityValues. + * + * @return an array of strings each of which describes a compression + * quality value + */ + public String[] getCompressionQualityDescriptions() + { + // Make sure exceptions are thrown when this image write param is + // in the wrong state. + super.getCompressionQualityDescriptions(); + + if (compressionQualityDescriptions == null) + { + compressionQualityDescriptions = new String[] + { + messages.getString("compression.minimum"), + messages.getString("compression.default"), + messages.getString("compression.maximum") + }; + } + + return compressionQualityDescriptions; + } + + /** + * Retrieve an array of compression quality values, ordered from + * lowest quality to highest quality. + * + * @return an array of compressions quality values + */ + public float[] getCompressionQualityValues() + { + // Make sure exceptions are thrown when this image write param is + // in the wrong state. + super.getCompressionQualityValues(); + + if (compressionQualityValues == null) + compressionQualityValues = new float[] { 0.05f, 0.75f, 0.95f }; + + return compressionQualityValues; + } + + /** + * Check if the encoding tables are set. + * + * @return true if the encoding tables are set, false otherwise + */ + public boolean areTablesSet() + { + // If qTables is not null then all tables are set. + return (qTables != null); + } + + /** + * Set the quantization and Huffman tables that will be used to + * encode the stream. Copies are created of the array arguments. + * The number of Huffman tables must be the same in both Huffman + * table arrays. No argument may be null and no array may be longer + * than four elements. + * + * @param qTables JPEG quantization tables + * @param DCHuffmanTables JPEG DC Huffman tables + * @param ACHuffmanTables JPEG AC Huffman tables + * + * @throws IllegalArgumentException if any argument is null, if any + * of the arrays are longer than four elements, or if the Huffman + * table arrays do not have the same number of elements + */ + public void setEncodeTables(JPEGQTable[] qTables, + JPEGHuffmanTable[] DCHuffmanTables, + JPEGHuffmanTable[] ACHuffmanTables) + { + if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) + throw new IllegalArgumentException("null argument"); + + if (qTables.length > 4 || DCHuffmanTables.length > 4 + || ACHuffmanTables.length > 4) + throw new IllegalArgumentException("argument has too many elements"); + + if (DCHuffmanTables.length != ACHuffmanTables.length) + throw new IllegalArgumentException("Huffman table arrays differ in length"); + + // Do a shallow copy. JPEGQTable's data is not directly + // modifyable since JPEGQTable.getTable returns a copy. Therefore + // it is safe to have multiple references to a single JPEGQTable. + // Likewise for JPEGHuffmanTable. + this.qTables = (JPEGQTable[]) qTables.clone(); + this.DCHuffmanTables = (JPEGHuffmanTable[]) DCHuffmanTables.clone(); + this.ACHuffmanTables = (JPEGHuffmanTable[]) ACHuffmanTables.clone(); + } + + /** + * Clear the quantization and Huffman encoding tables. + */ + public void unsetEncodeTables() + { + qTables = null; + DCHuffmanTables = null; + ACHuffmanTables = null; + } + + /** + * Retrieve the quantization tables. + * + * @returns an array of JPEG quantization tables + */ + public JPEGQTable[] getQTables() + { + return qTables == null ? qTables : (JPEGQTable[]) qTables.clone(); + } + + /** + * Retrieve the DC Huffman tables. + * + * @return an array of JPEG DC Huffman tables + */ + public JPEGHuffmanTable[] getDCHuffmanTables() + { + return DCHuffmanTables == null ? DCHuffmanTables + : (JPEGHuffmanTable[]) DCHuffmanTables.clone(); + } + + /** + * Retrieve the AC Huffman tables. + * + * @return an array of JPEG AC Huffman tables + */ + public JPEGHuffmanTable[] getACHuffmanTables() + { + return ACHuffmanTables == null ? ACHuffmanTables + : (JPEGHuffmanTable[]) ACHuffmanTables.clone(); + } + + /** + * Specify whether or not Huffman tables written to the output + * stream should be optimized. Every image encoded with this flag + * set will contain a Huffman table, and the generated Huffman + * tables will override those specified in the metadata. + * + * @param optimize true to generate optimized Huffman tables, false + * otherwise + */ + public void setOptimizeHuffmanTables(boolean optimize) + { + this.optimize = optimize; + } + + /** + * Check whether or not Huffman tables written to the output stream + * will be optimized. Unless otherwise set using + * setOptimizeHuffmanTables, this returns false. + * + * @return true Huffman tables written to the output stream will be + * optimized, false otherwise + */ + public boolean getOptimizeHuffmanTables() + { + return optimize; + } +} diff --git a/libjava/classpath/javax/imageio/plugins/jpeg/JPEGQTable.java b/libjava/classpath/javax/imageio/plugins/jpeg/JPEGQTable.java new file mode 100644 index 00000000000..a94e8b1880d --- /dev/null +++ b/libjava/classpath/javax/imageio/plugins/jpeg/JPEGQTable.java @@ -0,0 +1,196 @@ +/* JPEGQTable.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.imageio.plugins.jpeg; + +/** + * The JPEGQTable class represents a quantization table that can be + * used to encode or decode a JPEG stream. The standard JPEG + * luminance and chrominance quantization tables are provided as + * static fields. Table entries are stored in natural order, not + * zig-zag order. + */ +public class JPEGQTable +{ + /** + * The table entries, stored in natural order. + */ + private int[] table; + + /** + * The standard JPEG luminance quantization table. Values are + * stored in natural order. + */ + public static final JPEGQTable K1Luminance = new JPEGQTable(new int[] + { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 + }, false); + + /** + * The standard JPEG luminance quantization table, scaled by + * one-half. Values are stored in natural order. + */ + public static final JPEGQTable K1Div2Luminance = + K1Luminance.getScaledInstance(0.5f, true); + + /** + * The standard JPEG chrominance quantization table. Values are + * stored in natural order. + */ + public static final JPEGQTable K2Chrominance = new JPEGQTable(new int[] + { + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 + }, false); + + /** + * The standard JPEG chrominance quantization table, scaled by + * one-half. Values are stored in natural order. + */ + public static final JPEGQTable K2Div2Chrominance = + K2Chrominance.getScaledInstance(0.5f, true); + + /** + * Construct a new JPEG quantization table. A copy is created of + * the table argument. + * + * @param table the 64-element value table, stored in natural order + * + * @throws IllegalArgumentException if the table is null or if + * table's length is not equal to 64. + */ + public JPEGQTable(int[] table) + { + this(checkTable(table), true); + } + + /** + * Private constructor that avoids unnecessary copying and argument + * checking. + * + * @param table the 64-element value table, stored in natural order + * @param copy true if a copy should be created of the given table + */ + private JPEGQTable(int[] table, boolean copy) + { + this.table = copy ? (int[]) table.clone() : table; + } + + private static int[] checkTable(int[] table) + { + if (table == null || table.length != 64) + throw new IllegalArgumentException("invalid JPEG quantization table"); + + return table; + } + + /** + * Retrieve a copy of the quantization values for this table. + * + * @return a copy of the quantization value array + */ + public int[] getTable() + { + return (int[]) table.clone(); + } + + /** + * Retrieve a copy of this JPEG quantization table with every value + * scaled by the given scale factor, and clamped from 1 to 255 + * baseline or from 1 to 32767 otherwise. + * + * @param scaleFactor the factor by which to scale this table + * @param forceBaseline clamp scaled values to a maximum of 255 if + * true, 32767 if false + * + * @return a new scaled JPEG quantization table + */ + public JPEGQTable getScaledInstance(float scaleFactor, + boolean forceBaseline) + { + int[] scaledTable = getTable(); + int max = forceBaseline ? 255 : 32767; + + for (int i = 0; i < scaledTable.length; i++) + { + scaledTable[i] = Math.round (scaleFactor * (float) scaledTable[i]); + if (scaledTable[i] < 1) + scaledTable[i] = 1; + else if (scaledTable[i] > max) + scaledTable[i] = max; + } + + // Do not copy scaledTable. It is already a copy because we used + // getTable to retrieve it. + return new JPEGQTable(scaledTable, false); + } + + /** + * Create a string representing this JPEG quantization table. + */ + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + buffer.append("JPEGQTable:\n"); + for (int i = 0; i < 8; i++) + { + buffer.append(" "); + for (int j = 0; j < 8; j++) + { + buffer.append(table[i * 8 + j] + " "); + } + buffer.append("\n"); + } + + return buffer.toString(); + } +} diff --git a/libjava/classpath/javax/imageio/stream/FileCacheImageOutputStream.java b/libjava/classpath/javax/imageio/stream/FileCacheImageOutputStream.java index 16cd0a7a95e..ae655983436 100644 --- a/libjava/classpath/javax/imageio/stream/FileCacheImageOutputStream.java +++ b/libjava/classpath/javax/imageio/stream/FileCacheImageOutputStream.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.imageio.stream; +import gnu.classpath.NotImplementedException; + import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -92,14 +94,14 @@ public class FileCacheImageOutputStream extends ImageOutputStreamImpl } public int read() - throws IOException + throws IOException, NotImplementedException { // FIXME: Implement me. throw new Error("not implemented"); } public int read(byte[] data, int offset, int len) - throws IOException + throws IOException, NotImplementedException { // FIXME: Implement me. throw new Error("not implemented"); diff --git a/libjava/classpath/javax/imageio/stream/ImageInputStreamImpl.java b/libjava/classpath/javax/imageio/stream/ImageInputStreamImpl.java index 0967fee467a..c1a5dd404bc 100644 --- a/libjava/classpath/javax/imageio/stream/ImageInputStreamImpl.java +++ b/libjava/classpath/javax/imageio/stream/ImageInputStreamImpl.java @@ -55,7 +55,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream byte[] buffer = new byte[8]; protected int bitOffset; - protected ByteOrder byteOrder; + protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN; protected long flushedPos; protected long streamPos; diff --git a/libjava/classpath/javax/imageio/stream/ImageOutputStream.java b/libjava/classpath/javax/imageio/stream/ImageOutputStream.java index 49a1bcf33be..4688ad9351f 100644 --- a/libjava/classpath/javax/imageio/stream/ImageOutputStream.java +++ b/libjava/classpath/javax/imageio/stream/ImageOutputStream.java @@ -54,7 +54,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { /** - * @param postion + * @param position * * @throws IOException if an errror occurs */ diff --git a/libjava/classpath/javax/imageio/stream/ImageOutputStreamImpl.java b/libjava/classpath/javax/imageio/stream/ImageOutputStreamImpl.java index c708a2368d7..1179fed7dcd 100644 --- a/libjava/classpath/javax/imageio/stream/ImageOutputStreamImpl.java +++ b/libjava/classpath/javax/imageio/stream/ImageOutputStreamImpl.java @@ -38,7 +38,10 @@ exception statement from your version. */ package javax.imageio.stream; +import gnu.classpath.NotImplementedException; + import java.io.IOException; +import java.io.UTFDataFormatException; import java.nio.ByteOrder; /** @@ -52,8 +55,8 @@ public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl // Do nothing here. } - protected void flushBits() - throws IOException + protected final void flushBits() + throws IOException, NotImplementedException { // FIXME: Implement me. throw new Error("not implemented"); @@ -72,14 +75,14 @@ public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl throws IOException; public void writeBit(int bit) - throws IOException + throws IOException, NotImplementedException { // FIXME: Implement me. throw new Error("not implemented"); } public void writeBits(long bits, int numBits) - throws IOException + throws IOException, NotImplementedException { // FIXME: Implement me. throw new Error("not implemented"); @@ -100,13 +103,17 @@ public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl public void writeBytes(String data) throws IOException { - write(data.getBytes()); + // This is bogus, but it is how the method is specified. + // Sun ought to deprecate this method. + int len = data.length(); + for (int i = 0; i < len; ++i) + writeByte(data.charAt(i)); } public void writeChar(int value) throws IOException { - writeShort((short) value); + writeShort(value); } public void writeChars(char[] data, int offset, int len) @@ -119,14 +126,15 @@ public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl public void writeChars(String data) throws IOException { - // FIXME: Implement me. - throw new Error("not implemented"); + int len = data.length(); + for (int i = 0; i < len; ++i) + writeChar(data.charAt(i)); } public void writeDouble(double value) throws IOException { - writeLong((long) value); + writeLong(Double.doubleToLongBits(value)); } public void writeDoubles(double[] data, int offset, int len) @@ -139,7 +147,7 @@ public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl public void writeFloat(float value) throws IOException { - writeInt((int) value); + writeInt(Float.floatToIntBits(value)); } public void writeFloats(float[] data, int offset, int len) @@ -237,9 +245,52 @@ public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl writeShort(data[offset + i]); } - public void writeUTF(String data) + public void writeUTF(String value) throws IOException { - throw new Error("not implemented"); + // NOTE: this code comes directly from DataOutputStream. + int len = value.length(); + int sum = 0; + + for (int i = 0; i < len && sum <= 65535; ++i) + { + char c = value.charAt(i); + if (c >= '\u0001' && c <= '\u007f') + sum += 1; + else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff')) + sum += 2; + else + sum += 3; + } + + if (sum > 65535) + throw new UTFDataFormatException (); + + int pos = 0; + byte[] buf = new byte[sum]; + + for (int i = 0; i < len; ++i) + { + char c = value.charAt(i); + if (c >= '\u0001' && c <= '\u007f') + buf[pos++] = (byte) c; + else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff')) + { + buf[pos++] = (byte) (0xc0 | (0x1f & (c >> 6))); + buf[pos++] = (byte) (0x80 | (0x3f & c)); + } + else + { + // JSL says the first byte should be or'd with 0xc0, but + // that is a typo. Unicode says 0xe0, and that is what is + // consistent with DataInputStream. + buf[pos++] = (byte) (0xe0 | (0x0f & (c >> 12))); + buf[pos++] = (byte) (0x80 | (0x3f & (c >> 6))); + buf[pos++] = (byte) (0x80 | (0x3f & c)); + } + } + + writeShort (sum); + write(buf, 0, sum); } } diff --git a/libjava/classpath/javax/imageio/stream/MemoryCacheImageInputStream.java b/libjava/classpath/javax/imageio/stream/MemoryCacheImageInputStream.java index 3d9f6184697..935408c9a00 100644 --- a/libjava/classpath/javax/imageio/stream/MemoryCacheImageInputStream.java +++ b/libjava/classpath/javax/imageio/stream/MemoryCacheImageInputStream.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.imageio.stream; +import gnu.classpath.NotImplementedException; + import java.io.IOException; import java.io.InputStream; @@ -61,7 +63,7 @@ public class MemoryCacheImageInputStream extends ImageInputStreamImpl } public void flushBefore(long position) - throws IOException + throws IOException, NotImplementedException { // FIXME: Implement me. throw new Error("not implemented"); diff --git a/libjava/classpath/javax/imageio/stream/MemoryCacheImageOutputStream.java b/libjava/classpath/javax/imageio/stream/MemoryCacheImageOutputStream.java index 8914c3305df..17039f544e7 100644 --- a/libjava/classpath/javax/imageio/stream/MemoryCacheImageOutputStream.java +++ b/libjava/classpath/javax/imageio/stream/MemoryCacheImageOutputStream.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.imageio.stream; +import gnu.classpath.NotImplementedException; + import java.io.IOException; import java.io.OutputStream; @@ -61,7 +63,7 @@ public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl } public void flushBefore(long position) - throws IOException + throws IOException, NotImplementedException { // FIXME: Implement me. throw new Error("not implemented"); @@ -83,14 +85,14 @@ public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl } public int read() - throws IOException + throws IOException, NotImplementedException { // FIXME: Implement me. throw new Error("not implemented"); } public int read (byte[] data, int offset, int len) - throws IOException + throws IOException, NotImplementedException { // FIXME: Implement me. throw new Error("not implemented"); diff --git a/libjava/classpath/javax/naming/Binding.java b/libjava/classpath/javax/naming/Binding.java index 9d6608ababe..a34f8b3292c 100644 --- a/libjava/classpath/javax/naming/Binding.java +++ b/libjava/classpath/javax/naming/Binding.java @@ -39,31 +39,73 @@ exception statement from your version. */ package javax.naming; /** + * <code>Binding</code> represents the name-object mapping of a + * binding in a context. + * <p> + * Bindings are mappings of a name to an object and this class is used to + * specify such mappings. The bindings of a context are retrieved by the + * <code>Context#listBindings()</code> methods. + * </p> + * * @author Tom Tromey (tromey@redhat.com) - * @date May 16, 2001 + * @since 1.3 */ public class Binding extends NameClassPair { private static final long serialVersionUID = 8839217842691845890L; + /** + * Constructs an instance with the given name and object. + * + * @param name the name of the binding relative to the target context + * (may not be <code>null</code>) + * @param obj the bound object + */ public Binding (String name, Object obj) { super (name, null); boundObj = obj; } + /** + * Constructs an instance with the given name and object and a + * flag indicating if the name is relative to the target context. + * + * @param name the name of the binding relative to the target context + * (may not be <code>null</code>) + * @param obj the bound object + * @param isRelative flag indicating if the name is relative or not + */ public Binding (String name, Object obj, boolean isRelative) { super (name, null, isRelative); boundObj = obj; } + /** + * Constructs an instance with the given name, classname and object. + * + * @param name the name of the binding relative to the target context + * (may not be <code>null</code>) + * @param className the classname to set (maybe <code>null</code>) + * @param obj the bound object + */ public Binding (String name, String className, Object obj) { super (name, className); boundObj = obj; } + /** + * Constructs an instance with the given name, classname, object and a + * flag indicating if the name is relative to the target context. + * + * @param name the name of the binding relative to the target context + * (may not be <code>null</code>) + * @param className the classname to set (maybe <code>null</code>) + * @param isRelative flag indicating if the name is relative or not + * @param obj the bound object + */ public Binding (String name, String className, Object obj, boolean isRelative) { @@ -71,6 +113,15 @@ public class Binding extends NameClassPair boundObj = obj; } + /** + * Returns the classname of the bound object. + * <p> + * Returns the classname if set explicitly. If not and the bound object is + * not <code>null</code> the classname of the bound object is used. + * </p> + * + * @return The fully qualified classname (may be <code>null</code>). + */ public String getClassName () { String r = super.getClassName (); @@ -79,16 +130,29 @@ public class Binding extends NameClassPair return boundObj == null ? null : boundObj.getClass ().getName (); } + /** + * Returns the bound object of this binding. + * @return The bound object (maybe <code>null</code>). + */ public Object getObject () { return boundObj; } + /** + * Sets the bound object of this binding. + * @param obj the bound object. + */ public void setObject (Object obj) { boundObj = obj; } + /** + * Returns the string representation. + * @return The string as given by the NameClassPair superclass plus + * the bound objects string representation seperated by a colon. + */ public String toString () { // Format specified by the documentation. diff --git a/libjava/classpath/javax/naming/CompositeName.java b/libjava/classpath/javax/naming/CompositeName.java index 61adcf177a6..6f3466ca23c 100644 --- a/libjava/classpath/javax/naming/CompositeName.java +++ b/libjava/classpath/javax/naming/CompositeName.java @@ -1,5 +1,5 @@ /* CompositeName.java -- - Copyright (C) 2001, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,9 @@ exception statement from your version. */ package javax.naming; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Enumeration; import java.util.NoSuchElementException; @@ -45,10 +48,6 @@ import java.util.Vector; /** * @author Tom Tromey (tromey@redhat.com) - * @date May 16, 2001 - * - * FIXME: must write readObject and writeObject to conform to - * serialization spec. */ public class CompositeName implements Name, Cloneable, Serializable { @@ -316,6 +315,22 @@ public class CompositeName implements Name, Cloneable, Serializable } return result.toString (); } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + int size = s.readInt(); + elts = new Vector(size); + for (int i = 0; i < size; i++) + elts.add(s.readObject()); + } + + private void writeObject(ObjectOutputStream s) throws IOException + { + s.writeInt(elts.size()); + for (int i = 0; i < elts.size(); i++) + s.writeObject(elts.get(i)); + } private transient Vector elts; } diff --git a/libjava/classpath/javax/naming/NameClassPair.java b/libjava/classpath/javax/naming/NameClassPair.java index 127730af4ef..7925d45d8b7 100644 --- a/libjava/classpath/javax/naming/NameClassPair.java +++ b/libjava/classpath/javax/naming/NameClassPair.java @@ -41,18 +41,43 @@ package javax.naming; import java.io.Serializable; /** + * <code>NameClassPair</code> represents the name-classname mapping pair + * of a binding in a context. + * <p> + * Bindings are mappings of a name to an object and this class is used to + * specify the mapping of the name to the class type of the bound object. + * As classname the fully qualified classname is used. + * </p> + * * @author Tom Tromey (tromey@redhat.com) - * @date May 16, 2001 + * @since 1.3 */ public class NameClassPair implements Serializable { private static final long serialVersionUID = 5620776610160863339L; + /** + * Constructs an instance with the given name and classname. + * + * @param name the name of the binding relative to the target context + * (may not be <code>null</code>) + * @param className the name of the class. If <code>null</code> the bound + * object is also <code>null</code> + */ public NameClassPair (String name, String className) { this (name, className, true); } + /** + * Constructs an instance with the given name and classname and a + * flag indicating if the name is relative to the target context. + * + * @param name the name of the binding (may not be <code>null</code>) + * @param className the name of the class. If <code>null</code> the bound + * object is also <code>null</code> + * @param isRelative flag indicating if the name is relative or not + */ public NameClassPair (String name, String className, boolean isRelative) { this.name = name; @@ -60,36 +85,105 @@ public class NameClassPair implements Serializable this.isRel = isRelative; } + /** + * Returns the classname of the binding. + * @return The fully qualified classname or <code>null</code> if the + * bound object is null. + */ public String getClassName () { return className; } + /** + * Returns the name of the binding. + * @return The name. + */ public String getName () { return name; } + /** + * Checks whether the name is relative to the target context or not. + * @return <code>true</code> if the name is relative, + * <code>false</code> otherwise. + */ public boolean isRelative () { return isRel; } + /** + * Sets the classname of the bound object. + * @param name the classname to set (maybe <code>null</code>) + */ public void setClassName (String name) { this.className = name; } + /** + * Sets the name of the binding. + * @param name the name to set + */ public void setName (String name) { this.name = name; } + /** + * Sets if the name is relative to the target context. + * @param r <code>true</code> to mark as relative + */ public void setRelative (boolean r) { this.isRel = r; } + + /** + * Sets the full name for this binding. Setting the full name by this + * method is the only way to initialize full names of bindings if + * supported by a specific naming system. + * + * @param fullName the full name of this binding. If not set or set to + * <code>null</code> the <code>getNameInNamespace()</code> method will + * throw an exception + * + * @see #getNameInNamespace() + * + * @since 1.5 + */ + public void setNameInNamespace(String fullName) + { + this.fullName = fullName; + } + + /** + * Returns the full name for this binding. The full name of a binding is + * defined as the absolute name in its own namespace and is not valid + * outside. + * + * @return The full name in the bindings namespace. + * @throws UnsupportedOperationException if no full name is applicable in + * the specific naming system. + * + * @see Context#getNameInNamespace() + * + * @since 1.5 + */ + public String getNameInNamespace() + { + if (this.fullName == null) + throw new UnsupportedOperationException(); + + return this.fullName; + } + /** + * Returns the string representation. + * @return The string <code>getName() + ":" + getClassName()</code>. + */ public String toString () { // Specified by class documentation. @@ -100,4 +194,5 @@ public class NameClassPair implements Serializable private String name; private String className; private boolean isRel; + private String fullName; } diff --git a/libjava/classpath/javax/naming/directory/BasicAttribute.java b/libjava/classpath/javax/naming/directory/BasicAttribute.java index 047036585e4..c6419794f10 100644 --- a/libjava/classpath/javax/naming/directory/BasicAttribute.java +++ b/libjava/classpath/javax/naming/directory/BasicAttribute.java @@ -1,5 +1,5 @@ /* BasicAttribute.java -- - Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,9 @@ exception statement from your version. */ package javax.naming.directory; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.NoSuchElementException; import java.util.Vector; @@ -48,6 +51,7 @@ import javax.naming.OperationNotSupportedException; /** * @author Tom Tromey (tromey@redhat.com) * @date June 20, 2001 + * @since 1.3 */ public class BasicAttribute implements Attribute { @@ -297,11 +301,29 @@ public class BasicAttribute implements Attribute return one.equals (two); } + + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + int size = s.readInt(); + values = new Vector(size); + for (int i=0; i < size; i++) + values.add(s.readObject()); + } + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + s.writeInt(values.size()); + for (int i=0; i < values.size(); i++) + s.writeObject(values.get(i)); + } + // Used when enumerating this attribute. private class BasicAttributeEnumeration implements NamingEnumeration { - int where = -1; + int where = 0; public BasicAttributeEnumeration () { @@ -328,10 +350,9 @@ public class BasicAttribute implements Attribute public Object nextElement () throws NoSuchElementException { - if (where + 1 >= values.size ()) + if (where == values.size ()) throw new NoSuchElementException ("no more elements"); - ++where; - return values.get (where); + return values.get (where++); } } } diff --git a/libjava/classpath/javax/naming/directory/BasicAttributes.java b/libjava/classpath/javax/naming/directory/BasicAttributes.java index 37ec195771e..9318fbb2be7 100644 --- a/libjava/classpath/javax/naming/directory/BasicAttributes.java +++ b/libjava/classpath/javax/naming/directory/BasicAttributes.java @@ -1,5 +1,5 @@ /* BasicAttributes.java -- - Copyright (C) 2000, 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,9 @@ exception statement from your version. */ package javax.naming.directory; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.NoSuchElementException; import java.util.Vector; @@ -196,6 +199,24 @@ public class BasicAttributes implements Attributes // Package-private to avoid a trampoline. transient Vector attributes; + private void readObject(ObjectInputStream s) throws IOException, + ClassNotFoundException + { + s.defaultReadObject(); + int size = s.readInt(); + attributes = new Vector(size); + for (int i = 0; i < size; i++) + attributes.add(s.readObject()); + } + + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + s.writeInt(attributes.size()); + for (int i = 0; i < attributes.size(); i++) + s.writeObject(attributes.get(i)); + } + // Used when enumerating. private class BasicAttributesEnumeration implements NamingEnumeration { diff --git a/libjava/classpath/javax/naming/ldap/StartTlsRequest.java b/libjava/classpath/javax/naming/ldap/StartTlsRequest.java new file mode 100644 index 00000000000..b0a30b54f20 --- /dev/null +++ b/libjava/classpath/javax/naming/ldap/StartTlsRequest.java @@ -0,0 +1,108 @@ +/* StartTlsRequest.java -- extended ldap TLS request + 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.naming.ldap; + +import java.util.Iterator; + +import gnu.classpath.ServiceFactory; + +import javax.naming.NamingException; + +/** + * @since 1.4 + */ +public class StartTlsRequest + implements ExtendedRequest +{ + private static final long serialVersionUID = 4441679576360753397L; + + /** + * The assigned object identifier for this response. + */ + public static final String OID = "1.3.6.1.4.1.1466.20037"; + + /** + * Create a new instance. + */ + public StartTlsRequest() + { + } + + /** + * Return the response identifier. This is simply the value + * of the {@link #OID} field. + */ + public String getID() + { + return OID; + } + + /** + * Return the encoded value. This implementation always returns null. + */ + public byte[] getEncodedValue() + { + return null; + } + + /** + * Create a new extended reponse object, using the standard service + * provider approach to load a provider. The provider will be a subclass + * of StartTlsRequest with a no-argument constructor. The key is + * "javax.naming.ldap.StartTlsRequest". + * @param id the identifier, must be {@link #OID} or null + * @param berValue ignored + * @param offset ignored + * @param length ignored + * @throws NamingException if there is a problem creating the response + */ + public ExtendedResponse createExtendedResponse(String id, byte[] berValue, + int offset, int length) + throws NamingException + { + if (id != null && ! OID.equals(id)) + throw new NamingException("incorrect id: was \"" + id + + "\", but expected: \"" + OID + "\""); + Iterator it = ServiceFactory.lookupProviders(StartTlsRequest.class); + if (it.hasNext()) + return (ExtendedResponse) it.next(); + throw new NamingException("couldn't find provider for " + + "javax.naming.ldap.StartTlsRequest"); + } +} diff --git a/libjava/classpath/javax/naming/ldap/StartTlsResponse.java b/libjava/classpath/javax/naming/ldap/StartTlsResponse.java new file mode 100644 index 00000000000..68cd5bf86b0 --- /dev/null +++ b/libjava/classpath/javax/naming/ldap/StartTlsResponse.java @@ -0,0 +1,119 @@ +/* StartTlsResponse.java -- extended ldap TLS response + 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.naming.ldap; + +import java.io.IOException; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; + +/** + * @since 1.4 + */ +public abstract class StartTlsResponse + implements ExtendedResponse +{ + private static final long serialVersionUID = 8372842182579276418L; + + /** + * The assigned object identifier for this response. + */ + public static final String OID = "1.3.6.1.4.1.1466.20037"; + + /** + * Create a new instance. + */ + protected StartTlsResponse() + { + } + + /** + * Return the response identifier. This is simply the value + * of the {@link #OID} field. + */ + public String getID() + { + return OID; + } + + /** + * Return the encoded value. This implementation always returns null. + */ + public byte[] getEncodedValue() + { + return null; + } + + /** + * Set the list of cipher suites to use. + * @param cipherSuites the list of suites + * @see SSLSocketFactory#getSupportedCipherSuites() + */ + public abstract void setEnabledCipherSuites(String[] cipherSuites); + + /** + * Set the hostname verifier to use. This must be called before + * {@link #negotiate()}. + * @param verifier the hostname verifier + */ + public abstract void setHostnameVerifier(HostnameVerifier verifier); + + /** + * Negotiate the TLS session using the default SSL socket factory. + * @return the SSL session + * @throws IOException if communication fails for some reason + */ + public abstract SSLSession negotiate() throws IOException; + + /** + * Negotiate the TLS session using the supplied SSL socket factory. + * @param factory the socket factory to use + * @return the SSL session + * @throws IOException if communication fails for some reason + */ + public abstract SSLSession negotiate(SSLSocketFactory factory) + throws IOException; + + /** + * Close the connection. + * @throws IOException if communication fails for some reason + */ + public abstract void close() throws IOException; +} diff --git a/libjava/classpath/javax/net/ssl/HttpsURLConnection.java b/libjava/classpath/javax/net/ssl/HttpsURLConnection.java index 4c73edbcd2e..3f30dc1b800 100644 --- a/libjava/classpath/javax/net/ssl/HttpsURLConnection.java +++ b/libjava/classpath/javax/net/ssl/HttpsURLConnection.java @@ -1,5 +1,5 @@ /* HttpsURLConnection.java -- an HTTPS connection. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,7 +38,6 @@ exception statement from your version. */ package javax.net.ssl; -import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.security.cert.Certificate; @@ -90,9 +89,10 @@ public abstract class HttpsURLConnection extends HttpURLConnection * Creates a new HTTPS URL connection. * * @param url The URL of the connection being established. - * @throws IOException If the connection cannot be established. + * @specnote This was marked as throwing IOException in 1.4, + * but this was removed in 1.5. */ - protected HttpsURLConnection(URL url) throws IOException + protected HttpsURLConnection(URL url) { super(url); } diff --git a/libjava/classpath/javax/print/MultiDoc.java b/libjava/classpath/javax/print/MultiDoc.java index e7747bca7f8..6e9ec841f3a 100644 --- a/libjava/classpath/javax/print/MultiDoc.java +++ b/libjava/classpath/javax/print/MultiDoc.java @@ -1,5 +1,5 @@ /* MultiDoc.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,25 @@ import java.io.IOException; /** + * <code>MultiDoc</code> defines the interface for objects providing multiple + * documents for use in a print job. + * <p> + * Implementations of this interface are used to pass multiple documents, to be + * printed as one print job, to the <code>MultiDocPrintJob</code> instance. + * </p><p> + * There exists no implementation of this interface in the Java Print Service + * API. Implementors may assume the following usage in print jobs and the needed + * behaviour for implementations: The print job fetches the single documents via + * iteration by consecutive calls of the {@link #getDoc()} method to obtain the + * current document follwing calls of the {@link #next()} method to get the next + * multidoc object for the next <code>getDoc()</code> method call (if returned + * multidoc object is not <code>null</code>). The print service will fetch the + * document object and then retrieve the print data from the document before it + * proceeds with the next call for the next MultiDoc object in the sequence. + * </p><p> + * Implementations of this interface have to be multiple thread-safe. + * </p> + * * @author Michael Koch (konqueror@gmx.de) */ public interface MultiDoc @@ -49,16 +68,18 @@ public interface MultiDoc /** * Returns the current document. * - * @return the current document + * @return The current document. * * @throws IOException if an error occurs */ Doc getDoc() throws IOException; /** - * Returns the next <code>MultiDoc</code> object. + * Returns the next <code>MultiDoc</code> object that contains the + * next document for retrieval. * - * @return the next <code>MultiDoc</code> object + * @return The next <code>MultiDoc</code> object, or <code>null</code> + * if no more documents are available. * * @throws IOException if an error occurs */ diff --git a/libjava/classpath/javax/print/MultiDocPrintJob.java b/libjava/classpath/javax/print/MultiDocPrintJob.java index b096769b05a..36089b5d070 100644 --- a/libjava/classpath/javax/print/MultiDocPrintJob.java +++ b/libjava/classpath/javax/print/MultiDocPrintJob.java @@ -1,5 +1,5 @@ /* MultiDocPrintJob.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,17 +42,34 @@ import javax.print.attribute.PrintRequestAttributeSet; /** + * <code>MultiDocPrintJob</code> represents a print job which supports + * printing of multiple documents as one print job. + * <p> + * An instance can be obtained from every <code>MultiDocPrintService</code> + * available by calling the + * {@link javax.print.MultiDocPrintService#createMultiDocPrintJob()} method. + * A print job is bound to the print service it is created from. + * </p> + * * @author Michael Koch (konqueror@gmx.de) */ public interface MultiDocPrintJob extends DocPrintJob { /** - * Request a print of a <code>MultiDoc</code> object. + * Prints the documents supplied in the given <code>MultiDoc</code> object + * as one print job with the given printing attributes. * - * @param multiDoc the document to print - * @param attributes the printing attributes to apply + * @param multiDoc the documents to print. Every document must have a + * flavor supported by the bound print service. + * @param attributes the printing attributes to apply to the print job. If + * <code>null</code> the default attribute values will be used. * - * @throws PrintExeption if an error occurs + * @throws PrintException if an error occurs. The thrown exception may + * implement refining print exception interface to provide more detail of + * the error. + * + * @see FlavorException + * @see AttributeException */ void print(MultiDoc multiDoc, PrintRequestAttributeSet attributes) throws PrintException; diff --git a/libjava/classpath/javax/print/MultiDocPrintService.java b/libjava/classpath/javax/print/MultiDocPrintService.java index a71d23a28b1..105e7221005 100644 --- a/libjava/classpath/javax/print/MultiDocPrintService.java +++ b/libjava/classpath/javax/print/MultiDocPrintService.java @@ -1,5 +1,5 @@ /* MultiDocPrintService.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,6 +40,13 @@ package javax.print; /** + * <code>MultiDocPrintService</code> represents print services that are + * capable of printing multiple documents as one print job. It provides an + * additional method for the creation of a print job for multiple documents. + * + * @see javax.print.MultiDoc + * @see javax.print.MultiDocPrintJob + * * @author Michael Koch (konqueror@gmx.de) */ public interface MultiDocPrintService extends PrintService @@ -47,7 +54,7 @@ public interface MultiDocPrintService extends PrintService /** * Create a job that can print a <code>MultiDoc</code> object. * - * @return the new print job + * @return The created print job. */ MultiDocPrintJob createMultiDocPrintJob(); }
\ No newline at end of file diff --git a/libjava/classpath/javax/print/PrintServiceLookup.java b/libjava/classpath/javax/print/PrintServiceLookup.java index 2add8d1a6f7..57cb8dc9ffa 100644 --- a/libjava/classpath/javax/print/PrintServiceLookup.java +++ b/libjava/classpath/javax/print/PrintServiceLookup.java @@ -1,5 +1,5 @@ /* PrintServiceLookup.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,39 +38,266 @@ exception statement from your version. */ package javax.print; +import gnu.classpath.ServiceFactory; +import gnu.javax.print.CupsPrintServiceLookup; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; + import javax.print.attribute.AttributeSet; /** + * <code>PrintServiceLookup</code> implementations provide a way to lookup + * print services based on different constraints. + * <p> + * Implementations are located and loaded automatically through the SPI JAR + * file specification. Therefore implementation classes must provide a default + * constructor for instantiation. Furthermore, applications are able to + * register further instances directly at runtime. + * </p><p> + * If an SecurityManager is installed implementors should call + * <code>checkPrintJobAccess()</code> to disable access for untrusted code. + * This check is to be made in every lookup service implementation for + * flexibility. Print services registered by applications through + * <code>registerService(PrintService)</code> are suppressed in the + * lookup results if a security manager is installed and disallows access. + * </p> + * * @author Michael Koch (konqueror@gmx.de) + * @author Wolfgang Baer (WBaer@gmx.de) */ public abstract class PrintServiceLookup { + + private static final CupsPrintServiceLookup systemProvider; + private static final HashSet printServices; + private static final HashSet printServiceLookups; + + static + { + systemProvider = new CupsPrintServiceLookup(); + + printServices = new HashSet(); + printServiceLookups = new HashSet(); + + // check for service providers + Iterator it = ServiceFactory.lookupProviders(PrintServiceLookup.class); + + while (it.hasNext()) + printServiceLookups.add(it.next()); + } + /** * Constructs a <code>PrintServiceLookup</code> object. */ public PrintServiceLookup() { - // Do nothing here + // nothing to do here + } + + /** + * Explicitly registers the provided print service lookup implementation. + * <p> + * The registration will silently fail (returning <code>false</code>) if + * the lookup service is already registered or the registration somehow + * else fails. + * </p> + * + * @param sp the print service lookup implementation to register. + * @return <code>true</code> if registered, <code>false</code> otherwise. + */ + public static boolean registerServiceProvider(PrintServiceLookup sp) + { + return printServiceLookups.add(sp); + } + + /** + * Explicitly registers the provided print service instance. + * <p> + * The registration will silently fail (returning <code>false</code>) if + * the print service instance is already registered or the registration + * somehow else fails. + * </p> + * @param service the single print service to register. + * @return <code>true</code> if registered, <code>false</code> otherwise. + */ + public static boolean registerService(PrintService service) + { + if (service instanceof StreamPrintService) + return false; + + // security + try + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + + return printServices.add(service); + } + catch (SecurityException se) + { + return false; + } + } + + /** + * Searches print services capable of printing in the given document flavor + * which supports the specified printing attributes. + * + * @param flavor the document flavor to support. If <code>null</code> this + * constraint is ignored during lookup. + * @param attributes the printing attributes to support. If + * <code>null</code> this constraint is ignored during lookup. + * @return The resulting available print services, or an array of length 0 + * if none is found. + */ + public static final PrintService[] lookupPrintServices(DocFlavor flavor, + AttributeSet attributes) + { + ArrayList result = new ArrayList(); + + PrintService[] services = + systemProvider.getPrintServices(flavor, attributes); + result.addAll(Arrays.asList(services)); + + for (Iterator it = printServiceLookups.iterator(); it.hasNext(); ) + { + PrintServiceLookup lookup = (PrintServiceLookup) it.next(); + services = lookup.getPrintServices(flavor, attributes); + result.addAll(Arrays.asList(services)); + } + + for (Iterator it = printServices.iterator(); it.hasNext(); ) + { + PrintService service = (PrintService) it.next(); + if (systemProvider.checkPrintService(flavor, attributes, service)) + result.add(service); + } + + return (PrintService[]) result.toArray(new PrintService[result.size()]); + } + + /** + * Searches print services capable of multi document printing in all of the + * given document flavors and supporting the specified printing attributes. + * + * @param flavors the document flavors to support. If <code>null</code> this + * constraint is ignored during lookup. + * @param attributes the printing attributes to support. If + * <code>null</code> this constraint is ignored during lookup. + * @return The resulting available multi document print services, or an + * array of length 0 if none is found. + */ + public static final MultiDocPrintService[] lookupMultiDocPrintServices( + DocFlavor[] flavors, AttributeSet attributes) + { + ArrayList result = new ArrayList(); + + MultiDocPrintService[] services = + systemProvider.getMultiDocPrintServices(flavors, attributes); + result.addAll(Arrays.asList(services)); + + for (Iterator it = printServiceLookups.iterator(); it.hasNext(); ) + { + PrintServiceLookup lookup = (PrintServiceLookup) it.next(); + services = lookup.getMultiDocPrintServices(flavors, attributes); + result.addAll(Arrays.asList(services)); + } + + for (Iterator it = printServices.iterator(); it.hasNext(); ) + { + PrintService service = (PrintService) it.next(); + if (systemProvider.checkMultiDocPrintService(flavors, attributes, service)) + result.add(service); + } + + return (MultiDocPrintService[]) result.toArray( + new MultiDocPrintService[result.size()]); + } + + + /** + * Searches the default print service in the current environment. + * <p> + * If multiple lookup services are registered and each has a default + * print service the result is not specified. Usually the default + * print service of the native platform lookup service is returned. + * </p><p> + * The GNU classpath implementation will return the CUPS default + * printing service as the default print service, if available. + * </p><p> + * The default print service may be overriden by users through + * the property <code>javax.print.defaultPrinter</code>. A service + * specified must be found to be returned as the default. + * </p> + * + * @return The default print service, or <code>null</code> if none found. + */ + public static final PrintService lookupDefaultPrintService() + { + // TODO Find out what the property controls and use it + // String defaultPrinter = System.getProperty("javax.print.defaultPrinter"); + + // first test for platform specified default services + PrintService service = systemProvider.getDefaultPrintService(); + + if (service != null) + return service; + + // none available by systemDefaultProvider + // search in other registered ones and take first + for (Iterator it = printServiceLookups.iterator(); it.hasNext(); ) + { + service = ((PrintServiceLookup) it.next()).getDefaultPrintService(); + if (service != null) + return service; + } + + return null; } /** - * Not called direclty by applications. + * Not to be called directly by applications. + * + * @return The default lookup service of the implementing lookup service or + * <code>null</code> if there is no default one. */ public abstract PrintService getDefaultPrintService(); /** - * Not called direclty by applications. + * Not to be called directly by applications. + * + * @param flavors the document flavors which have to be supported. + * @param attributes the attributes which have to be supported. + * + * @return The multidoc print services of the implementing lookup service + * for the given parameters, or an array of length 0 if none is available. */ - public abstract MultiDocPrintService[] getMultiDocPrintServices(DocFlavor[] flavors, AttributeSet attributes); + public abstract MultiDocPrintService[] + getMultiDocPrintServices(DocFlavor[] flavors, AttributeSet attributes); /** - * Not called direclty by applications. + * Not to be called directly by applications. + * + * @return All known print services of the implementing lookup service + * regardless of supported features, or an array of length 0 if none is + * available. */ public abstract PrintService[] getPrintServices(); /** - * Not called direclty by applications. + * Not to be called directly by applications. + * + * @param flavor the document flavor which has to be supported. + * @param attributes the attributes which have to be supported. + * + * @return The print services of the implementing lookup service + * for the given parameters, or an array of length 0 if none is available. */ - public abstract PrintService[] getPrintServices(DocFlavor flavor, AttributeSet attributes); + public abstract PrintService[] + getPrintServices(DocFlavor flavor, AttributeSet attributes); } diff --git a/libjava/classpath/javax/print/ServiceUI.java b/libjava/classpath/javax/print/ServiceUI.java new file mode 100644 index 00000000000..4a7b5bd4a4e --- /dev/null +++ b/libjava/classpath/javax/print/ServiceUI.java @@ -0,0 +1,137 @@ +/* ServiceUI.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.print; + +import gnu.javax.print.PrinterDialog; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.util.Arrays; + +import javax.print.attribute.PrintRequestAttributeSet; + +/** + * <code>ServiceUI</code> provides a method to create a graphical + * print dialog. + * <p> + * The graphical print dialog enables the user to browse the available + * print services on the system. It provides user interfaces to interact + * with the most common printing attributes likes specifying the number of + * copies to print or the page ranges. + * </p><p> + * The initial appearance of the print dialog as shown to the user may be + * specified by providing the default selected print service as well as + * initial values for the printing attributes in the user interface. + * </p> + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class ServiceUI +{ + + /** + * Default constructor. + */ + public ServiceUI() + { + // nothing to do here - only one static method + } + + /** + * Creates a modal graphical printing dialog at the specified location on + * the screen. + * <p> + * The dialog will return the user selected print service and the given + * attributes set will contain the modified printing attributes. If the + * user cancels the printing dialog <code>null</code> will be returned and + * the printing attributes set will be unmodified. + * </p><p> + * The values of the given attributes set (if not empty) will be displayed + * initially unless the are unsupported by the print service. If a print + * service does not support a particular value it is substituted with the + * default value of the print service. + * </p> + * + * @param gc the screen to use. <code>null</code> is default screen. + * @param x the coordinate of the upper left edge of the dialog in screen + * coordinates (not relative to the parent frame). + * @param y the coordinate of the upper left edge of the dialog in screen + * coordinates (not relative to the parent frame). + * @param services the print services to browse (not null). + * @param defaultService the default service. If <code>null</code> + * the first of the print services in the services array will be used. + * @param flavor the flavours to be printed. + * @param attributes the attributes requested. Will be updated + * by selections done by the user in the dialog. + * + * @return The selected print service or <code>null</code> if user + * has cancelled the printer dialog. + * + * @throws HeadlessException if GraphicsEnvironment is headless + * @throws IllegalArgumentException if services is <code>null</code> or an + * empty array, attributes are <code>null</code> or the given default + * <code>PrintService<code> is not part of the print service array. + */ + public static PrintService printDialog(GraphicsConfiguration gc, int x, + int y, PrintService[] services, PrintService defaultService, + DocFlavor flavor, PrintRequestAttributeSet attributes) + throws HeadlessException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException("GraphicsEnvironment is headless."); + + if (services == null || services.length == 0 || attributes == null) + throw new IllegalArgumentException("Given print service array / " + + "attributes may not be null"); + + if (defaultService != null && + ! Arrays.asList(services).contains(defaultService)) + throw new IllegalArgumentException("defaultService is not contained " + + " in the print service array"); + + PrinterDialog dialog = new PrinterDialog(gc, services, defaultService, + flavor, attributes); + + dialog.setLocation(x, y); + dialog.show(); + + return dialog.getSelectedPrintService(); + } +} diff --git a/libjava/classpath/javax/print/attribute/package.html b/libjava/classpath/javax/print/attribute/package.html index 37f24d56b47..0ab01ab1bfe 100644 --- a/libjava/classpath/javax/print/attribute/package.html +++ b/libjava/classpath/javax/print/attribute/package.html @@ -1,6 +1,6 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <!-- package.html - describes classes in javax.print.attribute package. - Copyright (C) 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,6 +43,35 @@ exception statement from your version. --> <p>Provides classes and interfaces describing the roles and syntax of attribute objects in the Java Print Service API.</p> <p> +The package contains the base attribute interface and several subinterfaces +describing the different attribute roles of printing attributes. Furthermore, +abstract classes defining the syntax of attributes are provided. For +collections of attributes based on their roles different set interfaces and +implementing classes are available. +</p><p> +Existing attribute roles are: +<ul> +<li><a href="PrintServiceAttribute.html">PrintServiceAttribute</a>s +describing the state and other informations of a PrintService.</li> +<li><a href="PrintJobAttribute.html">PrintJobAttribute</a>s describing +the state of the print job.</li> +<li><a href="PrintRequestAttribute.html">PrintRequestAttribute</a>s specifying +how a print job should be printed and are applied to a complete print job.</li> +<li><a href="PrintJobAttribute.html">PrintJobAttribute</a> s specifying +how a single document in the print job should be printed.</li> +</ul> +</p><p> +Every attribute is of a certain syntax which defines its type and the +representation of its value. The different syntax types are provided as +abstract syntax classes (e.g. <code>IntegerSyntax</code>). Concrete attribute +implementations are subclasses of these abstract syntax classes. +</p><p> +Attributes may be collected as sets of attributes. Different interfaces for +attribute collections per role and implementations based on a HashMap are +provided (for example <a href="HashPrintJobAttributeSet.html"> +HashPrintJobAttributeSet</a> for the print job attributes). +</p> +<p> <b>Since:</b> 1.4 </p> </body> diff --git a/libjava/classpath/javax/print/attribute/standard/package.html b/libjava/classpath/javax/print/attribute/standard/package.html index 4248acfcedc..f6bec5fb118 100644 --- a/libjava/classpath/javax/print/attribute/standard/package.html +++ b/libjava/classpath/javax/print/attribute/standard/package.html @@ -1,7 +1,7 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<!-- package.html - describes classes in javax.print.attribute.standard +<!-- package.html - describes classes in javax.print.attribute.standard package. - Copyright (C) 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,8 +41,18 @@ exception statement from your version. --> <head><title>GNU Classpath - javax.print.attribute.standard</title></head> <body> -<p>Provides the printing attribute classes of the Java Print -Service API.</p> +Provides the printing attribute classes of the Java Print Service API. +<p> +The package contains the available printing attributes. Some attributes are +used by the print service implementations to inform about the state of print +services and print jobs. Other attributes are needs to be provided by the +user/program to specify how a print job or a document in a print job should +be printed. +</p><p> +<b>Note:</b> Printing attributes can implement more than one attribute role +and therefore be used to specify e.g. print request attributes as well as +document attributes. +</p> <p> <b>Since:</b> 1.4 </p> diff --git a/libjava/classpath/javax/print/event/package.html b/libjava/classpath/javax/print/event/package.html index f811013d10d..5091a716fa0 100644 --- a/libjava/classpath/javax/print/event/package.html +++ b/libjava/classpath/javax/print/event/package.html @@ -1,6 +1,6 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <!-- package.html - describes classes in javax.print.event package. - Copyright (C) 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,7 +40,15 @@ exception statement from your version. --> <head><title>GNU Classpath - javax.print.event</title></head> <body> -<p>Provides events and listeners to be used with the Java Print Service API.</p> +Provides events and listeners to be used with the Java Print Service API. +<p> +The provided listeners are used to register with print services and/or +print jobs to receive state information or to monitor the progress of +print jobs. Print jobs don't need to be implemented synchronous and +therefore should be monitored to know if they succeed or fail. For this +common task the <a href="PrintJobAdapter.html">PrintJobAdapter</a> class +is provided. +</p> <p> <b>Since:</b> 1.4 </p> diff --git a/libjava/classpath/javax/print/package.html b/libjava/classpath/javax/print/package.html index dfa4b0f8d4b..7527432f2b6 100644 --- a/libjava/classpath/javax/print/package.html +++ b/libjava/classpath/javax/print/package.html @@ -1,6 +1,6 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <!-- package.html - describes classes in javax.print package. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,9 +38,203 @@ exception statement from your version. --> <html> <head><title>GNU Classpath - javax.print</title></head> - <body> -<p></p> +Provides the basic interfaces and classes of the Java Print Service API. +<p> +The Java Print Service API enables programmers to: +<ul> +<li>Discover print services for printing to printer devices and to output +streams. The discovery process can be constrained to return only print +services supporting specific document formats or printing attributes.</li> +<li>Print client-formatted print data like Postscript, PDF or various +image formats and service-formatted print data from Java.</li> +<li>Submit, cancel and monitor single and multi document print jobs.</li> +<li>Provide users a graphical print service browser with printing attribute +selection.</li> +</ul> +</p> +<p> +<h2>Print Service Discovery</h2> + +Print service types in the JPS API: +<ul> +<li><a href="PrintService.html">PrintService</a>:<br>The base interface +describing a print service capable of printing a supplied document for a +given document format to the printer device it is representing.</li><br> +<li><a href="MultiDocPrintService.html">MultiDocPrintService</a>:<br>Extends +the PrintService interface and provides a print service which is capable of +printing multiple documents as one print job to its printer device.</li><br> +<li><a href="StreamPrintService.html">StreamPrintService</a>:<br>Extends the +PrintService interface and provides a print service which is capable of +printing into a supplied output stream instead of to a physical printer +device.</li> +</ul> +</p> +<p> +<h4>PrintService, MultiDocPrintService</h4> +Discovery is done by the use of the static methods in the +<a href="PrintServiceLookup.html">PrintServiceLookup</a> class. The discovery +process can be constrained by supplying the document formats and printing +attributes that need to be supported by the returned print service. Furthermore +the <a href="PrintServiceLookup.html#lookupDefaultPrintService()"> +lookupDefaultPrintService()</a> method enables to lookup the default print +service of the platforms printing system. +</p> +<p> +<h4>StreamPrintService</h4> +StreamPrintService provides the same functionality as a print service for output +to a supplied <code>OutputStream</code>. Available stream print services are +discovered via the static methods in the <a href="StreamPrintServiceFactory.html"> +StreamPrintServiceFactory</a> factory. The query can be constrained by supplying +the the requested document format support and the needed output format. +</p> + +<h2>Document formats</h2> + +The format of the printing documents are specified by the +<a href="DocFlavor.html">DocFlavor</a> class in the JPS API. It provides the +description of the format in which the print data will be supplied in a print +job to the print service and consists of two parts: +<ul> +<li>The MIME type (Multipurpose Internet Mail Extensions types as described in +RFC 2045/2046) specifying the media format of the print data.</li> +<br> +<li>The representation class name which is the fully qualified name of the +class providing the print data to the print job. For example if the print data +is supplied as a byte array the representation class name will be "[B" or for +an input stream "java.io.InputStream".</li> +</ul> +The Java Print Service API differentiates between two types of print data, +client-formatted and service-formatted. Client-formatted print data is already +provided in a formatted representation by the client e.g. in an image format +or as postscript. For service-formatted print data, the Java Print Service +implementation produces the formatted print data. Here the doc flavor's +representation class name does specify an interface instead of the actual +print data source. The print service will call the methods of the given +implementation of this interface with a special Graphics object capable of +producing formatted print data from the graphics routines inside the +interface methods. +</ul> +<h2>Printing attributes</h2> + +Print services as well as print jobs report their state and capabilities +by the way of supplying printing attributes. Also the behaviour of print +jobs (like how many copies should be printed) is controlled via printing +attributes. For these requirements the JPS API defines different roles +of attributes and common syntax classes in the package +<code>javax.print.attribute</code>. The actual available printing attributes +are implemented in the <code>javax.print.attribute.standard</code> package. +<ul> + +<li>Print service attributes:<br> +These printing attributes of role +<a href="attribute/PrintServiceAttribute.html">PrintServiceAttribute</a> report +the status and other informations of a PrintService. Example for informations +available in the print services attributes are the attribute +<code>PagesPerMinute</code> providing the number of pages a printer can print +per minute. Status attributes like the <code>PrinterState</code> attribute +gives the current state (e.g. printer currently processes or is idle) of the +printer.</li> +<br> +<li>Print job attributes:<br> +Print job attributes of role <a href="attribute/PrintJobAttribute.html"> +PrintJobAttribute</a> inform about the status of given print job. For example +the <code>NumberOfInterveningJobs</code> attribute provides the number of jobs +ahead in the print service queue before this job. Status attributes like the +<code>JobState</code> attribute gives the current state of the print job (like +pending, processing or canceled).</li> +<br> +<li>Print request attributes:<br> +The attributes of role <a href="attribute/PrintRequestAttribute.html"> +PrintRequestAttribute</a> specify the behaviour of a complete print job. +The print request attributes apply to all documents in a print job, whereas +the doc attributes only apply to the specific document in a print job. +Most of the print request attributes are also doc attributes and therefore +implementing both attribute role interfaces. +</li> +<br> +<li>Doc attributes:<br> +As described above the <a href="attribute/PrintJobAttribute.html"> +PrintJobAttribute</a> attributes are specific to a single document in the +print job. +</li> +</ul> +<h2>Example of using the API</h2> +<pre> +import java.io.*; +<br> +import javax.print.*; +import javax.print.attribute.*; +import javax.print.attribute.standard.*; +import javax.print.event.*; +<br> +public class Beispiel +{ + public static void main(String[] args) + { + // Using the predefined doc flavor for postscript mimetype + DocFlavor flavor = DocFlavor.INPUT_STREAM.POSTSCRIPT; +<br> + // Looking for printservice supporting this doc flavor + PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, null); +<br> + // Just take the first + PrintService service = services[0]; + System.out.println("Name :" + service.getName()); +<br> + try + { + // Create a print job + DocPrintJob job = service.createPrintJob(); +<br> + // We want to print a file so we construct an inputstream + // on the file to supply the print data as given in the doc flavor + File file = new File("File.ps"); + InputStream stream = new FileInputStream(file); +<br> + // Build a attribute set with the wanted printing attributes + HashPrintRequestAttributeSet attr = new HashPrintRequestAttributeSet(); + attr.add(new Copies(2)); // two copies + attr.add(new PageRanges(2, 7)); // only the 2-7 pages +<br> + // Construct a doc object with the provided class SimpleDoc + SimpleDoc doc = new SimpleDoc(stream, flavor, null); +<br> + // register us as the print - use the adapter class + // and override the interesing failure condition + job.addPrintJobListener(new PrintJobAdapter() + { + public void printJobFailed(PrintJobEvent arg0) + { + System.out.println("The PrintJob failed."); + } + }); +<br> + // start the printing process + job.print(doc, attr); +<br> + // lets assume we want to cancel it + if (job instanceof CancelablePrintJob) + { + CancelablePrintJob cancelJob = (CancelablePrintJob) job; + cancelJob.cancel(); + } +<br> + } + catch (PrintException e) + { + e.printStackTrace(); + } + catch (FileNotFoundException e) + { + e.printStackTrace(); + } + } +} +</pre> +<p> +<b>Since:</b> 1.4 +</p> </body> </html> diff --git a/libjava/classpath/javax/security/auth/kerberos/DelegationPermission.java b/libjava/classpath/javax/security/auth/kerberos/DelegationPermission.java new file mode 100644 index 00000000000..33e1f9893b3 --- /dev/null +++ b/libjava/classpath/javax/security/auth/kerberos/DelegationPermission.java @@ -0,0 +1,136 @@ +/* DelegationPermission.java -- kerberos delegation permission + 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.security.auth.kerberos; + +import java.security.BasicPermission; +import java.security.Permission; +import java.security.PermissionCollection; +import java.util.Enumeration; +import java.util.Vector; + +/** + * @since 1.4 + */ +public final class DelegationPermission + extends BasicPermission +{ + // FIXME: Enable this when serialization works. + // private static final long serialVersionUID = 883133252142523922L; + + /** + * Create a new instance with the given name. + */ + public DelegationPermission(String name) + { + super(name); + checkSyntax(name); + } + + /** + * Create a new instance with the given name and actions. + * + * The name consists of two parts: first the subordinate + * service principal, then the target service principal. + * Each principal is surrounded by quotes; the two are separated + * by a space. + * + * @param name the name + * @param actions the actions; this is ignored + */ + public DelegationPermission(String name, String actions) + { + super(name, actions); + checkSyntax(name); + } + + private static void checkSyntax(String name) + { + int index = name.indexOf('"', 1); + int len = name.length(); + if (name.charAt(0) != '"' || name.charAt(len - 1) != '"' + || index == -1 || index + 3 >= len + || name.charAt(index + 1) != ' ' + || name.charAt(index + 2) != '"') + // FIXME: better message here. + throw new IllegalArgumentException("invalid syntax for principals"); + } + + public boolean implies(Permission perm) + { + return equals(perm); + } + + public PermissionCollection newPermissionCollection() + { + // FIXME: don't know how to serialize here. I suspect this + // class has to have a particular name, etc ... + return new PermissionCollection() + { + private Vector permissions = new Vector(); + + public void add(Permission perm) + { + if (isReadOnly()) + throw new SecurityException("readonly"); + if (! (perm instanceof DelegationPermission)) + throw new IllegalArgumentException("can only add DelegationPermissions"); + permissions.add(perm); + } + + public boolean implies(Permission perm) + { + if (! (perm instanceof DelegationPermission)) + return false; + Enumeration e = elements(); + while (e.hasMoreElements()) + { + DelegationPermission dp = (DelegationPermission) e.nextElement(); + if (dp.implies(perm)) + return true; + } + return false; + } + + public Enumeration elements() + { + return permissions.elements(); + } + }; + } +} diff --git a/libjava/classpath/javax/security/auth/kerberos/KerberosKey.java b/libjava/classpath/javax/security/auth/kerberos/KerberosKey.java new file mode 100644 index 00000000000..3372a162f93 --- /dev/null +++ b/libjava/classpath/javax/security/auth/kerberos/KerberosKey.java @@ -0,0 +1,180 @@ +/* KerberosKey.java -- kerberos key + 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.security.auth.kerberos; + +import gnu.classpath.NotImplementedException; + +import java.io.Serializable; + +import javax.crypto.SecretKey; +import javax.security.auth.DestroyFailedException; +import javax.security.auth.Destroyable; + +/** + * This class represents a Kerberos key. See the Kerberos + * authentication RFC for more information: + * <a href="http://www.ietf.org/rfc/rfc1510.txt">RFC 1510</a>. + * + * @since 1.4 + */ +public class KerberosKey + implements Serializable, SecretKey, Destroyable +{ + private static final long serialVersionUID = -4625402278148246993L; + + private KerberosPrincipal principal; + private int versionNum; + private KeyImpl key; + + /** + * Construct a new key with the indicated principal and key. + * @param principal the principal + * @param key the key's data + * @param type the key's type + * @param version the key's version number + */ + public KerberosKey(KerberosPrincipal principal, byte[] key, int type, + int version) + { + this.principal = principal; + this.versionNum = version; + this.key = new KeyImpl(key, type); + } + + /** + * Construct a new key with the indicated principal and a password. + * @param principal the principal + * @param passwd the password to use + * @param algo the algorithm; if null the "DES" algorithm is used + */ + public KerberosKey(KerberosPrincipal principal, char[] passwd, String algo) + // Not implemented because KeyImpl really does nothing here. + throws NotImplementedException + { + this.principal = principal; + this.versionNum = 0; // FIXME: correct? + this.key = new KeyImpl(passwd, algo); + } + + /** + * Return the name of the algorithm used to create this key. + */ + public final String getAlgorithm() + { + checkDestroyed(); + return key.algorithm; + } + + /** + * Return the format of this key. This implementation always returns "RAW". + */ + public final String getFormat() + { + checkDestroyed(); + // Silly, but specified. + return "RAW"; + } + + /** + * Return the principal associated with this key. + */ + public final KerberosPrincipal getPrincipal() + { + checkDestroyed(); + return principal; + } + + /** + * Return the type of this key. + */ + public final int getKeyType() + { + checkDestroyed(); + return key.type; + } + + /** + * Return the version number of this key. + */ + public final int getVersionNumber() + { + checkDestroyed(); + return versionNum; + } + + /** + * Return the encoded form of this key. + */ + public final byte[] getEncoded() + { + checkDestroyed(); + return (byte[]) key.key.clone(); + } + + /** + * Destroy this key. + */ + public void destroy() throws DestroyFailedException + { + if (key == null) + throw new DestroyFailedException("already destroyed"); + key = null; + } + + /** + * Return true if this key has been destroyed. After this has been + * called, other methods on this object will throw IllegalStateException. + */ + public boolean isDestroyed() + { + return key == null; + } + + private void checkDestroyed() + { + if (key == null) + throw new IllegalStateException("key is destroyed"); + } + + public String toString() + { + // FIXME: random choice here. + return principal + ":" + versionNum; + } +} diff --git a/libjava/classpath/javax/security/auth/kerberos/KerberosPrincipal.java b/libjava/classpath/javax/security/auth/kerberos/KerberosPrincipal.java new file mode 100644 index 00000000000..d52b5cf9e6c --- /dev/null +++ b/libjava/classpath/javax/security/auth/kerberos/KerberosPrincipal.java @@ -0,0 +1,207 @@ +/* KerberosPrincipal.java -- a kerberos principal + 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.security.auth.kerberos; + +import gnu.classpath.NotImplementedException; +import gnu.classpath.SystemProperties; + +import java.io.Serializable; +import java.security.Principal; + +/** + * This represents a Kerberos principal. See the Kerberos + * authentication RFC for more information: + * <a href="http://www.ietf.org/rfc/rfc1510.txt">RFC 1510</a>. + * + * @since 1.4 + */ +public final class KerberosPrincipal + implements Serializable, Principal +{ + // Uncomment when serialization is correct. + // private static final long serialVersionUID = -7374788026156829911L; + + /** + * Constant from the RFC: "Just the name of the principal as in DCE, or + * for users". + */ + public static final int KRB_NT_PRINCIPAL = 1; + + /** + * Constant from the RFC: "Service and other unique instance (krbtgt)". + */ + public static final int KRB_NT_SRV_HST = 3; + + /** + * Constant from the RFC: "Service with host name as instance (telnet, + * rcommands)". + */ + public static final int KRB_NT_SRV_INST = 2; + + /** + * Constant from the RFC: "Service with host as remaining components". + */ + public static final int KRB_NT_SRV_XHST = 4; + + /** + * Constant from the RFC: "Unique ID". + */ + public static final int KRB_NT_UID = 5; + + /** + * Constant from the RFC: "Name type not known". + */ + public static final int KRB_NT_UNKNOWN = 0; + + private String name; + private int type; + private String realm; + + /** + * Create a new instance with the given name and a type of + * {@link #KRB_NT_PRINCIPAL}. + * @param name the principal's name + */ + public KerberosPrincipal(String name) + { + this(name, KRB_NT_PRINCIPAL); + } + + /** + * Create a new instance with the given name and type. The name is + * parsed according to the rules in the RFC. If there is no realm, + * then the local realm is used instead. + * + * @param name the principal's name + * @param type the principal's type + */ + public KerberosPrincipal(String name, int type) + // Marked as unimplemented because we don't look for the realm as needed. + throws NotImplementedException + { + if (type < KRB_NT_UNKNOWN || type > KRB_NT_UID) + throw new IllegalArgumentException("unknown type: " + type); + this.name = name; + this.type = type; + this.realm = parseRealm(); + } + + private String parseRealm() + { + // Handle quoting as specified by the Kerberos RFC. + int i, len = name.length(); + boolean quoted = false; + for (i = 0; i < len; ++i) + { + if (quoted) + { + quoted = false; + continue; + } + char c = name.charAt(i); + if (c == '\\') + { + quoted = true; + continue; + } + if (c == '@') + break; + } + if (quoted || i == len - 1) + throw new IllegalArgumentException("malformed principal: " + name); + if (i < len) + { + // We have the realm. FIXME: verify its syntax? + return name.substring(i + 1); + } + // Try to find the default realm. + String def = SystemProperties.getProperty("java.security.krb5.realm"); + if (def != null) + return def; + // Now ask the system. + // FIXME: use java.security.krb5.conf, + // or $JAVA_HOME/lib/security/krb5.conf to find the krb config file. + // Then pass to native code using krb5_set_config_files() and + // krb5_get_default_realm(). But... what about /etc/krb5.conf? + throw new IllegalArgumentException("default realm can't be found"); + } + + /** + * Return the name of this principal. + */ + public String getName() + { + return name; + } + + /** + * Return the realm of this principal. + */ + public String getRealm() + { + return realm; + } + + /** + * Return the type of this principal. + */ + public int getNameType() + { + return type; + } + + public int hashCode() + { + return name.hashCode(); + } + + public boolean equals(Object other) + { + if (! (other instanceof KerberosPrincipal)) + return false; + KerberosPrincipal kp = (KerberosPrincipal) other; + return name.equals(kp.name) && type == kp.type; + } + + public String toString() + { + // This is what came to mind. + return name + ":" + type; + } +} diff --git a/libjava/classpath/javax/security/auth/kerberos/KerberosTicket.java b/libjava/classpath/javax/security/auth/kerberos/KerberosTicket.java new file mode 100644 index 00000000000..85e25374987 --- /dev/null +++ b/libjava/classpath/javax/security/auth/kerberos/KerberosTicket.java @@ -0,0 +1,339 @@ +/* KerberosTicket.java -- a kerberos ticket + 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.security.auth.kerberos; + +import gnu.classpath.NotImplementedException; + +import java.io.Serializable; +import java.net.InetAddress; +import java.util.Date; + +import javax.crypto.SecretKey; +import javax.security.auth.DestroyFailedException; +import javax.security.auth.Destroyable; +import javax.security.auth.RefreshFailedException; +import javax.security.auth.Refreshable; + +/** + * This class represents a Kerberos ticket. See the Kerberos + * authentication RFC for more information: + * <a href="http://www.ietf.org/rfc/rfc1510.txt">RFC 1510</a>. + * + * @since 1.4 + */ +public class KerberosTicket + implements Destroyable, Serializable, Refreshable +{ + private static final long serialVersionUID = 7395334370157380539L; + + // Indices of the various flags. From the kerberos spec. + // We only list the ones we use. + private static final int FORWARDABLE = 1; + private static final int FORWARDED = 2; + private static final int PROXIABLE = 3; + private static final int PROXY = 4; + private static final int POSTDATED = 6; + private static final int RENEWABLE = 8; + private static final int INITIAL = 9; + private static final int NUM_FLAGS = 12; + + private byte[] asn1Encoding; + private KeyImpl sessionKey; + private boolean[] flags; + private Date authTime; + private Date startTime; + private Date endTime; + private Date renewTill; + private KerberosPrincipal client; + private KerberosPrincipal server; + private InetAddress[] clientAddresses; + + /** + * Create a new ticket given all the facts about it. + * + * Note that flags may be null or "short"; any flags not specified + * will be taken to be false. + * + * If the key is not renewable, then renewTill may be null. + * + * If authTime is null, then it is taken to be the same as startTime. + * + * If clientAddresses is null, then the ticket can be used anywhere. + * + * @param asn1Encoding the contents of the ticket, as ASN1 + * @param client the client principal + * @param server the server principal + * @param key the contents of the session key + * @param type the type of the key + * @param flags an array of flags, as specified by the RFC + * @param authTime when the client was authenticated + * @param startTime starting time at which the ticket is valid + * @param endTime ending time, after which the ticket is invalid + * @param renewTill for a rewewable ticket, the time before which it must + * be renewed + * @param clientAddresses a possibly-null array of addresses where this + * ticket may be used + */ + public KerberosTicket(byte[] asn1Encoding, KerberosPrincipal client, + KerberosPrincipal server, byte[] key, int type, + boolean[] flags, Date authTime, Date startTime, + Date endTime, Date renewTill, + InetAddress[] clientAddresses) + { + this.asn1Encoding = (byte[]) asn1Encoding.clone(); + this.sessionKey = new KeyImpl(key, type); + this.flags = new boolean[NUM_FLAGS]; + if (flags != null) + System.arraycopy(flags, 0, this.flags, 0, + Math.min(flags.length, NUM_FLAGS)); + this.flags = (boolean[]) flags.clone(); + this.authTime = (Date) authTime.clone(); + this.startTime = (Date) ((startTime == null) + ? authTime : startTime).clone(); + this.endTime = (Date) endTime.clone(); + this.renewTill = (Date) renewTill.clone(); + this.client = client; + this.server = server; + this.clientAddresses = (clientAddresses == null + ? null + : (InetAddress[]) clientAddresses.clone()); + } + + /** + * Destroy this ticket. This discards secret information. After this + * method is called, other methods will throw IllegalStateException. + */ + public void destroy() throws DestroyFailedException + { + if (sessionKey == null) + throw new DestroyFailedException("already destroyed"); + sessionKey = null; + asn1Encoding = null; + } + + /** + * Return true if this ticket has been destroyed. + */ + public boolean isDestroyed() + { + return sessionKey == null; + } + + /** + * Return true if the ticket is currently valid. This is true if + * the system time is between the ticket's start and end times. + */ + public boolean isCurrent() + { + long now = System.currentTimeMillis(); + return startTime.getTime() <= now && now <= endTime.getTime(); + } + + /** + * If the ticket is renewable, and the renewal time has not yet elapsed, + * attempt to renew the ticket. + * @throws RefreshFailedException if the renewal fails for any reason + */ + public void refresh() throws RefreshFailedException, NotImplementedException + { + if (! isRenewable()) + throw new RefreshFailedException("not renewable"); + if (renewTill != null + && System.currentTimeMillis() >= renewTill.getTime()) + throw new RefreshFailedException("renewal time elapsed"); + // FIXME: must contact the KDC. + // Use the java.security.krb5.kdc property... + throw new RefreshFailedException("not implemented"); + } + + /** + * Return the client principal for this ticket. + */ + public final KerberosPrincipal getClient() + { + return client; + } + + /** + * Return the server principal for this ticket. + */ + public final KerberosPrincipal getServer() + { + return server; + } + + /** + * Return true if this ticket is forwardable. + */ + public final boolean isForwardable() + { + return flags[FORWARDABLE]; + } + + /** + * Return true if this ticket has been forwarded. + */ + public final boolean isForwarded() + { + return flags[FORWARDED]; + } + + /** + * Return true if this ticket is proxiable. + */ + public final boolean isProxiable() + { + return flags[PROXIABLE]; + } + + /** + * Return true if this ticket is a proxy ticket. + */ + public final boolean isProxy() + { + return flags[PROXY]; + } + + /** + * Return true if this ticket was post-dated. + */ + public final boolean isPostdated() + { + return flags[POSTDATED]; + } + + /** + * Return true if this ticket is renewable. + */ + public final boolean isRenewable() + { + return flags[RENEWABLE]; + } + + /** + * Return true if this ticket was granted by an application + * server, and not via a ticket-granting ticket. + */ + public final boolean isInitial() + { + return flags[INITIAL]; + } + + /** + * Return the flags for this ticket as a boolean array. + * See the RFC to understand what the different entries mean. + */ + public final boolean[] getFlags() + { + return (boolean[]) flags.clone(); + } + + /** + * Return the authentication time for this ticket. + */ + public final Date getAuthTime() + { + return (Date) authTime.clone(); + } + + /** + * Return the start time for this ticket. + */ + public final Date getStartTime() + { + return (Date) startTime.clone(); + } + + /** + * Return the end time for this ticket. + */ + public final Date getEndTime() + { + return (Date) endTime.clone(); + } + + /** + * Return the renewal time for this ticket. For a non-renewable + * ticket, this will return null. + */ + public final Date getRenewTill() + { + return flags[RENEWABLE] ? ((Date) renewTill.clone()) : null; + } + + /** + * Return the allowable client addresses for this ticket. This will + * return null if the ticket can be used anywhere. + */ + public final InetAddress[] getClientAddresses() + { + return (clientAddresses == null + ? null + : (InetAddress[]) clientAddresses.clone()); + } + + /** + * Return the encoded form of this ticket. + */ + public final byte[] getEncoded() + { + checkDestroyed(); + return (byte[]) sessionKey.key.clone(); + } + + /** + * Return the secret key associated with this ticket. + */ + public final SecretKey getSessionKey() + { + checkDestroyed(); + return sessionKey; + } + + private void checkDestroyed() + { + if (sessionKey == null) + throw new IllegalStateException("key is destroyed"); + } + + public String toString() + { + return "FIXME bob"; + } +} diff --git a/libjava/classpath/javax/security/auth/kerberos/KeyImpl.java b/libjava/classpath/javax/security/auth/kerberos/KeyImpl.java new file mode 100644 index 00000000000..6773dfa3e87 --- /dev/null +++ b/libjava/classpath/javax/security/auth/kerberos/KeyImpl.java @@ -0,0 +1,93 @@ +/* KeyImpl.java -- kerberos key implementation + 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.security.auth.kerberos; + +import java.io.Serializable; + +import javax.crypto.SecretKey; + +/** + * Note that the name of this class is fixed by the serialization + * spec, even though the class itself is not public. + */ +final class KeyImpl implements Serializable, SecretKey +{ + // Enable this when serialization works. + // private static final long serialVersionUID = -7889313790214321193L; + + public String algorithm; + public int type; + public byte[] key; + + public KeyImpl(byte[] key, int type) + { + // From kerberos spec. + if (type == 0) + this.algorithm = null; + else if (type == 1) + this.algorithm = "DES"; + else + this.algorithm = "FIXME"; + this.type = type; + this.key = (byte[]) key.clone(); + } + + public KeyImpl(char[] passwd, String algo) + { + this.algorithm = (algo == null) ? "DES" : algo; + this.type = 0; // FIXME + this.key = null; // double FIXME + } + + public String getAlgorithm() + { + return algorithm; + } + + public byte[] getEncoded() + { + return key; + } + + public String getFormat() + { + // FIXME. + return null; + } +} diff --git a/libjava/classpath/javax/security/auth/kerberos/ServicePermission.java b/libjava/classpath/javax/security/auth/kerberos/ServicePermission.java new file mode 100644 index 00000000000..452f8e966ad --- /dev/null +++ b/libjava/classpath/javax/security/auth/kerberos/ServicePermission.java @@ -0,0 +1,172 @@ +/* ServicePermission.java -- kerberos service permission + 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.security.auth.kerberos; + +import java.security.Permission; +import java.security.PermissionCollection; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * This represents permission to access to a Kerberos service principal. + * See the Kerberos authentication RFC for more information: + * <a href="http://www.ietf.org/rfc/rfc1510.txt">RFC 1510</a>. + * + * @since 1.4 + */ +public final class ServicePermission + extends Permission +{ + // FIXME: Enable this when serialization works. + // private static final long serialVersionUID = -1227585031618624935L; + + private static final int INITIATE = 1; + private static final int ACCEPT = 2; + + private int flags; + + /** + * Create a new service permission with the indicated name and actions. + * + * The name is the name of the kerberos principal for the service. + * + * The actions are a comma-separated list of strings. The recognized + * actions are "initiate" and "accept". The "initiate" action means + * that the holder of the permission can access the service. The + * "accept" action means that the holder of the permission can operate + * as this service. + * + * @param name the prinicpal's name + * @param action the allowed actions + */ + public ServicePermission(String name, String action) + { + super(name); + parseActions(action); + } + + public boolean implies(Permission perm) + { + if (! (perm instanceof ServicePermission)) + return false; + ServicePermission sp = (ServicePermission) perm; + if ((flags & sp.flags) != sp.flags) + return false; + return getName().equals(sp.getName()); + } + + public boolean equals(Object obj) + { + if (! (obj instanceof ServicePermission)) + return false; + ServicePermission sp = (ServicePermission) obj; + return flags == sp.flags && getName().equals(sp.getName()); + } + + public int hashCode() + { + return getName().hashCode() + flags; + } + + /** + * Return a string representing the actions. + */ + public String getActions() + { + if (flags == (INITIATE | ACCEPT)) + return "initiate,accept"; + if (flags == INITIATE) + return "initiate"; + if (flags == ACCEPT) + return "accept"; + return ""; + } + + public PermissionCollection newPermissionCollection() + { + return new PermissionCollection() + { + private Vector permissions = new Vector(); + + public void add(Permission perm) + { + if (isReadOnly()) + throw new SecurityException("readonly"); + if (! (perm instanceof ServicePermission)) + throw new IllegalArgumentException("can only add DelegationPermissions"); + permissions.add(perm); + } + + public boolean implies(Permission perm) + { + if (! (perm instanceof ServicePermission)) + return false; + Enumeration e = elements(); + while (e.hasMoreElements()) + { + ServicePermission sp = (ServicePermission) e.nextElement(); + if (sp.implies(perm)) + return true; + } + return false; + } + + public Enumeration elements() + { + return permissions.elements(); + } + }; + } + + private void parseActions(String actions) + { + StringTokenizer tok = new StringTokenizer(actions, ","); + while (tok.hasMoreTokens()) + { + String token = tok.nextToken(); + if ("accept".equals(token)) + flags |= ACCEPT; + else if ("initiate".equals(token)) + flags |= INITIATE; + else + throw new IllegalArgumentException("unrecognized token: " + token); + } + } +} diff --git a/libjava/classpath/javax/security/auth/x500/X500Principal.java b/libjava/classpath/javax/security/auth/x500/X500Principal.java index fcbb4950a39..d78b0d3eec4 100644 --- a/libjava/classpath/javax/security/auth/x500/X500Principal.java +++ b/libjava/classpath/javax/security/auth/x500/X500Principal.java @@ -395,7 +395,7 @@ public final class X500Principal implements Principal, Serializable buf.append((char) ch); } sep = in.read(); - if (sep != '+' || sep != ',') + if (sep != '+' && sep != ',') throw new IOException("illegal character: " + (char) ch); return buf.toString(); } diff --git a/libjava/classpath/javax/sound/midi/InvalidMidiDataException.java b/libjava/classpath/javax/sound/midi/InvalidMidiDataException.java index d7f770757a4..9f5690069d5 100644 --- a/libjava/classpath/javax/sound/midi/InvalidMidiDataException.java +++ b/libjava/classpath/javax/sound/midi/InvalidMidiDataException.java @@ -66,25 +66,4 @@ public class InvalidMidiDataException extends Exception { super(s); } - - /** - * Create an InvalidMidiDataException object. - * - * @param s the exception message string - * @param cause the root cause of the exception - */ - public InvalidMidiDataException(String s, Throwable cause) - { - super(s, cause); - } - - /** - * Create an InvalidMidiDataException object. - * - * @param cause the root cause of the exception - */ - public InvalidMidiDataException(Throwable cause) - { - super(cause); - } } diff --git a/libjava/classpath/javax/sound/midi/MetaMessage.java b/libjava/classpath/javax/sound/midi/MetaMessage.java index 2ca93accd77..f7c4fb4246a 100644 --- a/libjava/classpath/javax/sound/midi/MetaMessage.java +++ b/libjava/classpath/javax/sound/midi/MetaMessage.java @@ -76,7 +76,7 @@ public class MetaMessage extends MidiMessage * Create a MetaMessage object. * @param data a complete system exclusive message */ - public MetaMessage(byte[] data) + protected MetaMessage(byte[] data) { super(data); int index = 2; diff --git a/libjava/classpath/javax/sound/midi/MidiDevice.java b/libjava/classpath/javax/sound/midi/MidiDevice.java index 6f43c25481d..387cceac2d8 100644 --- a/libjava/classpath/javax/sound/midi/MidiDevice.java +++ b/libjava/classpath/javax/sound/midi/MidiDevice.java @@ -134,7 +134,7 @@ public interface MidiDevice * @param description the device description * @param version the device version string */ - public Info(String name, String vendor, String description, String version) + protected Info(String name, String vendor, String description, String version) { this.name = name; this.vendor = vendor; @@ -150,7 +150,7 @@ public interface MidiDevice * @return true if this is the same object * @see java.lang.Object#equals(java.lang.Object) */ - public boolean equals(Object obj) + public final boolean equals(Object obj) { return super.equals(obj); } @@ -161,7 +161,7 @@ public interface MidiDevice * @return the hash code for this object * @see java.lang.Object#hashCode() */ - public int hashCode() + public final int hashCode() { return super.hashCode(); } @@ -171,7 +171,7 @@ public interface MidiDevice * * @return the device name */ - public String getName() + public final String getName() { return name; } @@ -181,7 +181,7 @@ public interface MidiDevice * * @return the device vendor */ - public String getVendor() + public final String getVendor() { return vendor; } @@ -191,7 +191,7 @@ public interface MidiDevice * * @return the device description */ - public String getDescription() + public final String getDescription() { return description; } @@ -201,7 +201,7 @@ public interface MidiDevice * * @return the device version */ - public String getVersion() + public final String getVersion() { return version; } @@ -212,7 +212,7 @@ public interface MidiDevice * @return the device name * @see java.lang.Object#toString() */ - public String toString() + public final String toString() { return name; } diff --git a/libjava/classpath/javax/sound/midi/MidiSystem.java b/libjava/classpath/javax/sound/midi/MidiSystem.java index 8ea12eb7002..627dd95e950 100644 --- a/libjava/classpath/javax/sound/midi/MidiSystem.java +++ b/libjava/classpath/javax/sound/midi/MidiSystem.java @@ -64,6 +64,11 @@ import javax.sound.midi.spi.SoundbankReader; */ public class MidiSystem { + private MidiSystem() + { + // Not instantiable. + } + /** * Get an array of all available MIDI devices. * diff --git a/libjava/classpath/javax/sound/midi/MidiUnavailableException.java b/libjava/classpath/javax/sound/midi/MidiUnavailableException.java index d4b85e810aa..a992c16a789 100644 --- a/libjava/classpath/javax/sound/midi/MidiUnavailableException.java +++ b/libjava/classpath/javax/sound/midi/MidiUnavailableException.java @@ -66,25 +66,4 @@ public class MidiUnavailableException extends Exception { super(s); } - - /** - * Create an MidiUnavailableException object. - * - * @param s the exception message string - * @param cause the root cause of the exception - */ - public MidiUnavailableException(String s, Throwable cause) - { - super(s, cause); - } - - /** - * Create an MidiUnavailableException object. - * - * @param cause the root cause of the exception - */ - public MidiUnavailableException(Throwable cause) - { - super(cause); - } } diff --git a/libjava/classpath/javax/sound/midi/Sequencer.java b/libjava/classpath/javax/sound/midi/Sequencer.java index 894d876e91f..24ee2505c56 100644 --- a/libjava/classpath/javax/sound/midi/Sequencer.java +++ b/libjava/classpath/javax/sound/midi/Sequencer.java @@ -385,7 +385,7 @@ public interface Sequencer extends MidiDevice /** * SyncMode objects use the Object hashCode. */ - public int hashCode() + public final int hashCode() { return super.hashCode(); } diff --git a/libjava/classpath/javax/sound/midi/ShortMessage.java b/libjava/classpath/javax/sound/midi/ShortMessage.java index 43c0e25fe72..ef01d11683e 100644 --- a/libjava/classpath/javax/sound/midi/ShortMessage.java +++ b/libjava/classpath/javax/sound/midi/ShortMessage.java @@ -48,11 +48,6 @@ package javax.sound.midi; public class ShortMessage extends MidiMessage { /** - * Status byte for System Exclusive message. - */ - public static final int SYSTEM_EXCLUSIVE = 0xF0; - - /** * Status byte for Time Code message. */ public static final int MIDI_TIME_CODE = 0xF1; @@ -170,7 +165,7 @@ public class ShortMessage extends MidiMessage * * @param data the message data */ - public ShortMessage(byte[] data) + protected ShortMessage(byte[] data) { super(data); } @@ -263,9 +258,6 @@ public class ShortMessage extends MidiMessage case 0xF5: // FIXME: unofficial bus select. Not in spec?? return 1; - case SYSTEM_EXCLUSIVE: - return 0; // FIXME: is this correct? - case TUNE_REQUEST: case END_OF_EXCLUSIVE: case TIMING_CLOCK: diff --git a/libjava/classpath/javax/sound/midi/SysexMessage.java b/libjava/classpath/javax/sound/midi/SysexMessage.java index 7ab60f4b6af..6471a3eb217 100644 --- a/libjava/classpath/javax/sound/midi/SysexMessage.java +++ b/libjava/classpath/javax/sound/midi/SysexMessage.java @@ -69,7 +69,7 @@ public class SysexMessage extends MidiMessage * Create a SysexMessage object. * @param data a complete system exclusive message */ - public SysexMessage(byte[] data) + protected SysexMessage(byte[] data) { super(data); } diff --git a/libjava/classpath/javax/sound/midi/Track.java b/libjava/classpath/javax/sound/midi/Track.java index da7ef2ef3b9..d06c8cc1dfb 100644 --- a/libjava/classpath/javax/sound/midi/Track.java +++ b/libjava/classpath/javax/sound/midi/Track.java @@ -54,11 +54,16 @@ public class Track /** * The list of MidiEvents for this track. */ - protected Vector events; + Vector events; // A HashSet to speed processing private HashSet eventSet; - + + // This is only instantiable within this package. + Track() + { + } + /** * Add a new event to this track. Specific events may only be added once. * The event will be inserted into the appropriate spot in the event list diff --git a/libjava/classpath/javax/sound/sampled/AudioSystem.java b/libjava/classpath/javax/sound/sampled/AudioSystem.java index 0b0b754b59e..2f64f92c5c1 100644 --- a/libjava/classpath/javax/sound/sampled/AudioSystem.java +++ b/libjava/classpath/javax/sound/sampled/AudioSystem.java @@ -68,6 +68,11 @@ public class AudioSystem */ public static final int NOT_SPECIFIED = -1; + // This class is not instantiable. + private AudioSystem() + { + } + /** * Return the file format of a given File. * @param f the file to check diff --git a/libjava/classpath/javax/sound/sampled/BooleanControl.java b/libjava/classpath/javax/sound/sampled/BooleanControl.java index aae1e23a298..147a7f8b02f 100644 --- a/libjava/classpath/javax/sound/sampled/BooleanControl.java +++ b/libjava/classpath/javax/sound/sampled/BooleanControl.java @@ -42,7 +42,7 @@ package javax.sound.sampled; * A BooleanControl is a Control which has two states. * @since 1.3 */ -public class BooleanControl extends Control +public abstract class BooleanControl extends Control { /** * A Type specialized to represent a boolean control. diff --git a/libjava/classpath/javax/sound/sampled/CompoundControl.java b/libjava/classpath/javax/sound/sampled/CompoundControl.java index 8664abca808..057bdfd7248 100644 --- a/libjava/classpath/javax/sound/sampled/CompoundControl.java +++ b/libjava/classpath/javax/sound/sampled/CompoundControl.java @@ -42,7 +42,7 @@ package javax.sound.sampled; * A compound control provides control over several other controls. * @since 1.3 */ -public class CompoundControl extends Control +public abstract class CompoundControl extends Control { /** * This describes a single compound control. diff --git a/libjava/classpath/javax/sound/sampled/Control.java b/libjava/classpath/javax/sound/sampled/Control.java index 810c2edd54d..4759a335373 100644 --- a/libjava/classpath/javax/sound/sampled/Control.java +++ b/libjava/classpath/javax/sound/sampled/Control.java @@ -43,7 +43,7 @@ package javax.sound.sampled; * for instance its volume. * @since 1.3 */ -public class Control +public abstract class Control { /** * This describes a single control. @@ -75,7 +75,7 @@ public class Control /** * Return the name of this Type. */ - public String toString() + public final String toString() { return name; } diff --git a/libjava/classpath/javax/sound/sampled/EnumControl.java b/libjava/classpath/javax/sound/sampled/EnumControl.java index 798f3a91c96..1ddc8a9a838 100644 --- a/libjava/classpath/javax/sound/sampled/EnumControl.java +++ b/libjava/classpath/javax/sound/sampled/EnumControl.java @@ -43,7 +43,7 @@ package javax.sound.sampled; * values. * @since 1.3 */ -public class EnumControl extends Control +public abstract class EnumControl extends Control { /** * This Type describes an EnumControl. diff --git a/libjava/classpath/javax/sound/sampled/FloatControl.java b/libjava/classpath/javax/sound/sampled/FloatControl.java index 409c90de2cd..bbdb24bab23 100644 --- a/libjava/classpath/javax/sound/sampled/FloatControl.java +++ b/libjava/classpath/javax/sound/sampled/FloatControl.java @@ -39,7 +39,7 @@ exception statement from your version. */ package javax.sound.sampled; /** @since 1.3 */ -public class FloatControl extends Control +public abstract class FloatControl extends Control { /** * An instance of this class describes a particular floating point control. diff --git a/libjava/classpath/javax/sound/sampled/LineEvent.java b/libjava/classpath/javax/sound/sampled/LineEvent.java index db925935b4a..dd4a9ae9a94 100644 --- a/libjava/classpath/javax/sound/sampled/LineEvent.java +++ b/libjava/classpath/javax/sound/sampled/LineEvent.java @@ -126,7 +126,7 @@ public class LineEvent extends EventObject /** * Return the frame position associated with this event. */ - public long getFramePosition() + public final long getFramePosition() { return framePosition; } @@ -134,7 +134,7 @@ public class LineEvent extends EventObject /** * Return the Line associated with this event. */ - public Line getLine() + public final Line getLine() { return line; } @@ -142,7 +142,7 @@ public class LineEvent extends EventObject /** * Return the Type associated with this event. */ - public Type getType() + public final Type getType() { return type; } diff --git a/libjava/classpath/javax/sound/sampled/Mixer.java b/libjava/classpath/javax/sound/sampled/Mixer.java index b9afba3fe87..ff657cfd1dc 100644 --- a/libjava/classpath/javax/sound/sampled/Mixer.java +++ b/libjava/classpath/javax/sound/sampled/Mixer.java @@ -62,7 +62,7 @@ public interface Mixer extends Line * @param desc a descriptive string * @param vers the mixer's version */ - public Info(String name, String vendor, String desc, String vers) + protected Info(String name, String vendor, String desc, String vers) { this.name = name; this.description = desc; @@ -83,7 +83,7 @@ public interface Mixer extends Line /** * Return the name of the mixer. */ - public String getName() + public final String getName() { return name; } @@ -91,7 +91,7 @@ public interface Mixer extends Line /** * Return the mixer's description. */ - public String getDescription() + public final String getDescription() { return description; } @@ -99,7 +99,7 @@ public interface Mixer extends Line /** * Return the mixer's vendor. */ - public String getVendor() + public final String getVendor() { return vendor; } @@ -107,12 +107,12 @@ public interface Mixer extends Line /** * Return the mixer's version. */ - public String getVersion() + public final String getVersion() { return version; } - public String toString() + public final String toString() { return ("name=" + name + "; description=" + description + "; vendor=" + vendor + "; version=" + version); diff --git a/libjava/classpath/javax/sound/sampled/Port.java b/libjava/classpath/javax/sound/sampled/Port.java index 7b3daafd3aa..fb39e6c07ee 100644 --- a/libjava/classpath/javax/sound/sampled/Port.java +++ b/libjava/classpath/javax/sound/sampled/Port.java @@ -127,7 +127,7 @@ public interface Port extends Line return super.matches(other) && equals(other); } - public String toString() + public final String toString() { return super.toString() + "; name=" + name + "; isSource=" + isSource; } diff --git a/libjava/classpath/javax/sound/sampled/ReverbType.java b/libjava/classpath/javax/sound/sampled/ReverbType.java index a089593777d..c7cced8a75f 100644 --- a/libjava/classpath/javax/sound/sampled/ReverbType.java +++ b/libjava/classpath/javax/sound/sampled/ReverbType.java @@ -84,7 +84,7 @@ public class ReverbType /** * Return the decay time. */ - public int getDecayTime() + public final int getDecayTime() { return decayTime; } @@ -92,7 +92,7 @@ public class ReverbType /** * Return the early reflection delay. */ - public int getEarlyReflectionDelay() + public final int getEarlyReflectionDelay() { return earlyReflectionDelay; } @@ -100,7 +100,7 @@ public class ReverbType /** * Return the early reflection intensity. */ - public float getEarlyReflectionIntensity() + public final float getEarlyReflectionIntensity() { return earlyReflectionIntensity; } @@ -108,7 +108,7 @@ public class ReverbType /** * Return the late reflection delay. */ - public int getLateReflectionDelay() + public final int getLateReflectionDelay() { return lateReflectionDelay; } @@ -116,7 +116,7 @@ public class ReverbType /** * Return the late reflection intensity. */ - public float getLateReflectionIntensity() + public final float getLateReflectionIntensity() { return lateReflectionIntensity; } @@ -133,7 +133,7 @@ public class ReverbType /** * Return a description of this ReverbType. */ - public String toString() + public final String toString() { return ("name=" + name + "; earlyReflectionDelay=" + earlyReflectionDelay + "; earlyReflectionIntensity=" + earlyReflectionIntensity diff --git a/libjava/classpath/javax/swing/AbstractAction.java b/libjava/classpath/javax/swing/AbstractAction.java index 4a2334570aa..ffd122fe027 100644 --- a/libjava/classpath/javax/swing/AbstractAction.java +++ b/libjava/classpath/javax/swing/AbstractAction.java @@ -40,9 +40,6 @@ package javax.swing; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.HashMap; @@ -110,32 +107,6 @@ public abstract class AbstractAction } /** - * readObject - * - * @param stream the stream to read from - * - * @exception ClassNotFoundException TODO - * @exception IOException if an error occurs - */ - private void readObject(ObjectInputStream stream) - throws ClassNotFoundException, IOException - { - // TODO - } - - /** - * writeObject - * - * @param stream the stream to write to - * - * @exception IOException if an error occurs - */ - private void writeObject(ObjectOutputStream stream) throws IOException - { - // TODO - } - - /** * Returns a clone of the action. * * @return A clone of the action. diff --git a/libjava/classpath/javax/swing/AbstractButton.java b/libjava/classpath/javax/swing/AbstractButton.java index 3d289084e20..348daece174 100644 --- a/libjava/classpath/javax/swing/AbstractButton.java +++ b/libjava/classpath/javax/swing/AbstractButton.java @@ -37,12 +37,17 @@ exception statement from your version. */ package javax.swing; +import gnu.classpath.NotImplementedException; + +import java.awt.Component; import java.awt.Graphics; import java.awt.Image; import java.awt.Insets; import java.awt.ItemSelectable; +import java.awt.LayoutManager; import java.awt.Point; import java.awt.Rectangle; +import java.awt.Shape; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; @@ -51,17 +56,26 @@ import java.awt.image.ImageObserver; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.Serializable; +import java.util.Enumeration; +import javax.accessibility.Accessible; import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleIcon; +import javax.accessibility.AccessibleRelation; import javax.accessibility.AccessibleRelationSet; +import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleText; import javax.accessibility.AccessibleValue; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.ButtonUI; +import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.Position; +import javax.swing.text.View; /** @@ -275,6 +289,42 @@ public abstract class AbstractButton extends JComponent protected ChangeEvent changeEvent = new ChangeEvent(this); /** + * Indicates if the borderPainted property has been set by a client + * program or by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientBorderPaintedSet = false; + + /** + * Indicates if the rolloverEnabled property has been set by a client + * program or by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientRolloverEnabledSet = false; + + /** + * Indicates if the iconTextGap property has been set by a client + * program or by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientIconTextGapSet = false; + + /** + * Indicates if the contentAreaFilled property has been set by a client + * program or by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientContentAreaFilledSet = false; + + /** * Fired in a PropertyChangeEvent when the "borderPainted" property changes. */ public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted"; @@ -388,134 +438,405 @@ public abstract class AbstractButton extends JComponent // Nothing to do here yet. } + /** + * Returns the accessible state set of this object. In addition to the + * superclass's states, the <code>AccessibleAbstractButton</code> + * supports the following states: {@link AccessibleState#ARMED}, + * {@link AccessibleState#FOCUSED}, {@link AccessibleState#PRESSED} and + * {@link AccessibleState#CHECKED}. + * + * @return the curren state of this accessible object + */ public AccessibleStateSet getAccessibleStateSet() { - return null; // TODO + AccessibleStateSet state = super.getAccessibleStateSet(); + + if (getModel().isArmed()) + state.add(AccessibleState.ARMED); + if (getModel().isPressed()) + state.add(AccessibleState.PRESSED); + if (isSelected()) + state.add(AccessibleState.CHECKED); + + return state; } + /** + * Returns the accessible name for the button. + */ public String getAccessibleName() { - return null; // TODO + String result = super.getAccessibleName(); + if (result == null) + result = text; + return result; } + /** + * Returns the accessible icons of this object. If the AbstractButton's + * icon is an Accessible, and it's AccessibleContext is an AccessibleIcon, + * then this AccessibleIcon is returned, otherwise <code>null</code>. + * + * @return the accessible icons of this object, or <code>null</code> if + * there is no accessible icon + */ public AccessibleIcon[] getAccessibleIcon() { - return null; // TODO + AccessibleIcon[] ret = null; + Icon icon = getIcon(); + if (icon instanceof Accessible) + { + AccessibleContext ctx = ((Accessible) icon).getAccessibleContext(); + if (ctx instanceof AccessibleIcon) + { + ret = new AccessibleIcon[]{ (AccessibleIcon) ctx }; + } + } + return ret; } + /** + * Returns the accessible relations of this AccessibleAbstractButton. + * If the AbstractButton is part of a ButtonGroup, then all the buttons + * in this button group are added as targets in a MEMBER_OF relation, + * otherwise an empty relation set is returned (from super). + * + * @return the accessible relations of this AccessibleAbstractButton + */ public AccessibleRelationSet getAccessibleRelationSet() { - return null; // TODO + AccessibleRelationSet relations = super.getAccessibleRelationSet(); + ButtonModel model = getModel(); + if (model instanceof DefaultButtonModel) + { + ButtonGroup group = ((DefaultButtonModel) model).getGroup(); + if (group != null) + { + Object[] target = new Object[group.getButtonCount()]; + Enumeration els = group.getElements(); + + for (int index = 0; els.hasMoreElements(); ++index) + { + target[index] = els.nextElement(); + } + + AccessibleRelation rel = + new AccessibleRelation(AccessibleRelation.MEMBER_OF); + rel.setTarget(target); + relations.add(rel); + } + } + return relations; } + /** + * Returns the accessible action associated with this object. For buttons, + * this will be <code>this</code>. + * + * @return <code>this</code> + */ public AccessibleAction getAccessibleAction() { - return null; // TODO + return this; } + /** + * Returns the accessible value of this AccessibleAbstractButton, which + * is always <code>this</code>. + * + * @return the accessible value of this AccessibleAbstractButton, which + * is always <code>this</code> + */ public AccessibleValue getAccessibleValue() { - return null; // TODO + return this; } + /** + * Returns the number of accessible actions that are supported by this + * object. Buttons support one action by default ('press button'), so this + * method always returns <code>1</code>. + * + * @return <code>1</code>, the number of supported accessible actions + */ public int getAccessibleActionCount() { - return 0; // TODO + return 1; } - public String getAccessibleActionDescription(int value0) + /** + * Returns a description for the action with the specified index or + * <code>null</code> if such action does not exist. + * + * @param actionIndex the zero based index to the actions + * + * @return a description for the action with the specified index or + * <code>null</code> if such action does not exist + */ + public String getAccessibleActionDescription(int actionIndex) { - return null; // TODO + String descr = null; + if (actionIndex == 0) + { + // FIXME: Supply localized descriptions in the UIDefaults. + descr = UIManager.getString("AbstractButton.clickText"); + } + return descr; } - public boolean doAccessibleAction(int value0) + /** + * Performs the acccessible action with the specified index on this object. + * Since buttons have only one action by default (which is to press the + * button), this method performs a 'press button' when the specified index + * is <code>0</code> and nothing otherwise. + * + * @param actionIndex a zero based index into the actions of this button + * + * @return <code>true</code> if the specified action has been performed + * successfully, <code>false</code> otherwise + */ + public boolean doAccessibleAction(int actionIndex) { - return false; // TODO + boolean retVal = false; + if (actionIndex == 0) + { + doClick(); + retVal = true; + } + return retVal; } + /** + * Returns the current value of this object as a number. This + * implementation returns an <code>Integer(1)</code> if the button is + * selected, <code>Integer(0)</code> if the button is not selected. + * + * @return the current value of this object as a number + */ public Number getCurrentAccessibleValue() { - return null; // TODO + Integer retVal; + if (isSelected()) + retVal = new Integer(1); + else + retVal = new Integer(0); + return retVal; } - public boolean setCurrentAccessibleValue(Number value0) + /** + * Sets the current accessible value as object. If the specified number + * is 0 the button will be deselected, otherwise the button will + * be selected. + * + * @param value 0 for deselected button, other for selected button + * + * @return <code>true</code> if the value has been set, <code>false</code> + * otherwise + */ + public boolean setCurrentAccessibleValue(Number value) { - return false; // TODO + boolean retVal = false; + if (value != null) + { + if (value.intValue() == 0) + setSelected(false); + else + setSelected(true); + retVal = true; + } + return retVal; } + /** + * 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> + */ public Number getMinimumAccessibleValue() { - return null; // TODO + return new Integer(0); } + /** + * Returns the maximum accessible value for the AccessibleAbstractButton, + * which is <code>1</code>. + * + * @return the maximum accessible value for the AccessibleAbstractButton, + * which is <code>1</code> + */ public Number getMaximumAccessibleValue() { - return null; // TODO + return new Integer(1); } + /** + * Returns the accessible text for this AccessibleAbstractButton. This + * will be <code>null</code> if the button has a non-HTML label, otherwise + * <code>this</code>. + * + * @return the accessible text for this AccessibleAbstractButton + */ public AccessibleText getAccessibleText() { - return null; // TODO + AccessibleText accessibleText = null; + if (getClientProperty(BasicHTML.propertyKey) != null) + accessibleText = this; + + return accessibleText; } - public int getIndexAtPoint(Point value0) + /** + * Returns the index of the label's character at the specified point, + * relative to the local bounds of the button. This only works for + * HTML labels. + * + * @param p the point, relative to the buttons local bounds + * + * @return the index of the label's character at the specified point + */ + public int getIndexAtPoint(Point p) { - return 0; // TODO + int index = -1; + View view = (View) getClientProperty(BasicHTML.propertyKey); + if (view != null) + { + Rectangle shape = new Rectangle(0, 0, getWidth(), getHeight()); + index = view.viewToModel(p.x, p.y, shape, new Position.Bias[1]); + } + return index; } - public Rectangle getCharacterBounds(int value0) + /** + * Returns the bounds of the character at the specified index of the + * button's label. This will only work for HTML labels. + * + * @param i the index of the character of the label + * + * @return the bounds of the character at the specified index of the + * button's label + */ + public Rectangle getCharacterBounds(int i) { - return null; // TODO + Rectangle rect = null; + View view = (View) getClientProperty(BasicHTML.propertyKey); + if (view != null) + { + Rectangle shape = new Rectangle(0, 0, getWidth(), getHeight()); + try + { + Shape s = view.modelToView(i, shape, Position.Bias.Forward); + rect = s.getBounds(); + } + catch (BadLocationException ex) + { + rect = null; + } + } + return rect; } + /** + * Returns the number of characters in the button's label. + * + * @return the bounds of the character at the specified index of the + * button's label + */ public int getCharCount() { - return 0; // TODO + int charCount; + View view = (View) getClientProperty(BasicHTML.propertyKey); + if (view != null) + { + charCount = view.getDocument().getLength(); + } + else + { + charCount = getAccessibleName().length(); + } + return charCount; } + /** + * This always returns <code>-1</code> since there is no caret in a button. + * + * @return <code>-1</code> since there is no caret in a button + */ public int getCaretPosition() { - return 0; // TODO + return -1; } public String getAtIndex(int value0, int value1) + throws NotImplementedException { return null; // TODO } public String getAfterIndex(int value0, int value1) + throws NotImplementedException { return null; // TODO } public String getBeforeIndex(int value0, int value1) + throws NotImplementedException { return null; // TODO } - public AttributeSet getCharacterAttribute(int value0) + /** + * Returns the text attribute for the character at the specified character + * index. + * + * @param i the character index + * + * @return the character attributes for the specified character or + * <code>null</code> if the character has no attributes + */ + public AttributeSet getCharacterAttribute(int i) { - return null; // TODO + AttributeSet atts = null; + View view = (View) getClientProperty(BasicHTML.propertyKey); + if (view != null) + { + + } + return atts; } + /** + * This always returns <code>-1</code> since + * button labels can't be selected. + * + * @return <code>-1</code>, button labels can't be selected + */ public int getSelectionStart() { - return 0; // TODO + return -1; } + /** + * This always returns <code>-1</code> since + * button labels can't be selected. + * + * @return <code>-1</code>, button labels can't be selected + */ public int getSelectionEnd() { - return 0; // TODO + return -1; } + /** + * Returns the selected text. This always returns <code>null</code> since + * button labels can't be selected. + * + * @return <code>null</code>, button labels can't be selected + */ public String getSelectedText() { - return null; // TODO - } - - private Rectangle getTextRectangle() - { - return null; // TODO + return null; } } @@ -905,6 +1226,7 @@ public abstract class AbstractButton extends JComponent */ public void setRolloverEnabled(boolean r) { + clientRolloverEnabledSet = true; if (rollOverEnabled != r) { rollOverEnabled = r; @@ -1137,9 +1459,9 @@ public abstract class AbstractButton extends JComponent */ public void setBorderPainted(boolean b) { + clientBorderPaintedSet = true; if (borderPainted == b) return; - boolean old = borderPainted; borderPainted = b; firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, old, b); @@ -1283,15 +1605,18 @@ public abstract class AbstractButton extends JComponent * Set the value of the {@link #iconTextGap} property. * * @param i The new value of the property + * + * @since 1.4 */ public void setIconTextGap(int i) { + clientIconTextGapSet = true; if (iconTextGap == i) return; int old = iconTextGap; iconTextGap = i; - fireStateChanged(); + firePropertyChange("iconTextGap", new Integer(old), new Integer(i)); revalidate(); repaint(); } @@ -1300,6 +1625,8 @@ public abstract class AbstractButton extends JComponent * Get the value of the {@link #iconTextGap} property. * * @return The current value of the property + * + * @since 1.4 */ public int getIconTextGap() { @@ -1917,15 +2244,16 @@ public abstract class AbstractButton extends JComponent */ public void setContentAreaFilled(boolean b) { + clientContentAreaFilledSet = true; if (contentAreaFilled == b) return; - boolean old = contentAreaFilled; - contentAreaFilled = b; - firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, old, b); // The JDK sets the opaque property to the value of the contentAreaFilled // property, so should we do. setOpaque(b); + boolean old = contentAreaFilled; + contentAreaFilled = b; + firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, old, b); } /** @@ -2044,4 +2372,97 @@ public abstract class AbstractButton extends JComponent multiClickThreshhold = threshhold; } + + /** + * Adds the specified component to this AbstractButton. This overrides the + * default in order to install an {@link OverlayLayout} layout manager + * before adding the component. The layout manager is only installed if + * no other layout manager has been installed before. + * + * @param comp the component to be added + * @param constraints constraints for the layout manager + * @param index the index at which the component is added + * + * @since 1.5 + */ + protected void addImpl(Component comp, Object constraints, int index) + { + // We use a client property here, so that no extra memory is used in + // the common case with no layout manager. + if (getClientProperty("AbstractButton.customLayoutSet") == null) + setLayout(new OverlayLayout(this)); + super.addImpl(comp, constraints, index); + } + + /** + * Sets a layout manager on this AbstractButton. This is overridden in order + * to detect if the application sets a custom layout manager. If no custom + * layout manager is set, {@link #addImpl(Component, Object, int)} installs + * an OverlayLayout before adding a component. + * + * @param layout the layout manager to install + * + * @since 1.5 + */ + public void setLayout(LayoutManager layout) + { + // We use a client property here, so that no extra memory is used in + // the common case with no layout manager. + putClientProperty("AbstractButton.customLayoutSet", Boolean.TRUE); + super.setLayout(layout); + } + + /** + * Helper method for + * {@link LookAndFeel#installProperty(JComponent, String, Object)}. + * + * @param propertyName the name of the property + * @param value the value of the property + * + * @throws IllegalArgumentException if the specified property cannot be set + * by this method + * @throws ClassCastException if the property value does not match the + * property type + * @throws NullPointerException if <code>c</code> or + * <code>propertyValue</code> is <code>null</code> + */ + void setUIProperty(String propertyName, Object value) + { + if (propertyName.equals("borderPainted")) + { + if (! clientBorderPaintedSet) + { + setBorderPainted(((Boolean) value).booleanValue()); + clientBorderPaintedSet = false; + } + } + else if (propertyName.equals("rolloverEnabled")) + { + if (! clientRolloverEnabledSet) + { + setRolloverEnabled(((Boolean) value).booleanValue()); + clientRolloverEnabledSet = false; + } + } + else if (propertyName.equals("iconTextGap")) + { + if (! clientIconTextGapSet) + { + setIconTextGap(((Integer) value).intValue()); + clientIconTextGapSet = false; + } + } + else if (propertyName.equals("contentAreaFilled")) + { + if (! clientContentAreaFilledSet) + { + setContentAreaFilled(((Boolean) value).booleanValue()); + clientContentAreaFilledSet = false; + } + } + else + { + super.setUIProperty(propertyName, value); + } + } } diff --git a/libjava/classpath/javax/swing/ActionMap.java b/libjava/classpath/javax/swing/ActionMap.java index 65e193d2e79..0d6706c3b81 100644 --- a/libjava/classpath/javax/swing/ActionMap.java +++ b/libjava/classpath/javax/swing/ActionMap.java @@ -1,5 +1,5 @@ /* ActionMap.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,9 +37,6 @@ exception statement from your version. */ package javax.swing; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Arrays; import java.util.HashMap; @@ -195,30 +192,4 @@ public class ActionMap return null; } - /** - * writeObject - * - * @param stream the stream to write to - * - * @exception IOException If an error occurs - */ - private void writeObject(ObjectOutputStream stream) - throws IOException - { - // TODO - } - - /** - * readObject - * - * @param stream the stream to read from - * - * @exception ClassNotFoundException If the serialized class cannot be found - * @exception IOException If an error occurs - */ - private void readObject(ObjectInputStream stream) - throws ClassNotFoundException, IOException - { - // TODO - } } diff --git a/libjava/classpath/javax/swing/ButtonGroup.java b/libjava/classpath/javax/swing/ButtonGroup.java index 94f0109e634..2f8d19831cb 100644 --- a/libjava/classpath/javax/swing/ButtonGroup.java +++ b/libjava/classpath/javax/swing/ButtonGroup.java @@ -91,8 +91,12 @@ public class ButtonGroup implements Serializable { b.getModel().setGroup(this); if (b.isSelected()) - sel = b.getModel(); - buttons.addElement(b); + { + if (sel == null) + sel = b.getModel(); + else + b.setSelected(false); + } buttons.addElement(b); } /** diff --git a/libjava/classpath/javax/swing/CompatibilityFocusTraversalPolicy.java b/libjava/classpath/javax/swing/CompatibilityFocusTraversalPolicy.java new file mode 100644 index 00000000000..40c2010c322 --- /dev/null +++ b/libjava/classpath/javax/swing/CompatibilityFocusTraversalPolicy.java @@ -0,0 +1,164 @@ +/* CompatibilityFocusTraversalPolicy.java -- Provides compatibility to old + focus API + 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; + +import java.awt.Component; +import java.awt.Container; +import java.awt.FocusTraversalPolicy; +import java.util.HashMap; + +/** + * Provides compatibility to the older focus API in + * {@link JComponent#setNextFocusableComponent(Component)}. + * + * @author Roman Kennke (kennke@aicas.com) + */ +class CompatibilityFocusTraversalPolicy + extends FocusTraversalPolicy +{ + + /** + * The focus traversal policy that has been installed on the focus cycle + * root before, and to which we fall back. + */ + private FocusTraversalPolicy fallback; + + /** + * Maps components to their next focused components. + */ + private HashMap forward; + + /** + * Maps components to their previous focused components. + */ + private HashMap backward; + + /** + * Creates a new CompatibilityFocusTraversalPolicy with the specified + * policy as fallback. + * + * @param p the fallback policy + */ + CompatibilityFocusTraversalPolicy(FocusTraversalPolicy p) + { + fallback = p; + forward = new HashMap(); + backward = new HashMap(); + } + + public Component getComponentAfter(Container root, Component current) + { + Component next = (Component) forward.get(current); + if (next == null && fallback != null) + next = fallback.getComponentAfter(root, current); + return next; + } + + public Component getComponentBefore(Container root, Component current) + { + Component previous = (Component) backward.get(current); + if (previous == null && fallback != null) + previous = fallback.getComponentAfter(root, current); + return previous; + } + + public Component getFirstComponent(Container root) + { + Component first = null; + if (fallback != null) + first = fallback.getFirstComponent(root); + return first; + } + + public Component getLastComponent(Container root) + { + Component last = null; + if (fallback != null) + last = fallback.getLastComponent(root); + return last; + } + + public Component getDefaultComponent(Container root) + { + Component def = null; + if (fallback != null) + def = fallback.getDefaultComponent(root); + return def; + } + + /** + * Sets a next focused component for a specified component. This is called + * by {@link JComponent#setNextFocusableComponent(Component)}. + * + * @param current the current component + * @param next the next focused component + */ + void setNextFocusableComponent(Component current, Component next) + { + forward.put(current, next); + backward.put(next, current); + } + + /** + * Sets a next focused component for a specified component. This is called + * by {@link JComponent#setNextFocusableComponent(Component)}. + * + * @param current the current component + * @param next the next focused component + */ + void addNextFocusableComponent(Component current, Component next) + { + forward.put(current, next); + backward.put(next, current); + } + + /** + * Removes a focused component mapping. This is called + * by {@link JComponent#setNextFocusableComponent(Component)}. + * + * @param current the current component + * @param next the next focused component + */ + void removeNextFocusableComponent(Component current, Component next) + { + forward.remove(current); + backward.remove(next); + } +} diff --git a/libjava/classpath/javax/swing/DefaultCellEditor.java b/libjava/classpath/javax/swing/DefaultCellEditor.java index 7f1c395ad03..9c951d39530 100644 --- a/libjava/classpath/javax/swing/DefaultCellEditor.java +++ b/libjava/classpath/javax/swing/DefaultCellEditor.java @@ -171,9 +171,7 @@ public class DefaultCellEditor /** * Cancel the cell editing session. This method notifies the registered * cell editor listeners (including the table) that the editing has been - * canceled. - * - * @returns boolean + * canceled. */ public void cancelCellEditing() { diff --git a/libjava/classpath/javax/swing/DefaultComboBoxModel.java b/libjava/classpath/javax/swing/DefaultComboBoxModel.java index ea261a33bbf..ab80b61f1f9 100644 --- a/libjava/classpath/javax/swing/DefaultComboBoxModel.java +++ b/libjava/classpath/javax/swing/DefaultComboBoxModel.java @@ -1,5 +1,5 @@ /* DefaultComboBoxModel.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. @@ -107,22 +107,24 @@ public class DefaultComboBoxModel extends AbstractListModel public DefaultComboBoxModel(Vector vector) { this.list = vector; - if (vector.size() > 0) + if (getSize() > 0) selectedItem = vector.get(0); } /** * Adds an element to the model's item list and sends a {@link ListDataEvent} * to all registered listeners. If the new element is the first item added - * to the list, it is set as the selected item. + * to the list, and the selected item is <code>null</code>, the new element + * is set as the selected item. * * @param object item to add to the model's item list. */ public void addElement(Object object) { - list.add(object); - fireIntervalAdded(this, list.size() - 1, list.size() - 1); - if (list.size() == 1) + list.addElement(object); + int index = list.size() - 1; + fireIntervalAdded(this, index, index); + if (list.size() == 1 && selectedItem == null) setSelectedItem(object); } @@ -141,14 +143,14 @@ public class DefaultComboBoxModel extends AbstractListModel public void removeElementAt(int index) { int selected = getIndexOf(selectedItem); - list.remove(index); if (selected == index) // choose a new selected item { if (selected > 0) selectedItem = getElementAt(selected - 1); else - selectedItem = getElementAt(selected); + selectedItem = getElementAt(selected + 1); } + list.removeElementAt(index); fireIntervalRemoved(this, index, index); } diff --git a/libjava/classpath/javax/swing/DefaultDesktopManager.java b/libjava/classpath/javax/swing/DefaultDesktopManager.java index 7f62c948625..0304461ad4e 100644 --- a/libjava/classpath/javax/swing/DefaultDesktopManager.java +++ b/libjava/classpath/javax/swing/DefaultDesktopManager.java @@ -124,8 +124,6 @@ public class DefaultDesktopManager implements DesktopManager, Serializable public void closeFrame(JInternalFrame frame) { Container c = frame.getParent(); - frame.doDefaultCloseAction(); - if (c != null) { if (frame.isIcon()) @@ -244,7 +242,9 @@ public class DefaultDesktopManager implements DesktopManager, Serializable c.add(icon); icon.setVisible(true); } + Rectangle b = frame.getBounds(); c.remove(frame); + c.repaint(b.x, b.y, b.width, b.height); } } @@ -501,7 +501,11 @@ public class DefaultDesktopManager implements DesktopManager, Serializable JDesktopIcon icon = frame.getDesktopIcon(); Container c = icon.getParent(); if (c != null && icon != null) - c.remove(icon); + { + Rectangle b = icon.getBounds(); + c.remove(icon); + c.repaint(b.x, b.y, b.width, b.height); + } } /** diff --git a/libjava/classpath/javax/swing/DefaultFocusManager.java b/libjava/classpath/javax/swing/DefaultFocusManager.java index 08db651680a..103a7f36c43 100644 --- a/libjava/classpath/javax/swing/DefaultFocusManager.java +++ b/libjava/classpath/javax/swing/DefaultFocusManager.java @@ -1,5 +1,5 @@ /* DefaultFocusManager.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. @@ -49,9 +49,10 @@ import java.util.Stack; * * @author Andrew Selkirk */ -public class DefaultFocusManager extends FocusManager { +public class DefaultFocusManager extends FocusManager +{ - /** + /** * historyStack */ private Stack historyStack; @@ -77,7 +78,7 @@ public class DefaultFocusManager extends FocusManager { // TODO } // processKeyEvent() - /** + /** * focusNextComponent * * @param component @@ -88,7 +89,7 @@ public class DefaultFocusManager extends FocusManager { // TODO } // focusNextComponent() - /** + /** * focusPreviousComponent * * @param component @@ -99,66 +100,66 @@ public class DefaultFocusManager extends FocusManager { // TODO } // focusPreviousComponent() - /** + /** * getFirstComponent * * @param container * TODO - * @returns Component + * @return Component */ public Component getFirstComponent(Container container) { return null; // TODO } // getFirstComponent() - /** + /** * getLastComponent * * @param container * TODO - * @returns Component + * @return Component */ public Component getLastComponent(Container container) { return null; // TODO } // getLastComponent() - /** + /** * getComponentBefore * * @param container * TODO * @param component * TODO - * @returns Component + * @return Component */ public Component getComponentBefore(Container container, Component component) { return null; // TODO } // getComponentBefore() - /** + /** * getComponentAfter * * @param container * TODO * @param component * TODO - * @returns Component + * @return Component */ public Component getComponentAfter(Container container, Component component) { return null; // TODO } // getComponentAfter() - /** + /** * compareTabOrder * * @param component1 * TODO * @param component2 * TODO - * @returns boolean + * @return boolean */ public boolean compareTabOrder(Component component1, Component component2) { diff --git a/libjava/classpath/javax/swing/DefaultListSelectionModel.java b/libjava/classpath/javax/swing/DefaultListSelectionModel.java index 7ec4e614c8f..998aee45279 100644 --- a/libjava/classpath/javax/swing/DefaultListSelectionModel.java +++ b/libjava/classpath/javax/swing/DefaultListSelectionModel.java @@ -162,11 +162,14 @@ public class DefaultListSelectionModel implements Cloneable, /** * Sets the value of the {@link #selectionMode} property. * - * @param a The new value of the property + * @param mode The new value of the property */ - public void setSelectionMode(int a) + public void setSelectionMode(int mode) { - selectionMode = a; + if (mode < ListSelectionModel.SINGLE_SELECTION + || mode > ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) + throw new IllegalArgumentException("Unrecognised mode: " + mode); + selectionMode = mode; } /** @@ -286,8 +289,14 @@ public class DefaultListSelectionModel implements Cloneable, int beg = sel.nextSetBit(0), end = -1; for(int i=beg; i >= 0; i=sel.nextSetBit(i+1)) end = i; - if (sel.equals(oldSel) == false) - fireValueChanged(beg, end, valueIsAdjusting); + + BitSet old = (BitSet) oldSel; + + // The new and previous lead location requires repainting. + old.set(oldLeadIndex, !sel.get(oldLeadIndex)); + old.set(leadSelectionIndex, !sel.get(leadSelectionIndex)); + + fireDifference(sel, old); } /** @@ -492,8 +501,7 @@ public class DefaultListSelectionModel implements Cloneable, leadSelectionIndex = index1; anchorSelectionIndex = index0; sel.set(lo, hi+1); - if (sel.equals(oldSel) == false) - fireValueChanged(lo, hi, valueIsAdjusting); + fireDifference(sel, (BitSet) oldSel); } } @@ -530,8 +538,8 @@ public class DefaultListSelectionModel implements Cloneable, //TODO: will probably need MouseDragged to test properly and know if this works setAnchorSelectionIndex(index0); leadSelectionIndex = index1; - if (sel.equals(oldSel) == false) - fireValueChanged(lo, hi, valueIsAdjusting); + + fireDifference(sel, (BitSet) oldSel); } /** @@ -539,20 +547,48 @@ public class DefaultListSelectionModel implements Cloneable, */ public void clearSelection() { - oldSel = sel.clone(); - int sz = sel.size(); + // Find the selected interval. + int from = sel.nextSetBit(0); + if (from < 0) + return; // Empty selection - nothing to do. + int to = from; + + int i; + + for (i = from; i>=0; i=sel.nextSetBit(i+1)) + to = i; + sel.clear(); - if (sel.equals(oldSel) == false) - fireValueChanged(0, sz, valueIsAdjusting); + fireValueChanged(from, to, valueIsAdjusting); } /** - * Clears the current selection and marks a given interval as - * "selected". If the current selection mode is - * <code>SINGLE_SELECTION</code> only the index <code>index2</code> is - * selected. - * - * @param index0 The low end of the new selection + * Fire the change event, covering the difference between the two sets. + * + * @param current the current set + * @param x the previous set, the object will be reused. + */ + private void fireDifference(BitSet current, BitSet x) + { + x.xor(current); + int from = x.nextSetBit(0); + if (from < 0) + return; // No difference. + int to = from; + int i; + + for (i = from; i >= 0; i = x.nextSetBit(i+1)) + to = i; + + fireValueChanged(from, to, valueIsAdjusting); + } + + /** + * Clears the current selection and marks a given interval as "selected". If + * the current selection mode is <code>SINGLE_SELECTION</code> only the + * index <code>index2</code> is selected. + * + * @param index0 The low end of the new selection * @param index1 The high end of the new selection */ public void setSelectionInterval(int index0, int index1) @@ -560,7 +596,7 @@ public class DefaultListSelectionModel implements Cloneable, if (index0 == -1 || index1 == -1) return; - oldSel = sel.clone(); + BitSet oldSel = (BitSet) sel.clone(); sel.clear(); if (selectionMode == SINGLE_SELECTION) index0 = index1; @@ -571,8 +607,8 @@ public class DefaultListSelectionModel implements Cloneable, // update the anchorSelectionIndex and leadSelectionIndex variables setAnchorSelectionIndex(index0); leadSelectionIndex=index1; - if (sel.equals(oldSel) == false) - fireValueChanged(lo, hi, valueIsAdjusting); + + fireDifference(sel, oldSel); } /** @@ -744,6 +780,7 @@ public class DefaultListSelectionModel implements Cloneable, DefaultListSelectionModel model = (DefaultListSelectionModel) super.clone(); model.sel = (BitSet) sel.clone(); + model.listenerList = new EventListenerList(); return model; } } diff --git a/libjava/classpath/javax/swing/DefaultSingleSelectionModel.java b/libjava/classpath/javax/swing/DefaultSingleSelectionModel.java index 8f4d405f9d4..1c6f473fdd3 100644 --- a/libjava/classpath/javax/swing/DefaultSingleSelectionModel.java +++ b/libjava/classpath/javax/swing/DefaultSingleSelectionModel.java @@ -1,5 +1,5 @@ /* DefaultSingleSelectionModel.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. @@ -59,7 +59,7 @@ public class DefaultSingleSelectionModel /** * changeEvent */ - protected transient ChangeEvent changeEvent = new ChangeEvent(this); + protected transient ChangeEvent changeEvent; /** * listenerList @@ -67,12 +67,13 @@ public class DefaultSingleSelectionModel protected EventListenerList listenerList = new EventListenerList(); /** - * index + * The selected index (or -1 for no selection). */ private int index = -1; /** - * Constructor DefaultSingleSelectionModel + * Creates a new <code>DefaultSingleSelectionModel</code> with no current + * selection. */ public DefaultSingleSelectionModel() { @@ -80,8 +81,11 @@ public class DefaultSingleSelectionModel } /** - * getSelectedIndex - * @return int + * Returns the selected index or <code>-1</code> if there is no selection. + * + * @return The selected index. + * + * @see #setSelectedIndex(int) */ public int getSelectedIndex() { @@ -89,27 +93,38 @@ public class DefaultSingleSelectionModel } /** - * setSelectedIndex - * @param index TODO + * Sets the selected index and, if this is different to the previous + * selection, sends a {@link ChangeEvent} to all registered listeners. + * + * @param index the index (use <code>-1</code> to represent no selection). + * + * @see #getSelectedIndex() + * @see #clearSelection */ public void setSelectedIndex(int index) { - this.index = index; - fireStateChanged(); + if (this.index != index) + { + this.index = index; + fireStateChanged(); + } } /** - * clearSelection + * Clears the selection by setting the selected index to <code>-1</code> and + * sends a {@link ChangeEvent} to all registered listeners. If the selected + * index is already <code>-1</code>, this method does nothing. */ public void clearSelection() { - index = -1; - fireStateChanged(); + setSelectedIndex(-1); } /** - * isSelected - * @return boolean + * Returns <code>true</code> if there is a selection, and <code>false</code> + * otherwise. + * + * @return A boolean. */ public boolean isSelected() { @@ -117,9 +132,10 @@ public class DefaultSingleSelectionModel } /** - * addChangeListener + * Registers a listener to receive {@link ChangeEvent} notifications from + * this model whenever the selected index changes. * - * @param listener the listener to add + * @param listener the listener to add. */ public void addChangeListener(ChangeListener listener) { @@ -127,9 +143,10 @@ public class DefaultSingleSelectionModel } /** - * removeChangeListener + * Deregisters a listener so that it no longer receives {@link ChangeEvent} + * notifications from this model. * - * @param listener the listener to remove + * @param listener the listener to remove. */ public void removeChangeListener(ChangeListener listener) { @@ -141,8 +158,9 @@ public class DefaultSingleSelectionModel */ protected void fireStateChanged() { + if (changeEvent == null) + changeEvent = new ChangeEvent(this); ChangeListener[] listeners = getChangeListeners(); - for (int i = 0; i < listeners.length; i++) listeners[i].stateChanged(changeEvent); } diff --git a/libjava/classpath/javax/swing/FocusManager.java b/libjava/classpath/javax/swing/FocusManager.java index a2109ee06c6..21e4482d186 100644 --- a/libjava/classpath/javax/swing/FocusManager.java +++ b/libjava/classpath/javax/swing/FocusManager.java @@ -485,7 +485,7 @@ public abstract class FocusManager /** * getCurrentManager - * @returns FocusManager + * @return FocusManager */ public static FocusManager getCurrentManager() { diff --git a/libjava/classpath/javax/swing/ImageIcon.java b/libjava/classpath/javax/swing/ImageIcon.java index 9e6265830a3..cedf4be35a6 100644 --- a/libjava/classpath/javax/swing/ImageIcon.java +++ b/libjava/classpath/javax/swing/ImageIcon.java @@ -1,5 +1,5 @@ /* ImageIcon.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. @@ -39,6 +39,7 @@ package javax.swing; import java.awt.Component; import java.awt.Graphics; +import java.awt.IllegalComponentStateException; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Toolkit; @@ -60,7 +61,8 @@ public class ImageIcon implements Icon, Serializable, Accessible { /** - * Accessibility support for ImageIcon. + * Provides the accessibility features for the <code>ImageIcon</code> + * class. */ protected class AccessibleImageIcon extends AccessibleContext @@ -69,7 +71,7 @@ public class ImageIcon private static final long serialVersionUID = 2113430526551336564L; /** - * Creates a new instance of AccessibleImageIcon. + * Creates a new instance of <code>AccessibleImageIcon</code>. */ protected AccessibleImageIcon() { @@ -77,10 +79,9 @@ public class ImageIcon } /** - * Returns the AccessibleRole of ImageIcon, which is - * {@link AccessibleRole#ICON}. + * Returns the accessible role for the <code>ImageIcon</code>. * - * @return {@link AccessibleRole#ICON} + * @return {@link AccessibleRole#ICON}. */ public AccessibleRole getAccessibleRole() { @@ -88,45 +89,47 @@ public class ImageIcon } /** - * Returns the accessible state of this ImageIcon. + * Returns the accessible state for the <code>ImageIcon</code>. To + * match the reference implementation, this method always returns + * <code>null</code>. * - * @return the accessible state of this ImageIcon + * @return <code>null</code>. */ public AccessibleStateSet getAccessibleStateSet() { - // TODO: which state information from ImageIcon is returned here?? - return new AccessibleStateSet(); + // refer to Sun's bug report 4269253 + return null; } /** - * Returns the accessible parent of this object, which is <code>null</code> - * in this case, because ImageIcons have no parent. + * Returns the accessible parent of this object. To match the reference + * implementation, this method always returns <code>null</code>. * - * @return <code>null</code>, because ImageIcons have no parent + * @return <code>null</code>. */ public Accessible getAccessibleParent() { - // TODO: ImageIcons have no parent, have they ?? + // refer to Sun's bug report 4269253 return null; } /** - * Returns the index of this object in its accessible parent, which is - * -1 here, because ImageIcons have no accessible parent. + * Returns the index of this object in its accessible parent. To match + * the reference implementation, this method always returns <code>-1</code>. * - * @return -1 because ImageIcons have no parent + * @return <code>-1</code>. */ public int getAccessibleIndexInParent() { - // TODO: do ImageIcons have parents?? + // refer to Sun's bug report 4269253 return -1; } /** * Returns the number of accessible children of this component, - * which is 0, because ImageIcons have no children. + * which is 0, because an {@link ImageIcon} has no children. * - * @return 0 because ImageIcons have no children + * @return <code>0</code>. */ public int getAccessibleChildrenCount() { @@ -135,11 +138,12 @@ public class ImageIcon /** * Returns the accessible child at index <code>i</code>, which is - * <code>null</code> in this case because ImageIcons have no children. + * <code>null</code> in this case because an {@link ImageIcon} has no + * children. * * @param i the index of the child to be fetched * - * @return <code>null</code> because ImageIcons have no children + * @return <code>null</code>. */ public Accessible getAccessibleChild(int i) { @@ -147,21 +151,25 @@ public class ImageIcon } /** - * Returns the locale of this object. This returns the default locale - * that is set for the current VM. + * Returns the locale of this object. To match the reference + * implementation, this method always returns <code>null</code>. * - * @return the locale of this object + * @return <code>null</code>. */ - public Locale getLocale() + public Locale getLocale() + throws IllegalComponentStateException { - return Locale.getDefault(); + // refer to Sun's bug report 4269253 + return null; } /** - * Returns the accessible Icon description. This returns the - * actual 'description' property of the ImageIcon. + * Returns the accessible icon description. This returns the + * <code>description</code> property of the underlying {@link ImageIcon}. * - * @return the accessible Icon description + * @return The description (possibly <code>null</code>). + * + * @see #setAccessibleIconDescription(String) */ public String getAccessibleIconDescription() { @@ -169,10 +177,12 @@ public class ImageIcon } /** - * Sets the accessible Icon description. This sets the - * actual 'description' property of the ImageIcon. + * Sets the accessible icon description. This sets the + * <code>description</code> property of the underlying {@link ImageIcon}. * - * @param newDescr the description to be set + * @param newDescr the description (<code>null</code> permitted). + * + * @see #getAccessibleIconDescription() */ public void setAccessibleIconDescription(String newDescr) { @@ -180,10 +190,10 @@ public class ImageIcon } /** - * Returns the icon height. This returns the iconHeight property of - * the underlying Icon. + * Returns the icon height. This returns the <code>iconHeight</code> + * property of the underlying {@link ImageIcon}. * - * @return the icon height + * @return The icon height. */ public int getAccessibleIconHeight() { @@ -191,10 +201,10 @@ public class ImageIcon } /** - * Returns the icon width. This returns the iconWidth property of - * the underlying Icon. + * Returns the icon width. This returns the <code>iconWidth</code> property + * of the underlying {@link ImageIcon}. * - * @return the icon width + * @return The icon width. */ public int getAccessibleIconWidth() { @@ -278,12 +288,12 @@ public class ImageIcon } /** - * Creates an ImageIcon from the given URL without any description - * set. + * Creates an ImageIcon from the given URL and sets the description + * to the URL String representation. */ public ImageIcon(URL url) { - this(url, null); + this(url, url.toString()); } /** @@ -427,6 +437,7 @@ public class ImageIcon finally { loadStatus = tracker.statusID(id - 1, false); + tracker.removeImage(image, id - 1); } } @@ -445,9 +456,11 @@ public class ImageIcon } /** - * Returns the AccessibleContext for this ImageIcon. + * Returns the object that provides accessibility features for this + * <code>ImageIcon</code> instance. * - * @return the AccessibleContext for this ImageIcon + * @return The accessible context (an instance of + * {@link AccessibleImageIcon}). */ public AccessibleContext getAccessibleContext() { diff --git a/libjava/classpath/javax/swing/InputMap.java b/libjava/classpath/javax/swing/InputMap.java index cc65dfeed3e..28fccd9b9cd 100644 --- a/libjava/classpath/javax/swing/InputMap.java +++ b/libjava/classpath/javax/swing/InputMap.java @@ -190,8 +190,11 @@ public class InputMap Set set = new HashSet(); if (parent != null) - set.addAll(Arrays.asList(parent.allKeys())); - + { + Object[] parentKeys = parent.allKeys(); + if (parentKeys != null) + set.addAll(Arrays.asList(parentKeys)); + } set.addAll(inputMap.keySet()); if (set.size() == 0) return null; diff --git a/libjava/classpath/javax/swing/JButton.java b/libjava/classpath/javax/swing/JButton.java index ff0ecfccfd4..787adb87cf1 100644 --- a/libjava/classpath/javax/swing/JButton.java +++ b/libjava/classpath/javax/swing/JButton.java @@ -1,5 +1,5 @@ /* JButton.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. @@ -72,49 +72,82 @@ public class JButton extends AbstractButton } private static final long serialVersionUID = -1907255238954382202L; - boolean def; - boolean is_def; + /** + * Indicates if this button is capable to become the default button. + */ + private boolean defaultCapable; + + /** + * Creates a new button with an empty string for the button text and no + * icon. + */ public JButton() { this(null, null); } + /** + * Creates a new button from the specified action. + * + * @param a the action (<code>null</code> permitted). + * + * @see AbstractButton#setAction(Action) + */ public JButton(Action a) { this(); setAction(a); } + /** + * Creates a new button with the specified icon (and an empty string for + * the button text). + * + * @param icon the icon (<code>null</code> permitted). + */ public JButton(Icon icon) { this(null, icon); } + /** + * Creates a new button with the specified text and no icon. + * + * @param text the button text (<code>null</code> permitted, will be + * substituted by an empty string). + */ public JButton(String text) { this(text, null); } + /** + * Creates a new button with the specified text and icon. + * + * @param text the button text (<code>null</code> permitted, will be + * substituted by an empty string). + * @param icon the icon (<code>null</code> permitted). + */ public JButton(String text, Icon icon) { super(); init(text, icon); setModel(new DefaultButtonModel()); - } - - public Object[] getSelectedObjects() - { - return null; + defaultCapable = true; } protected void configurePropertiesFromAction(Action a) - { - // Factory method which sets the AbstractButton's properties according to - // values from the Action instance. + { super.configurePropertiesFromAction(a); } + /** + * Returns the object that provides accessibility features for this + * <code>JButton</code> component. + * + * @return The accessible context (an instance of {@link AccessibleJButton}). + */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) @@ -122,6 +155,13 @@ public class JButton extends AbstractButton return accessibleContext; } + /** + * Returns the suffix (<code>"ButtonUI"</code> in this case) used to + * determine the class name for a UI delegate that can provide the look and + * feel for a <code>JButton</code>. + * + * @return <code>"ButtonUI"</code>. + */ public String getUIClassID() { // Returns a string that specifies the name of the L&F class that renders @@ -129,28 +169,65 @@ public class JButton extends AbstractButton return "ButtonUI"; } + /** + * Returns <code>true</code> if this button is the default button in + * its <code>JRootPane</code>. The default button gets automatically + * activated when the user presses <code>ENTER</code> (or whatever + * key this is bound to in the current Look and Feel). + * + * @return <code>true</code> if this button is the default button in + * its <code>JRootPane</code> + * + * @see #isDefaultCapable() + * @see #setDefaultCapable(boolean) + * @see JRootPane#getDefaultButton() + * @see JRootPane#setDefaultButton(JButton) + */ public boolean isDefaultButton() { - // Returns whether or not this button is the default button on the - // RootPane. - return is_def; + // The default button is managed by the JRootPane, so the safest way + // to determine this property is to ask the root pane of this button, + // if it exists. + JRootPane rp = SwingUtilities.getRootPane(this); + boolean isDefault = false; + if (rp != null) + isDefault = rp.getDefaultButton() == this; + return isDefault; } + /** + * Returns <code>true</code> if this button can act as the default button. + * This is <code>true</code> by default. + * + * @return <code>true</code> if this button can act as the default button + * + * @see #setDefaultCapable(boolean) + * @see #isDefaultButton() + * @see JRootPane#getDefaultButton() + * @see JRootPane#setDefaultButton(JButton) + */ public boolean isDefaultCapable() { // Returns whether or not this button is capable of being the default // button on the RootPane. - return def; + return defaultCapable; } + /** + * Returns an implementation-dependent string describing the attributes of + * this <code>JButton</code>. + * + * @return A string describing the attributes of this <code>JButton</code> + * (never <code>null</code>). + */ protected String paramString() { String superParam = super.paramString(); // 41 is the maximum number of chars which may be needed. StringBuffer sb = new StringBuffer(41); - sb.append(",defaultButton=").append(is_def); - sb.append(",defaultCapable=").append(def); + sb.append(",defaultButton=").append(isDefaultButton()); + sb.append(",defaultCapable=").append(defaultCapable); return superParam + sb.toString(); } @@ -169,11 +246,27 @@ public class JButton extends AbstractButton super.removeNotify(); } + /** + * Sets the <code>defaultCapable</code> property which indicates if + * this button may become the default button in its <code>JRootPane</code>. + * + * @param defaultCapable <code>true</code> if this button can become the + * default button in its JRootPane, <code>false</code> otherwise + * + * @see #setDefaultCapable(boolean) + * @see #isDefaultButton() + * @see JRootPane#getDefaultButton() + * @see JRootPane#setDefaultButton(JButton) + */ public void setDefaultCapable(boolean defaultCapable) { - def = defaultCapable; + this.defaultCapable = defaultCapable; } + /** + * Sets this button's UI delegate to the default (obtained from the + * {@link UIManager}) for the current look and feel. + */ public void updateUI() { setUI((ButtonUI) UIManager.getUI(this)); diff --git a/libjava/classpath/javax/swing/JColorChooser.java b/libjava/classpath/javax/swing/JColorChooser.java index a9650ffb7e0..674f0fd82f2 100644 --- a/libjava/classpath/javax/swing/JColorChooser.java +++ b/libjava/classpath/javax/swing/JColorChooser.java @@ -301,10 +301,9 @@ public class JColorChooser extends JComponent implements Accessible throw new AWTError("No suitable parent found for Component."); JDialog dialog; if (parent instanceof Frame) - dialog = new ModalDialog((Frame) parent, title); + dialog = new JDialog((Frame) parent, title, true); else - dialog = new ModalDialog((Dialog) parent, title); - dialog.setModal(modal); + dialog = new JDialog((Dialog) parent, title, true); dialog.getContentPane().setLayout(new BorderLayout()); @@ -362,8 +361,7 @@ public class JColorChooser extends JComponent implements Accessible public void updateUI() { setUI((ColorChooserUI) UIManager.getUI(this)); - revalidate(); - } // updateUI() + } /** * This method returns a String identifier for the UI Class to be used with @@ -643,64 +641,4 @@ public class JColorChooser extends JComponent implements Accessible } } - /** - * This is a custom JDialog that will notify when it is hidden and the modal - * property is set. - */ - static class ModalDialog extends JDialog - { - /** The modal property. */ - private boolean modal; - - /** - * Creates a new ModalDialog object with the given parent and title. - * - * @param parent The parent of the JDialog. - * @param title The title of the JDialog. - */ - public ModalDialog(Frame parent, String title) - { - super(parent, title); - } - - /** - * Creates a new ModalDialog object with the given parent and title. - * - * @param parent The parent of the JDialog. - * @param title The title of the JDialog. - */ - public ModalDialog(Dialog parent, String title) - { - super(parent, title); - } - - /** - * This method sets the modal property. - * - * @param modal The modal property. - */ - public void setModal(boolean modal) - { - this.modal = modal; - } - - /** - * This method shows the ModalDialog. - */ - public void show() - { - super.show(); - if (modal) - makeModal(this); - } - - /** - * This method hides the ModalDialog. - */ - public synchronized void hide() - { - super.hide(); - notifyAll(); - } - } } diff --git a/libjava/classpath/javax/swing/JComboBox.java b/libjava/classpath/javax/swing/JComboBox.java index cd30840a6aa..175237a775a 100644 --- a/libjava/classpath/javax/swing/JComboBox.java +++ b/libjava/classpath/javax/swing/JComboBox.java @@ -1,5 +1,5 @@ /* JComboBox.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing; +import gnu.classpath.NotImplementedException; + import java.awt.ItemSelectable; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -55,8 +57,8 @@ import javax.accessibility.AccessibleRole; import javax.accessibility.AccessibleSelection; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; -import javax.swing.event.PopupMenuListener; import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; import javax.swing.plaf.ComboBoxUI; /** @@ -252,7 +254,6 @@ public class JComboBox extends JComponent implements ItemSelectable, public void updateUI() { setUI((ComboBoxUI) UIManager.getUI(this)); - invalidate(); } /** @@ -927,7 +928,7 @@ public class JComboBox extends JComponent implements ItemSelectable, */ public void actionPerformed(ActionEvent e) { - setSelectedItem(((ComboBoxEditor) e.getSource()).getItem()); + setSelectedItem(getEditor().getItem()); setPopupVisible(false); } @@ -944,8 +945,19 @@ public class JComboBox extends JComponent implements ItemSelectable, */ public boolean selectWithKeyChar(char keyChar) { - // FIXME: Need to implement - return false; + if (keySelectionManager == null) + { + keySelectionManager = createDefaultKeySelectionManager(); + } + + int index = keySelectionManager.selectionForKey(keyChar, getModel()); + boolean retVal = false; + if (index >= 0) + { + setSelectedIndex(index); + retVal = true; + } + return retVal; } /** @@ -1090,15 +1102,33 @@ public class JComboBox extends JComponent implements ItemSelectable, } /** - * A string that describes this JComboBox. Normally only used for debugging. + * Returns an implementation-dependent string describing the attributes of + * this <code>JComboBox</code>. * - * @return A string describing this JComboBox + * @return A string describing the attributes of this <code>JComboBox</code> + * (never <code>null</code>). */ protected String paramString() { - return "JComboBox"; + String superParamStr = super.paramString(); + StringBuffer sb = new StringBuffer(); + sb.append(",isEditable=").append(isEditable()); + sb.append(",lightWeightPopupEnabled=").append(isLightWeightPopupEnabled()); + sb.append(",maximumRowCount=").append(getMaximumRowCount()); + + sb.append(",selectedItemReminder="); + if (selectedItemReminder != null) + sb.append(selectedItemReminder); + return superParamStr + sb.toString(); } + /** + * Returns the object that provides accessibility features for this + * <code>JComboBox</code> component. + * + * @return The accessible context (an instance of + * {@link AccessibleJComboBox}). + */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) @@ -1207,82 +1237,105 @@ public class JComboBox extends JComponent implements ItemSelectable, { private static final long serialVersionUID = 8217828307256675666L; - protected AccessibleJComboBox() + /** + * @specnote This constructor was protected in 1.4, but made public + * in 1.5. + */ + public AccessibleJComboBox() { // Nothing to do here. } public int getAccessibleChildrenCount() + throws NotImplementedException { return 0; } public Accessible getAccessibleChild(int value0) + throws NotImplementedException { return null; } public AccessibleSelection getAccessibleSelection() + throws NotImplementedException { return null; } public Accessible getAccessibleSelection(int value0) + throws NotImplementedException { return null; } public boolean isAccessibleChildSelected(int value0) + throws NotImplementedException { return false; } + /** + * Returns the accessible role for the <code>JComboBox</code> component. + * + * @return {@link AccessibleRole#COMBO_BOX}. + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.COMBO_BOX; } public AccessibleAction getAccessibleAction() + throws NotImplementedException { return null; } public String getAccessibleActionDescription(int value0) + throws NotImplementedException { return null; } public int getAccessibleActionCount() + throws NotImplementedException { return 0; } public boolean doAccessibleAction(int value0) + throws NotImplementedException { return false; } public int getAccessibleSelectionCount() + throws NotImplementedException { return 0; } public void addAccessibleSelection(int value0) + throws NotImplementedException { // TODO: Implement this properly. } public void removeAccessibleSelection(int value0) + throws NotImplementedException { // TODO: Implement this properly. } public void clearAccessibleSelection() + throws NotImplementedException { // TODO: Implement this properly. } public void selectAllAccessibleSelection() + throws NotImplementedException { // TODO: Implement this properly. } diff --git a/libjava/classpath/javax/swing/JComponent.java b/libjava/classpath/javax/swing/JComponent.java index ddd70860869..d916d05837e 100644 --- a/libjava/classpath/javax/swing/JComponent.java +++ b/libjava/classpath/javax/swing/JComponent.java @@ -67,10 +67,10 @@ import java.awt.event.MouseEvent; import java.awt.peer.LightweightPeer; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.io.Serializable; +import java.util.ArrayList; import java.util.EventListener; import java.util.Hashtable; import java.util.Locale; @@ -81,6 +81,7 @@ import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleExtendedComponent; import javax.accessibility.AccessibleKeyBinding; import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; import javax.swing.border.Border; import javax.swing.border.CompoundBorder; @@ -104,7 +105,7 @@ public abstract class JComponent extends Container implements Serializable private static final long serialVersionUID = -7908749299918704233L; /** - * Accessibility support is currently missing. + * The accessible context of this <code>JComponent</code>. */ protected AccessibleContext accessibleContext; @@ -117,78 +118,186 @@ public abstract class JComponent extends Container implements Serializable implements AccessibleExtendedComponent { /** - * Accessibility support for <code>JComponent</code>'s focus handler. + * Receives notification if the focus on the JComponent changes and + * fires appropriate PropertyChangeEvents to listeners registered with + * the AccessibleJComponent. */ protected class AccessibleFocusHandler implements FocusListener { + /** + * Creates a new AccessibleFocusHandler. + */ protected AccessibleFocusHandler() { - // TODO: Implement this properly. + // Nothing to do here. } + + /** + * Receives notification when the JComponent gained focus and fires + * a PropertyChangeEvent to listeners registered on the + * AccessibleJComponent with a property name of + * {@link AccessibleContext#ACCESSIBLE_STATE_PROPERTY} and a new value + * of {@link AccessibleState#FOCUSED}. + */ public void focusGained(FocusEvent event) { - // TODO: Implement this properly. + AccessibleJComponent.this.firePropertyChange + (AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, + AccessibleState.FOCUSED); } + + /** + * Receives notification when the JComponent lost focus and fires + * a PropertyChangeEvent to listeners registered on the + * AccessibleJComponent with a property name of + * {@link AccessibleContext#ACCESSIBLE_STATE_PROPERTY} and an old value + * of {@link AccessibleState#FOCUSED}. + */ public void focusLost(FocusEvent valevent) { - // TODO: Implement this properly. + AccessibleJComponent.this.firePropertyChange + (AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + AccessibleState.FOCUSED, null); } } /** - * Accessibility support for <code>JComponent</code>'s container handler. + * Receives notification if there are child components are added or removed + * from the JComponent and fires appropriate PropertyChangeEvents to + * interested listeners on the AccessibleJComponent. */ protected class AccessibleContainerHandler implements ContainerListener { + /** + * Creates a new AccessibleContainerHandler. + */ protected AccessibleContainerHandler() { - // TODO: Implement this properly. + // Nothing to do here. } + + /** + * Receives notification when a child component is added to the + * JComponent and fires a PropertyChangeEvent on listeners registered + * with the AccessibleJComponent with a property name of + * {@link AccessibleContext#ACCESSIBLE_CHILD_PROPERTY}. + * + * @param event the container event + */ public void componentAdded(ContainerEvent event) { - // TODO: Implement this properly. + Component c = event.getChild(); + if (c != null && c instanceof Accessible) + { + AccessibleContext childCtx = c.getAccessibleContext(); + AccessibleJComponent.this.firePropertyChange + (AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, null, childCtx); + } } - public void componentRemoved(ContainerEvent valevent) + + /** + * Receives notification when a child component is removed from the + * JComponent and fires a PropertyChangeEvent on listeners registered + * with the AccessibleJComponent with a property name of + * {@link AccessibleContext#ACCESSIBLE_CHILD_PROPERTY}. + * + * @param event the container event + */ + public void componentRemoved(ContainerEvent event) { - // TODO: Implement this properly. + Component c = event.getChild(); + if (c != null && c instanceof Accessible) + { + AccessibleContext childCtx = c.getAccessibleContext(); + AccessibleJComponent.this.firePropertyChange + (AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, childCtx, null); + } } } private static final long serialVersionUID = -7047089700479897799L; - + + /** + * Receives notification when a child component is added to the + * JComponent and fires a PropertyChangeEvent on listeners registered + * with the AccessibleJComponent. + * + * @specnote AccessibleAWTContainer has a protected field with the same + * name. Looks like a bug or nasty misdesign to me. + */ protected ContainerListener accessibleContainerHandler; - protected FocusListener accessibleFocusHandler; /** - * Manages the property change listeners; + * Receives notification if the focus on the JComponent changes and + * fires appropriate PropertyChangeEvents to listeners registered with + * the AccessibleJComponent. + * + * @specnote AccessibleAWTComponent has a protected field + * accessibleAWTFocusHandler. Looks like a bug or nasty misdesign + * to me. */ - private PropertyChangeSupport changeSupport; + protected FocusListener accessibleFocusHandler; + /** + * Creates a new AccessibleJComponent. + */ protected AccessibleJComponent() { - changeSupport = new PropertyChangeSupport(this); + // Nothing to do here. } /** * Adds a property change listener to the list of registered listeners. * + * This sets up the {@link #accessibleContainerHandler} and + * {@link #accessibleFocusHandler} fields and calls + * <code>super.addPropertyChangeListener(listener)</code>. + * * @param listener the listener to add */ public void addPropertyChangeListener(PropertyChangeListener listener) { - changeSupport.addPropertyChangeListener(listener); + // Tests seem to indicate that this method also sets up the other two + // handlers. + if (accessibleContainerHandler == null) + { + accessibleContainerHandler = new AccessibleContainerHandler(); + addContainerListener(accessibleContainerHandler); + } + if (accessibleFocusHandler == null) + { + accessibleFocusHandler = new AccessibleFocusHandler(); + addFocusListener(accessibleFocusHandler); + } + super.addPropertyChangeListener(listener); } /** - * Removes a propery change listener from the list of registered listeners. + * Removes a property change listener from the list of registered listeners. + * + * This uninstalls the {@link #accessibleContainerHandler} and + * {@link #accessibleFocusHandler} fields and calls + * <code>super.removePropertyChangeListener(listener)</code>. * * @param listener the listener to remove */ public void removePropertyChangeListener(PropertyChangeListener listener) { - changeSupport.removePropertyChangeListener(listener); + // Tests seem to indicate that this method also resets the other two + // handlers. + if (accessibleContainerHandler != null) + { + removeContainerListener(accessibleContainerHandler); + accessibleContainerHandler = null; + } + if (accessibleFocusHandler != null) + { + removeFocusListener(accessibleFocusHandler); + accessibleFocusHandler = null; + } + super.removePropertyChangeListener(listener); } /** @@ -198,14 +307,11 @@ public abstract class JComponent extends Container implements Serializable */ public int getAccessibleChildrenCount() { - int count = 0; - Component[] children = getComponents(); - for (int i = 0; i < children.length; ++i) - { - if (children[i] instanceof Accessible) - count++; - } - return count; + // TODO: The functionality should be performed in the superclass. + // Find out why this is overridden. However, it is very well possible + // that this is left over from times when there was no such superclass + // method. + return super.getAccessibleChildrenCount(); } /** @@ -217,18 +323,11 @@ public abstract class JComponent extends Container implements Serializable */ public Accessible getAccessibleChild(int i) { - int index = 0; - Component[] children = getComponents(); - Accessible found = null; - for (int j = 0; index != i; j++) - { - if (children[j] instanceof Accessible) - index++; - if (index == i) - found = (Accessible) children[index]; - } - // TODO: Figure out what to do when i is not a valid index. - return found; + // TODO: The functionality should be performed in the superclass. + // Find out why this is overridden. However, it is very well possible + // that this is left over from times when there was no such superclass + // method. + return super.getAccessibleChild(i); } /** @@ -238,9 +337,14 @@ public abstract class JComponent extends Container implements Serializable */ public AccessibleStateSet getAccessibleStateSet() { - // FIXME: Figure out which states should be set here, and which are - // inherited from the super class. - return super.getAccessibleStateSet(); + // Note: While the java.awt.Component has an 'opaque' property, it + // seems that it is not added to the accessible state set there, even + // if this property is true. However, it is handled for JComponent, so + // we add it here. + AccessibleStateSet state = super.getAccessibleStateSet(); + if (isOpaque()) + state.add(AccessibleState.OPAQUE); + return state; } /** @@ -256,9 +360,33 @@ public abstract class JComponent extends Container implements Serializable */ public String getAccessibleName() { - // TODO: Figure out what exactly to return here. It's possible that this - // method simply should return null. - return null; + String name = super.getAccessibleName(); + + // There are two fallbacks provided by the JComponent in the case the + // superclass returns null: + // - If the component is inside a titled border, then it inherits the + // name from the border title. + // - If the component is not inside a titled border but has a label + // (via JLabel.setLabelFor()), then it gets the name from the label's + // accessible context. + + if (name == null) + { + name = getTitledBorderText(); + } + + if (name == null) + { + Object l = getClientProperty(JLabel.LABEL_PROPERTY); + if (l instanceof Accessible) + { + AccessibleContext labelCtx = + ((Accessible) l).getAccessibleContext(); + name = labelCtx.getAccessibleName(); + } + } + + return name; } /** @@ -269,9 +397,32 @@ public abstract class JComponent extends Container implements Serializable */ public String getAccessibleDescription() { - // TODO: Figure out what exactly to return here. It's possible that this - // method simply should return null. - return null; + // There are two fallbacks provided by the JComponent in the case the + // superclass returns null: + // - If the component has a tooltip, then inherit the description from + // the tooltip. + // - If the component is not inside a titled border but has a label + // (via JLabel.setLabelFor()), then it gets the name from the label's + // accessible context. + String descr = super.getAccessibleDescription(); + + if (descr == null) + { + descr = getToolTipText(); + } + + if (descr == null) + { + Object l = getClientProperty(JLabel.LABEL_PROPERTY); + if (l instanceof Accessible) + { + AccessibleContext labelCtx = + ((Accessible) l).getAccessibleContext(); + descr = labelCtx.getAccessibleName(); + } + } + + return descr; } /** @@ -283,7 +434,6 @@ public abstract class JComponent extends Container implements Serializable */ public AccessibleRole getAccessibleRole() { - // TODO: Check if this is correct. return AccessibleRole.SWING_COMPONENT; } @@ -349,7 +499,8 @@ public abstract class JComponent extends Container implements Serializable */ public AccessibleKeyBinding getAccessibleKeyBinding() { - // TODO: Implement this properly. + // The reference implementation seems to always return null here, + // independent of the key bindings of the JComponent. So do we. return null; } } @@ -550,6 +701,16 @@ public abstract class JComponent extends Container implements Serializable private boolean paintingTile; /** + * A temporary buffer used for fast dragging of components. + */ + private Image dragBuffer; + + /** + * Indicates if the dragBuffer is already initialized. + */ + private boolean dragBufferInitialized; + + /** * A cached Rectangle object to be reused. Be careful when you use that, * so that it doesn't get modified in another context within the same * method call chain. @@ -606,6 +767,24 @@ public abstract class JComponent extends Container implements Serializable boolean isCompletelyDirty = false; /** + * Indicates if the opaque property has been set by a client program or by + * the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientOpaqueSet = false; + + /** + * Indicates if the autoscrolls property has been set by a client program or + * by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientAutoscrollsSet = false; + + /** * Creates a new <code>JComponent</code> instance. */ public JComponent() @@ -1218,7 +1397,12 @@ public abstract class JComponent extends Container implements Serializable */ public Component getNextFocusableComponent() { - return null; + Container focusRoot = this; + if (! this.isFocusCycleRoot()) + focusRoot = getFocusCycleRootAncestor(); + + FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); + return policy.getComponentAfter(focusRoot, this); } /** @@ -1412,7 +1596,7 @@ public abstract class JComponent extends Container implements Serializable */ public void grabFocus() { - // TODO: Implement this properly. + requestFocus(); } /** @@ -1556,20 +1740,58 @@ public abstract class JComponent extends Container implements Serializable } else { + if (getClientProperty("bufferedDragging") != null + && dragBuffer == null) + { + initializeDragBuffer(); + } + else if (getClientProperty("bufferedDragging") == null + && dragBuffer != null) + { + dragBuffer = null; + } + if (g.getClip() == null) g.setClip(0, 0, getWidth(), getHeight()); - Graphics g2 = getComponentGraphics(g); - paintComponent(g2); - paintBorder(g2); - paintChildren(g2); - Rectangle clip = g2.getClipBounds(); - if (clip.x == 0 && clip.y == 0 && clip.width == getWidth() - && clip.height == getHeight()) - RepaintManager.currentManager(this).markCompletelyClean(this); + if (dragBuffer != null && dragBufferInitialized) + { + g.drawImage(dragBuffer, 0, 0, this); + } + else + { + Graphics g2 = getComponentGraphics(g); + 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); + } } } /** + * Initializes the drag buffer by creating a new image and painting this + * component into it. + */ + private void initializeDragBuffer() + { + dragBufferInitialized = false; + // Allocate new dragBuffer if the current one is too small. + if (dragBuffer == null || dragBuffer.getWidth(this) < getWidth() + || dragBuffer.getHeight(this) < getHeight()) + { + dragBuffer = createImage(getWidth(), getHeight()); + } + Graphics g = dragBuffer.getGraphics(); + paint(g); + g.dispose(); + dragBufferInitialized = true; + } + + /** * Paint the component's border. This usually means calling {@link * Border#paintBorder} on the {@link #border} property, if it is * non-<code>null</code>. You may override this if you wish to customize @@ -1604,41 +1826,219 @@ public abstract class JComponent extends Container implements Serializable */ protected void paintChildren(Graphics g) { + if (getComponentCount() > 0) + { + if (isOptimizedDrawingEnabled()) + paintChildrenOptimized(g); + else + paintChildrenWithOverlap(g); + } + } + + /** + * Paints the children of this JComponent in the case when the component + * is not marked as optimizedDrawingEnabled, that means the container cannot + * guarantee that it's children are tiled. For this case we must + * perform a more complex optimization to determine the minimal rectangle + * to be painted for each child component. + * + * @param g the graphics context to use + */ + private void paintChildrenWithOverlap(Graphics g) + { Shape originalClip = g.getClip(); Rectangle inner = SwingUtilities.calculateInnerArea(this, rectCache); g.clipRect(inner.x, inner.y, inner.width, inner.height); Component[] children = getComponents(); - // Find the bottommost component that needs to be painted. This is a - // component that completely covers the current clip and is opaque. In - // this case we don't need to paint the components below it. - int startIndex = children.length - 1; - // No need to check for overlapping components when this component is - // optimizedDrawingEnabled (== it tiles its children). - if (! isOptimizedDrawingEnabled()) + // Find the rectangles that need to be painted for each child component. + // We push on this list arrays that have the Rectangles to be painted as + // the first elements and the component to be painted as the last one. + // Later we go through that list in reverse order and paint the rectangles. + ArrayList paintRegions = new ArrayList(children.length); + ArrayList paintRectangles = new ArrayList(); + ArrayList newPaintRects = new ArrayList(); + paintRectangles.add(g.getClipBounds()); + ArrayList componentRectangles = new ArrayList(); + + // Go through children from top to bottom and find out their paint + // rectangles. + for (int index = 0; paintRectangles.size() > 0 && + index < children.length; index++) { - for (int i = 0; i < children.length; i++) + Component comp = children[index]; + if (! comp.isVisible()) + continue; + + Rectangle compBounds = comp.getBounds(); + boolean isOpaque = comp instanceof JComponent + && ((JComponent) comp).isOpaque(); + + // Add all the current paint rectangles that intersect with the + // component to the component's paint rectangle array. + for (int i = paintRectangles.size() - 1; i >= 0; i--) { - Rectangle childBounds = children[i].getBounds(); - if (children[i].isOpaque() && children[i].isVisible() - && SwingUtilities.isRectangleContainingRectangle(childBounds, - g.getClipBounds())) + Rectangle r = (Rectangle) paintRectangles.get(i); + if (r.intersects(compBounds)) { - startIndex = i; - break; + Rectangle compRect = r.intersection(compBounds); + componentRectangles.add(compRect); + // If the component is opaque, split up each paint rect and + // add paintRect - compBounds to the newPaintRects array. + if (isOpaque) + { + int x, y, w, h; + Rectangle rect = new Rectangle(); + + // The north retangle. + x = Math.max(compBounds.x, r.x); + y = r.y; + w = Math.min(compBounds.width, r.width + r.x - x); + h = compBounds.y - r.y; + rect.setBounds(x, y, w, h); + if (! rect.isEmpty()) + { + newPaintRects.add(rect); + rect = new Rectangle(); + } + + // The south rectangle. + x = Math.max(compBounds.x, r.x); + y = compBounds.y + compBounds.height; + w = Math.min(compBounds.width, r.width + r.x - x); + h = r.height - (compBounds.y - r.y) - compBounds.height; + rect.setBounds(x, y, w, h); + if (! rect.isEmpty()) + { + newPaintRects.add(rect); + rect = new Rectangle(); + } + + // The west rectangle. + x = r.x; + y = r.y; + w = compBounds.x - r.x; + h = r.height; + rect.setBounds(x, y, w, h); + if (! rect.isEmpty()) + { + newPaintRects.add(rect); + rect = new Rectangle(); + } + + // The east rectangle. + x = compBounds.x + compBounds.width; + y = r.y; + w = r.width - (compBounds.x - r.x) - compBounds.width; + h = r.height; + rect.setBounds(x, y, w, h); + if (! rect.isEmpty()) + { + newPaintRects.add(rect); + } + } + else + { + // Not opaque, need to reuse the current paint rectangles + // for the next component. + newPaintRects.add(r); + } + } + else + { + newPaintRects.add(r); + } + } + + // Replace the paintRectangles with the new split up + // paintRectangles. + paintRectangles.clear(); + paintRectangles.addAll(newPaintRects); + newPaintRects.clear(); + + // Store paint rectangles if there are any for the current component. + int compRectsSize = componentRectangles.size(); + if (compRectsSize > 0) + { + componentRectangles.add(comp); + paintRegions.add(componentRectangles); + componentRectangles = new ArrayList(); } } + // paintingTile becomes true just before we start painting the component's // children. paintingTile = true; - for (int i = startIndex; i >= 0; --i) + + // We must go through the painting regions backwards, because the + // topmost components have been added first, followed by the components + // below. + int prEndIndex = paintRegions.size() - 1; + for (int i = prEndIndex; i >= 0; i--) { // paintingTile must be set to false before we begin to start painting // the last tile. if (i == 0) paintingTile = false; + ArrayList paintingRects = (ArrayList) paintRegions.get(i); + // The last element is always the component. + Component c = (Component) paintingRects.get(paintingRects.size() - 1); + int endIndex = paintingRects.size() - 2; + for (int j = 0; j <= endIndex; j++) + { + Rectangle cBounds = c.getBounds(); + Rectangle bounds = (Rectangle) paintingRects.get(j); + Rectangle oldClip = g.getClipBounds(); + if (oldClip == null) + oldClip = bounds; + + boolean translated = false; + try + { + g.setClip(bounds); + g.translate(cBounds.x, cBounds.y); + translated = true; + c.paint(g); + } + finally + { + if (translated) + g.translate(-cBounds.x, -cBounds.y); + g.setClip(oldClip); + } + } + } + g.setClip(originalClip); + } + + /** + * Paints the children of this container when it is marked as + * optimizedDrawingEnabled. In this case the container can guarantee that + * it's children are tiled, which allows for a much more efficient + * algorithm to determine the minimum rectangles to be painted for + * each child. + * + * @param g the graphics context to use + */ + private void paintChildrenOptimized(Graphics g) + { + Shape originalClip = g.getClip(); + Rectangle inner = SwingUtilities.calculateInnerArea(this, rectCache); + g.clipRect(inner.x, inner.y, inner.width, inner.height); + Component[] children = getComponents(); + + // paintingTile becomes true just before we start painting the component's + // children. + paintingTile = true; + for (int i = children.length - 1; i >= 0; i--) //children.length; i++) + { + // paintingTile must be set to false before we begin to start painting + // the last tile. + if (i == children.length - 1) + paintingTile = false; + if (!children[i].isVisible()) continue; @@ -1760,6 +2160,33 @@ public abstract class JComponent extends Container implements Serializable } /** + * Gets the root of the component given. If a parent of the + * component is an instance of Applet, then the applet is + * returned. The applet is considered the root for painting + * and adding/removing components. Otherwise, the root Window + * is returned if it exists. + * + * @param comp - The component to get the root for. + * @return the parent root. An applet if it is a parent, + * or the root window. If neither exist, null is returned. + */ + private Component getRoot(Component comp) + { + Applet app = null; + + while (comp != null) + { + if (app == null && comp instanceof Window) + return comp; + else if (comp instanceof Applet) + app = (Applet) comp; + comp = comp.getParent(); + } + + return app; + } + + /** * Performs double buffered repainting. */ private void paintDoubleBuffered(Rectangle r) @@ -1767,7 +2194,7 @@ public abstract class JComponent extends Container implements Serializable RepaintManager rm = RepaintManager.currentManager(this); // Paint on the offscreen buffer. - Component root = SwingUtilities.getRoot(this); + Component root = getRoot(this); Image buffer = rm.getOffscreenBuffer(this, root.getWidth(), root.getHeight()); //Rectangle targetClip = SwingUtilities.convertRectangle(this, r, root); @@ -1993,15 +2420,15 @@ public abstract class JComponent extends Container implements Serializable * Return the condition that determines whether a registered action * occurs in response to the specified keystroke. * + * As of 1.3 KeyStrokes can be registered with multiple simultaneous + * conditions. + * * @param ks The keystroke to return the condition of * * @return One of the values {@link #UNDEFINED_CONDITION}, {@link * #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}, {@link #WHEN_FOCUSED}, or {@link * #WHEN_IN_FOCUSED_WINDOW} * - * @deprecated As of 1.3 KeyStrokes can be registered with multiple - * simultaneous conditions. - * * @see #registerKeyboardAction(ActionListener, KeyStroke, int) * @see #unregisterKeyboardAction * @see #resetKeyboardActions @@ -2028,8 +2455,6 @@ public abstract class JComponent extends Container implements Serializable * @param ks The keystroke to retrieve the action of * * @return The action associated with the specified keystroke - * - * @deprecated Use {@link #getActionMap()} */ public ActionListener getActionForKeyStroke(KeyStroke ks) { @@ -2167,7 +2592,20 @@ public abstract class JComponent extends Container implements Serializable */ public void unregisterKeyboardAction(KeyStroke aKeyStroke) { - // FIXME: Must be implemented. + ActionMap am = getActionMap(); + // This loops through the conditions WHEN_FOCUSED, + // WHEN_ANCESTOR_OF_FOCUSED_COMPONENT and WHEN_IN_FOCUSED_WINDOW. + for (int cond = 0; cond < 3; cond++) + { + InputMap im = getInputMap(cond); + if (im != null) + { + Object action = im.get(aKeyStroke); + if (action != null && am != null) + am.remove(action); + im.remove(aKeyStroke); + } + } } @@ -2306,6 +2744,7 @@ public abstract class JComponent extends Container implements Serializable public void setAutoscrolls(boolean a) { autoscrolls = a; + clientAutoscrollsSet = true; } /** @@ -2444,7 +2883,29 @@ public abstract class JComponent extends Container implements Serializable */ public void setNextFocusableComponent(Component aComponent) { - // TODO: Implement this properly. + Container focusRoot = this; + if (! this.isFocusCycleRoot()) + focusRoot = getFocusCycleRootAncestor(); + + FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); + if (policy instanceof CompatibilityFocusTraversalPolicy) + { + policy = new CompatibilityFocusTraversalPolicy(policy); + focusRoot.setFocusTraversalPolicy(policy); + } + CompatibilityFocusTraversalPolicy p = + (CompatibilityFocusTraversalPolicy) policy; + + Component old = getNextFocusableComponent(); + if (old != null) + { + p.removeNextFocusableComponent(this, old); + } + + if (aComponent != null) + { + p.addNextFocusableComponent(this, aComponent); + } } /** @@ -2489,9 +2950,12 @@ public abstract class JComponent extends Container implements Serializable } /** - * Set the value of the {@link #opaque} property. + * Set if the component should paint all pixels withing its bounds. + * If this property is set to false, the component expects the cleared + * background. * - * @param isOpaque The new value of the property + * @param isOpaque if true, paint all pixels. If false, expect the clean + * background. * * @see ComponentUI#update */ @@ -2499,6 +2963,7 @@ public abstract class JComponent extends Container implements Serializable { boolean oldOpaque = opaque; opaque = isOpaque; + clientOpaqueSet = true; firePropertyChange("opaque", oldOpaque, opaque); } @@ -3174,4 +3639,44 @@ public abstract class JComponent extends Container implements Serializable km.registerEntireMap((ComponentInputMap) getInputMap(WHEN_IN_FOCUSED_WINDOW)); } + + /** + * Helper method for + * {@link LookAndFeel#installProperty(JComponent, String, Object)}. + * + * @param propertyName the name of the property + * @param value the value of the property + * + * @throws IllegalArgumentException if the specified property cannot be set + * by this method + * @throws ClassCastException if the property value does not match the + * property type + * @throws NullPointerException if <code>c</code> or + * <code>propertyValue</code> is <code>null</code> + */ + void setUIProperty(String propertyName, Object value) + { + if (propertyName.equals("opaque")) + { + if (! clientOpaqueSet) + { + setOpaque(((Boolean) value).booleanValue()); + clientOpaqueSet = false; + } + } + else if (propertyName.equals("autoscrolls")) + { + if (! clientAutoscrollsSet) + { + setAutoscrolls(((Boolean) value).booleanValue()); + clientAutoscrollsSet = false; + } + } + else + { + throw new IllegalArgumentException + ("Unsupported property for LookAndFeel.installProperty(): " + + propertyName); + } + } } diff --git a/libjava/classpath/javax/swing/JDesktopPane.java b/libjava/classpath/javax/swing/JDesktopPane.java index 43ab71e7e9f..454870ea6fc 100644 --- a/libjava/classpath/javax/swing/JDesktopPane.java +++ b/libjava/classpath/javax/swing/JDesktopPane.java @@ -56,7 +56,6 @@ import javax.swing.plaf.DesktopPaneUI; */ public class JDesktopPane extends JLayeredPane implements Accessible { - /** DOCUMENT ME! */ private static final long serialVersionUID = 766333777224038726L; /** @@ -85,15 +84,24 @@ public class JDesktopPane extends JLayeredPane implements Accessible private transient int dragMode = LIVE_DRAG_MODE; /** - * AccessibleJDesktopPane + * Indicates if the dragMode property has been set by a client + * program or by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientDragModeSet = false; + + /** + * Provides the accessibility features for the <code>JDesktopPane</code> + * component. */ protected class AccessibleJDesktopPane extends AccessibleJComponent { - /** DOCUMENT ME! */ private static final long serialVersionUID = 6079388927946077570L; /** - * Constructor AccessibleJDesktopPane + * Creates a new <code>AccessibleJDesktopPane</code> instance. */ protected AccessibleJDesktopPane() { @@ -101,9 +109,9 @@ public class JDesktopPane extends JLayeredPane implements Accessible } /** - * getAccessibleRole + * Returns the accessible role for the <code>JSlider</code> component. * - * @return AccessibleRole + * @return {@link AccessibleRole#DESKTOP_PANE}. */ public AccessibleRole getAccessibleRole() { @@ -153,6 +161,8 @@ public class JDesktopPane extends JLayeredPane implements Accessible if ((mode != LIVE_DRAG_MODE) && (mode != OUTLINE_DRAG_MODE)) throw new IllegalArgumentException("Drag mode not valid."); + clientDragModeSet = true; + // FIXME: Unsupported mode. if (mode == OUTLINE_DRAG_MODE) // throw new IllegalArgumentException("Outline drag modes are @@ -198,7 +208,6 @@ public class JDesktopPane extends JLayeredPane implements Accessible public void updateUI() { setUI((DesktopPaneUI) UIManager.getUI(this)); - invalidate(); } /** @@ -288,13 +297,22 @@ public class JDesktopPane extends JLayeredPane implements Accessible } /** - * This method returns a String that describes the JDesktopPane. + * Returns an implementation-dependent string describing the attributes of + * this <code>JDesktopPane</code>. * - * @return A String that describes the JDesktopPane. + * @return A string describing the attributes of this <code>JDesktopPane</code> + * (never <code>null</code>). */ protected String paramString() { - return "JDesktopPane"; + String superParamStr = super.paramString(); + StringBuffer sb = new StringBuffer(); + sb.append(",isOptimizedDrawingPossible="); + sb.append(isOptimizedDrawingEnabled()); + sb.append(",desktopManager="); + if (desktopManager != null) + sb.append(desktopManager); + return superParamStr + sb.toString(); } /** @@ -320,9 +338,11 @@ public class JDesktopPane extends JLayeredPane implements Accessible } /** - * getAccessibleContext + * Returns the object that provides accessibility features for this + * <code>JDesktopPane</code> component. * - * @return AccessibleContext + * @return The accessible context (an instance of + * {@link AccessibleJDesktopPane}). */ public AccessibleContext getAccessibleContext() { @@ -331,4 +351,34 @@ public class JDesktopPane extends JLayeredPane implements Accessible return accessibleContext; } + + /** + * Helper method for + * {@link LookAndFeel#installProperty(JComponent, String, Object)}. + * + * @param propertyName the name of the property + * @param value the value of the property + * + * @throws IllegalArgumentException if the specified property cannot be set + * by this method + * @throws ClassCastException if the property value does not match the + * property type + * @throws NullPointerException if <code>c</code> or + * <code>propertyValue</code> is <code>null</code> + */ + void setUIProperty(String propertyName, Object value) + { + if (propertyName.equals("dragMode")) + { + if (! clientDragModeSet) + { + setDragMode(((Integer) value).intValue()); + clientDragModeSet = false; + } + } + else + { + super.setUIProperty(propertyName, value); + } + } } diff --git a/libjava/classpath/javax/swing/JFileChooser.java b/libjava/classpath/javax/swing/JFileChooser.java index 72bd2bb28f5..7da3a132dbe 100644 --- a/libjava/classpath/javax/swing/JFileChooser.java +++ b/libjava/classpath/javax/swing/JFileChooser.java @@ -37,6 +37,8 @@ exception statement from your version. */ package javax.swing; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Frame; import java.awt.HeadlessException; @@ -49,7 +51,6 @@ import java.util.ArrayList; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; -import javax.swing.JDialog; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileSystemView; import javax.swing.filechooser.FileView; @@ -491,6 +492,7 @@ public class JFileChooser extends JComponent implements Accessible * @param b DOCUMENT ME! */ public void setDragEnabled(boolean b) + throws NotImplementedException { // FIXME: Implement } @@ -501,6 +503,7 @@ public class JFileChooser extends JComponent implements Accessible * @return DOCUMENT ME! */ public boolean getDragEnabled() + throws NotImplementedException { // FIXME: Implement return false; @@ -1488,7 +1491,6 @@ public class JFileChooser extends JComponent implements Accessible public void updateUI() { setUI((FileChooserUI) UIManager.getUI(this)); - revalidate(); } /** @@ -1528,7 +1530,9 @@ public class JFileChooser extends JComponent implements Accessible */ public AccessibleContext getAccessibleContext() { - return new AccessibleJFileChooser(); + if (accessibleContext == null) + accessibleContext = new AccessibleJFileChooser(); + return accessibleContext; } /** diff --git a/libjava/classpath/javax/swing/JInternalFrame.java b/libjava/classpath/javax/swing/JInternalFrame.java index 5bd6f781cd0..79dcc7326be 100644 --- a/libjava/classpath/javax/swing/JInternalFrame.java +++ b/libjava/classpath/javax/swing/JInternalFrame.java @@ -1,5 +1,5 @@ /* JInternalFrame.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,6 +44,7 @@ import java.awt.Graphics; import java.awt.KeyboardFocusManager; import java.awt.LayoutManager; import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; import java.beans.PropertyVetoException; import javax.accessibility.Accessible; @@ -67,11 +68,12 @@ public class JInternalFrame extends JComponent implements Accessible, WindowConstants, RootPaneContainer { - /** DOCUMENT ME! */ + private static final long serialVersionUID = -5425177187760785402L; /** - * DOCUMENT ME! + * Provides the accessibility features for the <code>JInternalFrame</code> + * component. */ protected class AccessibleJInternalFrame extends AccessibleJComponent implements AccessibleValue @@ -79,7 +81,7 @@ public class JInternalFrame extends JComponent implements Accessible, private static final long serialVersionUID = 5931936924175476797L; /** - * Creates a new AccessibleJInternalFrame object. + * Creates a new <code>AccessibleJInternalFrame</code> instance. */ protected AccessibleJInternalFrame() { @@ -87,75 +89,83 @@ public class JInternalFrame extends JComponent implements Accessible, } /** - * DOCUMENT ME! + * Returns the frame title. * - * @return DOCUMENT ME! + * @return The frame title. */ public String getAccessibleName() { - return null; + return getTitle(); } /** - * DOCUMENT ME! + * Returns the accessible role for the <code>JInternalFrame</code> + * component. * - * @return DOCUMENT ME! + * @return {@link AccessibleRole#INTERNAL_FRAME}. */ public AccessibleRole getAccessibleRole() { - return null; + return AccessibleRole.INTERNAL_FRAME; } /** - * DOCUMENT ME! + * Returns an object that provides access to the current, minimum and + * maximum values for the {@link JInternalFrame}. Since this class + * implements {@link AccessibleValue}, it returns itself. * - * @return DOCUMENT ME! + * @return The accessible value. */ public AccessibleValue getAccessibleValue() { - return null; + return this; } /** - * DOCUMENT ME! + * Returns the current layer for the {@link JInternalFrame} component, + * as an {@link Integer}. * - * @return DOCUMENT ME! + * @return The layer for the {@link JInternalFrame} component. */ public Number getCurrentAccessibleValue() { - return null; + return new Integer(getLayer()); } /** - * DOCUMENT ME! + * Returns the maximum permitted accessible value. * - * @return DOCUMENT ME! + * @return <code>Integer(Integer.MAX_VALUE)</code>. */ public Number getMaximumAccessibleValue() { - return null; + return new Integer(Integer.MAX_VALUE); } /** - * DOCUMENT ME! + * Returns the minimum permitted accessible value. * - * @return DOCUMENT ME! + * @return <code>Integer(Integer.MIN_VALUE)</code>. */ public Number getMinimumAccessibleValue() { - return null; + return new Integer(Integer.MIN_VALUE); } /** - * DOCUMENT ME! + * Sets the layer for the internal frame. * - * @param n DOCUMENT ME! + * @param n the layer (see the constants defined in {@link JLayeredPane}). * - * @return DOCUMENT ME! + * @return <code>true</code> if the value is set, and <code>false</code> + * if it was not set. */ public boolean setCurrentAccessibleValue(Number n) { - return false; + if (n == null) + return false; + setLayer(n.intValue()); + return true; } } @@ -165,7 +175,8 @@ public class JInternalFrame extends JComponent implements Accessible, public static class JDesktopIcon extends JComponent implements Accessible { /** - * DOCUMENT ME! + * Provides the accessibility features for the <code>JDesktopIcon</code> + * component. */ protected class AccessibleJDesktopIcon extends AccessibleJComponent implements AccessibleValue @@ -173,73 +184,83 @@ public class JInternalFrame extends JComponent implements Accessible, private static final long serialVersionUID = 5035560458941637802L; /** - * Creates a new AccessibleJDesktopIcon object. + * Creates a new <code>AccessibleJDesktopIcon</code> instance. */ protected AccessibleJDesktopIcon() { - super(); + super(); } /** - * DOCUMENT ME! + * Returns the accessible role for the <code>JDesktopIcon</code> + * component. * - * @return DOCUMENT ME! + * @return {@link AccessibleRole#DESKTOP_ICON}. */ public AccessibleRole getAccessibleRole() { - return null; + return AccessibleRole.DESKTOP_ICON; } /** - * DOCUMENT ME! + * Returns an object that provides access to the current, minimum and + * maximum values for the {@link JDesktopIcon}. Since this class + * implements {@link AccessibleValue}, it returns itself. * - * @return DOCUMENT ME! + * @return The accessible value. */ public AccessibleValue getAccessibleValue() { - return null; + return this; } /** - * DOCUMENT ME! + * Returns the current layer for the {@link JInternalFrame} component + * represented by this <code>JDesktopIcon</code>, as an {@link Integer}. * - * @return DOCUMENT ME! + * @return The layer. */ public Number getCurrentAccessibleValue() { - return null; + return new Integer(frame.getLayer()); } /** - * DOCUMENT ME! + * Returns the maximum permitted accessible value. * - * @return DOCUMENT ME! + * @return <code>Integer(Integer.MAX_VALUE)</code>. */ public Number getMaximumAccessibleValue() { - return null; + return new Integer(Integer.MAX_VALUE); } /** - * DOCUMENT ME! + * Returns the minimum permitted accessible value. * - * @return DOCUMENT ME! + * @return <code>Integer(Integer.MIN_VALUE)</code>. */ public Number getMinimumAccessibleValue() { - return null; + return new Integer(Integer.MIN_VALUE); } /** - * DOCUMENT ME! + * Sets the layer for the internal frame represented by this + * <code>JDesktopIcon</code> component. * - * @param n DOCUMENT ME! + * @param n the layer (see the constants defined in + * {@link JLayeredPane}). * - * @return DOCUMENT ME! + * @return <code>true</code> if the value is set, and <code>false</code> + * if it was not set. */ public boolean setCurrentAccessibleValue(Number n) { - return false; + if (n == null) + return false; + frame.setLayer(n.intValue()); + return true; } } @@ -259,15 +280,17 @@ public class JInternalFrame extends JComponent implements Accessible, updateUI(); } - /** - * DOCUMENT ME! - * - * @return DOCUMENT ME! - */ + /** + * Returns the object that provides accessibility features for this + * <code>JDesktopIcon</code> component. + * + * @return The accessible context (an instance of + * {@link AccessibleJDesktopIcon}). + */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) - accessibleContext = new AccessibleJDesktopIcon(); + accessibleContext = new AccessibleJDesktopIcon(); return accessibleContext; } @@ -477,12 +500,13 @@ public class JInternalFrame extends JComponent implements Accessible, private transient boolean wasIcon = false; /** - * Creates a new JInternalFrame object that has no title, and is - * non-resizable, non-maximizable, non-iconifiable, and non-closable. + * Creates a new JInternalFrame object that has an empty string for its + * title, and is non-resizable, non-maximizable, non-iconifiable, and + * non-closable. */ public JInternalFrame() { - this(null, false, false, false, false); + this("", false, false, false, false); } /** @@ -559,8 +583,9 @@ public class JInternalFrame extends JComponent implements Accessible, this.iconable = iconifiable; storedBounds = new Rectangle(); setRootPane(createRootPane()); - // JInternalFrames are invisible by default. + // JInternalFrames are invisible and opaque by default. setVisible(false); + setOpaque(true); updateUI(); setRootPaneCheckingEnabled(true); // Done the init stage, now adds go to content pane. } @@ -726,9 +751,11 @@ public class JInternalFrame extends JComponent implements Accessible, } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JInternalFrame</code> component. * - * @return DOCUMENT ME! + * @return The accessible context (an instance of + * {@link AccessibleJInternalFrame}). */ public AccessibleContext getAccessibleContext() { @@ -748,10 +775,16 @@ public class JInternalFrame extends JComponent implements Accessible, } /** - * This method returns the default action taken when this JInternalFrame is - * closed. + * Returns a code for the default action taken when this + * <code>JInternalFrame</code> is closed. * - * @return The default action taken when this JInternalFrame is closed. + * @return The action code (usually one of + * {@link WindowConstants#DO_NOTHING_ON_CLOSE}, + * {@link WindowConstants#HIDE_ON_CLOSE}, or + * {@link WindowConstants#DISPOSE_ON_CLOSE}). + * + * @see #setDefaultCloseOperation(int) + * @see #doDefaultCloseAction() */ public int getDefaultCloseOperation() { @@ -759,11 +792,10 @@ public class JInternalFrame extends JComponent implements Accessible, } /** - * This method returns the JDesktopIcon that represents this JInternalFrame - * while it is iconified. + * Returns the <code>JDesktopIcon</code> that represents this + * <code>JInternalFrame</code> while it is iconified. * - * @return The JDesktopIcon that represents this JInternalFrame while it is - * iconified. + * @return The desktop icon component. */ public JDesktopIcon getDesktopIcon() { @@ -878,7 +910,12 @@ public class JInternalFrame extends JComponent implements Accessible, // instead of the static method (this would lead to infinite // recursion). return pane.getLayer((Component) this); - return -1; + + Integer layer = (Integer) getClientProperty(JLayeredPane.LAYER_PROPERTY); + if (layer != null) + return layer.intValue(); + + return JLayeredPane.DEFAULT_LAYER.intValue(); } /** @@ -950,9 +987,11 @@ public class JInternalFrame extends JComponent implements Accessible, } /** - * This method sets the title of the JInternalFrame. + * Returns the frame's title. * - * @return The String displayed in the TitlePane of this JInternalFrame. + * @return The frame's title (can be <code>null</code>). + * + * @see #setTitle(String) */ public String getTitle() { @@ -1171,13 +1210,15 @@ public class JInternalFrame extends JComponent implements Accessible, } /** - * This method returns a String describing this JInternalFrame. + * An implementation dependent string describing the current state of this + * <code>JInternalFrame</code> instance. * - * @return A String describing this JInternalFrame. + * @return A string describing the current state of this + * <code>JInternalFrame</code> instance. */ protected String paramString() { - return super.paramString(); + return super.paramString() + ",title=" + getTitle(); } /** @@ -1189,7 +1230,7 @@ public class JInternalFrame extends JComponent implements Accessible, { // If we're removing the root pane, use super.remove. Otherwise // pass it on to the content pane instead. - if (comp==rootPane) + if (comp==rootPane || ! isRootPaneCheckingEnabled()) super.remove(comp); else getContentPane().remove(comp); @@ -1238,7 +1279,11 @@ public class JInternalFrame extends JComponent implements Accessible, */ public void setClosable(boolean b) { - closable = b; + if (closable != b) + { + closable = b; + firePropertyChange("closable", ! closable, closable); + } } /** @@ -1287,12 +1332,17 @@ public class JInternalFrame extends JComponent implements Accessible, } /** - * This method sets the action taken when this JInternalFrame is closed. + * Sets a code for the action to be taken when this + * <code>JInternalFrame</code> is closed. Note that no validation is + * performed on the <code>operation</code> code, any integer will be + * accepted (nevertheless, you should pass in one of the listed values). * - * @param operation One of DO_NOTHING_ON_CLOSE, HIDE_ON_CLOSE or - * DISPOSE_ON_CLOSE. - * - * @throws Error If the given operation is not one of the allowed modes. + * @param operation one of {@link WindowConstants#DO_NOTHING_ON_CLOSE}, + * {@link WindowConstants#HIDE_ON_CLOSE} or + * {@link WindowConstants#DISPOSE_ON_CLOSE}. + * + * @see #getDefaultCloseOperation() + * @see #doDefaultCloseAction() */ public void setDefaultCloseOperation(int operation) { @@ -1304,16 +1354,24 @@ public class JInternalFrame extends JComponent implements Accessible, } /** - * This method sets the JDesktopIcon that represents this JInternalFrame - * while it is iconified. + * Sets the <code>JDesktopIcon</code> instance that represents this + * <code>JInternalFrame</code> while it is iconified and, if the new icon is + * not the same instance as the existing icon, sends a + * {@link PropertyChangeEvent} (with the property name + * <code>"desktopIcon"</code>) to all registered listeners.. * - * @param d The JDesktopIcon that represents this JInternalFrame while it is - * iconified. + * @param d the icon. + * + * @see #getDesktopIcon() */ public void setDesktopIcon(JDesktopIcon d) { - d.setInternalFrame(this); - desktopIcon = d; + if (desktopIcon != d) + { + JDesktopIcon oldIcon = desktopIcon; + desktopIcon = d; + firePropertyChange("desktopIcon", oldIcon, d); + } } /** @@ -1396,7 +1454,11 @@ public class JInternalFrame extends JComponent implements Accessible, */ public void setIconifiable(boolean b) { - iconable = b; + if (iconable != b) + { + iconable = b; + firePropertyChange("iconable", ! iconable, iconable); + } } /** @@ -1461,7 +1523,11 @@ public class JInternalFrame extends JComponent implements Accessible, */ public void setMaximizable(boolean b) { - maximizable = b; + if (maximizable != b) + { + maximizable = b; + firePropertyChange("maximizable", ! maximizable, maximizable); + } } /** @@ -1538,7 +1604,11 @@ public class JInternalFrame extends JComponent implements Accessible, */ public void setResizable(boolean b) { - resizable = b; + if (b != resizable) + { + resizable = b; + firePropertyChange("resizable", ! resizable, resizable); + } } /** @@ -1594,6 +1664,9 @@ public class JInternalFrame extends JComponent implements Accessible, if (selected) restoreSubcomponentFocus(); + if (isShowing()) + repaint(); + firePropertyChange(IS_SELECTED_PROPERTY, ! isSelected, isSelected); if (isSelected) @@ -1604,10 +1677,13 @@ public class JInternalFrame extends JComponent implements Accessible, } /** - * This method sets the title displayed in the TitlePane of this - * JInternalFrame. + * Sets the title for the <code>JInternalFrame</code> and sends a + * {@link PropertyChangeEvent} (with the property name + * {@link #TITLE_PROPERTY}) to all registered listeners. * - * @param title The title displayed. + * @param title the new title (<code>null</code> permitted). + * + * @see #getTitle() */ public void setTitle(String title) { @@ -1615,9 +1691,9 @@ public class JInternalFrame extends JComponent implements Accessible, return; if (title == null || this.title == null || ! this.title.equals(title)) { - String old = title; - this.title = title; - firePropertyChange(TITLE_PROPERTY, old, this.title); + String old = this.title; + this.title = title; + firePropertyChange(TITLE_PROPERTY, old, this.title); } } diff --git a/libjava/classpath/javax/swing/JLabel.java b/libjava/classpath/javax/swing/JLabel.java index a9adc96b2f4..a993fb8f3e0 100644 --- a/libjava/classpath/javax/swing/JLabel.java +++ b/libjava/classpath/javax/swing/JLabel.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Font; import java.awt.Image; @@ -67,15 +69,15 @@ public class JLabel extends JComponent implements Accessible, SwingConstants implements AccessibleText, AccessibleExtendedComponent { /** - * Returns the selected text. This is an empty string since JLabels + * Returns the selected text. This is null since JLabels * are not selectable. * - * @return the selected text + * @return <code>null</code> because JLabels cannot have selected text */ public String getSelectedText() { - // We return "" here since JLabel's text is not selectable. - return ""; + // We return null here since JLabel's text is not selectable. + return null; } /** @@ -85,8 +87,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants */ public int getSelectionStart() { - // TODO: Figure out what should be returned here, because JLabels don't - // allow selection. I guess -1 for now. + // JLabel don't have selected text, so we return -1 here. return -1; } @@ -97,8 +98,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants */ public int getSelectionEnd() { - // TODO: Figure out what should be returned here, because JLabels don't - // allow selection. I guess -1 for now. + // JLabel don't have selected text, so we return -1 here. return -1; } @@ -115,6 +115,8 @@ public class JLabel extends JComponent implements Accessible, SwingConstants */ public AttributeSet getCharacterAttribute(int index) { + // FIXME: Return null here for simple labels, and query the HTML + // view for HTML labels. return new SimpleAttributeSet(); } @@ -259,6 +261,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants */ public int getCharCount() { + // FIXME: Query HTML view for HTML labels. return text.length(); } @@ -271,6 +274,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants * @return the bounding box of the character at the specified index */ public Rectangle getCharacterBounds(int index) + throws NotImplementedException { // FIXME: Implement this correctly. return new Rectangle(); @@ -286,6 +290,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants * point */ public int getIndexAtPoint(Point point) + throws NotImplementedException { // FIXME: Implement this correctly. return 0; @@ -295,6 +300,8 @@ public class JLabel extends JComponent implements Accessible, SwingConstants /** DOCUMENT ME! */ private static final long serialVersionUID = 5496508283662221534L; + static final String LABEL_PROPERTY = "labeledBy"; + /** * The Component the label will give focus to when its mnemonic is * activated. @@ -337,7 +344,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants */ public JLabel() { - this(null, null, LEADING); + this("", null, LEADING); } /** @@ -348,7 +355,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants */ public JLabel(Icon image) { - this(null, image, CENTER); + this("", image, CENTER); } /** @@ -361,7 +368,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants */ public JLabel(Icon image, int horizontalAlignment) { - this(null, image, horizontalAlignment); + this("", image, horizontalAlignment); } /** @@ -452,7 +459,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants */ protected String paramString() { - return "JLabel"; + return super.paramString(); } /** @@ -510,6 +517,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants Icon oldIcon = icon; icon = newIcon; firePropertyChange("icon", oldIcon, newIcon); + repaint(); } } @@ -860,8 +868,23 @@ public class JLabel extends JComponent implements Accessible, SwingConstants { if (c != labelFor) { + // We put the label into the client properties for the labeled + // component so that it can be read by the AccessibleJComponent. + // The other option would be to reserve a default visible field + // in JComponent, but since this is relativly seldomly used, it + // would be unnecessary waste of memory to do so. Component oldLabelFor = labelFor; + if (oldLabelFor instanceof JComponent) + { + ((JComponent) oldLabelFor).putClientProperty(LABEL_PROPERTY, null); + } + labelFor = c; + if (labelFor instanceof JComponent) + { + ((JComponent) labelFor).putClientProperty(LABEL_PROPERTY, this); + } + firePropertyChange("labelFor", oldLabelFor, labelFor); } } diff --git a/libjava/classpath/javax/swing/JLayeredPane.java b/libjava/classpath/javax/swing/JLayeredPane.java index ffd803c8706..f887c24506f 100644 --- a/libjava/classpath/javax/swing/JLayeredPane.java +++ b/libjava/classpath/javax/swing/JLayeredPane.java @@ -599,6 +599,7 @@ public class JLayeredPane extends JComponent implements Accessible int newIdx = insertIndexForLayer(layer, index); setLayer(comp, layer); super.addImpl(comp, layerConstraint, newIdx); + repaint(comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight()); } /** diff --git a/libjava/classpath/javax/swing/JList.java b/libjava/classpath/javax/swing/JList.java index d0e1090b8c9..55978a4c695 100644 --- a/libjava/classpath/javax/swing/JList.java +++ b/libjava/classpath/javax/swing/JList.java @@ -1,5 +1,5 @@ /* JList.java -- - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -965,11 +965,19 @@ public class JList extends JComponent implements Accessible, Scrollable int visibleRowCount; /** - * Fire a {@link ListSelectionEvent} to all the registered ListSelectionListeners. + * Fire a {@link ListSelectionEvent} to all the registered + * ListSelectionListeners. + * + * @param firstIndex the lowest index covering the selection change. + * @param lastIndex the highest index covering the selection change. + * @param isAdjusting a flag indicating if this event is one in a series + * of events updating the selection. */ - protected void fireSelectionValueChanged(int firstIndex, int lastIndex, boolean isAdjusting) + protected void fireSelectionValueChanged(int firstIndex, int lastIndex, + boolean isAdjusting) { - ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex, lastIndex, isAdjusting); + ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex, + lastIndex, isAdjusting); ListSelectionListener listeners[] = getListSelectionListeners(); for (int i = 0; i < listeners.length; ++i) { @@ -1022,48 +1030,56 @@ public class JList extends JComponent implements Accessible, Scrollable /** - * Creates a new JList object. + * Creates a new <code>JList</code> object. */ public JList() { - init(); + init(new DefaultListModel()); } /** - * Creates a new JList object. + * Creates a new <code>JList</code> object. * - * @param listData Initial data to populate the list with + * @param items the initial list items. */ - public JList(Object[] listData) + public JList(Object[] items) { - init(); - setListData(listData); + init(createListModel(items)); } /** - * Creates a new JList object. + * Creates a new <code>JList</code> object. * - * @param listData Initial data to populate the list with + * @param items the initial list items. */ - public JList(Vector listData) + public JList(Vector items) { - init(); - setListData(listData); + init(createListModel(items)); } /** - * Creates a new JList object. + * Creates a new <code>JList</code> object. * - * @param listData Initial data to populate the list with + * @param model a model containing the list items (<code>null</code> not + * permitted). + * + * @throws IllegalArgumentException if <code>model</code> is + * <code>null</code>. */ - public JList(ListModel listData) + public JList(ListModel model) { - init(); - setModel(listData); + init(model); } - void init() + /** + * Initializes the list. + * + * @param m the list model (<code>null</code> not permitted). + */ + private void init(ListModel m) { + if (m == null) + throw new IllegalArgumentException("Null model not permitted."); dragEnabled = false; fixedCellHeight = -1; fixedCellWidth = -1; @@ -1075,9 +1091,17 @@ public class JList extends JComponent implements Accessible, Scrollable cellRenderer = new DefaultListCellRenderer(); listListener = new ListListener(); - setModel(new DefaultListModel()); - setSelectionModel(createSelectionModel()); - setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + model = m; + if (model != null) + model.addListDataListener(listListener); + + selectionModel = createSelectionModel(); + if (selectionModel != null) + { + selectionModel.addListSelectionListener(listListener); + selectionModel.setSelectionMode + (ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + } setLayout(null); updateUI(); @@ -1117,6 +1141,8 @@ public class JList extends JComponent implements Accessible, Scrollable * #prototypeCellValue} property is set, but setting it explicitly * overrides the height computed from {@link #prototypeCellValue}. * + * @param h the height. + * * @see #getFixedCellHeight * @see #getPrototypeCellValue */ @@ -1127,7 +1153,7 @@ public class JList extends JComponent implements Accessible, Scrollable int old = fixedCellHeight; fixedCellHeight = h; - firePropertyChange("fixedCellWidth", old, h); + firePropertyChange("fixedCellHeight", old, h); } @@ -1154,6 +1180,8 @@ public class JList extends JComponent implements Accessible, Scrollable * #prototypeCellValue} property is set, but setting it explicitly * overrides the width computed from {@link #prototypeCellValue}. * + * @param w the width. + * * @see #getFixedCellHeight * @see #getPrototypeCellValue */ @@ -1229,6 +1257,16 @@ public class JList extends JComponent implements Accessible, Scrollable return (ListSelectionListener[]) getListeners(ListSelectionListener.class); } + /** + * Returns the selection mode for the list (one of: + * {@link ListSelectionModel#SINGLE_SELECTION}, + * {@link ListSelectionModel#SINGLE_INTERVAL_SELECTION} and + * {@link ListSelectionModel#MULTIPLE_INTERVAL_SELECTION}). + * + * @return The selection mode. + * + * @see #setSelectionMode(int) + */ public int getSelectionMode() { return selectionModel.getSelectionMode(); @@ -1274,6 +1312,9 @@ public class JList extends JComponent implements Accessible, Scrollable * For each element <code>a[i]</code> of the provided array * <code>a</code>, calls {@link #setSelectedIndex} on <code>a[i]</code>. * + * @param a an array of selected indices (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. * @see #setSelectionMode * @see #selectionModel */ @@ -1536,7 +1577,9 @@ public class JList extends JComponent implements Accessible, Scrollable */ public void ensureIndexIsVisible(int i) { - scrollRectToVisible(getUI().getCellBounds(this, i, i)); + Rectangle r = getUI().getCellBounds(this, i, i); + if (r != null) + scrollRectToVisible(r); } /** @@ -1547,20 +1590,53 @@ public class JList extends JComponent implements Accessible, Scrollable * @param listData The object array to build a new list model on * @see #setModel */ - public void setListData(final Object[] listData) + public void setListData(Object[] listData) { - setModel(new AbstractListModel() - { - public int getSize() - { - return listData.length; - } + setModel(createListModel(listData)); + } - public Object getElementAt(int i) - { - return listData[i]; - } - }); + /** + * Returns a {@link ListModel} backed by the specified array. + * + * @param items the list items (don't use <code>null</code>). + * + * @return A list model containing the specified items. + */ + private ListModel createListModel(final Object[] items) + { + return new AbstractListModel() + { + public int getSize() + { + return items.length; + } + public Object getElementAt(int i) + { + return items[i]; + } + }; + } + + /** + * Returns a {@link ListModel} backed by the specified vector. + * + * @param items the list items (don't use <code>null</code>). + * + * @return A list model containing the specified items. + */ + private ListModel createListModel(final Vector items) + { + return new AbstractListModel() + { + public int getSize() + { + return items.size(); + } + public Object getElementAt(int i) + { + return items.get(i); + } + }; } /** @@ -1571,20 +1647,9 @@ public class JList extends JComponent implements Accessible, Scrollable * @param listData The object array to build a new list model on * @see #setModel */ - public void setListData(final Vector listData) + public void setListData(Vector listData) { - setModel(new AbstractListModel() - { - public int getSize() - { - return listData.size(); - } - - public Object getElementAt(int i) - { - return listData.elementAt(i); - } - }); + setModel(createListModel(listData)); } /** @@ -1655,7 +1720,21 @@ public class JList extends JComponent implements Accessible, Scrollable repaint(); } - + /** + * Returns the selection model for the {@link JList} component. Note that + * this class contains a range of convenience methods for configuring the + * selection model:<br> + * <ul> + * <li>{@link #clearSelection()};</li> + * <li>{@link #setSelectionMode(int)};</li> + * <li>{@link #addSelectionInterval(int, int)};</li> + * <li>{@link #setSelectedIndex(int)};</li> + * <li>{@link #setSelectedIndices(int[])};</li> + * <li>{@link #setSelectionInterval(int, int)}.</li> + * </ul> + * + * @return The selection model. + */ public ListSelectionModel getSelectionModel() { return selectionModel; @@ -2010,41 +2089,96 @@ public class JList extends JComponent implements Accessible, Scrollable return retVal; } + /** + * Returns the index of the anchor item in the current selection, or + * <code>-1</code> if there is no anchor item. + * + * @return The item index. + */ public int getAnchorSelectionIndex() { return selectionModel.getAnchorSelectionIndex(); } + /** + * Returns the index of the lead item in the current selection, or + * <code>-1</code> if there is no lead item. + * + * @return The item index. + */ public int getLeadSelectionIndex() { return selectionModel.getLeadSelectionIndex(); } + /** + * Returns the lowest item index in the current selection, or <code>-1</code> + * if there is no selection. + * + * @return The index. + * + * @see #getMaxSelectionIndex() + */ public int getMinSelectionIndex() { - return selectionModel.getMaxSelectionIndex(); + return selectionModel.getMinSelectionIndex(); } + /** + * Returns the highest item index in the current selection, or + * <code>-1</code> if there is no selection. + * + * @return The index. + * + * @see #getMinSelectionIndex() + */ public int getMaxSelectionIndex() { return selectionModel.getMaxSelectionIndex(); } + /** + * Clears the current selection. + */ public void clearSelection() { selectionModel.clearSelection(); } + /** + * Sets the current selection to the items in the specified range (inclusive). + * Note that <code>anchor</code> can be less than, equal to, or greater than + * <code>lead</code>. + * + * @param anchor the index of the anchor item. + * @param lead the index of the anchor item. + */ public void setSelectionInterval(int anchor, int lead) { selectionModel.setSelectionInterval(anchor, lead); } + /** + * Adds the specified interval to the current selection. Note that + * <code>anchor</code> can be less than, equal to, or greater than + * <code>lead</code>. + * + * @param anchor the index of the anchor item. + * @param lead the index of the lead item. + */ public void addSelectionInterval(int anchor, int lead) { selectionModel.addSelectionInterval(anchor, lead); } + /** + * Removes the specified interval from the current selection. Note that + * <code>index0</code> can be less than, equal to, or greater than + * <code>index1</code>. + * + * @param index0 an index for one end of the range. + * @param index1 an index for the other end of the range. + */ public void removeSelectionInterval(int index0, int index1) { selectionModel.removeSelectionInterval(index0, index1); @@ -2138,7 +2272,14 @@ public class JList extends JComponent implements Accessible, Scrollable */ public Rectangle getCellBounds(int index0, int index1) { - return getUI().getCellBounds(this, index0, index1); + ListUI ui = getUI(); + Rectangle bounds = null; + if (ui != null) + { + bounds = ui.getCellBounds(this, index0, index1); + } + // When the UI is null, this method also returns null in the RI. + return bounds; } /** @@ -2201,4 +2342,28 @@ public class JList extends JComponent implements Accessible, Scrollable } return index; } + + /** + * Returns a string describing the attributes for the <code>JList</code> + * component, for use in debugging. The return value is guaranteed to be + * non-<code>null</code>, but the format of the string may vary between + * implementations. + * + * @return A string describing the attributes of the <code>JList</code>. + */ + protected String paramString() + { + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",fixedCellHeight=").append(getFixedCellHeight()); + sb.append(",fixedCellWidth=").append(getFixedCellWidth()); + sb.append(",selectionBackground="); + if (getSelectionBackground() != null) + sb.append(getSelectionBackground()); + sb.append(",selectionForeground="); + if (getSelectionForeground() != null) + sb.append(getSelectionForeground()); + sb.append(",visibleRowCount=").append(getVisibleRowCount()); + sb.append(",layoutOrientation=").append(getLayoutOrientation()); + return sb.toString(); + } } diff --git a/libjava/classpath/javax/swing/JMenu.java b/libjava/classpath/javax/swing/JMenu.java index a160dd44857..37ed1485481 100644 --- a/libjava/classpath/javax/swing/JMenu.java +++ b/libjava/classpath/javax/swing/JMenu.java @@ -1,5 +1,5 @@ /* JMenu.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Point; import java.awt.event.KeyEvent; @@ -293,8 +295,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement */ public void updateUI() { - super.setUI((MenuItemUI) UIManager.getUI(this)); - invalidate(); + setUI((MenuItemUI) UIManager.getUI(this)); } /** @@ -765,7 +766,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement */ protected void processKeyEvent(KeyEvent event) { - // TODO: Implement this properly. + MenuSelectionManager.defaultManager().processKeyEvent(event); } /** @@ -822,26 +823,31 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement } public int getAccessibleChildrenCount() + throws NotImplementedException { return 0; } public Accessible getAccessibleChild(int value0) + throws NotImplementedException { return null; } public AccessibleSelection getAccessibleSelection() + throws NotImplementedException { return null; } public Accessible getAccessibleSelection(int value0) + throws NotImplementedException { return null; } public boolean isAccessibleChildSelected(int value0) + throws NotImplementedException { return false; } @@ -852,26 +858,31 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement } public int getAccessibleSelectionCount() + throws NotImplementedException { return 0; } public void addAccessibleSelection(int value0) + throws NotImplementedException { // TODO: Implement this properly. } public void removeAccessibleSelection(int value0) + throws NotImplementedException { // TODO: Implement this properly. } public void clearAccessibleSelection() + throws NotImplementedException { // TODO: Implement this properly. } public void selectAllAccessibleSelection() + throws NotImplementedException { // TODO: Implement this properly. } diff --git a/libjava/classpath/javax/swing/JMenuBar.java b/libjava/classpath/javax/swing/JMenuBar.java index 60726fb39bf..18e47dcd96d 100644 --- a/libjava/classpath/javax/swing/JMenuBar.java +++ b/libjava/classpath/javax/swing/JMenuBar.java @@ -658,6 +658,5 @@ public class JMenuBar extends JComponent implements Accessible, MenuElement public void updateUI() { setUI((MenuBarUI) UIManager.getUI(this)); - invalidate(); } } diff --git a/libjava/classpath/javax/swing/JMenuItem.java b/libjava/classpath/javax/swing/JMenuItem.java index b2cfbd14ae8..272c1cfe6ce 100644 --- a/libjava/classpath/javax/swing/JMenuItem.java +++ b/libjava/classpath/javax/swing/JMenuItem.java @@ -1,5 +1,5 @@ /* JMenuItem.java -- - Copyright (C) 2002, 2004, 2005,2006 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; @@ -204,9 +206,7 @@ public class JMenuItem extends AbstractButton implements Accessible, */ public void updateUI() { - MenuItemUI mi = ((MenuItemUI) UIManager.getUI(this)); - setUI(mi); - invalidate(); + setUI((MenuItemUI) UIManager.getUI(this)); } /** @@ -398,7 +398,15 @@ public class JMenuItem extends AbstractButton implements Accessible, public void processKeyEvent(KeyEvent event, MenuElement[] path, MenuSelectionManager manager) { - // Need to implement. + MenuKeyEvent e = new MenuKeyEvent(event.getComponent(), event.getID(), + event.getWhen(), event.getModifiers(), + event.getKeyCode(), event.getKeyChar(), + path, manager); + processMenuKeyEvent(e); + + // Consume original key event, if the menu key event has been consumed. + if (e.isConsumed()) + event.consume(); } /** @@ -436,7 +444,20 @@ public class JMenuItem extends AbstractButton implements Accessible, */ public void processMenuKeyEvent(MenuKeyEvent event) { - // Need to implement. + switch (event.getID()) + { + case KeyEvent.KEY_PRESSED: + fireMenuKeyPressed(event); + break; + case KeyEvent.KEY_RELEASED: + fireMenuKeyReleased(event); + break; + case KeyEvent.KEY_TYPED: + fireMenuKeyTyped(event); + break; + default: + break; + } } /** @@ -652,16 +673,26 @@ public class JMenuItem extends AbstractButton implements Accessible, } /** - * A string that describes this JMenuItem. Normally only used - * for debugging. + * Returns a string describing the attributes for the <code>JToolTip</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 JMenuItem + * @return A string describing the attributes of the <code>JMenuItem</code>. */ protected String paramString() { + // calling super seems to be sufficient here... return super.paramString(); } + /** + * Returns the object that provides accessibility features for this + * <code>JMenuItem</code> component. + * + * @return The accessible context (an instance of + * {@link AccessibleJMenuItem}). + */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) @@ -670,13 +701,19 @@ public class JMenuItem extends AbstractButton implements Accessible, return accessibleContext; } + /** + * Provides the accessibility features for the <code>JMenuItem</code> + * component. + * + * @see JMenuItem#getAccessibleContext() + */ protected class AccessibleJMenuItem extends AccessibleAbstractButton implements ChangeListener { private static final long serialVersionUID = 6748924232082076534L; /** - * Creates a new AccessibleJMenuItem object. + * Creates a new <code>AccessibleJMenuItem</code> instance. */ AccessibleJMenuItem() { @@ -684,10 +721,16 @@ public class JMenuItem extends AbstractButton implements Accessible, } public void stateChanged(ChangeEvent event) + throws NotImplementedException { // TODO: What should be done here, if anything? } + /** + * Returns the accessible role for the <code>JMenuItem</code> component. + * + * @return {@link AccessibleRole#MENU_ITEM}. + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.MENU_ITEM; diff --git a/libjava/classpath/javax/swing/JOptionPane.java b/libjava/classpath/javax/swing/JOptionPane.java index 705eca832fe..0bef12b61fc 100644 --- a/libjava/classpath/javax/swing/JOptionPane.java +++ b/libjava/classpath/javax/swing/JOptionPane.java @@ -75,13 +75,14 @@ public class JOptionPane extends JComponent implements Accessible } /** - * DOCUMENT ME! + * Returns the accessible role of this object, which is always + * {@link AccessibleRole#OPTION_PANE}. * - * @return DOCUMENT ME! + * @return the accessible role of this object */ public AccessibleRole getAccessibleRole() { - return null; + return AccessibleRole.OPTION_PANE; } } @@ -1475,7 +1476,6 @@ public class JOptionPane extends JComponent implements Accessible public void updateUI() { setUI((OptionPaneUI) UIManager.getUI(this)); - invalidate(); } /** diff --git a/libjava/classpath/javax/swing/JPanel.java b/libjava/classpath/javax/swing/JPanel.java index 815e452dc05..3bd71d1c2d5 100644 --- a/libjava/classpath/javax/swing/JPanel.java +++ b/libjava/classpath/javax/swing/JPanel.java @@ -1,5 +1,5 @@ /* JPanel.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. @@ -80,54 +80,108 @@ public class JPanel extends JComponent implements Accessible } } + /** + * Creates a new panel with a new instance of {@link FlowLayout} as the + * layout manager and double-buffering enabled. + */ public JPanel() { this(new FlowLayout(), true); } - public JPanel(boolean double_buffered) + /** + * Creates a new panel with double-buffering enabled or disabled as + * specified. The default layout manager is an instance of + * {@link FlowLayout}. + * + * @param isDoubleBuffered a flag that controls whether or not + * double-buffering is enabled. + */ + public JPanel(boolean isDoubleBuffered) { - this(new FlowLayout(), double_buffered); + this(new FlowLayout(), isDoubleBuffered); } + /** + * Creates a new panel with the specified layout manager. Double-buffering + * is enabled by default. + * + * @param layout the layout manager (<code>null</code> permitted). + */ public JPanel(LayoutManager layout) { this(layout, true); } + /** + * Creates a new panel with the specified layout manager and + * double-buffering. + * + * @param layout the layout manager (<code>null</code> permitted). + * @param isDoubleBuffered a flag that controls whether or not + * double-buffering is enabled. + */ public JPanel(LayoutManager layout, boolean isDoubleBuffered) { - if (layout == null) - { - // TODO: Is this correct? Or should we throw a NPE? - layout = new FlowLayout(); - } setLayout(layout); - setOpaque(true); - + setOpaque(true); + setDoubleBuffered(isDoubleBuffered); updateUI(); } + /** + * Returns the suffix (<code>"PanelUI"</code> in this case) used to + * determine the class name for a UI delegate that can provide the look and + * feel for a <code>JPanel</code>. + * + * @return <code>"PanelUI"</code>. + */ public String getUIClassID() { return "PanelUI"; } + /** + * Sets the UI delegate for the <code>JPanel</code> component. + * + * @param ui the UI delegate. + * + * @since 1.4 + * @see #getUI() + */ public void setUI(PanelUI ui) { super.setUI(ui); } + /** + * Returns the UI delegate for the <code>JPanel</code> component. + * + * @return The UI delegate. + * + * @since 1.4 + * @see #setUI(PanelUI) + */ public PanelUI getUI() { return (PanelUI) ui; } + /** + * Sets this panel's UI delegate to the default (obtained from the + * {@link UIManager}) for the current look and feel. + */ public void updateUI() { setUI((PanelUI) UIManager.getUI(this)); } + /** + * Returns the object that provides accessibility features for this + * <code>JPanel</code> component. + * + * @return The accessible context (an instance of {@link AccessibleJPanel}). + */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) @@ -135,7 +189,14 @@ public class JPanel extends JComponent implements Accessible return accessibleContext; } - protected String paramString() + /** + * Returns an implementation-dependent string describing the attributes of + * this <code>JPanel</code>. + * + * @return A string describing the attributes of this <code>JPanel</code> + * (never <code>null</code>). + */ + protected String paramString() { return super.paramString(); } diff --git a/libjava/classpath/javax/swing/JPopupMenu.java b/libjava/classpath/javax/swing/JPopupMenu.java index 74f733e921e..a54bd777fd4 100644 --- a/libjava/classpath/javax/swing/JPopupMenu.java +++ b/libjava/classpath/javax/swing/JPopupMenu.java @@ -292,7 +292,6 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement public void updateUI() { setUI((PopupMenuUI) UIManager.getUI(this)); - invalidate(); } /** @@ -542,11 +541,25 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement this.visible = visible; if (old != isVisible()) { - firePropertyChange("visible", old, isVisible()); if (visible) { + if (invoker != null && !(invoker instanceof JMenu)) + { + MenuElement[] menuEls; + if (getSubElements().length > 0) + { + menuEls = new MenuElement[2]; + menuEls[0] = this; + menuEls[1] = getSubElements()[0]; + } + else + { + menuEls = new MenuElement[1]; + menuEls[0] = this; + } + MenuSelectionManager.defaultManager().setSelectedPath(menuEls); + } firePopupMenuWillBecomeVisible(); - PopupFactory pf = PopupFactory.getSharedInstance(); pack(); popup = pf.getPopup(invoker, this, popupLocationX, popupLocationY); @@ -554,9 +567,11 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement } else { + getSelectionModel().clearSelection(); firePopupMenuWillBecomeInvisible(); popup.hide(); } + firePropertyChange("visible", old, isVisible()); } } diff --git a/libjava/classpath/javax/swing/JProgressBar.java b/libjava/classpath/javax/swing/JProgressBar.java index e7ee8004c09..db936f64a34 100644 --- a/libjava/classpath/javax/swing/JProgressBar.java +++ b/libjava/classpath/javax/swing/JProgressBar.java @@ -39,10 +39,12 @@ exception statement from your version. */ package javax.swing; import java.awt.Graphics; +import java.beans.PropertyChangeEvent; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleValue; import javax.swing.border.Border; @@ -79,17 +81,16 @@ public class JProgressBar extends JComponent implements SwingConstants, Accessible { /** - * AccessibleJProgressBar + * Provides the accessibility features for the <code>JProgressBar</code> + * component. */ - // FIXME: This inner class is a complete stub and needs to be implemented - // properly. protected class AccessibleJProgressBar extends AccessibleJComponent implements AccessibleValue { private static final long serialVersionUID = -2938130009392721813L; /** - * Constructor AccessibleJProgressBar + * Creates a new <code>AccessibleJProgressBar</code> instance. */ protected AccessibleJProgressBar() { @@ -97,19 +98,25 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * getAccessibleStateSet + * Returns a set containing the current state of the {@link JProgressBar} + * component. * - * @return AccessibleStateSet + * @return The accessible state set. */ public AccessibleStateSet getAccessibleStateSet() { - return null; + AccessibleStateSet result = super.getAccessibleStateSet(); + if (orientation == JProgressBar.HORIZONTAL) + result.add(AccessibleState.HORIZONTAL); + else if (orientation == JProgressBar.VERTICAL) + result.add(AccessibleState.VERTICAL); + return result; } /** - * getAccessibleRole + * Returns the accessible role for the <code>JProgressBar</code> component. * - * @return AccessibleRole + * @return {@link AccessibleRole#PROGRESS_BAR}. */ public AccessibleRole getAccessibleRole() { @@ -117,56 +124,71 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * getAccessibleValue + * Returns an object that provides access to the current, minimum and + * maximum values. * - * @return AccessibleValue + * @return The accessible value. */ public AccessibleValue getAccessibleValue() { - return null; + return this; } /** - * getCurrentAccessibleValue + * Returns the current value of the {@link JProgressBar} component, as an + * {@link Integer}. * - * @return Number + * @return The current value of the {@link JProgressBar} component. */ public Number getCurrentAccessibleValue() { - return null; - } + return new Integer(getValue()); + } /** - * setCurrentAccessibleValue + * Sets the current value of the {@link JProgressBar} component and sends a + * {@link PropertyChangeEvent} (with the property name + * {@link AccessibleContext#ACCESSIBLE_VALUE_PROPERTY}) to all registered + * listeners. If the supplied value is <code>null</code>, this method + * does nothing and returns <code>false</code>. * - * @param value0 TODO + * @param value the new progress bar value (<code>null</code> permitted). * - * @return boolean + * @return <code>true</code> if the slider value is updated, and + * <code>false</code> otherwise. */ - public boolean setCurrentAccessibleValue(Number value0) + public boolean setCurrentAccessibleValue(Number value) { - return false; - } + if (value == null) + return false; + Number oldValue = getCurrentAccessibleValue(); + setValue(value.intValue()); + firePropertyChange(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, oldValue, + new Integer(getValue())); + return true; + } /** - * getMinimumAccessibleValue + * Returns the minimum value of the {@link JProgressBar} component, as an + * {@link Integer}. * - * @return Number + * @return The minimum value of the {@link JProgressBar} component. */ public Number getMinimumAccessibleValue() { - return null; - } + return new Integer(getMinimum()); + } /** - * getMaximumAccessibleValue + * Returns the maximum value of the {@link JProgressBar} component, as an + * {@link Integer}. * - * @return Number + * @return The maximum value of the {@link JProgressBar} component. */ public Number getMaximumAccessibleValue() { - return null; - } + return new Integer(getMaximum()); + } } private static final long serialVersionUID = 1980046021813598781L; @@ -465,7 +487,6 @@ public class JProgressBar extends JComponent implements SwingConstants, public void updateUI() { setUI((ProgressBarUI) UIManager.getUI(this)); - invalidate(); } /** @@ -613,15 +634,28 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns a string that can be used to - * describe this JProgressBar. This method is usually - * only used for debugging purposes. + * Returns an implementation-dependent string describing the attributes of + * this <code>JProgressBar</code>. * - * @return A string that describes this JProgressBar. + * @return A string describing the attributes of this + * <code>JProgressBar</code> (never <code>null</code>). */ protected String paramString() { - return "JProgressBar"; + String superParamStr = super.paramString(); + StringBuffer sb = new StringBuffer(); + sb.append(",orientation="); + if (orientation == HORIZONTAL) + sb.append("HORIZONTAL"); + else + sb.append("VERTICAL"); + sb.append(",paintBorder=").append(isBorderPainted()); + sb.append(",paintString=").append(isStringPainted()); + sb.append(",progressString="); + if (progressString != null) + sb.append(progressString); + sb.append(",indeterminateString=").append(isIndeterminate()); + return superParamStr + sb.toString(); } /** @@ -655,9 +689,11 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JProgressBar</code> component. * - * @return DOCUMENT ME! + * @return The accessible context (an instance of + * {@link AccessibleJProgressBar}). */ public AccessibleContext getAccessibleContext() { diff --git a/libjava/classpath/javax/swing/JRadioButtonMenuItem.java b/libjava/classpath/javax/swing/JRadioButtonMenuItem.java index 61a8dbab300..0d7c1d10533 100644 --- a/libjava/classpath/javax/swing/JRadioButtonMenuItem.java +++ b/libjava/classpath/javax/swing/JRadioButtonMenuItem.java @@ -1,5 +1,5 @@ /* JRadioButtonMenuItem.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. @@ -168,16 +168,27 @@ public class JRadioButtonMenuItem extends JMenuItem implements Accessible } /** - * A string that describes this JRadioButtonMenuItem. Normally only used - * for debugging. + * Returns a string describing the attributes for the + * <code>JRadioButtonMenuItem</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 JRadioButtonMenuItem + * @return A string describing the attributes of the + * <code>JRadioButtonMenuItem</code>. */ protected String paramString() { - return "JRadioButtonMenuItem"; + // calling super seems to be sufficient here... + return super.paramString(); } + /** + * Returns the object that provides accessibility features for this + * <code>JRadioButtonMenuItem</code> component. + * + * @return The accessible context (an instance of + * {@link AccessibleJRadioButtonMenuItem}). + */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) @@ -186,18 +197,30 @@ public class JRadioButtonMenuItem extends JMenuItem implements Accessible return accessibleContext; } + /** + * Provides the accessibility features for the + * <code>JRadioButtonMenuItem</code> component. + * + * @see JRadioButtonMenuItem#getAccessibleContext() + */ protected class AccessibleJRadioButtonMenuItem extends AccessibleJMenuItem { private static final long serialVersionUID = 4381471510145292179L; /** - * Creates a new AccessibleJRadioButtonMenuItem object. + * Creates a new <code>AccessibleJRadioButtonMenuItem</code> instance. */ protected AccessibleJRadioButtonMenuItem() { // Nothing to do here. } + /** + * Returns the accessible role for the <code>JRadioButtonMenuItem</code> + * component. + * + * @return {@link AccessibleRole#RADIO_BUTTON}. + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.RADIO_BUTTON; diff --git a/libjava/classpath/javax/swing/JRootPane.java b/libjava/classpath/javax/swing/JRootPane.java index dec43956ca3..a2cd9c7a000 100644 --- a/libjava/classpath/javax/swing/JRootPane.java +++ b/libjava/classpath/javax/swing/JRootPane.java @@ -50,6 +50,7 @@ import java.awt.Rectangle; import java.io.Serializable; import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; import javax.swing.plaf.RootPaneUI; @@ -624,12 +625,15 @@ public class JRootPane extends JComponent implements Accessible public void setDefaultButton(JButton newButton) { - if (defaultButton == newButton) - return; - - JButton oldButton = defaultButton; - defaultButton = newButton; - firePropertyChange("defaultButton", oldButton, newButton); + // We only change the default button if the new button is defaultCapable + // or null and the old and new button are different objects. + if (defaultButton != newButton + && (newButton == null || newButton.isDefaultCapable())) + { + JButton oldButton = defaultButton; + defaultButton = newButton; + firePropertyChange("defaultButton", oldButton, newButton); + } } /** @@ -674,4 +678,17 @@ public class JRootPane extends JComponent implements Accessible { return ! glassPane.isVisible(); } + + /** + * Returns the accessible context for this JRootPane. This will be + * an instance of {@link AccessibleJRootPane}. + * + * @return the accessible context for this JRootPane + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJRootPane(); + return accessibleContext; + } } diff --git a/libjava/classpath/javax/swing/JScrollBar.java b/libjava/classpath/javax/swing/JScrollBar.java index a2cc76c656b..bca2468738b 100644 --- a/libjava/classpath/javax/swing/JScrollBar.java +++ b/libjava/classpath/javax/swing/JScrollBar.java @@ -1,5 +1,5 @@ /* JScrollBar.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. @@ -42,10 +42,12 @@ import java.awt.Adjustable; import java.awt.Dimension; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; +import java.beans.PropertyChangeEvent; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleValue; import javax.swing.plaf.ScrollBarUI; @@ -60,7 +62,8 @@ import javax.swing.plaf.ScrollBarUI; public class JScrollBar extends JComponent implements Adjustable, Accessible { /** - * DOCUMENT ME! + * Provides the accessibility features for the <code>JScrollBar</code> + * component. */ protected class AccessibleJScrollBar extends JComponent.AccessibleJComponent implements AccessibleValue @@ -68,7 +71,7 @@ public class JScrollBar extends JComponent implements Adjustable, Accessible private static final long serialVersionUID = -7758162392045586663L; /** - * Creates a new AccessibleJSlider object. + * Creates a new <code>AccessibleJScrollBar</code> instance. */ protected AccessibleJScrollBar() { @@ -76,75 +79,96 @@ public class JScrollBar extends JComponent implements Adjustable, Accessible } /** - * DOCUMENT ME! + * Returns a set containing the current state of the {@link JScrollBar} + * component. * - * @return DOCUMENT ME! + * @return The accessible state set. */ public AccessibleStateSet getAccessibleStateSet() { - return null; + AccessibleStateSet result = super.getAccessibleStateSet(); + if (orientation == JScrollBar.HORIZONTAL) + result.add(AccessibleState.HORIZONTAL); + else if (orientation == JScrollBar.VERTICAL) + result.add(AccessibleState.VERTICAL); + return result; } /** - * DOCUMENT ME! + * Returns the accessible role for the <code>JScrollBar</code> component. * - * @return DOCUMENT ME! + * @return {@link AccessibleRole#SCROLL_BAR}. */ public AccessibleRole getAccessibleRole() { - return null; + return AccessibleRole.SCROLL_BAR; } /** - * DOCUMENT ME! + * Returns an object that provides access to the current, minimum and + * maximum values. * - * @return DOCUMENT ME! + * @return The accessible value. */ public AccessibleValue getAccessibleValue() { - return null; + return this; } /** - * DOCUMENT ME! + * Returns the current value of the {@link JScrollBar} component, as an + * {@link Integer}. * - * @return DOCUMENT ME! + * @return The current value of the {@link JScrollBar} component. */ public Number getCurrentAccessibleValue() { - return null; + return new Integer(getValue()); } /** - * setCurrentAccessibleValue + * Sets the current value of the {@link JScrollBar} component and sends a + * {@link PropertyChangeEvent} (with the property name + * {@link AccessibleContext#ACCESSIBLE_VALUE_PROPERTY}) to all registered + * listeners. If the supplied value is <code>null</code>, this method + * does nothing and returns <code>false</code>. * - * @param value0 TODO + * @param value the new slider value (<code>null</code> permitted). * - * @return boolean + * @return <code>true</code> if the slider value is updated, and + * <code>false</code> otherwise. */ - public boolean setCurrentAccessibleValue(Number value0) + public boolean setCurrentAccessibleValue(Number value) { - return false; + if (value == null) + return false; + Number oldValue = getCurrentAccessibleValue(); + setValue(value.intValue()); + firePropertyChange(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, oldValue, + new Integer(getValue())); + return true; } /** - * getMinimumAccessibleValue + * Returns the minimum value of the {@link JScrollBar} component, as an + * {@link Integer}. * - * @return Number + * @return The minimum value of the {@link JScrollBar} component. */ public Number getMinimumAccessibleValue() { - return null; + return new Integer(getMinimum()); } /** - * getMaximumAccessibleValue + * Returns the maximum value of the {@link JScrollBar} component, as an + * {@link Integer}. * - * @return Number + * @return The maximum value of the {@link JScrollBar} component. */ public Number getMaximumAccessibleValue() { - return null; + return new Integer(getMaximum() - model.getExtent()); } } @@ -233,8 +257,6 @@ public class JScrollBar extends JComponent implements Adjustable, Accessible public void updateUI() { setUI((ScrollBarUI) UIManager.getUI(this)); - invalidate(); - repaint(); } /** @@ -632,9 +654,11 @@ public class JScrollBar extends JComponent implements Adjustable, Accessible } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JScrollBar</code> component. * - * @return DOCUMENT ME! + * @return The accessible context (an instance of + * {@link AccessibleJScrollBar}). */ public AccessibleContext getAccessibleContext() { diff --git a/libjava/classpath/javax/swing/JScrollPane.java b/libjava/classpath/javax/swing/JScrollPane.java index 45dfbf50619..09e37378be9 100644 --- a/libjava/classpath/javax/swing/JScrollPane.java +++ b/libjava/classpath/javax/swing/JScrollPane.java @@ -631,8 +631,7 @@ public class JScrollPane extends JComponent public void updateUI() { - ScrollPaneUI b = (ScrollPaneUI)UIManager.getUI(this); - setUI(b); + setUI((ScrollPaneUI) UIManager.getUI(this)); } /** diff --git a/libjava/classpath/javax/swing/JSeparator.java b/libjava/classpath/javax/swing/JSeparator.java index 602af6a380c..c87783b73eb 100644 --- a/libjava/classpath/javax/swing/JSeparator.java +++ b/libjava/classpath/javax/swing/JSeparator.java @@ -37,12 +37,13 @@ exception statement from your version. */ package javax.swing; +import java.beans.PropertyChangeEvent; + import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; import javax.swing.plaf.SeparatorUI; - /** * The JSeparator. It is mostly used to divide/space out * components. @@ -51,14 +52,15 @@ public class JSeparator extends JComponent implements SwingConstants, Accessible { /** - * AccessibleJSeparator + * Provides the accessibility features for the <code>JSeparator</code> + * component. */ protected class AccessibleJSeparator extends AccessibleJComponent { private static final long serialVersionUID = 916332890553201095L; /** - * Constructor AccessibleJSeparator + * Creates a new <code>AccessibleJSeparator</code> instance. */ protected AccessibleJSeparator() { @@ -66,9 +68,9 @@ public class JSeparator extends JComponent implements SwingConstants, } /** - * getAccessibleRole + * Returns the accessible role for the <code>JSeparator</code> component. * - * @return AccessibleRole + * @return {@link AccessibleRole#SEPARATOR}. */ public AccessibleRole getAccessibleRole() { @@ -82,7 +84,7 @@ public class JSeparator extends JComponent implements SwingConstants, private transient int orientation = HORIZONTAL; /** - * Creates a new horizontal JSeparator object. + * Creates a new horizontal <code>JSeparator</code> object. */ public JSeparator() { @@ -90,9 +92,13 @@ public class JSeparator extends JComponent implements SwingConstants, } /** - * Creates a new JSeparator object with the given orientation. + * Creates a new <code>JSeparator</code> object with the given orientation. * - * @param orientation The orientation of the JSeparator. + * @param orientation the orientation (either {@link #HORIZONTAL} or + * {@link #VERTICAL}). + * + * @throws IllegalArgumentException if <code>orientation</code> is not + * one of the specified values. */ public JSeparator(int orientation) { @@ -104,10 +110,9 @@ public class JSeparator extends JComponent implements SwingConstants, } /** - * This method returns the UI delegate being - * used with the JSeparator. + * Returns the UI delegate being used with the <code>JSeparator</code>. * - * @return SeparatorUI The JSeparator's UI delegate. + * @return The JSeparator's UI delegate. */ public SeparatorUI getUI() { @@ -115,10 +120,9 @@ public class JSeparator extends JComponent implements SwingConstants, } /** - * This method sets the UI delegate to use - * with the JSeparator. + * Sets the separator's UI delegate. * - * @param ui The UI delegate to use. + * @param ui the UI delegate. */ public void setUI(SeparatorUI ui) { @@ -126,8 +130,8 @@ public class JSeparator extends JComponent implements SwingConstants, } /** - * This method resets the UI delegate to the - * default for the current look and feel. + * Sets this separator's UI delegate to the default (obtained from the + * {@link UIManager}) for the current look and feel. */ public void updateUI() { @@ -135,11 +139,11 @@ public class JSeparator extends JComponent implements SwingConstants, } /** - * This method returns the identifier string - * that is used to determine the UI delegate - * from the current look and feel. + * Returns the suffix (<code>"SeparatorUI"</code> in this case) used to + * determine the class name for a UI delegate that can provide the look and + * feel for a <code>JSeparator</code>. * - * @return String The identifier string for the UI. + * @return <code>"SeparatorUI"</code>. */ public String getUIClassID() { @@ -147,9 +151,11 @@ public class JSeparator extends JComponent implements SwingConstants, } /** - * This method returns the JSeparator's orientation. + * Returns the orientation of the <code>JSeparator</code>. * - * @return int The JSeparator's orientation. + * @return The orientation (one of {@link #HORIZONTAL} and {@link #VERTICAL}). + * + * @see #setOrientation(int) */ public int getOrientation() { @@ -157,33 +163,50 @@ public class JSeparator extends JComponent implements SwingConstants, } /** - * This method changes the JSeparator's orientation. + * Sets the orientation for the <code>JSeparator</code> and sends a + * {@link PropertyChangeEvent} (with the property name + * <code>orientation</code>) to all registered listeners. * - * @param orientation The JSeparator's orientation. + * @param orientation the orientation (either {@link #HORIZONTAL} or + * {@link #VERTICAL}). + * + * @throws IllegalArgumentException if <code>orientation</code> is not + * one of the specified values. + * + * @see #getOrientation() */ public void setOrientation(int orientation) { if (orientation != HORIZONTAL && orientation != VERTICAL) throw new IllegalArgumentException(orientation + " is not a valid orientation."); + int old = this.orientation; this.orientation = orientation; + firePropertyChange("orientation", old, orientation); } /** - * This method returns a string desribing the JSeparator. - * Normally only used in debugging. + * Returns an implementation-dependent string describing the attributes of + * this <code>JSeparator</code>. * - * @return String A string describing the JSeparator. + * @return A string describing the attributes of this <code>JSeparator</code> + * (never <code>null</code>). */ protected String paramString() { - return "JSeparator"; + String superParamStr = super.paramString(); + if (orientation == HORIZONTAL) + return superParamStr + ",orientation=HORIZONTAL"; + else + return superParamStr + ",orientation=VERTICAL"; } /** - * getAccessibleContext + * Returns the object that provides accessibility features for this + * <code>JSeparator</code> component. * - * @return AccessibleContext + * @return The accessible context (an instance of + * {@link AccessibleJSeparator}). */ public AccessibleContext getAccessibleContext() { diff --git a/libjava/classpath/javax/swing/JSlider.java b/libjava/classpath/javax/swing/JSlider.java index b28b06abad7..ed94c4ecc19 100644 --- a/libjava/classpath/javax/swing/JSlider.java +++ b/libjava/classpath/javax/swing/JSlider.java @@ -1,5 +1,5 @@ /* JSlider.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. @@ -50,6 +50,7 @@ import java.util.Hashtable; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleValue; import javax.swing.event.ChangeEvent; @@ -57,13 +58,12 @@ import javax.swing.event.ChangeListener; import javax.swing.plaf.SliderUI; /** - * The JSlider is a Swing component that allows selection of a value within a + * A visual component that allows selection of a value within a * range by adjusting a thumb in a track. The values for the minimum, * maximum, extent and value are stored in a {@link * DefaultBoundedRangeModel}. - * * <p> - * JSliders have the following properties: + * A <code>JSlider</code> component has the following properties: * </p> * * <table> @@ -72,38 +72,38 @@ import javax.swing.plaf.SliderUI; * <tr><td> inverted </td><td> slider </td><td> yes </td></tr> * <tr><td> labelTable </td><td> slider </td><td> yes </td></tr> * <tr><td> majorTickSpacing </td><td> slider </td><td> yes </td></tr> - * <tr><td> maximum </td><td> model </td><td> no </td></tr> - * <tr><td> minimum </td><td> model </td><td> no </td></tr> + * <tr><td> maximum </td><td> model </td><td> yes </td></tr> + * <tr><td> minimum </td><td> model </td><td> yes </td></tr> * <tr><td> minorTickSpacing </td><td> slider </td><td> yes </td></tr> * <tr><td> model </td><td> slider </td><td> yes </td></tr> * <tr><td> orientation </td><td> slider </td><td> yes </td></tr> * <tr><td> paintLabels </td><td> slider </td><td> yes </td></tr> * <tr><td> paintTicks </td><td> slider </td><td> yes </td></tr> - * <tr><td> snapToTicks </td><td> slider </td><td> no </td></tr> + * <tr><td> snapToTicks </td><td> slider </td><td> yes </td></tr> * <tr><td> value </td><td> model </td><td> no </td></tr> * <tr><td> valueIsAdjusting </td><td> model </td><td> no </td></tr> * </table> * * <p> - * The various behavioral aspects of these properties follows: + * The various behavioural aspects of these properties follows: * </p> * * <ul> * <li> - * When non-bound properties stored in the slider change, the slider fires - * ChangeEvents to its ChangeListeners. + * When a non-bound property stored in the slider changes, the slider fires + * a {@link ChangeEvent} to its change listeners. * </li> * <li> - * When bound properties stored in the slider change, the slider fires - * PropertyChangeEvents to its PropertyChangeListeners + * When a bound property stored in the slider changes, the slider fires a + * {@link PropertyChangeEvent} to its property change listeners. * </li> * <li> - * If any of the model's properties change, it fires a ChangeEvent to its - * ChangeListeners, which include the slider. + * If any of the model's properties change, it fires a {@link ChangeEvent} to + * its listeners, which include the slider. * </li> * <li> - * If the slider receives a ChangeEvent from its model, it will propagate the - * ChangeEvent to its ChangeListeners, with the ChangeEvent's "source" + * If the slider receives a {@link ChangeEvent} from its model, it will + * propagate the event to its own change listeners, with the event's "source" * property set to refer to the slider, rather than the model. * </li> * </ul> @@ -112,21 +112,19 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, ImageObserver, MenuContainer, Serializable { - /** DOCUMENT ME! */ private static final long serialVersionUID = -1441275936141218479L; /** - * DOCUMENT ME! + * Provides the accessibility features for the <code>JSlider</code> + * component. */ - // FIXME: This inner class is a complete stub and needs to be implemented - // properly. protected class AccessibleJSlider extends JComponent.AccessibleJComponent implements AccessibleValue { private static final long serialVersionUID = -6301740148041106789L; /** - * Creates a new AccessibleJSlider object. + * Creates a new <code>AccessibleJSlider</code> instance. */ protected AccessibleJSlider() { @@ -134,75 +132,97 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * DOCUMENT ME! + * Returns a set containing the current state of the {@link JSlider} + * component. * - * @return DOCUMENT ME! + * @return The accessible state set. */ public AccessibleStateSet getAccessibleStateSet() { - return null; + AccessibleStateSet result = super.getAccessibleStateSet(); + if (orientation == JSlider.HORIZONTAL) + result.add(AccessibleState.HORIZONTAL); + else if (orientation == JSlider.VERTICAL) + result.add(AccessibleState.VERTICAL); + return result; } /** - * DOCUMENT ME! + * Returns the accessible role for the <code>JSlider</code> component. * - * @return DOCUMENT ME! + * @return {@link AccessibleRole#SLIDER}. */ public AccessibleRole getAccessibleRole() { - return null; + return AccessibleRole.SLIDER; } /** - * DOCUMENT ME! + * Returns an object that provides access to the current, minimum and + * maximum values for the {@link JSlider}. Since this class implements + * {@link AccessibleValue}, it returns itself. * - * @return DOCUMENT ME! + * @return The accessible value. */ public AccessibleValue getAccessibleValue() { - return null; + return this; } /** - * DOCUMENT ME! + * Returns the current value of the {@link JSlider} component, as an + * {@link Integer}. * - * @return DOCUMENT ME! + * @return The current value of the {@link JSlider} component. */ public Number getCurrentAccessibleValue() { - return null; + return new Integer(getValue()); } /** - * setCurrentAccessibleValue + * Sets the current value of the {@link JSlider} component and sends a + * {@link PropertyChangeEvent} (with the property name + * {@link AccessibleContext#ACCESSIBLE_VALUE_PROPERTY}) to all registered + * listeners. If the supplied value is <code>null</code>, this method + * does nothing and returns <code>false</code>. * - * @param value0 TODO + * @param value the new slider value (<code>null</code> permitted). * - * @return boolean + * @return <code>true</code> if the slider value is updated, and + * <code>false</code> otherwise. */ - public boolean setCurrentAccessibleValue(Number value0) + public boolean setCurrentAccessibleValue(Number value) { - return false; + if (value == null) + return false; + Number oldValue = getCurrentAccessibleValue(); + setValue(value.intValue()); + firePropertyChange(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, oldValue, + new Integer(getValue())); + return true; } /** - * getMinimumAccessibleValue + * Returns the minimum value of the {@link JSlider} component, as an + * {@link Integer}. * - * @return Number + * @return The minimum value of the {@link JSlider} component. */ public Number getMinimumAccessibleValue() { - return null; + return new Integer(getMinimum()); } /** - * getMaximumAccessibleValue + * Returns the maximum value of the {@link JSlider} component, as an + * {@link Integer}. * - * @return Number + * @return The maximum value of the {@link JSlider} component. */ public Number getMaximumAccessibleValue() { - return null; + return new Integer(getMaximum()); } } @@ -221,33 +241,36 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, */ private transient Dictionary labelTable; - /** The model used to describe the slider. */ + /** The model used to store the slider's range and current value. */ protected BoundedRangeModel sliderModel; - /** The space between major ticks. */ + /** The space/distance between major ticks. */ protected int majorTickSpacing; - /** The space between minor ticks. */ + /** The space/distance between minor ticks. */ protected int minorTickSpacing; /** Whether the slider snaps its values to ticks. */ protected boolean snapToTicks = false; - /** The orientation of the slider. */ + /** The orientation (horizontal or vertical) of the slider. */ protected int orientation = HORIZONTAL; /** Whether the slider is inverted. */ private transient boolean isInverted; - /** The ChangeListener that listens to the model. */ + /** + * The listener that monitors the slider's model and forwards events to the + * slider's listeners (see <code>createChangeListener()</code>). + */ protected ChangeListener changeListener; - /** The ChangeEvent that is passed to all listeners of this slider. */ + /** The change event that is passed to all listeners of this slider. */ protected transient ChangeEvent changeEvent; /** - * Creates a new horizontal JSlider object with a minimum of 0, a maximum of - * 100, and a value of 50. + * Creates a new horizontal <code>JSlider</code> instance with a minimum of + * 0, a maximum of 100, and a value of 50. */ public JSlider() { @@ -255,8 +278,8 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * Creates a new JSlider object with the given orientation and a minimum of - * 0, a maximum of 100, and a value of 50. + * Creates a new <code>JSlider</code> instance with the given orientation + * and a minimum of 0, a maximum of 100, and a value of 50. * * @param orientation The orientation of the slider ({@link #HORIZONTAL} or * {@link #VERTICAL}). @@ -270,12 +293,15 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * Creates a new horizontal JSlider object with the given maximum and - * minimum and a value that is halfway between the minimum and the + * Creates a new horizontal <code>JSlider</code> instance with the given + * maximum and minimum and a value that is halfway between the minimum and the * maximum. * - * @param minimum The minimum value of the JSlider. - * @param maximum The maximum value of the JSlider. + * @param minimum The minimum value. + * @param maximum The maximum value. + * + * @throws IllegalArgumentException if <code>minimum</code> is greater than + * <code>maximum</code>. */ public JSlider(int minimum, int maximum) { @@ -283,12 +309,17 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * Creates a new horizontal JSlider object with the given minimum, maximum, - * and value. + * Creates a new horizontal <code>JSlider</code> instance with the given + * minimum, maximum, and value. * - * @param minimum The minimum value of the JSlider. - * @param maximum The maximum value of the JSlider. - * @param value The initial value of the JSlider. + * @param minimum The minimum value. + * @param maximum The maximum value. + * @param value The initial value. + * + * @throws IllegalArgumentException if <code>value</code> is not in the + * specified range. + * @throws IllegalArgumentException if <code>minimum</code> is greater than + * <code>maximum</code>. */ public JSlider(int minimum, int maximum, int value) { @@ -296,8 +327,8 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * Creates a new JSlider object with the given orientation, minimum, - * maximum, and value. + * Creates a new <code>JSlider</code> instance with the given orientation, + * minimum, maximum, and value. * * @param orientation The orientation of the slider ({@link #HORIZONTAL} or * {@link #VERTICAL}). @@ -306,13 +337,18 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, * @param value The initial value of the JSlider. * * @throws IllegalArgumentException if <code>orientation</code> is not one of - * the specified values. + * the specified values. + * @throws IllegalArgumentException if <code>value</code> is not in the + * specified range. + * @throws IllegalArgumentException if <code>minimum</code> is greater than + * <code>maximum</code>. */ public JSlider(int orientation, int minimum, int maximum, int value) { sliderModel = new DefaultBoundedRangeModel(value, 0, minimum, maximum); if (orientation != HORIZONTAL && orientation != VERTICAL) - throw new IllegalArgumentException(orientation + " is not a legal orientation"); + throw new IllegalArgumentException(orientation + + " is not a legal orientation"); this.orientation = orientation; changeListener = createChangeListener(); sliderModel.addChangeListener(changeListener); @@ -320,7 +356,8 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * Creates a new horizontal JSlider object with the given model. + * Creates a new horizontal <code>JSlider</code> instance with the given + * model. * * @param model The model (<code>null</code> not permitted). * @@ -335,9 +372,11 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method returns the current value of the slider. + * Returns the slider's value (from the slider's model). * - * @return The value of the slider stored in the model. + * @return The value of the slider. + * + * @see #setValue(int) */ public int getValue() { @@ -345,9 +384,15 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method sets the value of the slider. + * Sets the slider's value and sends a {@link ChangeEvent} to all + * registered listeners. Note that the model will fire a change event to all + * of its registered listeners first (with the model as the event source) and + * then the slider will fire another change event to all of its registered + * listeners (this time with the slider as the event source). * - * @param value The slider's new value. + * @param value the new value. + * + * @see #getValue() */ public void setValue(int value) { @@ -355,7 +400,7 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method returns the slider's UI delegate. + * Returns the slider's UI delegate. * * @return The slider's UI delegate. */ @@ -365,9 +410,9 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method sets the slider's UI delegate. + * Sets the slider's UI delegate. * - * @param ui A SliderUI object to use with this slider. + * @param ui the UI delegate. */ public void setUI(SliderUI ui) { @@ -375,21 +420,20 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method sets this slider's UI to the UIManager's default for the - * current look and feel. + * Sets this slider's UI delegate to the default (obtained from the + * {@link UIManager}) for the current look and feel. */ public void updateUI() { setUI((SliderUI) UIManager.getUI(this)); - invalidate(); - repaint(); } /** - * This method returns a name to identify which look and feel class will be - * the UI delegate for the slider. + * Returns the suffix (<code>"SliderUI"</code> in this case) used to + * determine the class name for a UI delegate that can provide the look and + * feel for a <code>JSlider</code>. * - * @return The Look and Feel classID. "SliderUI" + * @return <code>"SliderUI"</code>. */ public String getUIClassID() { @@ -397,29 +441,36 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * Creates a ChangeListener for this Slider. + * Creates a {@link ChangeListener} that is added to the slider's model and + * forwards change events generated by the model to the listeners that are + * registered with the <code>JSlider</code> (by calling the + * {@link #fireStateChanged} method). * - * @return A new ChangeListener. + * @return A new listener. */ protected ChangeListener createChangeListener() { return new ChangeListener() { - public void stateChanged(ChangeEvent ce) - { - // No need to trigger a repaint since the UI listens to the model - // as well. All we need to do is pass on the stateChanged event - // to our listeners. - fireStateChanged(); - } + public void stateChanged(ChangeEvent ce) + { + // No need to trigger a repaint since the UI listens to the model + // as well. All we need to do is pass on the stateChanged event + // to our listeners. + fireStateChanged(); + } }; } /** - * This method registers a listener to this slider. The listener will be - * informed of new ChangeEvents. + * Registers a listener with the slider so that it will receive + * {@link ChangeEvent} notifications. Note that change events generated + * by the slider's model will be forwarded automatically to the slider's + * listeners. * - * @param listener The listener to register. + * @param listener the listener to register. + * + * @see #removeChangeListener(ChangeListener) */ public void addChangeListener(ChangeListener listener) { @@ -427,9 +478,12 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method removes a listener from this slider. + * Removes a listener from this slider so that it will no longer receive + * {@link ChangeEvent} notifications from the slider. * * @param listener The listener to remove. + * + * @see #addChangeListener(ChangeListener) */ public void removeChangeListener(ChangeListener listener) { @@ -437,9 +491,8 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method is called whenever the model fires a ChangeEvent. It should - * propagate the ChangeEvent to its listeners with a new ChangeEvent that - * identifies the slider as the source. + * Sends a {@link ChangeEvent} to all registered listeners, with this slider + * as the source. */ protected void fireStateChanged() { @@ -448,16 +501,19 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, 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 an array of all ChangeListeners listening to this - * slider. + * Returns an array containing all the {@link ChangeListener} instances + * registered with this slider. If no listeners are registered, this method + * returns an empty array. * - * @return An array of ChangeListeners listening to this slider. + * @return An array array containing all the {@link ChangeListener} instances + * registered with this slider (possibly empty, but never + * <code>null</code>). */ public ChangeListener[] getChangeListeners() { @@ -465,9 +521,12 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method returns the model of the slider. + * Returns the slider's model, which stores the minimum, maximum and current + * values. * * @return The slider's model. + * + * @see #setModel(BoundedRangeModel) */ public BoundedRangeModel getModel() { @@ -475,11 +534,16 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method changes the "model" property. It also needs to unregister - * any listeners to the old model and register any listeners to the new - * model. + * Sets the slider's model and sends a {@link PropertyChangeEvent} (with the + * property name "model") to all registered listeners. The change listener + * that the slider registered with the original model is removed and added + * to the new model (this ensures that {@link ChangeEvent} notifications + * generated by the model are automatically forwarded to listeners that are + * registered with the slider). * * @param model The model to use with the slider. + * + * @see #getModel() */ public void setModel(BoundedRangeModel model) { @@ -488,18 +552,20 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, // and bork the next time it tries to access the model. if (model != sliderModel) { - BoundedRangeModel oldModel = sliderModel; - sliderModel = model; - oldModel.removeChangeListener(changeListener); - sliderModel.addChangeListener(changeListener); - firePropertyChange("model", oldModel, sliderModel); + BoundedRangeModel oldModel = sliderModel; + sliderModel = model; + oldModel.removeChangeListener(changeListener); + sliderModel.addChangeListener(changeListener); + firePropertyChange("model", oldModel, sliderModel); } } /** - * This method returns the minimum value of the slider. + * Returns the minimum value of the slider (from the slider's model). * * @return The minimum value of the slider. + * + * @see #setMinimum(int) */ public int getMinimum() { @@ -507,9 +573,20 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method sets the minimum value of the slider. - * + * Sets the minimum value of the slider and fires a + * {@link PropertyChangeEvent} (with the property name "minimum") to all + * registered listeners. Note that: + * <p> + * <ul> + * <li>the minimum value is stored in the slider's model (see + * {@link #getModel()});</li> + * <li>in addition to the property change event, the slider also fires a + * {@link ChangeEvent}.</li> + * </ul> + * * @param minimum The minimum value of the slider. + * + * @see #getMinimum() */ public void setMinimum(int minimum) { @@ -520,9 +597,11 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method returns the maximum value of the slider. + * Returns the slider's maximum value (obtained from the slider's model). * * @return The maximum value of the slider. + * + * @see #setMaximum(int) */ public int getMaximum() { @@ -530,9 +609,20 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method sets the maximum value of the slider. + * Sets the maximum value of the slider and fires a + * {@link PropertyChangeEvent} (with the property name "maximum") to all + * registered listeners. Note that: + * <p> + * <ul> + * <li>the maximum value is stored in the slider's model (see + * {@link #getModel()});</li> + * <li>in addition to the property change event, the slider also fires a + * {@link ChangeEvent}.</li> + * </ul> * * @param maximum The maximum value of the slider. + * + * @see #getMaximum() */ public void setMaximum(int maximum) { @@ -543,10 +633,11 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method returns this slider's isAdjusting value which is true if the - * thumb is being dragged. + * Returns the <code>valueIsAdjusting</code> flag from the slider's model. * - * @return The slider's isAdjusting value. + * @return The <code>valueIsAdjusting</code> flag from the slider's model. + * + * @see #setValueIsAdjusting(boolean) */ public boolean getValueIsAdjusting() { @@ -554,9 +645,12 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method sets the isAdjusting value for the slider. + * Sets the <code>valueIsAdjusting</code> flag in the slider's model, and + * sends a {@link ChangeEvent} to all registered listeners. * - * @param adjusting The slider's isAdjusting value. + * @param adjusting the new flag value. + * + * @see #getValueIsAdjusting() */ public void setValueIsAdjusting(boolean adjusting) { @@ -564,9 +658,11 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method returns the extent value for this slider. + * Returns the slider's extent value, obtained from the slider's model. * - * @return The extent value for this slider. + * @return The extent value. + * + * @see #setExtent(int) */ public int getExtent() { @@ -574,9 +670,15 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method sets the extent value for this slider. + * Sets the slider's extent value and sends a {@link ChangeEvent} to all + * registered listeners. Note that the model will fire a change event to all + * of its registered listeners first (with the model as the event source) and + * then the slider will fire another change event to all of its registered + * listeners (this time with the slider as the event source). * * @param extent The extent value for this slider. + * + * @see #getExtent() */ public void setExtent(int extent) { @@ -584,9 +686,12 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method returns the slider orientation. + * Returns the orientation of the slider, either {@link JSlider#HORIZONTAL} + * or {@link JSlider#VERTICAL}. * * @return The orientation of the slider. + * + * @see #setOrientation(int) */ public int getOrientation() { @@ -594,28 +699,37 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method changes the "orientation" property of this slider. If the - * orientation is not VERTICAL or HORIZONTAL, this method does nothing. + * Sets the orientation for the slider and sends a + * {@link PropertyChangeEvent} (with the property name "orientation") to all + * registered listeners. * - * @param orientation The orientation of this slider. + * @param orientation the orientation (one of {@link JSlider#HORIZONTAL} or + * {@link JSlider#VERTICAL}). + * + * @throws IllegalArgumentException if <code>orientation</code> is not one of + * the permitted values. + * + * @see #getOrientation() */ public void setOrientation(int orientation) { if (orientation != VERTICAL && orientation != HORIZONTAL) - throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL"); + throw new IllegalArgumentException( + "orientation must be one of: VERTICAL, HORIZONTAL"); if (orientation != this.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 the label table for this slider. + * Returns the label table for the slider. * - * @return The label table for this slider. + * @return The label table for the slider (possibly <code>null</code>). + * + * @see #setLabelTable(Dictionary) */ public Dictionary getLabelTable() { @@ -623,23 +737,27 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method changes the "labelTable" property of this slider. + * Sets the table of labels for the slider and sends a + * {@link PropertyChangeEvent} (with the property name "labelTable") to all + * registered listeners. * - * @param table The label table for this slider. + * @param table the table of labels (<code>null</code> permitted). + * + * @see #getLabelTable() */ public void setLabelTable(Dictionary table) { if (table != labelTable) { - Dictionary oldTable = labelTable; - labelTable = table; - firePropertyChange("labelTable", oldTable, labelTable); + Dictionary oldTable = labelTable; + labelTable = table; + firePropertyChange("labelTable", oldTable, labelTable); } } /** - * This method is called to reset UI delegates for the labels in the - * labelTable to a default for the current look and feel. + * Resets the UI delegates for the labels in the <code>labelTable</code> to + * the default for the current look and feel. */ protected void updateLabelUIs() { @@ -647,20 +765,20 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, return; for (Enumeration list = labelTable.elements(); list.hasMoreElements();) { - JLabel label = (JLabel) list.nextElement(); - label.updateUI(); + JLabel label = (JLabel) list.nextElement(); + label.updateUI(); } } /** - * Creates a hashtable of (Integer, JLabel) pairs that can be used as a - * label table for this slider. The labels will start from the sliders - * minimum and increase by the increment. Each label will have a text - * string indicating their integer value. + * Creates a hashtable of <code>(Integer, JLabel)</code> pairs that can be + * used as a label table for this slider. The labels will start from the + * slider's minimum and increase by the increment. Each label will have a text + * string indicating its integer value. * * @param increment The increment between labels (must be > 0). * - * @return A hashtable with the labels and their keys. + * @return A hashtable containing the labels. * * @throws IllegalArgumentException if <code>increment</code> is not greater * than zero. @@ -671,10 +789,10 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * Creates a hashtable of (Integer, JLabel) pairs that can be used as a - * label table for this slider. The labels will start from the given start - * value and increase by the increment. Each label will have a text string - * indicating its integer value. + * Creates a hashtable of <code>(Integer, JLabel)</code> pairs that can be + * used as a label table for this slider. The labels will start from the + * given start value and increase by the increment. Each label will have a + * text string indicating its integer value. * * @param increment The increment between labels (must be > 0). * @param start The value to start from. @@ -699,29 +817,29 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, for (int i = start; i <= max; i += increment) { - label = new JLabel(String.valueOf(i)); - label.setVerticalAlignment(CENTER); - label.setHorizontalAlignment(CENTER); - - // Make sure these labels have the width and height - // they want. - dim = label.getPreferredSize(); - label.setBounds(label.getX(), label.getY(), - (int) dim.getWidth(), - (int) dim.getHeight()); - table.put(new Integer(i), label); + label = new JLabel(String.valueOf(i)); + label.setVerticalAlignment(CENTER); + label.setHorizontalAlignment(CENTER); + + // Make sure these labels have the width and height + // they want. + dim = label.getPreferredSize(); + label.setBounds(label.getX(), label.getY(), + (int) dim.getWidth(), + (int) dim.getHeight()); + table.put(new Integer(i), label); } return table; } /** - * This method returns whether the slider is inverted. Horizontal sliders - * that are not inverted will have the minimums on the left. If they are - * inverted, the minimums will be on the right. Vertical sliders that are - * not inverted will have the minimums at the bottom. If they are inverted, - * the minimums will be at the top. + * Returns the flag that controls whether or not the value scale for the + * slider is inverted (the default value is <code>false</code>). * - * @return Whether this slider is inverted. + * @return The flag that controls whether or not the value scale for the + * slider is inverted. + * + * @see #setInverted(boolean) */ public boolean getInverted() { @@ -729,30 +847,36 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method changes the "inverted" property for this slider.Horizontal - * sliders that are not inverted will have the minimums on the left. If - * they are inverted, the minimums will be on the right. Vertical sliders - * that are not inverted will have the minimums at the bottom. If they are - * inverted, the minimums will be at the top. However, if the slider's - * componentOrientation is set to RIGHT_TO_LEFT, then everything gets - * reversed again. + * Sets the flag that controls whether or not the value scale for the + * slider is inverted and, if the new flag value is different to the old flag + * value, sends a {@link PropertyChangeEvent} to all registered listeners. + * Typically, a horizontal slider will display a scale that increases from + * left to right, but this is reversed if the 'inverted' flag is set to + * <code>true</code>. Similarly, a vertical slider will display a scale that + * increases from bottom to top, and this is reversed if the 'inverted' flag + * is set to <code>true</code>. * - * @param inverted Whether the slider should be inverted. + * @param inverted the new flag value. + * + * @see #getInverted() */ public void setInverted(boolean inverted) { if (isInverted != inverted) { - boolean oldInverted = isInverted; - isInverted = inverted; - firePropertyChange("inverted", oldInverted, isInverted); + boolean oldInverted = isInverted; + isInverted = inverted; + firePropertyChange("inverted", oldInverted, isInverted); } } /** - * This method returns the amount of units between each major tick mark. + * Returns the distance between major tick marks along the slider's value + * scale. * * @return The amount of units between each major tick mark. + * + * @see #setMajorTickSpacing(int) */ public int getMajorTickSpacing() { @@ -760,26 +884,32 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method changes the "majorTickSpacing" property for this slider. The - * major tick spacing is the amount of units between each major tick mark. + * Sets the distance between major tick marks along the slider's value scale, + * and sends a {@link PropertyChangeEvent} (with the property name + * "majorTickSpacing") to all registered listeners. * - * @param spacing The amount of units between each major tick mark. + * @param spacing the distance between major tick marks. + * + * @see #getMajorTickSpacing() */ public void setMajorTickSpacing(int spacing) { if (majorTickSpacing != spacing) { - int oldSpacing = majorTickSpacing; - majorTickSpacing = spacing; - firePropertyChange("majorTickSpacing", oldSpacing, - majorTickSpacing); + int oldSpacing = majorTickSpacing; + majorTickSpacing = spacing; + firePropertyChange("majorTickSpacing", oldSpacing, majorTickSpacing); } } /** - * This method returns the amount of units between each minor tick mark. + * Returns the distance between minor tick marks along the slider's value + * scale. * - * @return The amount of units between each minor tick mark. + * @return The distance between minor tick marks along the slider's value + * scale. + * + * @see #setMinorTickSpacing(int) */ public int getMinorTickSpacing() { @@ -787,28 +917,32 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method changes the "minorTickSpacing" property for this slider. The - * minor tick spacing is the amount of units between each minor tick mark. + * Sets the distance between minor tick marks along the slider's value scale, + * and sends a {@link PropertyChangeEvent} (with the property name + * "minorTickSpacing") to all registered listeners. * - * @param spacing The amount of units between each minor tick mark. + * @param spacing the distance between minor tick marks. + * + * @see #getMinorTickSpacing() */ public void setMinorTickSpacing(int spacing) { if (minorTickSpacing != spacing) { - int oldSpacing = minorTickSpacing; - minorTickSpacing = spacing; - firePropertyChange("minorTickSpacing", oldSpacing, - minorTickSpacing); + int oldSpacing = minorTickSpacing; + minorTickSpacing = spacing; + firePropertyChange("minorTickSpacing", oldSpacing, minorTickSpacing); } } /** - * This method returns whether this slider is snapping to ticks. Sliders - * that snap to ticks will automatically move the thumb to the nearest tick - * mark. + * Returns the flag that controls whether the slider thumb will snap to ticks. + * Sliders that snap to ticks will automatically move the thumb to the + * nearest tick mark. * - * @return Whether this slider snaps to ticks. + * @return <code>true</code> if the slider thumb automatically. + * + * @see #setSnapToTicks(boolean) */ public boolean getSnapToTicks() { @@ -816,28 +950,32 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method sets whether this slider will snap to ticks. Sliders that - * snap to ticks will automatically move the thumb to the nearest tick - * mark. + * Sets the flag that controls whether the slider thumb will snap to ticks + * and sends a {@link PropertyChangeEvent} (with the property name + * 'snapToTicks') to all registered listeners. Sliders that snap to ticks + * will automatically move the thumb to the nearest tick mark. * - * @param snap Whether this slider snaps to ticks. + * @param snap the new flag value. + * + * @see #getSnapToTicks() */ public void setSnapToTicks(boolean snap) { if (snap != snapToTicks) { - snapToTicks = snap; - firePropertyChange("snapToTicks", !snap, snap); + snapToTicks = snap; + firePropertyChange("snapToTicks", !snap, snap); } } /** - * This method returns whether the slider will paint its tick marks. In - * addition to setting this property to true, one of minor tick spacing or - * major tick spacing must be set to a value greater than 0 in order for - * ticks to be painted. + * Returns the flag that controls whether or not tick marks are painted along + * the slider's value scale. * - * @return Whether ticks will be painted. + * @return <code>true</code> if tick marks should be painted, and + * <code>false</code> if tick marks should not be painted. + * + * @see #setPaintTicks(boolean) */ public boolean getPaintTicks() { @@ -845,27 +983,33 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method changes the "paintTicks" property for this slider. In - * addition to setting this property to true, one of minor tick spacing or - * major tick spacing must be set to a value greater than 0 in order for - * ticks to be painted. + * Sets the flag that controls whether or not tick marks are painted along + * the slider's value scale, and sends a {@link PropertyChangeEvent} (with + * the property name "paintTicks") to all registered listeners. In + * addition to setting this property to <code>true</code>, one or both of the + * minor tick spacing and major tick spacing attributes must be set to a + * value greater than 0 in order for ticks to be painted. * * @param paint Whether ticks will be painted. + * + * @see #getPaintTicks() */ public void setPaintTicks(boolean paint) { if (paint != paintTicks) { - boolean oldPaintTicks = paintTicks; - paintTicks = paint; - firePropertyChange("paintTicks", oldPaintTicks, paintTicks); + boolean oldPaintTicks = paintTicks; + paintTicks = paint; + firePropertyChange("paintTicks", oldPaintTicks, paintTicks); } } /** - * This method returns whether the track will be painted. + * Returns the flag that controls whether or not the track is painted. * * @return Whether the track will be painted. + * + * @see #setPaintTrack(boolean) */ public boolean getPaintTrack() { @@ -878,6 +1022,8 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, * registered listeners. * * @param paint Whether the track will be painted. + * + * @see #getPaintTrack() */ public void setPaintTrack(boolean paint) { @@ -889,9 +1035,12 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method returns whether labels will be painted. + * Returns the flag that controls whether or not labels are painted for the + * tick marks along the slider. * * @return Whether labels will be painted. + * + * @see #setPaintLabels(boolean) */ public boolean getPaintLabels() { @@ -899,36 +1048,62 @@ public class JSlider extends JComponent implements SwingConstants, Accessible, } /** - * This method changes the "paintLabels" property. + * Sets the flag that controls whether or not labels are painted for the + * tick marks along the slider and sends a {@link PropertyChangeEvent} (with + * the property name "paintLabels") to all registered listeners. * * @param paint Whether labels will be painted. + * + * @see #getPaintLabels() */ public void setPaintLabels(boolean paint) { if (paint != paintLabels) { - paintLabels = paint; - if (paint && majorTickSpacing > 0) + paintLabels = paint; + if (paint && majorTickSpacing > 0 && labelTable == null) labelTable = createStandardLabels(majorTickSpacing); - firePropertyChange("paintLabels", !paint, paint); + firePropertyChange("paintLabels", !paint, paint); } } /** - * This method is used primarily for debugging purposes and returns a string - * that can be used to represent this slider. + * Returns an implementation-dependent string describing the attributes of + * this <code>JSlider</code>. * - * @return A string representing this slider. + * @return A string describing the attributes of this <code>JSlider</code> + * (never <code>null</code>). */ protected String paramString() { - return "JSlider"; + String superParamStr = super.paramString(); + StringBuffer sb = new StringBuffer(); + sb.append(",isInverted=").append(getInverted()); + sb.append(",majorTickSpacing=").append(getMajorTickSpacing()); + sb.append(",minorTickSpacing=").append(getMinorTickSpacing()); + sb.append(",orientation="); + if (orientation == HORIZONTAL) + sb.append("HORIZONTAL"); + else + sb.append("VERTICAL"); + sb.append(",paintLabels=").append(getPaintLabels()); + sb.append(",paintTicks=").append(getPaintTicks()); + sb.append(",paintTrack=").append(getPaintTrack()); + sb.append(",snapToTicks=").append(getSnapToTicks()); + + // the following is output by the reference implementation. We don't + // strictly need to replicate this. Perhaps it has some meaning, but + // I couldn't determine it yet... + sb.append(",snapToValue=true"); + + return superParamStr + sb.toString(); } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JSlider</code> component. * - * @return DOCUMENT ME! + * @return The accessible context (an instance of {@link AccessibleJSlider}). */ public AccessibleContext getAccessibleContext() { diff --git a/libjava/classpath/javax/swing/JSpinner.java b/libjava/classpath/javax/swing/JSpinner.java index 882d216e126..70045ed5307 100644 --- a/libjava/classpath/javax/swing/JSpinner.java +++ b/libjava/classpath/javax/swing/JSpinner.java @@ -106,6 +106,10 @@ public class JSpinner extends JComponent add(ftf); ftf.setValue(spinner.getValue()); ftf.addPropertyChangeListener(this); + if(getComponentOrientation().isLeftToRight()) + ftf.setHorizontalAlignment(JTextField.RIGHT); + else + ftf.setHorizontalAlignment(JTextField.LEFT); spinner.addChangeListener(this); } diff --git a/libjava/classpath/javax/swing/JSplitPane.java b/libjava/classpath/javax/swing/JSplitPane.java index dc75dfe3184..c1151219854 100644 --- a/libjava/classpath/javax/swing/JSplitPane.java +++ b/libjava/classpath/javax/swing/JSplitPane.java @@ -1,5 +1,5 @@ /* JSplitPane.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,10 +40,12 @@ package javax.swing; import java.awt.Component; import java.awt.Graphics; +import java.beans.PropertyChangeEvent; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleValue; import javax.swing.plaf.SplitPaneUI; @@ -56,18 +58,18 @@ import javax.swing.plaf.SplitPaneUI; */ public class JSplitPane extends JComponent implements Accessible { + /** - * DOCUMENT ME! + * Provides the accessibility features for the <code>JSplitPane</code> + * component. */ - // FIXME: This inner class is a complete stub and must be implemented - // properly. protected class AccessibleJSplitPane extends JComponent.AccessibleJComponent implements AccessibleValue { private static final long serialVersionUID = -1788116871416305366L; /** - * Creates a new AccessibleJSplitPane object. + * Creates a new <code>AccessibleJSplitPane</code> instance. */ protected AccessibleJSplitPane() { @@ -75,75 +77,101 @@ public class JSplitPane extends JComponent implements Accessible } /** - * DOCUMENT ME! + * Returns a set containing the current state of the {@link JSplitPane} + * component. * - * @return DOCUMENT ME! + * @return The accessible state set. */ public AccessibleStateSet getAccessibleStateSet() { - return null; + AccessibleStateSet result = super.getAccessibleStateSet(); + if (getOrientation() == HORIZONTAL_SPLIT) + { + result.add(AccessibleState.HORIZONTAL); + } + else if (getOrientation() == VERTICAL_SPLIT) + { + result.add(AccessibleState.VERTICAL); + } + return result; } /** - * DOCUMENT ME! + * Returns the accessible role for the <code>JSplitPane</code> component. * - * @return DOCUMENT ME! + * @return {@link AccessibleRole#SPLIT_PANE}. */ public AccessibleRole getAccessibleRole() { - return null; + return AccessibleRole.SPLIT_PANE; } /** - * DOCUMENT ME! + * Returns an object that provides access to the current, minimum and + * maximum values for the {@link JSlider}. Since this class implements + * {@link AccessibleValue}, it returns itself. * - * @return DOCUMENT ME! + * @return The accessible value. */ public AccessibleValue getAccessibleValue() { - return null; + return this; } /** - * DOCUMENT ME! + * Returns the current divider location for the {@link JSplitPane} + * component, as an {@link Integer}. * - * @return DOCUMENT ME! + * @return The current divider location. */ public Number getCurrentAccessibleValue() { - return null; + return new Integer(getDividerLocation()); } /** - * DOCUMENT ME! + * Sets the divider location for the {@link JSplitPane} component and sends + * a {@link PropertyChangeEvent} (with the property name + * {@link AccessibleContext#ACCESSIBLE_VALUE_PROPERTY}) to all registered + * listeners. If the supplied value is <code>null</code>, this method + * does nothing and returns <code>false</code>. * - * @param value0 DOCUMENT ME! + * @param value the new slider value (<code>null</code> permitted). * - * @return DOCUMENT ME! + * @return <code>true</code> if the slider value is updated, and + * <code>false</code> otherwise. */ - public boolean setCurrentAccessibleValue(Number value0) + public boolean setCurrentAccessibleValue(Number value) { - return false; + if (value == null) + return false; + Number oldValue = getCurrentAccessibleValue(); + setDividerLocation(value.intValue()); + firePropertyChange(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, oldValue, + new Integer(value.intValue())); + return true; } /** - * DOCUMENT ME! + * Returns the minimum divider location for the {@link JSplitPane} + * component, as an {@link Integer}. * - * @return DOCUMENT ME! + * @return The minimum divider location. */ public Number getMinimumAccessibleValue() { - return null; + return new Integer(getMinimumDividerLocation()); } /** - * DOCUMENT ME! + * Returns the maximum divider location for the {@link JSplitPane} + * component, as an {@link Integer}. * - * @return DOCUMENT ME! + * @return The maximum divider location. */ public Number getMaximumAccessibleValue() { - return null; + return new Integer(getMaximumDividerLocation()); } } @@ -223,6 +251,24 @@ public class JSplitPane extends JComponent implements Accessible private transient double resizeWeight; /** + * Indicates if the dividerSize property has been set by a client program or + * by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientDividerSizeSet = false; + + /** + * Indicates if the oneTouchExpandable property has been set by a client + * program or by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientOneTouchExpandableSet = false; + + /** * Creates a new JSplitPane object with the given orientation, layout mode, * and left and right components. * @@ -353,9 +399,11 @@ public class JSplitPane extends JComponent implements Accessible } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JSplitPane</code> component. * - * @return DOCUMENT ME! + * @return The accessible context (an instance of + * {@link AccessibleJSplitPane}). */ public AccessibleContext getAccessibleContext() { @@ -541,14 +589,27 @@ public class JSplitPane extends JComponent implements Accessible } /** - * This method returns a String that describes this JSplitPane. The string - * is primarily used for debugging purposes. + * Returns an implementation-dependent string describing the attributes of + * this <code>JSplitPane</code>. * - * @return A String used for debugging purposes. + * @return A string describing the attributes of this <code>JSplitPane</code> + * (never <code>null</code>). */ protected String paramString() { - return "JSplitPane"; + // FIXME: the next line can be restored once PR27208 is fixed + String superParamStr = ""; //super.paramString(); + StringBuffer sb = new StringBuffer(); + sb.append(",continuousLayout=").append(isContinuousLayout()); + sb.append(",dividerSize=").append(getDividerSize()); + sb.append(",lastDividerLocation=").append(getLastDividerLocation()); + sb.append(",oneTouchExpandable=").append(isOneTouchExpandable()); + sb.append(",orientation="); + if (orientation == HORIZONTAL_SPLIT) + sb.append("HORIZONTAL_SPLIT"); + else + sb.append("VERTICAL_SPLIT"); + return superParamStr + sb.toString(); } /** @@ -652,16 +713,23 @@ public class JSplitPane extends JComponent implements Accessible /** * This method sets the location of the divider. - * - * @param location The location of the divider. + * + * @param location The location of the divider. The negative value forces to + * compute the new location from the preferred sizes of the split + * pane components. */ public void setDividerLocation(int location) { if (ui != null && location != getDividerLocation()) { - int oldLocation = getDividerLocation(); - ((SplitPaneUI) ui).setDividerLocation(this, location); - firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldLocation, location); + int oldLocation = getDividerLocation(); + if (location < 0) + ((SplitPaneUI) ui).resetToPreferredSizes(this); + else + ((SplitPaneUI) ui).setDividerLocation(this, location); + + firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldLocation, + getDividerLocation()); } } @@ -672,6 +740,7 @@ public class JSplitPane extends JComponent implements Accessible */ public void setDividerSize(int newSize) { + clientDividerSizeSet = true; if (newSize != dividerSize) { int oldSize = dividerSize; @@ -723,6 +792,7 @@ public class JSplitPane extends JComponent implements Accessible */ public void setOneTouchExpandable(boolean newValue) { + clientOneTouchExpandableSet = true; if (newValue != oneTouchExpandable) { boolean oldValue = oneTouchExpandable; @@ -733,11 +803,15 @@ public class JSplitPane extends JComponent implements Accessible } /** - * This method sets the orientation of the JSplitPane. + * Sets the orientation for the <code>JSplitPane</code> and sends a + * {@link PropertyChangeEvent} (with the property name + * {@link #ORIENTATION_PROPERTY}) to all registered listeners. * - * @param orientation The orientation of the JSplitPane. + * @param orientation the orientation (either {@link #HORIZONTAL_SPLIT} + * or {@link #VERTICAL_SPLIT}). * - * @throws IllegalArgumentException DOCUMENT ME! + * @throws IllegalArgumentException if <code>orientation</code> is not one of + * the listed values. */ public void setOrientation(int orientation) { @@ -764,7 +838,14 @@ public class JSplitPane extends JComponent implements Accessible */ public void setResizeWeight(double value) { - resizeWeight = value; + if (value < 0.0 || value > 1.0) + throw new IllegalArgumentException("Value outside permitted range."); + if (this.resizeWeight != value) + { + double old = resizeWeight; + resizeWeight = value; + firePropertyChange(RESIZE_WEIGHT_PROPERTY, old, value); + } } /** @@ -810,8 +891,6 @@ public class JSplitPane extends JComponent implements Accessible public void updateUI() { setUI((SplitPaneUI) UIManager.getUI(this)); - invalidate(); - repaint(); } /** @@ -824,4 +903,42 @@ public class JSplitPane extends JComponent implements Accessible { return "SplitPaneUI"; } + + /** + * Helper method for + * {@link LookAndFeel#installProperty(JComponent, String, Object)}. + * + * @param propertyName the name of the property + * @param value the value of the property + * + * @throws IllegalArgumentException if the specified property cannot be set + * by this method + * @throws ClassCastException if the property value does not match the + * property type + * @throws NullPointerException if <code>c</code> or + * <code>propertyValue</code> is <code>null</code> + */ + void setUIProperty(String propertyName, Object value) + { + if (propertyName.equals("dividerSize")) + { + if (! clientDividerSizeSet) + { + setDividerSize(((Integer) value).intValue()); + clientDividerSizeSet = false; + } + } + else if (propertyName.equals("oneTouchExpandable")) + { + if (! clientOneTouchExpandableSet) + { + setOneTouchExpandable(((Boolean) value).booleanValue()); + clientOneTouchExpandableSet = false; + } + } + else + { + super.setUIProperty(propertyName, value); + } + } } diff --git a/libjava/classpath/javax/swing/JTabbedPane.java b/libjava/classpath/javax/swing/JTabbedPane.java index 3c91a5ea397..34ab8eeaa66 100644 --- a/libjava/classpath/javax/swing/JTabbedPane.java +++ b/libjava/classpath/javax/swing/JTabbedPane.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.Point; @@ -102,6 +104,7 @@ public class JTabbedPane extends JComponent implements Serializable, * @param e the change event describing the change */ public void stateChanged(ChangeEvent e) + throws NotImplementedException { // Implement this properly. } @@ -113,6 +116,7 @@ public class JTabbedPane extends JComponent implements Serializable, * @return the accessible role of the <code>JTabbedPane</code> */ public AccessibleRole getAccessibleRole() + throws NotImplementedException { return null; } @@ -125,6 +129,7 @@ public class JTabbedPane extends JComponent implements Serializable, * <code>JTabbedPane</code> */ public int getAccessibleChildrenCount() + throws NotImplementedException { return 0; } @@ -153,6 +158,7 @@ public class JTabbedPane extends JComponent implements Serializable, * @return the current selection state of the <code>JTabbedPane</code> */ public AccessibleSelection getAccessibleSelection() + throws NotImplementedException { return null; } @@ -169,6 +175,7 @@ public class JTabbedPane extends JComponent implements Serializable, * this location */ public Accessible getAccessibleAt(Point p) + throws NotImplementedException { return null; } @@ -183,6 +190,7 @@ public class JTabbedPane extends JComponent implements Serializable, * <code>JTabbedPane</code> */ public int getAccessibleSelectionCount() + throws NotImplementedException { return 0; } @@ -195,6 +203,7 @@ public class JTabbedPane extends JComponent implements Serializable, * @return DOCUMENT ME! */ public Accessible getAccessibleSelection(int i) + throws NotImplementedException { return null; } @@ -207,6 +216,7 @@ public class JTabbedPane extends JComponent implements Serializable, * @return DOCUMENT ME! */ public boolean isAccessibleChildSelected(int i) + throws NotImplementedException { return false; } @@ -217,6 +227,7 @@ public class JTabbedPane extends JComponent implements Serializable, * @param i DOCUMENT ME! */ public void addAccessibleSelection(int i) + throws NotImplementedException { // TODO: Implement this properly. } @@ -227,6 +238,7 @@ public class JTabbedPane extends JComponent implements Serializable, * @param i DOCUMENT ME! */ public void removeAccessibleSelection(int i) + throws NotImplementedException { // TODO: Implement this properly. } @@ -235,6 +247,7 @@ public class JTabbedPane extends JComponent implements Serializable, * DOCUMENT ME! */ public void clearAccessibleSelection() + throws NotImplementedException { // TODO: Implement this properly. } @@ -243,6 +256,7 @@ public class JTabbedPane extends JComponent implements Serializable, * DOCUMENT ME! */ public void selectAllAccessibleSelection() + throws NotImplementedException { // TODO: Implement this properly. } @@ -379,7 +393,12 @@ public class JTabbedPane extends JComponent implements Serializable, */ public Color getBackground() { - return bg; + Color background; + if (bg == null) + background = JTabbedPane.this.getBackground(); + else + background = bg; + return background; } /** @@ -399,7 +418,12 @@ public class JTabbedPane extends JComponent implements Serializable, */ public Color getForeground() { - return fg; + Color foreground; + if (fg == null) + foreground = JTabbedPane.this.getForeground(); + else + foreground = fg; + return foreground; } /** @@ -585,12 +609,14 @@ public class JTabbedPane extends JComponent implements Serializable, } public AccessibleStateSet getAccessibleStateSet() + throws NotImplementedException { // FIXME: Implement this properly. return null; } public int getAccessibleIndexInParent() + throws NotImplementedException { // FIXME: Implement this properly. return 0; @@ -739,7 +765,6 @@ public class JTabbedPane extends JComponent implements Serializable, public void updateUI() { setUI((TabbedPaneUI) UIManager.getUI(this)); - invalidate(); } /** @@ -950,7 +975,11 @@ public class JTabbedPane extends JComponent implements Serializable, */ public Component getSelectedComponent() { - return getComponentAt(getSelectedIndex()); + int selectedIndex = getSelectedIndex(); + Component selected = null; + if (selectedIndex >= 0) + selected = getComponentAt(selectedIndex); + return selected; } /** @@ -1144,8 +1173,45 @@ public class JTabbedPane extends JComponent implements Serializable, public void removeTabAt(int index) { checkIndex(index, 0, tabs.size()); + + // We need to adjust the selection if we remove a tab that comes + // before the selected tab or if the selected tab is removed. + // This decrements the selected index by 1 if any of this is the case. + // Note that this covers all cases: + // - When the selected tab comes after the removed tab, this simply + // adjusts the selection so that after the removal the selected tab + // is still the same. + // - When we remove the currently selected tab, then the tab before the + // selected tab gets selected. + // - When the last tab is removed, then we have an index==0, which gets + // decremented to -1, which means no selection, which is 100% perfect. + int selectedIndex = getSelectedIndex(); + if (selectedIndex >= index) + setSelectedIndex(selectedIndex - 1); + + Component comp = getComponentAt(index); + + // Remove the tab object. tabs.remove(index); - getComponentAt(index).show(); + + // Remove the component. I think we cannot assume that the tab order + // is equal to the component order, so we iterate over the children + // here to find the and remove the correct component. + if (comp != null) + { + Component[] children = getComponents(); + for (int i = children.length - 1; i >= 0; --i) + { + if (children[i] == comp) + { + super.remove(i); + comp.setVisible(true); + break; + } + } + } + revalidate(); + repaint(); } /** @@ -1175,7 +1241,8 @@ public class JTabbedPane extends JComponent implements Serializable, */ public void removeAll() { - for (int i = tabs.size() - 1; i >= 0; i--) + setSelectedIndex(-1); + for (int i = getTabCount() - 1; i >= 0; i--) removeTabAt(i); } diff --git a/libjava/classpath/javax/swing/JTable.java b/libjava/classpath/javax/swing/JTable.java index fbf74934a0a..348534469a8 100644 --- a/libjava/classpath/javax/swing/JTable.java +++ b/libjava/classpath/javax/swing/JTable.java @@ -1018,19 +1018,7 @@ public class JTable * The CheckBox that is used for rendering. */ private final JCheckBox checkBox = new JCheckBox(); - - /** - * The check box must have the text field background and be centered. - */ - private BooleanCellRenderer() - { - // Render the checkbox identically as the text field. - JTextField f = new JTextField(); - checkBox.setForeground(f.getForeground()); - checkBox.setBackground(f.getBackground()); - checkBox.setHorizontalAlignment(SwingConstants.CENTER); - } - + /** * Get the check box. */ @@ -1041,14 +1029,13 @@ public class JTable /** * Returns the component that is used for rendering the value. - * + * * @param table the JTable * @param value the value of the object * @param isSelected is the cell selected? * @param hasFocus has the cell the focus? * @param row the row to render * @param column the cell to render - * * @return this component (the default table cell renderer) */ public Component getTableCellRendererComponent(JTable table, Object value, @@ -1056,6 +1043,32 @@ public class JTable boolean hasFocus, int row, int column) { + if (isSelected) + { + checkBox.setBackground(table.getSelectionBackground()); + checkBox.setForeground(table.getSelectionForeground()); + } + else + { + checkBox.setBackground(table.getBackground()); + checkBox.setForeground(table.getForeground()); + } + + if (hasFocus) + { + checkBox.setBorder( + UIManager.getBorder("Table.focusCellHighlightBorder")); + if (table.isCellEditable(row, column)) + { + checkBox.setBackground( + UIManager.getColor("Table.focusCellBackground")); + checkBox.setForeground( + UIManager.getColor("Table.focusCellForeground")); + } + } + else + checkBox.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + // Null is rendered as false. if (value == null) checkBox.setSelected(false); @@ -1233,8 +1246,12 @@ public class JTable { Icon iconValue = (Icon) value; setIcon(iconValue); - setText(""); } + else + { + setIcon(null); + } + setText(""); return this; } } @@ -1253,22 +1270,18 @@ public class JTable */ TableTextField() { - setBorder(null); + setBorder(BorderFactory.createLineBorder(getGridColor(), 2)); } /** - * Scroll the table, making the given rectangle of this component - * visible. Mind the component position with relate to the table. * With not this method overridden, the scroll pane scrolls to the * top left cornec (untranslated position of the caret) after the first - * keystroke. + * keystroke. */ public void scrollRectToVisible(Rectangle r) { - // In private class we known that the rectangle data will not be - // reused and we need not to clone it. - r.translate(getX(), getY()); - super.scrollRectToVisible(r); + // Do nothing here. If the editing session starts outside the visible + // bounds, the editCellAt will scroll. } } @@ -1317,7 +1330,6 @@ public class JTable */ public static final int AUTO_RESIZE_LAST_COLUMN = 3; - /** * A table mapping {@link java.lang.Class} objects to * {@link TableCellEditor} objects. This table is consulted by the @@ -1567,6 +1579,15 @@ public class JTable private Rectangle rectCache = new Rectangle(); /** + * Indicates if the rowHeight property has been set by a client program or by + * the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientRowHeightSet = false; + + /** * Creates a new <code>JTable</code> instance. */ public JTable () @@ -1643,13 +1664,22 @@ public class JTable public JTable (TableModel dm, TableColumnModel cm, ListSelectionModel sm) { boolean autoCreate = false; + TableColumnModel columnModel; if (cm != null) - setColumnModel(cm); + columnModel = cm; else { - setColumnModel(createDefaultColumnModel()); + columnModel = createDefaultColumnModel(); autoCreate = true; - } + } + + // Initialise the intercelar spacing before setting the column model to + // avoid firing unnecessary events. + // The initial incellar spacing is new Dimenstion(1,1). + rowMargin = 1; + columnModel.setColumnMargin(1); + setColumnModel(columnModel); + setSelectionModel(sm == null ? createDefaultSelectionModel() : sm); setModel(dm == null ? createDefaultDataModel() : dm); setAutoCreateColumnsFromModel(autoCreate); @@ -1709,7 +1739,6 @@ public class JTable this.showVerticalLines = true; this.editingColumn = -1; this.editingRow = -1; - setIntercellSpacing(new Dimension(1,1)); } /** @@ -1856,13 +1885,38 @@ public class JTable } /** - * Invoked when the the column selection changes. + * Invoked when the the column selection changes, repaints the changed + * columns. It is not recommended to override this method, register the + * listener instead. */ public void columnSelectionChanged (ListSelectionEvent event) { - repaint(); + // Does not make sense for the table with the single column. + if (getColumnCount() < 2) + return; + + int x0 = 0; + + // We must limit the indices to the bounds of the JTable's model, because + // we might get values of -1 or greater then columnCount in the case + // when columns get removed. + int idx0 = Math.max(0, Math.min(getColumnCount() - 1, + event.getFirstIndex())); + int idxn = Math.max(0, Math.min(getColumnCount() - 1, + event.getLastIndex())); + int i; + + for (i = 0; i < idx0; i++) + x0 += columnModel.getColumn(i).getWidth(); + + int xn = x0; + + for (i = idx0; i <= idxn; i++) + xn += columnModel.getColumn(i).getWidth(); + + repaint(x0, 0, xn-x0, getHeight()); } - + /** * Invoked when the editing is cancelled. */ @@ -1910,9 +1964,33 @@ public class JTable // affect the size parameters of the JTable. Otherwise we only need // to perform a repaint to update the view. if (event == null || event.getType() == TableModelEvent.INSERT) - revalidate(); + { + // Sync selection model with data model. + if (event != null) + { + int first = event.getFirstRow(); + if (first < 0) + first = 0; + int last = event.getLastRow(); + if (last < 0) + last = getRowCount() - 1; + selectionModel.insertIndexInterval(first, last - first + 1, true); + } + revalidate(); + } if (event == null || event.getType() == TableModelEvent.DELETE) { + // Sync selection model with data model. + if (event != null) + { + int first = event.getFirstRow(); + if (first < 0) + first = 0; + int last = event.getLastRow(); + if (last < 0) + last = getRowCount() - 1; + selectionModel.removeIndexInterval(first, last); + } if (dataModel.getRowCount() == 0) clearSelection(); revalidate(); @@ -1921,11 +1999,19 @@ public class JTable } /** - * Invoked when another table row is selected. + * Invoked when another table row is selected. It is not recommended + * to override thid method, register the listener instead. */ public void valueChanged (ListSelectionEvent event) { - repaint(); + // 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); } /** @@ -1938,21 +2024,18 @@ public class JTable */ public int columnAtPoint(Point point) { - if (point != null) - { - int ncols = getColumnCount(); - Dimension gap = getIntercellSpacing(); - TableColumnModel cols = getColumnModel(); - int x = point.x; + int ncols = getColumnCount(); + Dimension gap = getIntercellSpacing(); + TableColumnModel cols = getColumnModel(); + int x = point.x; - for (int i = 0; i < ncols; ++i) - { - int width = cols.getColumn(i).getWidth() - + (gap == null ? 0 : gap.width); - if (0 <= x && x < width) - return i; - x -= width; - } + for (int i = 0; i < ncols; ++i) + { + int width = cols.getColumn(i).getWidth() + + (gap == null ? 0 : gap.width); + if (0 <= x && x < width) + return i; + x -= width; } return -1; } @@ -1961,8 +2044,7 @@ public class JTable * Returns index of the row that contains specified point or -1 if this table * doesn't contain this point. * - * @param point - * point to identify the row + * @param point point to identify the row * @return index of the row that contains specified point or -1 if this table * doesn't contain this point. */ @@ -2004,9 +2086,6 @@ public class JTable int column, boolean includeSpacing) { - // moveToCellBeingEdited expects the cached value and clones it. - // If the caching would be removed later, uplate moveToCellBeingEdited - // as well. int height = getRowHeight(row); int width = columnModel.getColumn(column).getWidth(); int x_gap = columnModel.getColumnMargin(); @@ -2020,12 +2099,14 @@ public class JTable for (int i = 0; i < column; ++i) x += columnModel.getColumn(i).getWidth(); + + Rectangle rect = new Rectangle(); if (includeSpacing) - rectCache.setBounds(x, y, width, height +y_gap); + rect.setBounds(x, y, width, height +y_gap); else - rectCache.setBounds(x, y, width - x_gap, height); - return rectCache; + rect.setBounds(x, y, width - x_gap, height); + return rect; } public void clearSelection() @@ -2088,26 +2169,39 @@ public class JTable else return true; } - - public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) + + /** + * Return the preferred scrolling amount (in pixels) for the given scrolling + * direction and orientation. This method handles a partially exposed row by + * returning the distance required to completely expose the item. When + * scrolling the top item is completely exposed. + * + * @param visibleRect the currently visible part of the component. + * @param orientation the scrolling orientation + * @param direction the scrolling direction (negative - up, positive -down). + * The values greater than one means that more mouse wheel or similar + * events were generated, and hence it is better to scroll the longer + * distance. + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ + public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, + int direction) { - // FIXME: I don't exactly know what sun does here. in both cases they - // pick values which do *not* simply expose the next cell in a given - // scroll direction. + int h = (rowHeight + rowMargin); + int delta = h * direction; + // Round so that the top would start from the row boundary if (orientation == SwingConstants.VERTICAL) - return direction * rowHeight; - else { - int sum = 0; - for (int i = 0; i < getColumnCount(); ++i) - sum += columnModel.getColumn(0).getWidth(); - int inc = getColumnCount() == 0 ? 10 : sum / getColumnCount(); - return direction * inc; + // Completely expose the top row + int near = ((visibleRect.y + delta + h / 2) / h) * h; + int diff = visibleRect.y + delta - near; + delta -= diff; } + return delta; + // TODO when scrollng horizontally, scroll into the column boundary. } - /** * Get the cell editor, suitable for editing the given cell. The default * method requests the editor from the column model. If the column model does @@ -2372,7 +2466,7 @@ public class JTable /** * Get the value of the <code>columnCount</code> property by - * delegation to the @{link #columnModel} field. + * delegation to the {@link #columnModel} field. * * @return The current value of the columnCount property */ @@ -2383,7 +2477,7 @@ public class JTable /** * Get the value of the <code>rowCount</code> property by - * delegation to the @{link #dataModel} field. + * delegation to the {@link #dataModel} field. * * @return The current value of the rowCount property */ @@ -2404,7 +2498,7 @@ public class JTable /** * Get the value of the <code>selectedColumn</code> property by - * delegation to the @{link #columnModel} field. + * delegation to the {@link #columnModel} field. * * @return The current value of the selectedColumn property */ @@ -2473,7 +2567,7 @@ public class JTable /** * Get the value of the <code>selectedColumnCount</code> property by - * delegation to the @{link #columnModel} field. + * delegation to the {@link #columnModel} field. * * @return The current value of the selectedColumnCount property */ @@ -2484,7 +2578,7 @@ public class JTable /** * Get the value of the <code>selectedColumns</code> property by - * delegation to the @{link #columnModel} field. + * delegation to the {@link #columnModel} field. * * @return The current value of the selectedColumns property */ @@ -2505,7 +2599,7 @@ public class JTable /** * Get the value of the <code>selectedRowCount</code> property by - * delegation to the @{link #selectionModel} field. + * delegation to the {@link #selectionModel} field. * * @return The current value of the selectedRowCount property */ @@ -2516,7 +2610,7 @@ public class JTable /** * Get the value of the <code>selectedRows</code> property by - * delegation to the @{link #selectionModel} field. + * delegation to the {@link #selectionModel} field. * * @return The current value of the selectedRows property */ @@ -2694,7 +2788,9 @@ public class JTable { if (r < 1) throw new IllegalArgumentException(); - + + clientRowHeightSet = true; + rowHeight = r; revalidate(); repaint(); @@ -3260,8 +3356,6 @@ public class JTable public void updateUI() { setUI((TableUI) UIManager.getUI(this)); - revalidate(); - repaint(); } /** @@ -3501,8 +3595,7 @@ public class JTable } /** - * Set value for the cell at the given position. If the cell is not - * editable, this method returns without action. The modified cell is + * Set value for the cell at the given position. The modified cell is * repainted. * * @param value the value to set @@ -3511,8 +3604,6 @@ public class JTable */ public void setValueAt(Object value, int row, int column) { - if (!isCellEditable(row, column)) - return; dataModel.setValueAt(value, row, convertColumnIndexToModel(column)); repaint(getCellRect(row, column, true)); @@ -3660,18 +3751,14 @@ public class JTable private void moveToCellBeingEdited(Component component) { Rectangle r = getCellRect(editingRow, editingColumn, true); - // Place the text field so that it would not touch the table - // border. - - // TODO Figure out while 5 and which constant should here be. - int xOffset = 5; - r.x+=xOffset; - r.y++; - r.width -=xOffset; - r.height --; - - // Clone rectangle as getCellRect returns the cached value. - component.setBounds(new Rectangle(r)); + // Adjust bounding box of the editing component, so that it lies + // 'above' the grid on all edges, not only right and bottom. + // The table grid is painted only at the right and bottom edge of a cell. + r.x -= 1; + r.y -= 1; + r.width += 1; + r.height += 1; + component.setBounds(r); } /** @@ -3749,4 +3836,34 @@ public class JTable // TODO: Implement functionality of this property (in UI impl). return surrendersFocusOnKeystroke; } + + /** + * Helper method for + * {@link LookAndFeel#installProperty(JComponent, String, Object)}. + * + * @param propertyName the name of the property + * @param value the value of the property + * + * @throws IllegalArgumentException if the specified property cannot be set + * by this method + * @throws ClassCastException if the property value does not match the + * property type + * @throws NullPointerException if <code>c</code> or + * <code>propertyValue</code> is <code>null</code> + */ + void setUIProperty(String propertyName, Object value) + { + if (propertyName.equals("rowHeight")) + { + if (! clientRowHeightSet) + { + setRowHeight(((Integer) value).intValue()); + clientRowHeightSet = false; + } + } + else + { + super.setUIProperty(propertyName, value); + } + } } diff --git a/libjava/classpath/javax/swing/JTextField.java b/libjava/classpath/javax/swing/JTextField.java index 01c5c06a350..367503b739f 100644 --- a/libjava/classpath/javax/swing/JTextField.java +++ b/libjava/classpath/javax/swing/JTextField.java @@ -1,5 +1,5 @@ /* JTextField.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. @@ -42,6 +42,7 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Insets; +import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; @@ -110,8 +111,7 @@ public class JTextField extends JTextComponent private int columns; private int align; - private int scrollOffset; - + /** @since 1.3 */ private Action action; @@ -184,6 +184,9 @@ public class JTextField extends JTextComponent this.columns = columns; + // Initialize the horizontal visibility model. + horizontalVisibility = new DefaultBoundedRangeModel(); + setDocument(doc == null ? createDefaultModel() : doc); if (text != null) @@ -191,9 +194,6 @@ public class JTextField extends JTextComponent // default value for alignment align = LEADING; - - // Initialize the horizontal visibility model. - horizontalVisibility = new DefaultBoundedRangeModel(); } /** @@ -270,7 +270,7 @@ public class JTextField extends JTextComponent */ protected void fireActionPerformed() { - ActionEvent event = new ActionEvent(this, 0, notifyAction); + ActionEvent event = new ActionEvent(this, 0, getText()); ActionListener[] listeners = getActionListeners(); for (int index = 0; index < listeners.length; ++index) @@ -368,8 +368,7 @@ public class JTextField extends JTextComponent */ public int getScrollOffset() { - //FIXME: this should return horizontalVisibility's value - return scrollOffset; + return horizontalVisibility.getValue(); } /** @@ -379,8 +378,13 @@ public class JTextField extends JTextComponent */ public void setScrollOffset(int offset) { - //FIXME: this should actualy scroll the field if needed - scrollOffset = offset; + // Automatically sets to the highest possible value if + // offset is bigger than that. + horizontalVisibility.setValue( + Math.min(horizontalVisibility.getMaximum() + - horizontalVisibility.getExtent(), + offset)); + } /** @@ -525,9 +529,6 @@ public class JTextField extends JTextComponent */ public BoundedRangeModel getHorizontalVisibility() { - // TODO: The real implementation of this property is still missing. - // However, this is not done in JTextField but must instead be handled in - // javax.swing.text.FieldView. return horizontalVisibility; } @@ -544,4 +545,25 @@ public class JTextField extends JTextComponent { return ! (getParent() instanceof JViewport); } + + public void scrollRectToVisible(Rectangle r) + { + int v = horizontalVisibility.getValue(); + + // The extent value is the inner width of the text field. + int e = horizontalVisibility.getExtent(); + Insets i = getInsets(); + + // The x value in the rectangle (usually) denotes the new location + // of the caret. We check whether the location lies inside the left or + // right border and scroll into the appropriate direction. + // The calculation has to be shifted by the BoundedRangeModel's value + // because that value was already used to calculate r.x (this happens + // as part of a modelToView() call in FieldView). + if (r.x < i.left) + setScrollOffset(v + r.x - i.left); + else if (r.x > e + i.left) + setScrollOffset(r.x + v - e - i.left); + } + } diff --git a/libjava/classpath/javax/swing/JToggleButton.java b/libjava/classpath/javax/swing/JToggleButton.java index 077e5adb887..1769c5ee08a 100644 --- a/libjava/classpath/javax/swing/JToggleButton.java +++ b/libjava/classpath/javax/swing/JToggleButton.java @@ -179,7 +179,7 @@ public class JToggleButton extends AbstractButton implements Accessible /** * Checks if the button is selected. * - * @returns true if the button is selected + * @return <code>true</code> if the button is selected. */ public boolean isSelected() { diff --git a/libjava/classpath/javax/swing/JToolBar.java b/libjava/classpath/javax/swing/JToolBar.java index a508ee6d8e7..b576b4f2a31 100644 --- a/libjava/classpath/javax/swing/JToolBar.java +++ b/libjava/classpath/javax/swing/JToolBar.java @@ -50,7 +50,6 @@ import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; import javax.accessibility.AccessibleStateSet; -import javax.swing.JButton; import javax.swing.plaf.ToolBarUI; /** @@ -66,17 +65,15 @@ import javax.swing.plaf.ToolBarUI; public class JToolBar extends JComponent implements SwingConstants, Accessible { /** - * AccessibleJToolBar + * Provides the accessibility features for the <code>JToolBar</code> + * component. */ - // FIXME: This inner class is a complete stub and must be implemented - // properly. protected class AccessibleJToolBar extends AccessibleJComponent { - /** DOCUMENT ME! */ private static final long serialVersionUID = -5516888265903814215L; /** - * Constructor AccessibleJToolBar + * Creates a new <code>AccessibleJToolBar</code> instance. */ protected AccessibleJToolBar() { @@ -84,19 +81,23 @@ public class JToolBar extends JComponent implements SwingConstants, Accessible } /** - * getAccessibleStateSet + * Returns a set containing the current state of the {@link JToolBar} + * component. The current implementation simply calls the superclass. * - * @return AccessibleStateSet + * @return The accessible state set. */ public AccessibleStateSet getAccessibleStateSet() { - return null; // TODO + // running tests against the reference implementation, I was unable + // to find any state information that is set specifically by the + // tool bar... + return super.getAccessibleStateSet(); } /** - * getAccessibleRole + * Returns the accessible role for the <code>JToolBar</code> component. * - * @return AccessibleRole + * @return {@link AccessibleRole#TOOL_BAR}. */ public AccessibleRole getAccessibleRole() { @@ -426,8 +427,9 @@ public class JToolBar extends JComponent implements SwingConstants, Accessible setOrientation(orientation); setLayout(new DefaultToolBarLayout()); revalidate(); + setOpaque(true); updateUI(); - } // JToolBar() + } /** * This method adds a new JButton that performs the given Action to the @@ -481,9 +483,7 @@ public class JToolBar extends JComponent implements SwingConstants, Accessible public void updateUI() { setUI((ToolBarUI) UIManager.getUI(this)); - revalidate(); - repaint(); - } // updateUI() + } /** * This method returns the String identifier for the UI class to the used @@ -767,9 +767,10 @@ public class JToolBar extends JComponent implements SwingConstants, Accessible } // paramString() /** - * getAccessibleContext + * Returns the object that provides accessibility features for this + * <code>JToolBar</code> component. * - * @return AccessibleContext + * @return The accessible context (an instance of {@link AccessibleJToolBar}). */ public AccessibleContext getAccessibleContext() { diff --git a/libjava/classpath/javax/swing/JToolTip.java b/libjava/classpath/javax/swing/JToolTip.java index 6bc3e3fa287..836c122c6bf 100644 --- a/libjava/classpath/javax/swing/JToolTip.java +++ b/libjava/classpath/javax/swing/JToolTip.java @@ -39,6 +39,7 @@ exception statement from your version. */ package javax.swing; import java.awt.AWTEvent; +import java.beans.PropertyChangeEvent; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; @@ -52,14 +53,13 @@ import javax.swing.plaf.ToolTipUI; */ public class JToolTip extends JComponent implements Accessible { - /** DOCUMENT ME! */ + private static final long serialVersionUID = -1138929898906751643L; /** - * DOCUMENT ME! + * Provides the accessibility features for the <code>JToolTip</code> + * component. */ - // FIXME: This inner class is a complete stub and must be implemented - // properly. protected class AccessibleJToolTip extends AccessibleJComponent { private static final long serialVersionUID = -6222548177795408476L; @@ -73,34 +73,37 @@ public class JToolTip extends JComponent implements Accessible } /** - * DOCUMENT ME! + * Returns a description for the accessible component. * - * @return DOCUMENT ME! + * @return A description for the accessible component. */ public String getAccessibleDescription() { - return null; + String result = super.getAccessibleDescription(); + if (result == null) + result = text; + return result; } /** - * DOCUMENT ME! + * Returns the accessible role for the <code>JToolTip</code> component. * - * @return DOCUMENT ME! + * @return {@link AccessibleRole#TOOL_TIP}. */ public AccessibleRole getAccessibleRole() { - return null; + return AccessibleRole.TOOL_TIP; } } /** The text to display in the JToolTip. */ String text; - /** The JComponent this JToolTip is used for. */ + /** The component that the tool tip is associated with. */ JComponent component; /** - * Creates a new JToolTip object. + * Creates a new <code>JToolTip</code> instance. */ public JToolTip() { @@ -109,9 +112,11 @@ public class JToolTip extends JComponent implements Accessible } /** - * This method returns the text this JToolTip displays. + * Returns the text displayed by the tool tip. * - * @return The text that this JToolTip displays. + * @return The text (possibly <code>null</code>). + * + * @see #setTipText(String) */ public String getTipText() { @@ -119,19 +124,24 @@ public class JToolTip extends JComponent implements Accessible } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JToolTip</code> component. * - * @return DOCUMENT ME! + * @return The accessible context (an instance of {@link AccessibleJToolTip}). */ public AccessibleContext getAccessibleContext() { - return null; + if (accessibleContext == null) + accessibleContext = new AccessibleJToolTip(); + return accessibleContext; } /** - * This method returns the JComponent this JToolTip displays for. + * Returns the component that the tool tip is associated with. * - * @return The JComponent this JToolTip displays for. + * @return The component (possibly <code>null</code>). + * + * @see #setComponent(JComponent) */ public JComponent getComponent() { @@ -139,9 +149,9 @@ public class JToolTip extends JComponent implements Accessible } /** - * This method returns the UI responsible for displaying this JToolTip. + * Returns the current UI delegate for this component. * - * @return The UI responsible for displaying this JToolTip. + * @return The UI delegate. */ public ToolTipUI getUI() { @@ -149,9 +159,10 @@ public class JToolTip extends JComponent implements Accessible } /** - * This method returns the String identifier for the UI class. + * Returns the string suffix used to identify the UI class, in this case + * <code>"ToolTipUI"</code>. * - * @return The String identifier for the UI class. + * @return <code>"ToolTipUI"</code>. */ public String getUIClassID() { @@ -159,33 +170,52 @@ public class JToolTip extends JComponent implements Accessible } /** - * This method returns a debugging String describing the JToolTip. + * Returns a string describing the attributes for the <code>JToolTip</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 debugging String describing the JToolTip. + * @return A string describing the attributes of the <code>JToolTip</code>. */ protected String paramString() { - return "JToolTip"; + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",tiptext="); + if (text != null); + sb.append(text); + return sb.toString(); } /** - * This method sets the JComponent that the JToolTip displays for. + * Sets the component that the tool tip is associated with and sends a + * {@link PropertyChangeEvent} (with the property name 'component') to all + * registered listeners. * - * @param c The JComponent that the JToolTip displays for. + * @param c the component (<code>null</code> permitted). + * + * @see #getComponent() */ public void setComponent(JComponent c) { + JComponent oldValue = component; component = c; + firePropertyChange("component", oldValue, c); } /** - * This method sets the text that the JToolTip displays. + * Sets the text to be displayed by the tool tip and sends a + * {@link PropertyChangeEvent} (with the property name 'tiptext') to all + * registered listeners. * - * @param tipText The text that the JToolTip displays. + * @param tipText the text (<code>null</code> permitted). + * + * @see #getTipText() */ public void setTipText(String tipText) { + String oldValue = text; text = tipText; + firePropertyChange("tiptext", oldValue, tipText); } /** @@ -194,7 +224,5 @@ public class JToolTip extends JComponent implements Accessible public void updateUI() { setUI((ToolTipUI) UIManager.getUI(this)); - revalidate(); - repaint(); } } diff --git a/libjava/classpath/javax/swing/JTree.java b/libjava/classpath/javax/swing/JTree.java index 7876eeb6aaa..e3b8b7e7ca5 100644 --- a/libjava/classpath/javax/swing/JTree.java +++ b/libjava/classpath/javax/swing/JTree.java @@ -1276,10 +1276,16 @@ public class JTree extends JComponent implements Scrollable, Accessible */ public void valueChanged(TreeSelectionEvent ev) { - TreeSelectionEvent rewritten = + TreeSelectionEvent rewritten = (TreeSelectionEvent) ev.cloneWithSource(JTree.this); fireValueChanged(rewritten); - JTree.this.repaint(); + + // Only repaint the changed nodes. + TreePath[] changed = ev.getPaths(); + for (int i = 0; i < changed.length; i++) + { + repaint(getPathBounds(changed[i])); + } } } @@ -1396,8 +1402,6 @@ public class JTree extends JComponent implements Scrollable, Accessible private TreePath anchorSelectionPath; - private TreePath leadSelectionPath; - /** * This contains the state of all nodes in the tree. Al/ entries map the * TreePath of a note to to its state. Valid states are EXPANDED and @@ -1443,6 +1447,33 @@ public class JTree extends JComponent implements Scrollable, Accessible new TreeSelectionRedirector(); /** + * Indicates if the rowHeight property has been set by a client + * program or by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientRowHeightSet = false; + + /** + * Indicates if the scrollsOnExpand property has been set by a client + * program or by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientScrollsOnExpandSet = false; + + /** + * Indicates if the showsRootHandles property has been set by a client + * program or by the UI. + * + * @see #setUIProperty(String, Object) + * @see LookAndFeel#installProperty(JComponent, String, Object) + */ + private boolean clientShowsRootHandlesSet = false; + + /** * Creates a new <code>JTree</code> object. */ public JTree() @@ -1477,8 +1508,8 @@ public class JTree extends JComponent implements Scrollable, Accessible */ public JTree(TreeModel model) { - updateUI(); setRootVisible(true); + // The setModel also calls the updateUI setModel(model); setSelectionModel(new EmptySelectionModel()); selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); @@ -1535,7 +1566,15 @@ public class JTree extends JComponent implements Scrollable, Accessible TreeUI ui = getUI(); return ui != null ? ui.getPathForRow(this, row) : null; } - + + /** + * Get the pathes that are displayes between the two given rows. + * + * @param index0 the starting row, inclusive + * @param index1 the ending row, inclusive + * + * @return the array of the tree pathes + */ protected TreePath[] getPathBetweenRows(int index0, int index1) { TreeUI ui = getUI(); @@ -1619,19 +1658,48 @@ public class JTree extends JComponent implements Scrollable, Accessible */ public Dimension getPreferredScrollableViewportSize() { - return new Dimension (getPreferredSize().width, getVisibleRowCount()*getRowHeight()); + return getPreferredSize(); } - - public int getScrollableUnitIncrement(Rectangle visibleRect, - int orientation, int direction) + + /** + * Return the preferred scrolling amount (in pixels) for the given scrolling + * direction and orientation. This method handles a partially exposed row by + * returning the distance required to completely expose the item. + * + * @param visibleRect the currently visible part of the component. + * @param orientation the scrolling orientation + * @param direction the scrolling direction (negative - up, positive -down). + * The values greater than one means that more mouse wheel or similar + * events were generated, and hence it is better to scroll the longer + * distance. + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ + public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, + int direction) { - return 1; + int delta; + + // Round so that the top would start from the row boundary + if (orientation == SwingConstants.VERTICAL) + { + // One pixel down, otherwise picks another row too high. + int row = getClosestRowForLocation(visibleRect.x, visibleRect.y + 1); + row = row + direction; + if (row < 0) + row = 0; + + Rectangle newTop = getRowBounds(row); + delta = newTop.y - visibleRect.y; + } + else + delta = direction * rowHeight == 0 ? 20 : rowHeight; + return delta; } public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { - return 1; + return getScrollableUnitIncrement(visibleRect, orientation, direction); } public boolean getScrollableTracksViewportHeight() @@ -1885,9 +1953,19 @@ public class JTree extends JComponent implements Scrollable, Accessible if (rootVisible == flag) return; + // If the root is currently selected, unselect it + if (rootVisible && !flag) + { + TreeSelectionModel model = getSelectionModel(); + // The root is always shown in the first row + TreePath rootPath = getPathForRow(0); + model.removeSelectionPath(rootPath); + } + boolean oldValue = rootVisible; rootVisible = flag; firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, flag); + } public boolean getShowsRootHandles() @@ -1897,6 +1975,8 @@ public class JTree extends JComponent implements Scrollable, Accessible public void setShowsRootHandles(boolean flag) { + clientShowsRootHandlesSet = true; + if (showsRootHandles == flag) return; @@ -1996,6 +2076,8 @@ public class JTree extends JComponent implements Scrollable, Accessible public void setRowHeight(int height) { + clientRowHeightSet = true; + if (rowHeight == height) return; @@ -2050,27 +2132,8 @@ public class JTree extends JComponent implements Scrollable, Accessible { if (path == null) return; - - Object[] oPath = path.getPath(); - TreePath temp = new TreePath(oPath[0]); - boolean stop = false; - int i = 1; - while (!stop) - { - while (isVisible(temp)) - if (i < oPath.length) - temp = temp.pathByAddingChild(oPath[i++]); - else - { - stop = true; - break; - } - makeVisible(temp); - } Rectangle rect = getPathBounds(path); scrollRectToVisible(rect); - revalidate(); - repaint(); } public void scrollRowToVisible(int row) @@ -2085,6 +2148,7 @@ public class JTree extends JComponent implements Scrollable, Accessible public void setScrollsOnExpand(boolean scroll) { + clientScrollsOnExpandSet = true; if (scrollsOnExpand == scroll) return; @@ -2164,7 +2228,15 @@ public class JTree extends JComponent implements Scrollable, Accessible addSelectionPaths(paths); } - + + /** + * Select all rows between the two given indexes, inclusive. The method + * will not select the inner leaves and braches of the currently collapsed + * nodes in this interval. + * + * @param index0 the starting row, inclusive + * @param index1 the ending row, inclusive + */ public void addSelectionInterval(int index0, int index1) { TreePath[] paths = getPathBetweenRows(index0, index1); @@ -2220,7 +2292,10 @@ public class JTree extends JComponent implements Scrollable, Accessible public TreePath getLeadSelectionPath() { - return leadSelectionPath; + if (selectionModel == null) + return null; + else + return selectionModel.getLeadSelectionPath(); } /** @@ -2228,12 +2303,24 @@ public class JTree extends JComponent implements Scrollable, Accessible */ public void setLeadSelectionPath(TreePath path) { - if (leadSelectionPath == path) - return; - - TreePath oldValue = leadSelectionPath; - leadSelectionPath = path; - firePropertyChange(LEAD_SELECTION_PATH_PROPERTY, oldValue, path); + if (selectionModel != null) + { + TreePath oldValue = selectionModel.getLeadSelectionPath(); + if (path.equals(oldValue)) + return; + + // Repaint the previous and current rows with the lead selection path. + if (path != null) + { + repaint(getPathBounds(path)); + selectionModel.addSelectionPath(path); + } + + if (oldValue!=null) + repaint(getPathBounds(oldValue)); + + firePropertyChange(LEAD_SELECTION_PATH_PROPERTY, oldValue, path); + } } /** @@ -2369,7 +2456,8 @@ public class JTree extends JComponent implements Scrollable, Accessible public void expandPath(TreePath path) { // Don't expand if path is null - if (path == null) + // or is already expanded. + if (path == null || isExpanded(path)) return; try @@ -2906,13 +2994,69 @@ public class JTree extends JComponent implements Scrollable, Accessible } /** - * Sent when the tree has changed enough that we need to resize the bounds, - * but not enough that we need to remove the expanded node set (e.g nodes - * were expanded or collapsed, or nodes were inserted into the tree). You - * should never have to invoke this, the UI will invoke this as it needs to. + * <p> + * Sent when the tree has changed enough that we need to resize the bounds, + * but not enough that we need to remove the expanded node set (e.g nodes were + * expanded or collapsed, or nodes were inserted into the tree). You should + * never have to invoke this, the UI will invoke this as it needs to. + * </p> + * <p> + * If the tree uses {@link DefaultTreeModel}, you must call + * {@link DefaultTreeModel#reload(TreeNode)} or + * {@link DefaultTreeModel#reload()} after adding or removing nodes. Following + * the official Java 1.5 API standard, just calling treeDidChange, repaint() + * or revalidate() does <i>not</i> update the tree appearance properly. + * + * @see DefaultTreeModel#reload() */ public void treeDidChange() { repaint(); } + + /** + * Helper method for + * {@link LookAndFeel#installProperty(JComponent, String, Object)}. + * + * @param propertyName the name of the property + * @param value the value of the property + * + * @throws IllegalArgumentException if the specified property cannot be set + * by this method + * @throws ClassCastException if the property value does not match the + * property type + * @throws NullPointerException if <code>c</code> or + * <code>propertyValue</code> is <code>null</code> + */ + void setUIProperty(String propertyName, Object value) + { + if (propertyName.equals("rowHeight")) + { + if (! clientRowHeightSet) + { + setRowHeight(((Integer) value).intValue()); + clientRowHeightSet = false; + } + } + else if (propertyName.equals("scrollsOnExpand")) + { + if (! clientScrollsOnExpandSet) + { + setScrollsOnExpand(((Boolean) value).booleanValue()); + clientScrollsOnExpandSet = false; + } + } + else if (propertyName.equals("showsRootHandles")) + { + if (! clientShowsRootHandlesSet) + { + setShowsRootHandles(((Boolean) value).booleanValue()); + clientShowsRootHandlesSet = false; + } + } + else + { + super.setUIProperty(propertyName, value); + } + } } diff --git a/libjava/classpath/javax/swing/KeyboardManager.java b/libjava/classpath/javax/swing/KeyboardManager.java index aa9524cfe57..4f778f7330f 100644 --- a/libjava/classpath/javax/swing/KeyboardManager.java +++ b/libjava/classpath/javax/swing/KeyboardManager.java @@ -195,7 +195,7 @@ class KeyboardManager if (map == null) return; JComponent comp = map.getComponent(); - KeyStroke[] keys = map.keys(); + KeyStroke[] keys = map.allKeys(); if (keys == null) return; // Find the top-level container associated with this ComponentInputMap diff --git a/libjava/classpath/javax/swing/LookAndFeel.java b/libjava/classpath/javax/swing/LookAndFeel.java index 358a811b362..7f59f1b5f93 100644 --- a/libjava/classpath/javax/swing/LookAndFeel.java +++ b/libjava/classpath/javax/swing/LookAndFeel.java @@ -1,5 +1,5 @@ /* LookAndFeel.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. @@ -49,15 +49,25 @@ import javax.swing.plaf.ComponentInputMapUIResource; import javax.swing.plaf.IconUIResource; import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.UIResource; +import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.text.JTextComponent; +/** + * A <i>look-and-feel</i> controls most aspects of the appearance and + * operation of user interface components in <code>javax.swing</code>. A + * cross-platform look-and-feel (the {@link MetalLookAndFeel}) is provided. + * + * @see UIManager#getInstalledLookAndFeels() + * @see UIManager#setLookAndFeel(LookAndFeel) + */ public abstract class LookAndFeel { /** - * This method is called once by UIManager.setLookAndFeel to create - * the look and feel specific defaults table. + * Creates and returns a look-and-feel specific defaults table. This method + * is called once by {@link UIManager#setLookAndFeel(LookAndFeel)} and + * shouldn't be called again (as it creates a large table of defaults). * - * @return the UI defaults + * @return The UI defaults. */ public UIDefaults getDefaults() { @@ -71,10 +81,21 @@ public abstract class LookAndFeel */ public abstract String getDescription(); + /** + * Returns the value of <code>Toolkit.getDefaultToolkit() + * .getDesktopProperty(systemPropertyName)</code>, or + * <code>fallbackValue</code> if no such property is defined. + * + * @param systemPropertyName the system property name. + * @param fallbackValue the fallback value. + * + * @return The property value or <code>fallbackValue</code>. + */ public static Object getDesktopPropertyValue(String systemPropertyName, Object fallbackValue) { - Object value = Toolkit.getDefaultToolkit().getDesktopProperty(systemPropertyName); + Object value = Toolkit.getDefaultToolkit().getDesktopProperty( + systemPropertyName); return value != null ? value : fallbackValue; } @@ -93,11 +114,12 @@ public abstract class LookAndFeel public abstract String getName(); /** - * Returns true when the Look and Feel supports window decorations, - * false others. This method returns always false and needs to be overwritten - * when the derived Look and Feel supports this. + * Returns <code>true</code> when the look-and-feel supports window + * decorations, and <code>false</code> otherwise. This default implementation + * always returns <code>false</code> and needs to be overridden when the + * derived look-and-feel supports this. * - * @return false + * @return <code>false</code>. * * @since 1.4 */ @@ -107,8 +129,11 @@ public abstract class LookAndFeel } /** - * UIManager.setLookAndFeel calls this method before the first call - * (and typically the only call) to getDefaults(). + * Initializes the look-and-feel. The + * {@link UIManager#setLookAndFeel(LookAndFeel)} method calls this method + * before the first call (and typically the only call) to + * {@link #getDefaults()}. This default implementation does nothing, but + * subclasses can override this behaviour. */ public void initialize() { @@ -117,9 +142,13 @@ public abstract class LookAndFeel } /** - * Convenience method for installing a component's default Border object - * on the specified component if either the border is currently null - * or already an instance of UIResource. + * Convenience method for installing a component's default {@link Border} + * object on the specified component if either the border is currently + * <code>null</code> or already an instance of {@link UIResource}. + * + * @param c the component (<code>null</code> not permitted). + * @param defaultBorderName the border name (for lookup in the UIDefaults + * table). */ public static void installBorder(JComponent c, String defaultBorderName) { @@ -131,6 +160,12 @@ public abstract class LookAndFeel /** * Convenience method for initializing a component's foreground and * background color properties with values from the current defaults table. + * + * @param c the component (<code>null</code> not permitted). + * @param defaultBgName the key for the background color in the UIDefaults + * table. + * @param defaultFgName the key for the foreground color in the UIDefaults + * table. */ public static void installColors(JComponent c, String defaultBgName, String defaultFgName) @@ -147,8 +182,15 @@ public abstract class LookAndFeel } /** - * Convenience method for initializing a components foreground background - * and font properties with values from the current defaults table. + * Convenience method for initializing a component's foreground, background + * and font properties with values from the current defaults table. + * + * @param component the component (<code>null</code> not permitted). + * @param defaultBgName the key for the background color in the UIDefaults + * table. + * @param defaultFgName the key for the foreground color in the UIDefaults + * table. + * @param defaultFontName the key for the font in the UIDefaults table. */ public static void installColorsAndFont(JComponent component, String defaultBgName, @@ -164,8 +206,10 @@ public abstract class LookAndFeel } /** - * Returns <code>true</code> if the look and feel is the "native" look and - * feel for the current platform, and <code>false</code> otherwise. + * Returns <code>true</code> if the look-and-feel is the "native" + * look-and-feel for the current platform, and <code>false</code> otherwise. + * A native look-and-feel emulates the appearance and behaviour of the + * default windowing system on the host operating system. * * @return A flag indicating whether or not this is the native look and feel * for the current platform. @@ -173,13 +217,13 @@ public abstract class LookAndFeel public abstract boolean isNativeLookAndFeel(); /** - * Returns <code>true</code> if the look and feel is supported on the + * Returns <code>true</code> if the look-and-feel is supported on the * current operating system, and <code>false</code> otherwise. This - * mechanism is provided so that it is possible to prevent a look and feel + * mechanism is provided so that it is possible to prevent a look-and-feel * from being used on some operating systems (usually for legal, not * technical, reasons). * - * @return A flag indicating whether or not the look and feel is supported + * @return A flag indicating whether or not the look-and-feel is supported * on the current platform. */ public abstract boolean isSupportedLookAndFeel(); @@ -219,6 +263,8 @@ public abstract class LookAndFeel * * @param c the JComponent associated with the ComponentInputMap * @param keys the Object array describing the InputMap as above + * + * @return A new input map. */ public static ComponentInputMap makeComponentInputMap(JComponent c, Object[] keys) @@ -230,7 +276,13 @@ public abstract class LookAndFeel /** * Utility method that creates a UIDefaults.LazyValue that creates an - * ImageIcon UIResource for the specified gifFile filename. + * ImageIcon UIResource for the specified gifFile filename. + * + * @param baseClass the base class for accessing the icon resource. + * @param gifFile the file name. + * + * @return A {@link UIDefaults.LazyValue} that serves up an + * {@link IconUIResource}. */ public static Object makeIcon(Class baseClass, String gifFile) { @@ -252,6 +304,8 @@ public abstract class LookAndFeel * ActionMap. * * @param keys the Object array describing the InputMap as above + * + * @return A new input map. */ public static InputMap makeInputMap(Object[] keys) { @@ -269,7 +323,8 @@ public abstract class LookAndFeel * @param keyBindingList the array of KeyStroke-Action pairs * @return a JTextComponent.KeyBinding array */ - public static JTextComponent.KeyBinding[] makeKeyBindings(Object[] keyBindingList) + public static JTextComponent.KeyBinding[] makeKeyBindings( + Object[] keyBindingList) { JTextComponent.KeyBinding[] retBindings = new JTextComponent.KeyBinding[keyBindingList.length / 2]; @@ -280,15 +335,16 @@ public abstract class LookAndFeel stroke = (KeyStroke)keyBindingList[i]; else stroke = KeyStroke.getKeyStroke((String)keyBindingList[i]); - retBindings[i/2] = new JTextComponent.KeyBinding(stroke, (String)keyBindingList[i+1]); + retBindings[i/2] = new JTextComponent.KeyBinding(stroke, + (String) keyBindingList[i+1]); } return retBindings; } /** - * Invoked when the user attempts an invalid operation. The default implement - * just beeps. Subclasses that wish to change this need to override this - * method. + * Invoked when the user attempts an invalid operation. The default + * implementation just beeps. Subclasses that wish to change this need to + * override this method. * * @param component the component the error occured in */ @@ -320,10 +376,58 @@ public abstract class LookAndFeel /** * Convenience method for un-installing a component's default border on the * specified component if the border is currently an instance of UIResource. + * + * @param c the component (<code>null</code> not permitted). */ public static void uninstallBorder(JComponent c) { if (c.getBorder() instanceof UIResource) c.setBorder(null); } + + /** + * This methods installs a UI property if it hasn't already been set by an + * application. This method is used by UI delegates that install a default + * value for a property with a primitive type but do not want to override + * a value that has been set by an application. + * + * The supported properties depend on the actual type of the component and + * are listed in the table below. The supported properties are of course + * inherited to subclasses. + * + * <table> + * <tr><th>Type</th><th>Supported properties</th></tr> + * <tr><td><code>JComponent</code></td> + * <td><code>opaque, autoscrolls</code></td></tr> + * <tr><td><code>AbstractButton</code></td> + * <td><code>borderPainted, rolloverEnabled, iconTextGap, + * contentAreaFilled</code></td></tr> + * <tr><td><code>JDesktopPane</code></td> + * <td><code>dragMode</code></td></tr> + * <tr><td><code>JSplitPane</code></td> + * <td><code>dividerSize, oneTouchExpandable</code></td></tr> + * <tr><td><code>JTable</code></td> + * <td><code>rowHeight</code></td></tr> + * <tr><td><code>JTree</code></td> + * <td><code>rowHeight, scrollsOnExpand, showsRootHandles</code></td></tr> + * </table> + * + * @param c the component to install the property to + * @param propertyName the name of the property + * @param value the value of the property + * + * @throws IllegalArgumentException if the specified property cannot be set + * by this method + * @throws ClassCastException if the property value does not match the + * property type + * @throws NullPointerException if <code>c</code> or + * <code>propertyValue</code> is <code>null</code> + * + * @since 1.5 + */ + public static void installProperty(JComponent c, String propertyName, + Object value) + { + c.setUIProperty(propertyName, value); + } } diff --git a/libjava/classpath/javax/swing/MenuSelectionManager.java b/libjava/classpath/javax/swing/MenuSelectionManager.java index 4e52751065a..df7b42037db 100644 --- a/libjava/classpath/javax/swing/MenuSelectionManager.java +++ b/libjava/classpath/javax/swing/MenuSelectionManager.java @@ -216,28 +216,90 @@ public class MenuSelectionManager public boolean isComponentPartOfCurrentMenu(Component c) { MenuElement[] subElements; - for (int i = 0; i < selectedPath.size(); i++) + boolean ret = false; + for (int i = 0; i < selectedPath.size(); i++) { - subElements = ((MenuElement) selectedPath.get(i)).getSubElements(); - for (int j = 0; j < subElements.length; j++) - { - MenuElement me = subElements[j]; - if (me != null && (me.getComponent()).equals(c)) - return true; - } + // Check first element. + MenuElement first = (MenuElement) selectedPath.get(i); + if (SwingUtilities.isDescendingFrom(c, first.getComponent())) + { + ret = true; + break; + } + else + { + // Check sub elements. + subElements = first.getSubElements(); + for (int j = 0; j < subElements.length; j++) + { + MenuElement me = subElements[j]; + if (me != null + && (SwingUtilities.isDescendingFrom(c, me.getComponent()))) + { + ret = true; + break; + } + } + } } - return false; + return ret; } /** - * DOCUMENT ME! + * Processes key events on behalf of the MenuElements. MenuElement + * instances should always forward their key events to this method and + * get their {@link MenuElement#processKeyEvent(KeyEvent, MenuElement[], + * MenuSelectionManager)} eventually called back. * - * @param e DOCUMENT ME! + * @param e the key event */ public void processKeyEvent(KeyEvent e) { - throw new UnsupportedOperationException("not implemented"); + MenuElement[] selection = (MenuElement[]) + selectedPath.toArray(new MenuElement[selectedPath.size()]); + MenuElement[] path; + for (int index = selection.length - 1; index >= 0; index--) + { + MenuElement el = selection[index]; + // This method's main purpose is to forward key events to the + // relevant menu items, so that they can act in response to their + // mnemonics beeing typed. So we also need to forward the key event + // to all the subelements of the currently selected menu elements + // in the path. + MenuElement[] subEls = el.getSubElements(); + path = null; + for (int subIndex = 0; subIndex < subEls.length; subIndex++) + { + MenuElement sub = subEls[subIndex]; + // Skip elements that are not showing or not enabled. + if (sub == null || ! sub.getComponent().isShowing() + || ! sub.getComponent().isEnabled()) + { + continue; + } + + if (path == null) + { + path = new MenuElement[index + 2]; + System.arraycopy(selection, 0, path, 0, index + 1); + } + path[index + 1] = sub; + sub.processKeyEvent(e, path, this); + if (e.isConsumed()) + break; + } + if (e.isConsumed()) + break; + } + + // Dispatch to first element in selection if it hasn't been consumed. + if (! e.isConsumed()) + { + path = new MenuElement[1]; + path[0] = selection[0]; + path[0].processKeyEvent(e, path, this); + } } /** @@ -303,53 +365,35 @@ public class MenuSelectionManager return; } - int i; - int minSize = path.length; // size of the smaller path. + int minSize = path.length; // size of the smaller path. + int currentSize = selectedPath.size(); + int firstDiff = 0; - if (path.length > selectedPath.size()) + // Search first item that is different in the current and new path. + for (int i = 0; i < minSize; i++) { - minSize = selectedPath.size(); - - // if new selected path contains more elements then current - // selection then first add all elements at - // the indexes > selectedPath.size - for (i = selectedPath.size(); i < path.length; i++) - { - selectedPath.add(path[i]); - path[i].menuSelectionChanged(true); - } + if (i < currentSize && (MenuElement) selectedPath.get(i) == path[i]) + firstDiff++; + else + break; } - else if (path.length < selectedPath.size()) + // Remove items from selection and send notification. + for (int i = currentSize - 1; i >= firstDiff; i--) { - // if new selected path contains less elements then current - // selection then first remove all elements from the selection - // at the indexes > path.length - for (i = selectedPath.size() - 1; i >= path.length; i--) - { - ((MenuElement) selectedPath.get(i)).menuSelectionChanged(false); - selectedPath.remove(i); - } - - minSize = path.length; + MenuElement el = (MenuElement) selectedPath.get(i); + selectedPath.remove(i); + el.menuSelectionChanged(false); } - // Now compare elements in new and current selection path at the - // same location and adjust selection until - // same menu elements will be encountered at the - // same index in both current and new selection path. - MenuElement oldSelectedItem; - - for (i = minSize - 1; i >= 0; i--) + // Add new items to selection and send notification. + for (int i = firstDiff; i < minSize; i++) { - oldSelectedItem = (MenuElement) selectedPath.get(i); - - if (path[i].equals(oldSelectedItem)) - break; - - oldSelectedItem.menuSelectionChanged(false); - path[i].menuSelectionChanged(true); - selectedPath.setElementAt(path[i], i); + if (path[i] != null) + { + selectedPath.add(path[i]); + path[i].menuSelectionChanged(true); + } } fireStateChanged(); diff --git a/libjava/classpath/javax/swing/OverlayLayout.java b/libjava/classpath/javax/swing/OverlayLayout.java index 56b8c8bb67a..a2cccb9ce89 100644 --- a/libjava/classpath/javax/swing/OverlayLayout.java +++ b/libjava/classpath/javax/swing/OverlayLayout.java @@ -1,5 +1,5 @@ /* OverlayLayout.java -- A layout manager - 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. @@ -198,7 +198,7 @@ public class OverlayLayout implements LayoutManager2, Serializable * * @param target not used here * - * @returns the preferred size of the container that is laid out + * @return the preferred size of the container that is laid out */ public Dimension preferredLayoutSize(Container target) { @@ -216,7 +216,7 @@ public class OverlayLayout implements LayoutManager2, Serializable * * @param target not used here * - * @returns the minimum size of the container that is laid out + * @return the minimum size of the container that is laid out */ public Dimension minimumLayoutSize(Container target) { @@ -234,7 +234,7 @@ public class OverlayLayout implements LayoutManager2, Serializable * * @param target not used here * - * @returns the maximum size of the container that is laid out + * @return the maximum size of the container that is laid out */ public Dimension maximumLayoutSize(Container target) { @@ -252,7 +252,7 @@ public class OverlayLayout implements LayoutManager2, Serializable * * @param target not used here * - * @returns the X alignment of the container that is laid out + * @return the X alignment of the container that is laid out */ public float getLayoutAlignmentX(Container target) { @@ -270,7 +270,7 @@ public class OverlayLayout implements LayoutManager2, Serializable * * @param target not used here * - * @returns the X alignment of the container that is laid out + * @return the X alignment of the container that is laid out */ public float getLayoutAlignmentY(Container target) { diff --git a/libjava/classpath/javax/swing/Popup.java b/libjava/classpath/javax/swing/Popup.java index c3de69e05ab..308cd662d8d 100644 --- a/libjava/classpath/javax/swing/Popup.java +++ b/libjava/classpath/javax/swing/Popup.java @@ -285,6 +285,7 @@ public class Popup Point layeredPaneLoc = layeredPane.getLocationOnScreen(); panel.setLocation(x - layeredPaneLoc.x, y - layeredPaneLoc.y); layeredPane.add(panel, JLayeredPane.POPUP_LAYER); + panel.repaint(); } /** diff --git a/libjava/classpath/javax/swing/ProgressMonitor.java b/libjava/classpath/javax/swing/ProgressMonitor.java index 60f1c7145c0..73e36b9ca21 100644 --- a/libjava/classpath/javax/swing/ProgressMonitor.java +++ b/libjava/classpath/javax/swing/ProgressMonitor.java @@ -1,5 +1,5 @@ /* ProgressMonitor.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. @@ -100,10 +100,16 @@ public class ProgressMonitor boolean canceled; /** - * Constructor ProgressMonitor - * @param component The parent component of the progress dialog or <code>null</code>. - * @param message A constant message object which works in the way it does in <code>JOptionPane</code>. - * @param note A string message which can be changed while the operation goes on. + * Creates a new <code>ProgressMonitor</code> instance. This is used to + * monitor a task and pops up a dialog if the task is taking a long time to + * run. + * + * @param component The parent component of the progress dialog or + * <code>null</code>. + * @param message A constant message object which works in the way it does + * in {@link JOptionPane}. + * @param note A string message which can be changed while the operation goes + * on. * @param minimum The minimum value for the operation (start value). * @param maximum The maximum value for the operation (end value). */ @@ -178,9 +184,10 @@ public class ProgressMonitor } - /** Returns the minimum or start value of the operation. + /** + * Returns the minimum or start value of the operation. * - * @returns Minimum or start value of the operation. + * @return Minimum or start value of the operation. */ public int getMinimum() { @@ -207,7 +214,7 @@ public class ProgressMonitor /** * Return the maximum or end value of your operation. * - * @returns Maximum or end value. + * @return Maximum or end value. */ public int getMaximum() { @@ -228,7 +235,7 @@ public class ProgressMonitor /** * Returns whether the user canceled the operation. * - * @returns Whether the operation was canceled. + * @return Whether the operation was canceled. */ public boolean isCanceled() { @@ -243,7 +250,7 @@ public class ProgressMonitor * until the ProgressMonitor should decide whether * a progress dialog is to be shown or not. * - * @returns The duration in milliseconds. + * @return The duration in milliseconds. */ public int getMillisToDecideToPopup() { @@ -266,8 +273,12 @@ public class ProgressMonitor } /** - * getMillisToPopup - * @returns int + * Returns the number of milliseconds to wait before displaying the progress + * dialog. The default value is 2000. + * + * @return The number of milliseconds. + * + * @see #setMillisToPopup(int) */ public int getMillisToPopup() { @@ -275,8 +286,12 @@ public class ProgressMonitor } /** - * setMillisToPopup - * @param time TODO + * Sets the number of milliseconds to wait before displaying the progress + * dialog. + * + * @param time the number of milliseconds. + * + * @see #getMillisToPopup() */ public void setMillisToPopup(int time) { @@ -286,7 +301,7 @@ public class ProgressMonitor /** * Returns a message which is shown in the progress dialog. * - * @returns The changeable message visible in the progress dialog. + * @return The changeable message visible in the progress dialog. */ public String getNote() { @@ -313,7 +328,8 @@ public class ProgressMonitor } } - /** Internal method that creates the progress dialog. + /** + * Internal method that creates the progress dialog. */ void createDialog() { @@ -382,7 +398,11 @@ public class ProgressMonitor if (( now - timestamp ) > millisToDecideToPopup ) { first = false; - long expected = ( now - timestamp ) * ( max - min ) / ( progress - min ); + + + long expected = ( progress - min == 0 ) ? + ( now - timestamp ) * ( max - min ) : + ( now - timestamp ) * ( max - min ) / ( progress - min ); if ( expected > millisToPopup ) { diff --git a/libjava/classpath/javax/swing/ProgressMonitorInputStream.java b/libjava/classpath/javax/swing/ProgressMonitorInputStream.java index 02ac597b3a4..fec5c2ee03b 100644 --- a/libjava/classpath/javax/swing/ProgressMonitorInputStream.java +++ b/libjava/classpath/javax/swing/ProgressMonitorInputStream.java @@ -1,5 +1,5 @@ /* ProgressMonitorInputStream.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. @@ -46,7 +46,8 @@ import java.io.InterruptedIOException; import java.io.IOException; /** - * ProgressMonitorInputStream + * An input stream with a {@link ProgressMonitor}. + * * @author Andrew Selkirk * @author Robert Schuster (robertschuster@fsfe.org) * @status updated to 1.2 @@ -56,7 +57,7 @@ public class ProgressMonitorInputStream extends FilterInputStream { /** - * monitor + * The monitor watching the progress of the input stream. */ private ProgressMonitor monitor; @@ -66,10 +67,11 @@ public class ProgressMonitorInputStream extends FilterInputStream private int read; /** - * Constructor ProgressMonitorInputStream - * @param component TODO - * @param message TODO - * @param stream TODO + * Creates a new <code>ProgressMonitorInputStream</code>. + * + * @param component the parent component for the progress monitor dialog. + * @param message the task description. + * @param stream the underlying input stream. */ public ProgressMonitorInputStream(Component component, Object message, InputStream stream) @@ -87,12 +89,12 @@ public class ProgressMonitorInputStream extends FilterInputStream // Behave like the JDK here. } - monitor = new ProgressMonitor( - component, message, null, 0, max ); + monitor = new ProgressMonitor(component, message, null, 0, max); } /** - * reset + * Resets the input stream to the point where {@link #mark(int)} was called. + * * @exception IOException TODO */ public void reset() throws IOException @@ -106,9 +108,13 @@ public class ProgressMonitorInputStream extends FilterInputStream } /** - * read - * @exception IOException TODO - * @returns int + * Reads an unsigned byte from the input stream and returns it as an + * <code>int</code> in the range of 0-255. Returns -1 if the end of the + * stream has been reached. The progress monitor is updated. + * + * @return int + * + * @exception IOException if there is a problem reading the stream. */ public int read() throws IOException { @@ -122,10 +128,16 @@ public class ProgressMonitorInputStream extends FilterInputStream } /** - * read - * @param data TODO - * @exception IOException TODO - * @returns int + * Reads bytes from the input stream and stores them in the supplied array, + * and updates the progress monitor (or closes it if the end of the stream + * is reached). + * + * @param data the data array for returning bytes read from the stream. + * + * @return The number of bytes read, or -1 if there are no more bytes in the + * stream. + * + * @throws IOException if there is a problem reading bytes from the stream. */ public int read(byte[] data) throws IOException { @@ -147,12 +159,18 @@ public class ProgressMonitorInputStream extends FilterInputStream } /** - * read - * @param data TODO - * @param offset TODO - * @param length TODO - * @exception IOException TODO - * @returns int + * Reads up to <code>length</code> bytes from the input stream and stores + * them in the supplied array at the given index, and updates the progress + * monitor (or closes it if the end of the stream is reached). + * + * @param data the data array for returning bytes read from the stream. + * @param offset the offset into the array where the bytes should be written. + * @param length the maximum number of bytes to read from the stream. + * + * @return The number of bytes read, or -1 if there are no more bytes in the + * stream. + * + * @throws IOException if there is a problem reading bytes from the stream. */ public int read(byte[] data, int offset, int length) throws IOException { @@ -174,10 +192,14 @@ public class ProgressMonitorInputStream extends FilterInputStream } /** - * skip - * @param length TODO - * @exception IOException TODO - * @returns long + * Skips the specified number of bytes and updates the + * {@link ProgressMonitor}. + * + * @param length the number of bytes to skip. + * + * @return The actual number of bytes skipped. + * + * @throws IOException if there is a problem skipping bytes in the stream. */ public long skip(long length) throws IOException { @@ -196,8 +218,9 @@ public class ProgressMonitorInputStream extends FilterInputStream } /** - * close - * @exception IOException TODO + * Closes the input stream and the associated {@link ProgressMonitor}. + * + * @throws IOException if there is a problem closing the input stream. */ public void close() throws IOException { @@ -206,8 +229,9 @@ public class ProgressMonitorInputStream extends FilterInputStream } /** - * getProgressMonitor - * @returns ProgressMonitor + * Returns the {@link ProgressMonitor} used by this input stream. + * + * @return The progress monitor. */ public ProgressMonitor getProgressMonitor() { diff --git a/libjava/classpath/javax/swing/RepaintManager.java b/libjava/classpath/javax/swing/RepaintManager.java index ed0500992c5..345c348db52 100644 --- a/libjava/classpath/javax/swing/RepaintManager.java +++ b/libjava/classpath/javax/swing/RepaintManager.java @@ -38,6 +38,7 @@ exception statement from your version. */ package javax.swing; +import java.applet.Applet; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; @@ -161,9 +162,9 @@ public class RepaintManager if (o1 instanceof JComponent && o2 instanceof JComponent) { JComponent c1 = (JComponent) o1; - Rectangle d1 = (Rectangle) dirtyComponents.get(c1); + Rectangle d1 = (Rectangle) dirtyComponentsWork.get(c1); JComponent c2 = (JComponent) o2; - Rectangle d2 = (Rectangle) dirtyComponents.get(c2); + 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 " @@ -189,6 +190,12 @@ public class RepaintManager 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; @@ -263,6 +270,7 @@ public class RepaintManager public RepaintManager() { dirtyComponents = new HashMap(); + dirtyComponentsWork = new HashMap(); invalidComponents = new ArrayList(); repaintWorker = new RepaintWorker(); doubleBufferMaximumSize = new Dimension(2000,2000); @@ -414,7 +422,6 @@ public class RepaintManager { if (w <= 0 || h <= 0 || !component.isShowing()) return; - component.computeVisibleRect(rectCache); SwingUtilities.computeIntersection(x, y, w, h, rectCache); @@ -556,31 +563,36 @@ public class RepaintManager if (dirtyComponents.size() == 0) return; + // Swap dirtyRegions with dirtyRegionsWork to avoid locking. synchronized (dirtyComponents) { - // 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. - ArrayList repaintOrder = new ArrayList(dirtyComponents.size()); - repaintOrder.addAll(dirtyComponents.keySet()); - if (comparator == null) - comparator = new ComponentComparator(); - Collections.sort(repaintOrder, comparator); - repaintUnderway = true; - for (Iterator i = repaintOrder.iterator(); i.hasNext();) - { - JComponent comp = (JComponent) i.next(); - // If a component is marked completely clean in the meantime, then skip - // it. - Rectangle damaged = (Rectangle) dirtyComponents.get(comp); - if (damaged == null || damaged.isEmpty()) - continue; - comp.paintImmediately(damaged); - dirtyComponents.remove(comp); - } - repaintUnderway = false; - commitRemainingBuffers(); + HashMap swap = dirtyComponents; + dirtyComponents = dirtyComponentsWork; + 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()); + + if (comparator == null) + comparator = new ComponentComparator(); + Collections.sort(repaintOrder, comparator); + repaintUnderway = true; + for (Iterator i = repaintOrder.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); + } + repaintUnderway = false; + commitRemainingBuffers(); } /** @@ -597,7 +609,7 @@ public class RepaintManager public Image getOffscreenBuffer(Component component, int proposedWidth, int proposedHeight) { - Component root = SwingUtilities.getRoot(component); + Component root = getRoot(component); Image buffer = (Image) offscreenBuffers.get(root); if (buffer == null || buffer.getWidth(null) < proposedWidth @@ -612,7 +624,33 @@ public class RepaintManager } return buffer; } - + + /** + * Gets the root of the component given. If a parent of the + * component is an instance of Applet, then the applet is + * returned. The applet is considered the root for painting. + * Otherwise, the root Window is returned if it exists. + * + * @param comp - The component to get the root for. + * @return the parent root. An applet if it is a parent, + * or the root window. If neither exist, null is returned. + */ + private Component getRoot(Component comp) + { + Applet app = null; + + while (comp != null) + { + if (app == null && comp instanceof Window) + return comp; + else if (comp instanceof Applet) + app = (Applet) comp; + comp = comp.getParent(); + } + + return app; + } + /** * Blits the back buffer of the specified root component to the screen. If * the RepaintManager is currently working on a paint request, the commit @@ -663,8 +701,7 @@ public class RepaintManager dy1 = Math.min(bufferHeight, dy1); dx2 = Math.min(bufferWidth, dx2); dy2 = Math.min(bufferHeight, dy2); - g.drawImage(buffer, dx1, dy1, dx2, dy2, - dx1, dy1, dx2, dy2, root); + g.drawImage(buffer, 0, 0, root); g.dispose(); } // Otherwise queue this request up, until all the RepaintManager work diff --git a/libjava/classpath/javax/swing/ScrollPaneLayout.java b/libjava/classpath/javax/swing/ScrollPaneLayout.java index b00b5c4e7ae..31846fa557d 100644 --- a/libjava/classpath/javax/swing/ScrollPaneLayout.java +++ b/libjava/classpath/javax/swing/ScrollPaneLayout.java @@ -328,7 +328,13 @@ public class ScrollPaneLayout // parent is no JScrollPane, so do we. JScrollPane sc = (JScrollPane) parent; JViewport viewport = sc.getViewport(); - Dimension viewSize = viewport.getViewSize(); + Component view = viewport.getView(); + + // If there is no view in the viewport, there is no work to be done. + if (view == null) + return; + + Dimension viewSize = viewport.getView().getPreferredSize(); int x1 = 0, x2 = 0, x3 = 0, x4 = 0; int y1 = 0, y2 = 0, y3 = 0, y4 = 0; @@ -350,27 +356,49 @@ public class ScrollPaneLayout int vsbPolicy = sc.getVerticalScrollBarPolicy(); int hsbPolicy = sc.getHorizontalScrollBarPolicy(); + + int vsWidth = 0; + int hsHeight = 0; boolean showVsb = (vsb != null) && ((vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) || (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED && viewSize.height > (y4 - y2))); + + if (showVsb) + vsWidth = vsb.getPreferredSize().width; + + // The horizontal scroll bar may become necessary if the vertical scroll + // bar appears, reducing the space, left for the component. + boolean showHsb = (hsb != null) && ((hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) || (hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED - && viewSize.width > (x4 - x2))); - + && viewSize.width > (x4 - x2 - vsWidth))); + + if (showHsb) + hsHeight = hsb.getPreferredSize().height; + + // If the horizontal scroll bar appears, and the vertical scroll bar + // was not necessary assuming that there is no horizontal scroll bar, + // the vertical scroll bar may become necessary because the horizontal + // scroll bar reduces the vertical space for the component. if (!showVsb) - x3 = x4; - else - x3 = x4 - vsb.getPreferredSize().width; + { + showVsb = + (vsb != null) + && ((vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) + || (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED + && viewSize.height > (y4 - y2))); + + if (showVsb) + vsWidth = vsb.getPreferredSize().width; + } - if (!showHsb) - y3 = y4; - else - y3 = y4 - hsb.getPreferredSize().height; + x3 = x4 - vsWidth; + y3 = y4 - hsHeight; // now set the layout if (viewport != null) diff --git a/libjava/classpath/javax/swing/Scrollable.java b/libjava/classpath/javax/swing/Scrollable.java index 9dce665d626..396d530ede4 100644 --- a/libjava/classpath/javax/swing/Scrollable.java +++ b/libjava/classpath/javax/swing/Scrollable.java @@ -50,14 +50,57 @@ public interface Scrollable { Dimension getPreferredScrollableViewportSize(); + /** + * Return the preferred scrolling amount (in pixels) for the given + * scrolling direction and orientation when scrolling in small amounts + * like table lines. + * + * @param visibleRect the currently visible part of the component. + * @param orientation the scrolling orientation + * @param direction the scrolling direction (negative - up, positive -down). + * The values greater than one means that more mouse wheel or similar + * events were generated, and hence it is better to scroll the longer + * distance. + * + * @return the preferred scrolling distance, negative if up or left. + */ int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction); + /** + * Return the preferred scrolling amount (in pixels) for the given + * scrolling direction and orientation when scrolling in large amounts + * (pages). + * + * @param visibleRect the currently visible part of the component. + * @param orientation the scrolling orientation + * @param direction the scrolling direction (negative - up, positive -down). + * The values greater than one means that more mouse wheel or similar + * events were generated, and hence it is better to scroll the longer + * distance. + * + * @return the preferred scrolling distance, negative if up or left. + */ int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction); + /** + * Return true if the width of the scrollable is always equal to the + * view, where it is displayed, width (for instance, the text area with + * the word wrap). In such case, the horizontal scrolling should not be + * performed. + * + * @return true is no horizontal scrolling is assumed, faster otherwise. + */ boolean getScrollableTracksViewportWidth(); + /** + * Return true if the height of the scrollable is always equal to the view, + * where it is displayed, height.In such case, the vertical scrolling should + * not be performed. + * + * @return true is no horizontal scrolling is assumed, faster otherwise. + */ boolean getScrollableTracksViewportHeight(); } diff --git a/libjava/classpath/javax/swing/SingleSelectionModel.java b/libjava/classpath/javax/swing/SingleSelectionModel.java index d57443b56bb..9f33e33faaa 100644 --- a/libjava/classpath/javax/swing/SingleSelectionModel.java +++ b/libjava/classpath/javax/swing/SingleSelectionModel.java @@ -37,6 +37,7 @@ exception statement from your version. */ package javax.swing; +import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** @@ -49,37 +50,53 @@ import javax.swing.event.ChangeListener; public interface SingleSelectionModel { /** - * getSelectedIndex - * @returns int + * Returns the selected index or <code>-1</code> if there is no selection. + * + * @return The selected index. + * + * @see #setSelectedIndex(int) */ int getSelectedIndex(); /** - * setSelectedIndex - * @param index TODO + * Sets the selected index and, if this is different to the previous + * selection, sends a {@link ChangeEvent} to all registered listeners. + * + * @param index the index (use <code>-1</code> to represent no selection). + * + * @see #getSelectedIndex() + * @see #clearSelection */ void setSelectedIndex(int index); /** - * clearSelection + * Clears the selection by setting the selected index to <code>-1</code> and + * sends a {@link ChangeEvent} to all registered listeners. If the selected + * index is already <code>-1</code>, this method does nothing. */ void clearSelection(); /** - * isSelected - * @returns boolean + * Returns <code>true</code> if there is a selection, and <code>false</code> + * otherwise. + * + * @return A boolean. */ boolean isSelected(); /** - * addChangeListener - * @param listener TODO + * Registers a listener to receive {@link ChangeEvent} notifications from + * this model whenever the selected index changes. + * + * @param listener the listener to add. */ void addChangeListener(ChangeListener listener); /** - * removeChangeListener - * @param listener TODO + * Deregisters a listener so that it no longer receives {@link ChangeEvent} + * notifications from this model. + * + * @param listener the listener to remove. */ void removeChangeListener(ChangeListener listener); diff --git a/libjava/classpath/javax/swing/SizeSequence.java b/libjava/classpath/javax/swing/SizeSequence.java index dff966b3e35..26099a15461 100644 --- a/libjava/classpath/javax/swing/SizeSequence.java +++ b/libjava/classpath/javax/swing/SizeSequence.java @@ -1,5 +1,5 @@ /* SizeSequence.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,20 +38,22 @@ exception statement from your version. */ package javax.swing; /** - * SizeSequence + * A sequence of values that represent the dimensions (widths or heights) of + * some collection of items (for example, the widths of the columns in a table). + * * @author Andrew Selkirk - * @version 1.0 */ public class SizeSequence { + // TODO: Sun's API specification for this class contains an implementation + // note regarding the encoding for the element sizes. We currently use the + // simple size encoding but we should look at improving this. - /** - * sizes - */ - private int[] sizes = new int[0]; + /** Storage for the element sizes. */ + private int[] sizes; /** - * Constructor SizeSequence + * Creates a new empty <code>SizeSequence</code> instance. */ public SizeSequence() { @@ -59,8 +61,10 @@ public class SizeSequence } /** - * Constructor SizeSequence - * @param numEntries TODO + * Creates a new <code>SizeSequence</code> instance with the specified number + * of elements, each having a size of 0. + * + * @param numEntries the number of elements. */ public SizeSequence(int numEntries) { @@ -68,48 +72,66 @@ public class SizeSequence } /** - * Constructor SizeSequence - * @param numEntries TODO - * @param value TODO + * Creates a new <code>SizeSequence</code> instance with the specified number + * of elements all having the same size (<code>value</code>). + * + * @param numEntries the number of elements. + * @param value the value for each element. */ public SizeSequence(int numEntries, int value) { + sizes = new int[0]; insertEntries(0, numEntries, value); } /** - * Constructor SizeSequence - * @param sizes TODO + * Creates a new <code>SizeSequence</code> instance using the specified + * element sizes. + * + * @param sizes the element sizes (<code>null</code> not permitted). */ public SizeSequence(int[] sizes) { - setSizes(sizes); + this.sizes = (int[]) sizes.clone(); } /** - * setSize - * @param index TODO - * @param size TODO + * Sets the size of the element at the specified index. + * + * @param index the index. + * @param size the size. */ public void setSize(int index, int size) { - sizes[index] = size; + if (index >= 0 && index < sizes.length) + sizes[index] = size; } /** - * getIndex - * @param position TODO - * @returns int + * Returns the index of the element that contains the specified position. + * + * @param position the position. + * + * @return The index of the element that contains the specified position. */ public int getIndex(int position) { - return 0; // TODO + int i = 0; + int runningTotal = 0; + while (i < sizes.length && position >= runningTotal + sizes[i]) + { + runningTotal += sizes[i]; + i++; + } + return i; } /** - * getSize - * @param index TODO - * @returns int + * Returns the size of the specified element. + * + * @param index the element index. + * + * @return The size of the specified element. */ public int getSize(int index) { @@ -117,122 +139,81 @@ public class SizeSequence } /** - * setSizes - * @param sizes TODO + * Sets the sizes for the elements in the sequence. + * + * @param sizes the element sizes (<code>null</code> not permitted). */ public void setSizes(int[] sizes) { - int index; - // Initialize sizes. - this.sizes = new int[sizes.length]; - for (index = 0; index < sizes.length; index++) - this.sizes[index] = sizes[index]; - + this.sizes = (int[]) sizes.clone(); } /** - * getSizes - * @returns int[] + * Returns an array containing the sizes for all the elements in the sequence. + * + * @return The element sizes. */ public int[] getSizes() { - int[] array; - int index; - - // Create new array. - array = new int[sizes.length]; - for (index = 0; index < sizes.length; index++) - array[index] = sizes[index]; - - // Return newly created array. - return array; - + return (int[]) sizes.clone(); } /** - * getPosition - * @param index TODO - * @returns int + * Returns the position of the specified element. + * + * @param index the element index. + * + * @return The position. */ public int getPosition(int index) { int position; int loop; - - // Process sizes. position = 0; for (loop = 0; loop < index; loop++) position += sizes[loop]; - - // Return position. return position; } /** - * insertEntries - * @param start TODO - * @param length TODO - * @param value TODO + * Inserts new entries into the sequence at the <code>start</code> position. + * There are <code>length</code> new entries each having the specified + * <code>value</code>. + * + * @param start the start element. + * @param length the number of elements to insert. + * @param value the size for each of the new elements. */ public void insertEntries(int start, int length, int value) { - int[] array; - int index; - int arrayIndex; - int loop; - - // Create new array. - array = new int[sizes.length + length]; - arrayIndex = 0; - for (index = 0; index < sizes.length; index++) - { - if (index == start) - { - for (loop = 0; loop < length; loop++) - { - array[arrayIndex] = value; - arrayIndex++; - } - } - else - { - array[arrayIndex] = sizes[index]; - arrayIndex++; - } - } - - } + int[] newSizes = new int[sizes.length + length]; + System.arraycopy(sizes, 0, newSizes, 0, start); + for (int i = start; i < start + length; i++) + newSizes[i] = value; + System.arraycopy(sizes, start, newSizes, start + length, + sizes.length - start); + sizes = newSizes; + } /** - * removeEntries - * @param start TODO - * @param length TODO + * Removes the element(s) at index <code>start</code> (the number of elements + * removed is <code>length</code>). + * + * @param start the index of the first element to remove. + * @param length the number of elements to remove. */ public void removeEntries(int start, int length) { - int[] array; - int index; - int arrayIndex; - // Sanity check. if ((start + length) > sizes.length) throw new IllegalArgumentException("Specified start/length that " + "is greater than available sizes"); - // Create new array. - array = new int[sizes.length - length]; - arrayIndex = 0; - for (index = 0; index < sizes.length; index++) - { - if (index == start) - index += length - 1; - else - { - array[arrayIndex] = sizes[index]; - arrayIndex++; - } - } + int[] newSizes = new int[sizes.length - length]; + System.arraycopy(sizes, 0, newSizes, 0, start); + System.arraycopy(sizes, start + length, newSizes, start, + sizes.length - start - length); + sizes = newSizes; } - } diff --git a/libjava/classpath/javax/swing/SpinnerDateModel.java b/libjava/classpath/javax/swing/SpinnerDateModel.java index e0ccab776fb..e5ff76f1adf 100644 --- a/libjava/classpath/javax/swing/SpinnerDateModel.java +++ b/libjava/classpath/javax/swing/SpinnerDateModel.java @@ -59,13 +59,13 @@ public class SpinnerDateModel extends AbstractSpinnerModel private Calendar date; /** - * The start or earliest permitted date (<code>null</code> for no - * minimum). + * A constraint on the start or earliest permitted date (<code>null</code> + * for no minimum). */ private Comparable start; /** - * The end or latest permitted date (<code>null</code> for no + * A constraint on the end or latest permitted date (<code>null</code> for no * maximum). */ private Comparable end; @@ -77,7 +77,6 @@ public class SpinnerDateModel extends AbstractSpinnerModel /** * For compatability with Sun's JDK - * FIXME: Which fields should be serialized? */ private static final long serialVersionUID = -4802518107105940612L; @@ -92,23 +91,30 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Constructs a SpinnerDateModel which spins a given calendar field, - * using a given date and start and end date limits. - * @param value - the initial Date value - * @param start - start limit, as a Date object, or <code>null</code> - * for no lower limit. - * @param end - end limit, or <code>null</code> for no upper limit. - * @param calendarField - the <code>Calendar</code> field to spin, - * (Calendar.ZONE_OFFSET and Calendar.DST_OFFSET are invalid) + * Constructs a <code>SpinnerDateModel</code> with the specified value, lower + * and upper bounds, and which spins the specified calendar field. + * <p> + * The <code>start</code> and <code>end</code> limits must have a + * <code>compareTo</code> method that supports instances of {@link Date}, but + * do not themselves need to be instances of {@link Date} (although typically + * they are). + * + * @param value the initial value/date (<code>null</code> not permitted). + * @param start a constraint that specifies the earliest permitted date + * value, or <code>null</code> for no lower limit. + * @param end a constraint that specifies the latest permitted date value, + * or <code>null</code> for no upper limit. + * @param calendarField the <code>Calendar</code> field to spin, + * (Calendar.ZONE_OFFSET and Calendar.DST_OFFSET are invalid) */ public SpinnerDateModel(Date value, Comparable start, Comparable end, int calendarField) { if (value == null) throw new IllegalArgumentException("Null 'value' argument."); - if (start != null && value.compareTo(start) < 0) + if (start != null && start.compareTo(value) > 0) throw new IllegalArgumentException("Require value on or after start."); - if (end != null && value.compareTo(end) > 0) + if (end != null && end.compareTo(value) < 0) throw new IllegalArgumentException("Require value on or before end."); date = Calendar.getInstance(); date.setTime(value); @@ -129,9 +135,11 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the current date. + * Returns the current date/time. + * + * @return The current date/time (never <code>null</code>). * - * @return The current date. + * @see #getValue() */ public Date getDate() { @@ -139,9 +147,12 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the start date, or <code>null</code> if there is no minimum date. + * Returns the lower limit on the date/time value, or <code>null</code> if + * there is no minimum date/time. * - * @return The start date. + * @return The lower limit. + * + * @see #setStart(Comparable) */ public Comparable getStart() { @@ -149,9 +160,12 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the end date, or <code>null</code> if there is no maximum date. + * Returns the upper limit on the date/time value, or <code>null</code> if + * there is no maximum date/time. + * + * @return The upper limit. * - * @return The end date. + * @see #setEnd(Comparable) */ public Comparable getEnd() { @@ -160,9 +174,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel /** * Returns the current date in the sequence (this method returns the same as - * {@link #getDate()}. + * {@link #getDate()}). * - * @return The current date. + * @return The current date (never <code>null</code>). */ public Object getValue() { @@ -171,10 +185,13 @@ public class SpinnerDateModel extends AbstractSpinnerModel /** * Returns the next date in the sequence, or <code>null</code> if the - * next date is after the end date. The current date is not changed. + * next date is past the upper limit (if one is specified). The current date + * is not changed. * * @return The next date, or <code>null</code> if the current value is * the latest date represented by the model. + * + * @see #getEnd() */ public Object getNextValue() { @@ -190,11 +207,13 @@ public class SpinnerDateModel extends AbstractSpinnerModel /** * Returns the previous date in the sequence, or <code>null</code> if the - * previous date is prior to the start date. The current date is not - * changed. + * previous date is prior to the lower limit (if one is specified). The + * current date is not changed. * * @return The previous date, or <code>null</code> if the current value is * the earliest date represented by the model. + * + * @see #getStart() */ public Object getPreviousValue() { @@ -233,14 +252,16 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Sets the start date and, if the new date is different to the old date, - * sends a {@link ChangeEvent} to all registered listeners. A - * <code>null</code> date is interpreted as "no start date". No check - * is made to ensure that the new start date is on or before the current - * date - the caller is responsible for ensuring that this relationship - * holds. + * Sets the lower limit for the date/time value and, if the new limit is + * different to the old limit, sends a {@link ChangeEvent} to all registered + * listeners. A <code>null</code> value is interpreted as "no lower limit". + * No check is made to ensure that the current date/time is on or after the + * new lower limit - the caller is responsible for ensuring that this + * relationship holds. In addition, the caller should ensure that + * <code>start</code> is {@link Serializable}. * - * @param start the new start date (<code>null</code> permitted). + * @param start the new lower limit for the date/time value + * (<code>null</code> permitted). */ public void setStart(Comparable start) { @@ -252,13 +273,16 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Sets the end date and, if the new date is different to the old date, - * sends a {@link ChangeEvent} to all registered listeners. A - * <code>null</code> date is interpreted as "no end date". No check - * is made to ensure that the new end date is on or after the current date - - * the caller is responsible for ensuring that this relationship holds. + * Sets the upper limit for the date/time value and, if the new limit is + * different to the old limit, sends a {@link ChangeEvent} to all registered + * listeners. A <code>null</code> value is interpreted as "no upper limit". + * No check is made to ensure that the current date/time is on or before the + * new upper limit - the caller is responsible for ensuring that this + * relationship holds. In addition, the caller should ensure that + * <code>end</code> is {@link Serializable}. * - * @param end the new end date (<code>null</code> permitted). + * @param end the new upper limit for the date/time value (<code>null</code> + * permitted). */ public void setEnd(Comparable end) { diff --git a/libjava/classpath/javax/swing/SpinnerNumberModel.java b/libjava/classpath/javax/swing/SpinnerNumberModel.java index 389c536e47f..1abbbe377be 100644 --- a/libjava/classpath/javax/swing/SpinnerNumberModel.java +++ b/libjava/classpath/javax/swing/SpinnerNumberModel.java @@ -110,12 +110,14 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Creates a <code>SpinnerNumberModel</code> with the given attributes. + * Creates a <code>SpinnerNumberModel</code> with the given attributes. The + * caller should ensure that both <code>minimum</code> and + * <code>maximum</code> are serializable. * - * @param value the initial value. + * @param value the initial value (<code>null</code> not permitted). * @param minimum the minimum value (<code>null</code> permitted). * @param maximum the maximum value (<code>null</code> permitted). - * @param stepSize the step size. + * @param stepSize the step size (<code>null</code> not permitted). * * @throws IllegalArgumentException if minimum <= value <= maximum * does not hold @@ -171,9 +173,12 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Returns the current value. + * Returns the current value, which for this class is always an instance of + * {@link Number}. * * @return The current value. + * + * @see #getNumber() */ public Object getValue() { @@ -258,6 +263,8 @@ public class SpinnerNumberModel extends AbstractSpinnerModel * Returns the minimum value, or <code>null</code> if there is no minimum. * * @return The minimum value. + * + * @see #setMinimum(Comparable) */ public Comparable getMinimum() { @@ -270,9 +277,12 @@ public class SpinnerNumberModel extends AbstractSpinnerModel * <code>null</code> value is interpreted as "no minimum value". No check * is made to ensure that the new minimum is less than or equal to the * current value, the caller is responsible for ensuring that this - * relationship holds. + * relationship holds. In addition, the caller should ensure that + * <code>newMinimum</code> is {@link Serializable}. * * @param newMinimum the new minimum value (<code>null</code> permitted). + * + * @see #getMinimum() */ public void setMinimum(Comparable newMinimum) { @@ -287,6 +297,9 @@ public class SpinnerNumberModel extends AbstractSpinnerModel * Returns the maximum value, or <code>null</code> if there is no maximum. * * @return The maximum value. + * + * @see #getMinimum() + * @see #setMaximum(Comparable) */ public Comparable getMaximum() { @@ -299,9 +312,12 @@ public class SpinnerNumberModel extends AbstractSpinnerModel * <code>null</code> value is interpreted as "no maximum value". No check * is made to ensure that the new maximum is greater than or equal to the * current value, the caller is responsible for ensuring that this - * relationship holds. + * relationship holds. In addition, the caller should ensure that + * <code>newMaximum</code> is {@link Serializable}. * * @param newMaximum the new maximum (<code>null</code> permitted). + * + * @see #getMaximum() */ public void setMaximum(Comparable newMaximum) { @@ -315,7 +331,7 @@ public class SpinnerNumberModel extends AbstractSpinnerModel /** * Returns the step size. * - * @return The step size. + * @return The step size (never <code>null</code>). */ public Number getStepSize() { diff --git a/libjava/classpath/javax/swing/Spring.java b/libjava/classpath/javax/swing/Spring.java index b9890c7147f..477525960a2 100644 --- a/libjava/classpath/javax/swing/Spring.java +++ b/libjava/classpath/javax/swing/Spring.java @@ -60,7 +60,7 @@ public abstract class Spring { /** Indicates a not-set value. **/ - public static final int UNSET = -2147483648; + public static final int UNSET = Integer.MIN_VALUE; /** * Creates a new Spring object. This constructor is used by the static @@ -156,6 +156,33 @@ public abstract class Spring */ public abstract void setValue(int value); + private int getShrinkRange() + { + return (getPreferredValue() - getMinimumValue()); + } + + private int getExpandRange() + { + return (getMaximumValue() - getPreferredValue()); + } + + double getStrain() + { + int v = getValue(); + int p = getPreferredValue(); + int r = (v < p) ? getShrinkRange() : getExpandRange(); + if (r == 0) + r = 1; + return (double)(v - p) / r; + } + + void setStrain(double strain) + { + int r = (strain < 0) ? getShrinkRange() : getExpandRange(); + int v = (getPreferredValue() + (int)(strain * r)); + setValue(v); + } + /** * Creates and returns a Spring, which is always the sum of s1 and s2. * min_sum = min_s1 + min_s2, pref_sum = pref_s1 + pref_s2, max_sum = @@ -323,6 +350,11 @@ public abstract class Spring /** The actual value of the spring. */ private int value; + public String toString() + { + return "SimpleSpring of " + value; + } + /** * Creates a new SimpleSpring object. * @@ -335,7 +367,7 @@ public abstract class Spring min = newMin; pref = newPref; max = newMax; - value = Spring.UNSET; + value = newPref; } /** @@ -375,12 +407,8 @@ public abstract class Spring */ public int getValue() { - if (value == Spring.UNSET) - { - value = pref; - } - + return pref; return value; } @@ -391,21 +419,8 @@ public abstract class Spring */ public void setValue(int val) { - - if (val > max) - { - value = max; - } - else if (val < min) - { - value = min; - } - else - { - value = val; - } + value = val; } - } @@ -424,6 +439,11 @@ public abstract class Spring /** The current value for this Spring. */ private int value; + public String toString() + { + return "AddSpring of " + s1 + " and " + s2; + } + /** * Creates a new AddSpring object. * @@ -497,20 +517,24 @@ public abstract class Spring */ public void setValue(int val) { - - if (val > getMaximumValue()) - { - value = getMaximumValue(); - } - else if (val < getMinimumValue()) - { - value = getMinimumValue(); - } - else + if (val == Spring.UNSET) + { + if (value != Spring.UNSET) { - value = val; + s1.setValue(Spring.UNSET); + s2.setValue(Spring.UNSET); } + value = Spring.UNSET; + return; + } + + value = val; + //Spead the value over the two components + double fStrain = getStrain(); + s1.setStrain(fStrain); + int remainder = val - s1.getValue(); + s2.setValue(remainder); } } @@ -527,8 +551,10 @@ public abstract class Spring /** The Spring from which to calculate the negation. */ private final Spring s; - /** The current value of this Spring. */ - private int value; + public String toString() + { + return "MinusSpring of " + s; + } /** * Creates a new MinusSpring object. @@ -538,7 +564,6 @@ public abstract class Spring { super(); this.s = s; - value = Spring.UNSET; } /** Returns the maximum value of this Spring. @@ -577,11 +602,7 @@ public abstract class Spring */ public int getValue() { - if (value == Spring.UNSET) - { - value = -s.getValue(); - } - return value; + return -s.getValue(); } /** @@ -591,22 +612,11 @@ public abstract class Spring */ public void setValue(int val) { - - if (val > getMaximumValue()) - { - value = getMaximumValue(); - } - else if (val < getMinimumValue()) - { - value = getMinimumValue(); - } + if (val == Spring.UNSET) + s.setValue(Spring.UNSET); else - { - value = val; - } - + s.setValue(-val); } - } @@ -622,6 +632,11 @@ public abstract class Spring private final Spring s1; private final Spring s2; + public String toString() + { + return "MaxSpring of " + s1 + " and " + s2; + } + /** The current value of this Spring. */ private int value; @@ -684,7 +699,7 @@ public abstract class Spring public int getValue() { if (value == Spring.UNSET) - { + { int val1 = s1.getValue(); int val2 = s2.getValue(); value = Math.max(val1, val2); @@ -699,19 +714,32 @@ public abstract class Spring */ public void setValue(int val) { - - if (val > getMaximumValue()) - { - value = getMaximumValue(); - } - else if (val < getMinimumValue()) - { - value = getMinimumValue(); - } - else + if (val == Spring.UNSET) + { + if (value != Spring.UNSET) { - value = val; + s1.setValue(Spring.UNSET); + s2.setValue(Spring.UNSET); } + value = Spring.UNSET; + return; + } + + value = val; + + int p1 = s1.getPreferredValue(); + int p2 = s2.getPreferredValue(); + + if (p1 < p2) + { + s1.setValue(Math.min(val, p1)); + s2.setValue(val); + } + else + { + s1.setValue(val); + s2.setValue(Math.min(val, p2)); + } } } } diff --git a/libjava/classpath/javax/swing/SpringLayout.java b/libjava/classpath/javax/swing/SpringLayout.java index 8d46a736a58..d87050639fe 100644 --- a/libjava/classpath/javax/swing/SpringLayout.java +++ b/libjava/classpath/javax/swing/SpringLayout.java @@ -110,13 +110,22 @@ public class SpringLayout implements LayoutManager2 /** The Spring for the bottom edge. */ private Spring south; + /** + In each axis the user can set three values, i.e. x, width, east, if all + three are set, then there's no room for manoeuvre so in those cases the + third will be described by the below spring which is calculated in terms + of the other two + */ + private Spring v; + private Spring h; + /** * Creates a new Constraints object. * There is no constraint set. */ public Constraints() { - x = y = height = width = east = south = null; + x = y = height = width = east = south = v = h = null; } /** @@ -129,7 +138,7 @@ public class SpringLayout implements LayoutManager2 { this.x = x; this.y = y; - width = height = east = south = null; + width = height = east = south = v = h = null; } /** @@ -146,7 +155,7 @@ public class SpringLayout implements LayoutManager2 this.y = y; this.width = width; this.height = height; - east = south = null; + east = south = v = h = null; } /** @@ -180,22 +189,13 @@ public class SpringLayout implements LayoutManager2 { Spring retVal = null; if (edgeName.equals(SpringLayout.NORTH)) - retVal = y; + retVal = getY(); else if (edgeName.equals(SpringLayout.WEST)) - retVal = x; + retVal = getX(); else if (edgeName.equals(SpringLayout.SOUTH)) - { - retVal = south; - if ((retVal == null) && (y != null) && (height != null)) - retVal = Spring.sum(y, height); - } + retVal = getSouth(); else if (edgeName.equals(SpringLayout.EAST)) - { - retVal = east; - if ((retVal == null) && (x != null) && (width != null)) - retVal = Spring.sum(x, width); - } - + retVal = getEast(); return retVal; } @@ -206,12 +206,11 @@ public class SpringLayout implements LayoutManager2 */ public Spring getHeight() { - Spring retVal = height; - if ((retVal == null) && (y != null) && (south != null)) - { - retVal = Spring.sum(south, Spring.minus(y)); - } - return retVal; + if (height != null) + return height; + else if ((v == null) && (y != null) && (south != null)) + v = Spring.sum(south, Spring.minus(y)); + return v; } /** @@ -221,12 +220,11 @@ public class SpringLayout implements LayoutManager2 */ public Spring getWidth() { - Spring retVal = width; - if ((retVal == null) && (x != null) && (east != null)) - { - retVal = Spring.sum(east, Spring.minus(x)); - } - return retVal; + if (width != null) + return width; + else if ((h == null) && (x != null) && (east != null)) + h = Spring.sum(east, Spring.minus(x)); + return h; } /** @@ -236,12 +234,11 @@ public class SpringLayout implements LayoutManager2 */ public Spring getX() { - Spring retVal = x; - if ((retVal == null) && (width != null) && (east != null)) - { - retVal = Spring.sum(east, Spring.minus(width)); - } - return retVal; + if (x != null) + return x; + else if ((h == null) && (width != null) && (east != null)) + h = Spring.sum(east, Spring.minus(width)); + return h; } /** @@ -251,12 +248,39 @@ public class SpringLayout implements LayoutManager2 */ public Spring getY() { - Spring retVal = y; - if ((retVal == null) && (height != null) && (south != null)) - { - retVal = Spring.sum(south, Spring.minus(height)); - } - return retVal; + if (y != null) + return y; + else if ((v == null) && (height != null) && (south != null)) + v = Spring.sum(south, Spring.minus(height)); + return v; + } + + /** + * Returns the constraint for the lower edge of the component. + * + * @return the lower-edge constraint (== SOUTH). + */ + public Spring getSouth() + { + if (south != null) + return south; + else if ((v == null) && (height != null) && (y != null)) + v = Spring.sum(y, height); + return v; + } + + /** + * Returns the constraint for the right edge of the component. + * + * @return the right-edge constraint (== EAST). + */ + public Spring getEast() + { + if (east != null) + return east; + else if ((h == null) && (width != null) && (x != null)) + h = Spring.sum(x, width); + return h; } /** @@ -272,29 +296,13 @@ public class SpringLayout implements LayoutManager2 { if (edgeName.equals(SpringLayout.WEST)) - { - x = s; - if ((width != null) && (east != null)) - width = Spring.sum(east, Spring.minus(x)); - } + setX(s); else if (edgeName.equals(SpringLayout.NORTH)) - { - y = s; - if ((height != null) && (south != null)) - height = Spring.sum(south, Spring.minus(y)); - } + setY(s); else if (edgeName.equals(SpringLayout.EAST)) - { - east = s; - if ((x != null) && (width != null)) - x = Spring.sum(east, Spring.minus(width)); - } + setEast(s); else if (edgeName.equals(SpringLayout.SOUTH)) - { - south = s; - if ((height != null) && (y != null)) - y = Spring.sum(south, Spring.minus(height)); - } + setSouth(s); } @@ -306,9 +314,9 @@ public class SpringLayout implements LayoutManager2 public void setHeight(Spring s) { height = s; - if ((south != null) && (y != null)) - south = Spring.sum(y, height); - + v = null; + if ((south != null) && (y != null) && (height != null)) + south = null; } /** @@ -319,9 +327,9 @@ public class SpringLayout implements LayoutManager2 public void setWidth(Spring s) { width = s; - if ((east != null) && (x != null)) - east = Spring.sum(x, width); - + h = null; + if ((east != null) && (x != null) && (width != null)) + east = null; } /** @@ -332,9 +340,9 @@ public class SpringLayout implements LayoutManager2 public void setX(Spring s) { x = s; - if ((width != null) && (east != null)) - width = Spring.sum(east, Spring.minus(x)); - + h = null; + if ((width != null) && (east != null) && (x != null)) + width = null; } /** @@ -345,9 +353,55 @@ public class SpringLayout implements LayoutManager2 public void setY(Spring s) { y = s; - if ((height != null) && (south != null)) - height = Spring.sum(south, Spring.minus(y)); + v = null; + if ((height != null) && (south != null) && (y != null)) + height = null; + } + /** + * Sets the SOUTH-constraint. + * + * @param s the constraint to be set. + */ + public void setSouth(Spring s) + { + south = s; + v = null; + if ((height != null) && (south != null) && (y != null)) + y = null; + } + + /** + * Sets the EAST-constraint. + * + * @param s the constraint to be set. + */ + public void setEast(Spring s) + { + east = s; + h = null; + if ((width != null) && (east != null) && (x != null)) + x = null; + } + + public void dropCalcResult() + { + if (x != null) + x.setValue(Spring.UNSET); + if (y != null) + y.setValue(Spring.UNSET); + if (width != null) + width.setValue(Spring.UNSET); + if (height != null) + height.setValue(Spring.UNSET); + if (east != null) + east.setValue(Spring.UNSET); + if (south != null) + south.setValue(Spring.UNSET); + if (h != null) + h.setValue(Spring.UNSET); + if (v != null) + v.setValue(Spring.UNSET); } } @@ -356,7 +410,6 @@ public class SpringLayout implements LayoutManager2 */ public SpringLayout() { - constraintsMap = new HashMap(); } @@ -373,7 +426,6 @@ public class SpringLayout implements LayoutManager2 constraintsMap.put(component, constraint); } - /** * Adds a layout component and a constraint object to this layout. * This method is usually only called by a {@link java.awt.Container}s add @@ -389,6 +441,158 @@ public class SpringLayout implements LayoutManager2 } /** + * The trick to SpringLayout is that the network of Springs needs to + * completely created before the positioning results are generated. + * + * Using the springs directly during network creation will set their values + * before the network is completed, Using Deferred Springs during creation of + * the network allows all the edges to be connected together and the network + * to be created without resolving the Springs until their results need to be + * known, at which point the network is complete and the spring addition and + * and substitution calculations will work on a complete and valid network. + * + * @author Caolan McNamara (caolanm@redhat.com) + */ + private static class DeferredSpring extends Spring + { + private SpringLayout sl; + private String edgeName; + private Component c; + + public String toString() + { + return "DeferredSpring of edge" + edgeName + " of " + "something"; + } + + public DeferredSpring(SpringLayout s, String edge, Component component) + { + sl = s; + edgeName = edge; + c = component; + } + + private Spring resolveSpring() + { + return sl.getConstraints(c).getConstraint(edgeName); + } + + public int getMaximumValue() + { + return resolveSpring().getMaximumValue(); + } + + public int getMinimumValue() + { + return resolveSpring().getMinimumValue(); + } + + public int getPreferredValue() + { + return resolveSpring().getPreferredValue(); + } + + public int getValue() + { + int nRet = resolveSpring().getValue(); + if (nRet == Spring.UNSET) + nRet = getPreferredValue(); + return nRet; + } + + public void setValue(int size) + { + resolveSpring().setValue(size); + } + } + + private static abstract class DeferredDimension extends Spring + { + private int value; + + public DeferredDimension() + { + value = Spring.UNSET; + } + + public void setValue(int val) + { + value = val; + } + + public int getValue() + { + if (value == Spring.UNSET) + return getPreferredValue(); + return value; + } + } + + private static class DeferredWidth extends DeferredDimension + { + private Component c; + + + public DeferredWidth(Component component) + { + c = component; + } + + public String toString() + { + return "DeferredWidth of " + "something"; + } + + //clip max to a value we can do meaningful calculation with + public int getMaximumValue() + { + int widget_width = c.getMaximumSize().width; + return Math.min(Short.MAX_VALUE, widget_width); + } + + public int getMinimumValue() + { + return c.getMinimumSize().width; + } + + public int getPreferredValue() + { + return c.getPreferredSize().width; + } + } + + private static class DeferredHeight extends DeferredDimension + { + private Component c; + + public String toString() + { + return "DeferredHeight of " + "something"; + } + + public DeferredHeight(Component component) + { + c = component; + } + + //clip max to a value we can do meaningful calculations with it + public int getMaximumValue() + { + int widget_height = c.getMaximumSize().height; + return Math.min(Short.MAX_VALUE, widget_height); + } + + public int getMinimumValue() + { + return c.getMinimumSize().height; + } + + public int getPreferredValue() + { + return c.getPreferredSize().height; + } + } + + /** * Returns the constraint of the edge named by <code>edgeName</code>. * * @param c the component from which to get the constraint. @@ -399,8 +603,7 @@ public class SpringLayout implements LayoutManager2 */ public Spring getConstraint(String edgeName, Component c) { - Constraints constraints = getConstraints(c); - return constraints.getConstraint(edgeName); + return new DeferredSpring(this, edgeName, c); } /** @@ -416,28 +619,16 @@ public class SpringLayout implements LayoutManager2 Constraints constraints = (Constraints) constraintsMap.get(c); if (constraints == null) - { - Container parent = c.getParent(); - constraints = new Constraints(); - - if (parent != null) - { - constraints.setX(Spring.constant(parent.getInsets().left)); - constraints.setY(Spring.constant(parent.getInsets().top)); - } - else - { - constraints.setX(Spring.constant(0)); - constraints.setY(Spring.constant(0)); - } - } - constraints.setWidth(Spring.constant(c.getMinimumSize().width, - c.getPreferredSize().width, - c.getMaximumSize().width)); - constraints.setHeight(Spring.constant(c.getMinimumSize().height, - c.getPreferredSize().height, - c.getMaximumSize().height)); - constraintsMap.put(c, constraints); + { + constraints = new Constraints(); + + constraints.setWidth(new DeferredWidth(c)); + constraints.setHeight(new DeferredHeight(c)); + constraints.setX(Spring.constant(0)); + constraints.setY(Spring.constant(0)); + + constraintsMap.put(c, constraints); + } return constraints; } @@ -475,6 +666,22 @@ public class SpringLayout implements LayoutManager2 // nothing to do here yet } + private Constraints initContainer(Container p) + { + Constraints c = getConstraints(p); + + c.setX(Spring.constant(0)); + c.setY(Spring.constant(0)); + c.setWidth(null); + c.setHeight(null); + if (c.getEast() == null) + c.setEast(Spring.constant(0, 0, Integer.MAX_VALUE)); + if (c.getSouth() == null) + c.setSouth(Spring.constant(0, 0, Integer.MAX_VALUE)); + + return c; + } + /** * Lays out the container <code>p</code>. * @@ -482,28 +689,40 @@ public class SpringLayout implements LayoutManager2 */ public void layoutContainer(Container p) { + java.awt.Insets insets = p.getInsets(); - addLayoutComponent(p, new Constraints(Spring.constant(0), - Spring.constant(0))); + Component[] components = p.getComponents(); - int offsetX = p.getInsets().left; - int offsetY = p.getInsets().right; + Constraints cs = initContainer(p); + cs.dropCalcResult(); - Component[] components = p.getComponents(); - for (int index = 0; index < components.length; index++) - { + for (int index = 0 ; index < components.length; index++) + { Component c = components[index]; + getConstraints(c).dropCalcResult(); + } - Constraints constraints = getConstraints(c); - int x = constraints.getX().getValue(); - int y = constraints.getY().getValue(); - int width = constraints.getWidth().getValue(); - int height = constraints.getHeight().getValue(); + int offsetX = p.getInsets().left; + int offsetY = p.getInsets().right; - c.setLocation(x + offsetX, y + offsetY); - c.setSize(width, height); - } + cs.getX().setValue(0); + cs.getY().setValue(0); + cs.getWidth().setValue(p.getWidth() - offsetX - insets.right); + cs.getHeight().setValue(p.getHeight() - offsetY - insets.bottom); + for (int index = 0; index < components.length; index++) + { + Component c = components[index]; + + Constraints constraints = getConstraints(c); + + int x = constraints.getX().getValue(); + int y = constraints.getY().getValue(); + int width = constraints.getWidth().getValue(); + int height = constraints.getHeight().getValue(); + + c.setBounds(x + offsetX, y + offsetY, width, height); + } } /** @@ -515,29 +734,12 @@ public class SpringLayout implements LayoutManager2 */ public Dimension maximumLayoutSize(Container p) { - int maxX = 0; - int maxY = 0; + java.awt.Insets insets = p.getInsets(); - int offsetX = p.getInsets().left; - int offsetY = p.getInsets().right; + Constraints cs = initContainer(p); - Component[] components = p.getComponents(); - for (int index = 0; index < components.length; index++) - { - Component c = components[index]; - Constraints constraints = getConstraints(c); - int x = constraints.getX().getMaximumValue(); - int y = constraints.getY().getMaximumValue(); - int width = constraints.getWidth().getMaximumValue(); - int height = constraints.getHeight().getMaximumValue(); - - int rightEdge = offsetX + x + width; - if (rightEdge > maxX) - maxX = rightEdge; - int bottomEdge = offsetY + y + height; - if (bottomEdge > maxY) - maxY = bottomEdge; - } + int maxX = cs.getWidth().getMaximumValue() + insets.left + insets.right; + int maxY = cs.getHeight().getMaximumValue() + insets.top + insets.bottom; return new Dimension(maxX, maxY); } @@ -552,29 +754,12 @@ public class SpringLayout implements LayoutManager2 */ public Dimension minimumLayoutSize(Container p) { - int maxX = 0; - int maxY = 0; + java.awt.Insets insets = p.getInsets(); - int offsetX = p.getInsets().left; - int offsetY = p.getInsets().right; + Constraints cs = initContainer(p); - Component[] components = p.getComponents(); - for (int index = 0; index < components.length; index++) - { - Component c = components[index]; - Constraints constraints = getConstraints(c); - int x = constraints.getX().getMinimumValue(); - int y = constraints.getY().getMinimumValue(); - int width = constraints.getWidth().getMinimumValue(); - int height = constraints.getHeight().getMinimumValue(); - - int rightEdge = offsetX + x + width; - if (rightEdge > maxX) - maxX = rightEdge; - int bottomEdge = offsetY + y + height; - if (bottomEdge > maxY) - maxY = bottomEdge; - } + int maxX = cs.getWidth().getMinimumValue() + insets.left + insets.right; + int maxY = cs.getHeight().getMinimumValue() + insets.top + insets.bottom; return new Dimension(maxX, maxY); } @@ -588,29 +773,13 @@ public class SpringLayout implements LayoutManager2 */ public Dimension preferredLayoutSize(Container p) { - int maxX = 0; - int maxY = 0; + java.awt.Insets insets = p.getInsets(); - int offsetX = p.getInsets().left; - int offsetY = p.getInsets().right; + Constraints cs = initContainer(p); + + int maxX = cs.getWidth().getPreferredValue() + insets.left + insets.right; + int maxY = cs.getHeight().getPreferredValue() + insets.top + insets.bottom; - Component[] components = p.getComponents(); - for (int index = 0; index < components.length; index++) - { - Component c = components[index]; - Constraints constraints = getConstraints(c); - int x = constraints.getX().getPreferredValue(); - int y = constraints.getY().getPreferredValue(); - int width = constraints.getWidth().getPreferredValue(); - int height = constraints.getHeight().getPreferredValue(); - - int rightEdge = offsetX + x + width; - if (rightEdge > maxX) - maxX = rightEdge; - int bottomEdge = offsetY + y + height; - if (bottomEdge > maxY) - maxY = bottomEdge; - } return new Dimension(maxX, maxY); } @@ -628,12 +797,7 @@ public class SpringLayout implements LayoutManager2 public void putConstraint(String e1, Component c1, int pad, String e2, Component c2) { - Constraints constraints1 = getConstraints(c1); - Constraints constraints2 = getConstraints(c2); - - Spring strut = Spring.constant(pad); - Spring otherEdge = constraints2.getConstraint(e2); - constraints1.setConstraint(e1, Spring.sum(strut, otherEdge)); + putConstraint(e1, c1, Spring.constant(pad), e2, c2); } /** @@ -651,9 +815,8 @@ public class SpringLayout implements LayoutManager2 Component c2) { Constraints constraints1 = getConstraints(c1); - Constraints constraints2 = getConstraints(c2); - Spring otherEdge = constraints2.getConstraint(e2); + Spring otherEdge = getConstraint(e2, c2); constraints1.setConstraint(e1, Spring.sum(s, otherEdge)); } diff --git a/libjava/classpath/javax/swing/SwingUtilities.java b/libjava/classpath/javax/swing/SwingUtilities.java index 6762ccd804a..9d8e8df38f5 100644 --- a/libjava/classpath/javax/swing/SwingUtilities.java +++ b/libjava/classpath/javax/swing/SwingUtilities.java @@ -1,5 +1,5 @@ /* SwingUtilities.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. @@ -91,23 +91,23 @@ public class SwingUtilities * of the <em>component's</em> coordinate system, where (0,0) is the * upper left corner of the component's bounds. * - * @param c The component to measure the bounds of - * @param r A Rectangle to store the return value in, or - * <code>null</code> + * @param c the component to measure the bounds of (if <code>null</code>, + * this method returns <code>null</code>). + * @param r a carrier to store the return value in (if <code>null</code>, a + * new <code>Rectangle</code> instance is created). * - * @return The calculated area inside the component and its border - * insets + * @return The calculated area inside the component and its border insets. */ public static Rectangle calculateInnerArea(JComponent c, Rectangle r) { - Rectangle b = getLocalBounds(c); - if (r == null) - r = new Rectangle(); + if (c == null) + return null; + r = c.getBounds(r); Insets i = c.getInsets(); - r.x = b.x + i.left; - r.width = b.width - i.left - i.right; - r.y = b.y + i.top; - r.height = b.height - i.top - i.bottom; + r.x = i.left; + r.width = r.width - i.left - i.right; + r.y = i.top; + r.height = r.height - i.top - i.bottom; return r; } @@ -386,20 +386,17 @@ public class SwingUtilities app = (Applet) comp; comp = comp.getParent(); } - + if (win != null) return win; - else - return app; + return app; } /** - * Return true if a descends from b, in other words if b is an - * ancestor of a. - * + * Return true if a descends from b, in other words if b is an ancestor of a. + * * @param a The child to search the ancestry of * @param b The potential ancestor to search for - * * @return true if a is a descendent of b, false otherwise */ public static boolean isDescendingFrom(Component a, Component b) @@ -600,20 +597,46 @@ public class SwingUtilities */ public static void updateComponentTreeUI(Component comp) { - if (comp == null) - return; - - if (comp instanceof Container) + updateComponentTreeUIImpl(comp); + if (comp instanceof JComponent) { - Component[] children = ((Container)comp).getComponents(); - for (int i = 0; i < children.length; ++i) - updateComponentTreeUI(children[i]); + JComponent jc = (JComponent) comp; + jc.revalidate(); } - - if (comp instanceof JComponent) - ((JComponent)comp).updateUI(); + else + { + comp.invalidate(); + comp.validate(); + } + comp.repaint(); } + /** + * Performs the actual work for {@link #updateComponentTreeUI(Component)}. + * This calls updateUI() on c if it is a JComponent, and then walks down + * the component tree and calls this method on each child component. + * + * @param c the component to update the UI + */ + private static void updateComponentTreeUIImpl(Component c) + { + if (c instanceof JComponent) + { + JComponent jc = (JComponent) c; + jc.updateUI(); + } + + Component[] components = null; + if (c instanceof JMenu) + components = ((JMenu) c).getMenuComponents(); + else if (c instanceof Container) + components = ((Container) c).getComponents(); + if (components != null) + { + for (int i = 0; i < components.length; ++i) + updateComponentTreeUIImpl(components[i]); + } + } /** * <p>Layout a "compound label" consisting of a text string and an icon @@ -1128,7 +1151,9 @@ public class SwingUtilities child = parent; parent = child.getParent(); } - child.setParent(uiActionMap); + // Sanity check to avoid loops. + if (child != uiActionMap) + child.setParent(uiActionMap); } } @@ -1170,7 +1195,9 @@ public class SwingUtilities child = parent; parent = parent.getParent(); } - child.setParent(uiInputMap); + // Sanity check to avoid loops. + if (child != uiInputMap) + child.setParent(uiInputMap); } } diff --git a/libjava/classpath/javax/swing/UIManager.java b/libjava/classpath/javax/swing/UIManager.java index bf8739daca2..e1ee28b3f1a 100644 --- a/libjava/classpath/javax/swing/UIManager.java +++ b/libjava/classpath/javax/swing/UIManager.java @@ -1,5 +1,5 @@ /* UIManager.java -- - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -121,7 +121,8 @@ public class UIManager implements Serializable /** The installed look and feel(s). */ static LookAndFeelInfo [] installed = { - new LookAndFeelInfo("Metal", "javax.swing.plaf.metal.MetalLookAndFeel") + new LookAndFeelInfo("Metal", "javax.swing.plaf.metal.MetalLookAndFeel"), + new LookAndFeelInfo("GNU", "gnu.javax.swing.plaf.gnu.GNULookAndFeel") }; /** The installed auxiliary look and feels. */ @@ -612,7 +613,10 @@ public class UIManager implements Serializable */ public static void installLookAndFeel(LookAndFeelInfo info) { - // FIXME: not yet implemented + LookAndFeelInfo[] newInstalled = new LookAndFeelInfo[installed.length + 1]; + System.arraycopy(installed, 0, newInstalled, 0, installed.length); + newInstalled[newInstalled.length - 1] = info; + setInstalledLookAndFeels(newInstalled); } /** @@ -632,7 +636,7 @@ public class UIManager implements Serializable */ public static void setInstalledLookAndFeels(UIManager.LookAndFeelInfo[] infos) { - // FIXME: not yet implemented. + installed = infos; } /** diff --git a/libjava/classpath/javax/swing/ViewportLayout.java b/libjava/classpath/javax/swing/ViewportLayout.java index 674de959f6e..b61834e9e50 100644 --- a/libjava/classpath/javax/swing/ViewportLayout.java +++ b/libjava/classpath/javax/swing/ViewportLayout.java @@ -120,80 +120,83 @@ public class ViewportLayout implements LayoutManager, Serializable } /** - * Layout the view and viewport to respect the following rules. These are - * not precisely the rules described in sun's javadocs, but they are the - * rules which sun's swing implementation follows, if you watch its - * behavior: - * - * <ol> - * - * <li>If the port is smaller than the view, leave the view at its - * current size. Also, do not move the port, <em>unless</em> the port - * extends into space <em>past</em> the edge of the view. If so, move the - * port up or to the left, in view space, by the amount of empty space - * (keep the lower and right edges lined up)</li> + * Layout the view and viewport to respect the following rules. These are not + * precisely the rules described in sun's javadocs, but they are the rules + * which sun's swing implementation follows, if you watch its behavior: + * <ol> + * <li>If the port is smaller than the view, leave the view at its current + * size.</li> + * <li>If the view is smaller than the port, the view is top aligned.</li> + * <li>If the view tracks the port size, the view position is always zero and + * the size equal to the viewport size</li> * <li>In {@link JViewport#setViewSize(Dimension)}, the view size is never * set smaller that its minimum size.</li> - * * </ol> - * + * * @see JViewport#getViewSize * @see JViewport#setViewSize * @see JViewport#getViewPosition * @see JViewport#setViewPosition */ - public void layoutContainer(Container parent) + public void layoutContainer(Container parent) { // The way to interpret this function is basically to ignore the names // of methods it calls, and focus on the variable names here. getViewRect // doesn't, for example, return the view; it returns the port bounds in - // view space. Likwise setViewPosition doesn't reposition the view; it + // view space. Likwise setViewPosition doesn't reposition the view; it // positions the port, in view coordinates. - JViewport port = (JViewport) parent; + JViewport port = (JViewport) parent; Component view = port.getView(); - + if (view == null) return; - // These dimensions and positions are in *view space*. Do not mix + // These dimensions and positions are in *view space*. Do not mix // variables in here from port space (eg. parent.getBounds()). This // function should be entirely in view space, because the methods on // the viewport require inputs in view space. Rectangle portBounds = port.getViewRect(); - Dimension viewPref = view.getPreferredSize(); - Dimension viewMinimum = view.getMinimumSize(); - + Dimension viewPref = new Dimension(view.getPreferredSize()); + Point portLowerRight = new Point(portBounds.x + portBounds.width, portBounds.y + portBounds.height); - int overextension; // vertical implementation of the above rules - if ((! (view instanceof Scrollable) && viewPref.height < portBounds.height - || (view instanceof Scrollable - && ((Scrollable) view).getScrollableTracksViewportHeight()))) - viewPref.height = portBounds.height; - - // If the view is larger than the port, and port is partly outside - // the view, it is moved fully into the view area. - overextension = portLowerRight.y - viewPref.height; - if (overextension > 0) - portBounds.y -= overextension; - - // horizontal implementation of the above rules - if ((! (view instanceof Scrollable) && viewPref.width < portBounds.width - || (view instanceof Scrollable - && ((Scrollable) view).getScrollableTracksViewportWidth()))) - viewPref.width = portBounds.width; - - // If the view is larger than the port, and port is partly outside - // the view, it is moved fully into the view area. - overextension = portLowerRight.x - viewPref.width; - if (overextension > 0) - portBounds.x -= overextension; + if (view instanceof Scrollable) + { + Scrollable sView = (Scrollable) view; + + // If the view size matches viewport size, the port offset can + // only be zero. + if (sView.getScrollableTracksViewportWidth()) + { + viewPref.width = portBounds.width; + portBounds.x = 0; + } + if (sView.getScrollableTracksViewportHeight()) + { + viewPref.height = portBounds.height; + portBounds.y = 0; + } + } + + if (viewPref.width < portBounds.width) + viewPref.width = portBounds.width; + if (viewPref.height < portBounds.height) + viewPref.height = portBounds.height; + + // If the view is larger than the port, the port is top and right + // aligned. + if (portLowerRight.x > viewPref.width) + portBounds.x = 0; + + if (portLowerRight.y > viewPref.height) + portBounds.y = 0; port.setViewSize(viewPref); port.setViewPosition(portBounds.getLocation()); } + } diff --git a/libjava/classpath/javax/swing/border/AbstractBorder.java b/libjava/classpath/javax/swing/border/AbstractBorder.java index 7cbbcdaa83b..c995de1c202 100644 --- a/libjava/classpath/javax/swing/border/AbstractBorder.java +++ b/libjava/classpath/javax/swing/border/AbstractBorder.java @@ -1,5 +1,5 @@ /* AbstractBorder.java -- - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -68,7 +68,7 @@ public abstract class AbstractBorder implements Border, Serializable * Performs nothing, because the default implementation provided by * this class is an invisible, zero-width border. Subclasses will * likely want to override this method, but they are not required - * for doing so. + * to do so. * * @param c the component whose border is to be painted. * @param g the graphics for painting. @@ -87,9 +87,11 @@ public abstract class AbstractBorder implements Border, Serializable } /** - * Measures the width of this border. + * Returns the insets required for drawing this border around the specified + * component. * - * @param c the component whose border is to be measured. + * @param c the component that the border applies to (ignored here, + * subclasses may use it). * * @return an Insets object whose <code>left</code>, <code>right</code>, * <code>top</code> and <code>bottom</code> fields indicate the @@ -104,16 +106,23 @@ public abstract class AbstractBorder implements Border, Serializable } /** - * Determines the insets of this border. The implementation provided - * by AbstractButton sets the <code>left</code>, <code>right</code>, - * <code>top</code> and <code>bottom</code> fields of the passed - * <code>insets</code> parameter to zero. + * Returns the insets required for drawing this border around the specified + * component. The default implementation provided here sets the + * <code>left</code>, <code>right</code>, <code>top</code> and + * <code>bottom</code> fields of the passed <code>insets</code> parameter to + * zero. * - * @param c the component whose border is to be measured + * @param c the component that the border applies to (ignored here, + * subclasses may use it). + * @param insets an instance that will be overwritten and returned as the + * result (<code>null</code> not permitted). * - * @return the same object that was passed for <code>insets</code> + * @return The border insets (the same object that was passed as the + * <code>insets</code> argument). * * @see #getBorderInsets(Component) + * + * @throws NullPointerException if <code>insets</code> is <code>null</code>. */ public Insets getBorderInsets(Component c, Insets insets) { @@ -126,7 +135,7 @@ public abstract class AbstractBorder implements Border, Serializable * fills every pixel in its area when painting. Partially * translucent borders must return <code>false</code>, or ugly * artifacts can appear on screen. The default implementation - * provided by AbstractBorder always returns <code>false</code>. + * provided here always returns <code>false</code>. * * @return <code>false</code>. */ @@ -136,9 +145,9 @@ public abstract class AbstractBorder implements Border, Serializable } /** - * Returns a rectangle that covers the specified area minus this - * border. Components that wish to determine an area into which - * they can safely draw without intersecting with a border might + * Returns a rectangle that covers the specified area minus the insets + * required to draw this border. Components that wish to determine an area + * into which they can safely draw without intersecting with a border might * want to use this helper method. * * @param c the component in the center of this border. @@ -146,24 +155,30 @@ public abstract class AbstractBorder implements Border, Serializable * @param y the vertical position of the border. * @param width the width of the available area for the border. * @param height the height of the available area for the border. + * + * @return The interior rectangle. */ public Rectangle getInteriorRectangle(Component c, int x, int y, int width, int height) { - return getInteriorRectangle (c, this, x, y, width, height); + return getInteriorRectangle(c, this, x, y, width, height); } /** - * Returns a rectangle that covers the specified area minus a - * border. Components that wish to determine an area into which - * they can safely draw without intersecting with a border might - * want to use this helper method. + * Returns a rectangle that covers the specified area minus the insets + * required to draw the specified border (if the border is <code>null</code>, + * zero insets are assumed). Components that wish to determine an area into + * which they can safely draw without intersecting with a border might want + * to use this helper method. * * @param c the component in the center of this border. + * @param b the border (<code>null</code> permitted). * @param x the horizontal position of the border. * @param y the vertical position of the border. * @param width the width of the available area for the border. * @param height the height of the available area for the border. + * + * @return The interior rectangle. */ public static Rectangle getInteriorRectangle(Component c, Border b, int x, int y, int width, int height) @@ -172,7 +187,7 @@ public abstract class AbstractBorder implements Border, Serializable if (b != null) { - borderInsets = b.getBorderInsets (c); + borderInsets = b.getBorderInsets(c); x += borderInsets.left; y += borderInsets.top; width -= borderInsets.left + borderInsets.right; diff --git a/libjava/classpath/javax/swing/border/BevelBorder.java b/libjava/classpath/javax/swing/border/BevelBorder.java index 45b758cae41..403c35c045e 100644 --- a/libjava/classpath/javax/swing/border/BevelBorder.java +++ b/libjava/classpath/javax/swing/border/BevelBorder.java @@ -305,6 +305,8 @@ public class BevelBorder extends AbstractBorder * * @param c the component enclosed by this border. * + * @return The color. + * * @see #getHighlightInnerColor(java.awt.Component) * @see java.awt.Color#brighter() */ @@ -326,6 +328,8 @@ public class BevelBorder extends AbstractBorder * * @param c the component enclosed by this border. * + * @return The color. + * * @see java.awt.Component#getBackground() * @see java.awt.Color#brighter() */ @@ -347,6 +351,8 @@ public class BevelBorder extends AbstractBorder * * @param c the component enclosed by this border. * + * @return The color. + * * @see java.awt.Component#getBackground() * @see java.awt.Color#darker() */ @@ -367,6 +373,8 @@ public class BevelBorder extends AbstractBorder * * @param c the component enclosed by this border. * + * @return The color. + * * @see #getShadowInnerColor(java.awt.Component) * @see java.awt.Color#darker() */ @@ -384,6 +392,8 @@ public class BevelBorder extends AbstractBorder * highlighted edges when painting the border, or <code>null</code> * if that color will be derived from the background of the enclosed * Component. + * + * @return The color (possibly <code>null</code>). */ public Color getHighlightOuterColor() { @@ -396,6 +406,8 @@ public class BevelBorder extends AbstractBorder * highlighted edges when painting the border, or <code>null</code> * if that color will be derived from the background of the enclosed * Component. + * + * @return The color (possibly <code>null</code>). */ public Color getHighlightInnerColor() { @@ -408,6 +420,8 @@ public class BevelBorder extends AbstractBorder * shadowed edges when painting the border, or <code>null</code> if * that color will be derived from the background of the enclosed * Component. + * + * @return The color (possibly <code>null</code>). */ public Color getShadowInnerColor() { @@ -420,6 +434,8 @@ public class BevelBorder extends AbstractBorder * shadowed edges when painting the border, or <code>null</code> if * that color will be derived from the background of the enclosed * Component. + * + * @return The color (possibly <code>null</code>). */ public Color getShadowOuterColor() { @@ -430,6 +446,8 @@ public class BevelBorder extends AbstractBorder /** * Returns the appearance of this border, which is either {@link * #RAISED} or {@link #LOWERED}. + * + * @return The bevel type ({@link #RAISED} or {@link #LOWERED}). */ public int getBevelType() { diff --git a/libjava/classpath/javax/swing/border/CompoundBorder.java b/libjava/classpath/javax/swing/border/CompoundBorder.java index 998a9bab3bd..a69c5e20aeb 100644 --- a/libjava/classpath/javax/swing/border/CompoundBorder.java +++ b/libjava/classpath/javax/swing/border/CompoundBorder.java @@ -224,6 +224,8 @@ public class CompoundBorder extends AbstractBorder * Returns the outside border, which is painted outside both the * bordered Component and the inside border. It is valid for the * result to be <code>null</code>. + * + * @return The outside border (possibly <code>null</code>). */ public Border getOutsideBorder() { @@ -234,6 +236,8 @@ public class CompoundBorder extends AbstractBorder * Returns the inside border, which is painted between the bordered * Component and the outside border. It is valid for the result to * be <code>null</code>. + * + * @return The inside border (possibly <code>null</code>). */ public Border getInsideBorder () { diff --git a/libjava/classpath/javax/swing/border/EtchedBorder.java b/libjava/classpath/javax/swing/border/EtchedBorder.java index 22882b78cb1..cd48b18dad3 100644 --- a/libjava/classpath/javax/swing/border/EtchedBorder.java +++ b/libjava/classpath/javax/swing/border/EtchedBorder.java @@ -281,6 +281,8 @@ public class EtchedBorder extends AbstractBorder /** * Returns the appearance of this EtchedBorder, which is either * {@link #RAISED} or {@link #LOWERED}. + * + * @return The type ({@link #RAISED} or {@link #LOWERED}). */ public int getEtchType() { @@ -297,6 +299,8 @@ public class EtchedBorder extends AbstractBorder * * @param c the component enclosed by this border. * + * @return The color. + * * @see java.awt.Component#getBackground() * @see java.awt.Color#brighter() */ @@ -312,6 +316,8 @@ public class EtchedBorder extends AbstractBorder * Returns the color that will be used for highlighted parts when * painting the border, or <code>null</code> if that color will be * derived from the background of the enclosed Component. + * + * @return The highlight color (possibly <code>null</code>). */ public Color getHighlightColor() { @@ -328,6 +334,8 @@ public class EtchedBorder extends AbstractBorder * * @param c the component enclosed by this border. * + * @return The shadow color. + * * @see java.awt.Component#getBackground() * @see java.awt.Color#darker() */ @@ -344,6 +352,8 @@ public class EtchedBorder extends AbstractBorder * Returns the color that will be used for shadowed parts when * painting the border, or <code>null</code> if that color will be * derived from the background of the enclosed Component. + * + * @return The shadow color (possibly <code>null</code>). */ public Color getShadowColor() { diff --git a/libjava/classpath/javax/swing/border/LineBorder.java b/libjava/classpath/javax/swing/border/LineBorder.java index 36abddd915d..31e19fe1f2e 100644 --- a/libjava/classpath/javax/swing/border/LineBorder.java +++ b/libjava/classpath/javax/swing/border/LineBorder.java @@ -162,8 +162,10 @@ public class LineBorder extends AbstractBorder /** - * Returns a black, one pixel thick, plain LineBorder. The method - * may always return the same (singleton) LineBorder instance. + * Returns a black, one pixel thick, plain {@link LineBorder}. The method + * may always return the same (singleton) {@link LineBorder} instance. + * + * @return The border. */ public static Border createBlackLineBorder() { @@ -178,8 +180,10 @@ public class LineBorder extends AbstractBorder /** - * Returns a gray, one pixel thick, plain LineBorder. The method - * may always return the same (singleton) LineBorder instance. + * Returns a gray, one pixel thick, plain {@link LineBorder}. The method + * may always return the same (singleton) {@link LineBorder} instance. + * + * @return The border. */ public static Border createGrayLineBorder() { @@ -295,6 +299,8 @@ public class LineBorder extends AbstractBorder /** * Returns the color of the line. + * + * @return The line color (never <code>null</code>). */ public Color getLineColor() { @@ -304,6 +310,8 @@ public class LineBorder extends AbstractBorder /** * Returns the thickness of the line in pixels. + * + * @return The line thickness (in pixels). */ public int getThickness() { diff --git a/libjava/classpath/javax/swing/border/MatteBorder.java b/libjava/classpath/javax/swing/border/MatteBorder.java index 4d5b8c25360..114cac62338 100644 --- a/libjava/classpath/javax/swing/border/MatteBorder.java +++ b/libjava/classpath/javax/swing/border/MatteBorder.java @@ -299,6 +299,8 @@ public class MatteBorder extends EmptyBorder * Returns the color that is used for filling the border, or * <code>null</code> if the border is filled with repetitions of a * tile icon. + * + * @return The color (possibly <code>null</code>). */ public Color getMatteColor() { @@ -310,6 +312,8 @@ public class MatteBorder extends EmptyBorder * Returns the icon is used for tiling the border, or * <code>null</code> if the border is filled with a color instead of * an icon. + * + * @return The icon (possibly <code>null</code>). */ public Icon getTileIcon() { diff --git a/libjava/classpath/javax/swing/border/TitledBorder.java b/libjava/classpath/javax/swing/border/TitledBorder.java index 8d3ee13d4bb..38b57542334 100644 --- a/libjava/classpath/javax/swing/border/TitledBorder.java +++ b/libjava/classpath/javax/swing/border/TitledBorder.java @@ -912,8 +912,10 @@ public class TitledBorder extends AbstractBorder * Calculates the minimum size needed for displaying the border * and its title. * - * @param c the Component for which this TitledBorder consitutes + * @param c the Component for which this TitledBorder constitutes * a border. + * + * @return The minimum size. */ public Dimension getMinimumSize(Component c) { @@ -980,6 +982,10 @@ public class TitledBorder extends AbstractBorder /** * 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) { @@ -1172,6 +1178,8 @@ public class TitledBorder extends AbstractBorder /** * 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() { diff --git a/libjava/classpath/javax/swing/colorchooser/ColorSelectionModel.java b/libjava/classpath/javax/swing/colorchooser/ColorSelectionModel.java index 5f3070813ce..b660505fc17 100644 --- a/libjava/classpath/javax/swing/colorchooser/ColorSelectionModel.java +++ b/libjava/classpath/javax/swing/colorchooser/ColorSelectionModel.java @@ -1,5 +1,5 @@ /* ColorSelectionModel.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. @@ -40,42 +40,47 @@ package javax.swing.colorchooser; import java.awt.Color; +import javax.swing.JColorChooser; +import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** - * ColorSelectionModel + * A model that is used by the {@link JColorChooser} component to represent the + * selected color. + * * @author Andrew Selkirk - * @version 1.0 */ -public interface ColorSelectionModel { - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getSelectedColor - * @returns Color - */ - Color getSelectedColor(); - - /** - * setSelectedColor - * @param color TODO - */ - void setSelectedColor(Color color); - - /** - * addChangeListener - * @param listener TODO - */ - void addChangeListener(ChangeListener listener); - - /** - * removeChangeListener - * @param listener TODO - */ - void removeChangeListener(ChangeListener listener); - - -} // ColorSelectionModel +public interface ColorSelectionModel +{ + + /** + * Returns the selected color. + * + * @return The selected color. + */ + Color getSelectedColor(); + + /** + * Sets the selected color. + * + * @param color the selected color. + */ + void setSelectedColor(Color color); + + /** + * Registers a listener to receive {@link ChangeEvent} notifications + * from this model. + * + * @param listener the listener. + */ + void addChangeListener(ChangeListener listener); + + /** + * Deregisters a listener so that it no longer receives {@link ChangeEvent} + * notifications from this action. + * + * @param listener the listener. + */ + void removeChangeListener(ChangeListener listener); + +} diff --git a/libjava/classpath/javax/swing/event/ChangeEvent.java b/libjava/classpath/javax/swing/event/ChangeEvent.java index f75c15aac83..8854282a9fc 100644 --- a/libjava/classpath/javax/swing/event/ChangeEvent.java +++ b/libjava/classpath/javax/swing/event/ChangeEvent.java @@ -1,5 +1,5 @@ /* ChangeEvent.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,23 +37,30 @@ exception statement from your version. */ package javax.swing.event; -// Imports import java.util.EventObject; /** - * ChangeEvent + * An event used to signal a state change for an object. + * + * @see ChangeListener + * @see CellEditorListener + * @see TableColumnModelListener + * * @author Andrew Selkirk * @author Ronald Veldema */ -public class ChangeEvent extends EventObject { +public class ChangeEvent + extends EventObject +{ - /** - * ChangeEvent constructor - * @param source Source object - */ - public ChangeEvent(Object source) { - super(source); - } // ChangeEvent() + /** + * Creates a new <code>ChangeEvent</code> instance for the specified source. + * + * @param source the source for the event (<code>null</code> not permitted). + */ + public ChangeEvent(Object source) + { + super(source); + } - -} // ChangeEvent +} diff --git a/libjava/classpath/javax/swing/event/ChangeListener.java b/libjava/classpath/javax/swing/event/ChangeListener.java index 1e58b1d82d9..75809707bd4 100644 --- a/libjava/classpath/javax/swing/event/ChangeListener.java +++ b/libjava/classpath/javax/swing/event/ChangeListener.java @@ -1,5 +1,5 @@ /* ChangeListener.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,21 +37,27 @@ exception statement from your version. */ package javax.swing.event; -// Imports import java.util.EventListener; /** - * ChangeListener interface + * A <code>ChangeListener</code> can register with an object to receive + * notification of state changes (for objects that support this mechanism). + * * @author Andrew Selkirk * @author Ronald Veldema */ -public interface ChangeListener extends EventListener { - - /** - * State changed - * @param event Change Event - */ - void stateChanged(ChangeEvent event); - - -} // ChangeListener +public interface ChangeListener + extends EventListener +{ + + /** + * Called by an object to notify the listener that the object's state has + * changed. The incoming <code>event</code> identifies the + * <code>source</code> of the event, allowing the listener to differentiate + * when it is listening for changes in multiple sources. + * + * @param event the change event. + */ + void stateChanged(ChangeEvent event); + +} diff --git a/libjava/classpath/javax/swing/event/InternalFrameEvent.java b/libjava/classpath/javax/swing/event/InternalFrameEvent.java index badfa80aca7..4e289bfb71c 100644 --- a/libjava/classpath/javax/swing/event/InternalFrameEvent.java +++ b/libjava/classpath/javax/swing/event/InternalFrameEvent.java @@ -1,5 +1,5 @@ /* InternalFrameEvent.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. @@ -43,6 +43,8 @@ import java.awt.AWTEvent; import javax.swing.JInternalFrame; /** + * An event that indicates a change to a {@link JInternalFrame} component. + * * @author Andrew Selkirk */ public class InternalFrameEvent extends AWTEvent @@ -50,55 +52,59 @@ public class InternalFrameEvent extends AWTEvent private static final long serialVersionUID = -5204823611874873183L; /** - * Internal frame activated event + * Internal frame activated event. */ public static final int INTERNAL_FRAME_ACTIVATED = 25554; /** - * Internal frame closed event + * Internal frame closed event. */ public static final int INTERNAL_FRAME_CLOSED = 25551; /** - * Internal frame closing event + * Internal frame closing event. */ public static final int INTERNAL_FRAME_CLOSING = 25550; /** - * Internal frame deactivated event + * Internal frame deactivated event. */ public static final int INTERNAL_FRAME_DEACTIVATED = 25555; /** - * Internal frame deiconifed event + * Internal frame deiconifed event. */ public static final int INTERNAL_FRAME_DEICONIFIED = 25553; /** - * Internal frame frame first event + * Internal frame frame first event. */ public static final int INTERNAL_FRAME_FIRST = 25549; /** - * Internal frame iconified event + * Internal frame iconified event. */ public static final int INTERNAL_FRAME_ICONIFIED = 25552; /** - * Internal frame last event + * Internal frame last event. */ public static final int INTERNAL_FRAME_LAST = 25555; /** - * Internal frame opened event + * Internal frame opened event. */ public static final int INTERNAL_FRAME_OPENED = 25549; /** - * Creates a <code>JInternalFrameEvent</code> object. + * Creates a new <code>JInternalFrameEvent</code> instance. * - * @param source The source of this event. - * @param id Then event ID of this event. + * @param source the source of this event (<code>null</code> not permitted). + * @param id the event ID of this event (see the constants defined by this + * class). + * + * @throws IllegalArgumentException if <code>source</code> is + * <code>null</code>. */ public InternalFrameEvent(JInternalFrame source, int id) { @@ -106,10 +112,43 @@ public class InternalFrameEvent extends AWTEvent } /** - * Returns the <code>JInternalFrame</code> object stored in this event. + * Returns the <code>JInternalFrame</code> component that is the source for + * this event. + * + * @return The source. + * + * @since 1.3 */ public JInternalFrame getInternalFrame() { return (JInternalFrame) source; } + + /** + * Returns a string that indicates the event id. This is used by the + * {@link #toString()} method. + * + * @return A string that indicates the event id. + */ + public String paramString() + { + switch (id) { + case INTERNAL_FRAME_ACTIVATED: + return "INTERNAL_FRAME_ACTIVATED"; + case INTERNAL_FRAME_CLOSED: + return "INTERNAL_FRAME_CLOSED"; + case INTERNAL_FRAME_CLOSING: + return "INTERNAL_FRAME_CLOSING"; + case INTERNAL_FRAME_DEACTIVATED: + return "INTERNAL_FRAME_DEACTIVATED"; + case INTERNAL_FRAME_DEICONIFIED: + return "INTERNAL_FRAME_DEICONIFIED"; + case INTERNAL_FRAME_ICONIFIED: + return "INTERNAL_FRAME_ICONIFIED"; + case INTERNAL_FRAME_OPENED: + return "INTERNAL_FRAME_OPENED"; + default: + return "unknown type"; + } + } } diff --git a/libjava/classpath/javax/swing/event/TableColumnModelListener.java b/libjava/classpath/javax/swing/event/TableColumnModelListener.java index 90e1b29cc57..522e0a8c6ae 100644 --- a/libjava/classpath/javax/swing/event/TableColumnModelListener.java +++ b/libjava/classpath/javax/swing/event/TableColumnModelListener.java @@ -1,5 +1,5 @@ /* TableColumnModelListener.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,44 +37,58 @@ exception statement from your version. */ package javax.swing.event; -// Imports import java.util.EventListener; +import javax.swing.table.TableColumnModel; + /** - * TableColumnModelListener public interface + * A <code>TableColumnModelListener</code> can register with a + * {@link TableColumnModel} to receive notification of changes to the model. + * * @author Andrew Selkirk */ -public interface TableColumnModelListener extends EventListener { - - /** - * Column added - * @param event Table Column Model Event - */ - void columnAdded(TableColumnModelEvent event); - - /** - * Column margin changed - * @param event Change Event - */ - void columnMarginChanged(ChangeEvent event); - - /** - * Column moved - * @param event Table Column Model Event - */ - void columnMoved(TableColumnModelEvent event); - - /** - * Column removed - * @param event Table Column Model Event - */ - void columnRemoved(TableColumnModelEvent event); - - /** - * Column selection changed - * @param event List Selection Event - */ - void columnSelectionChanged(ListSelectionEvent event); - - -} // TableColumnModelListener +public interface TableColumnModelListener + extends EventListener +{ + + /** + * Called by the {@link TableColumnModel} to indicate that a column has been + * added to the model. + * + * @param event information about the column addition. + */ + void columnAdded(TableColumnModelEvent event); + + /** + * Called by the {@link TableColumnModel} to indicate that the model's + * column margin has changed. + * + * @param event the event (identifies the source). + */ + void columnMarginChanged(ChangeEvent event); + + /** + * Called by the {@link TableColumnModel} to indicate that a column has been + * moved. + * + * @param event information about the column move. + */ + void columnMoved(TableColumnModelEvent event); + + /** + * Called by the {@link TableColumnModel} to indicate that a column has been + * removed from the model. + * + * @param event information about the column removal. + */ + void columnRemoved(TableColumnModelEvent event); + + /** + * Called by the {@link TableColumnModel} to indicate that the column + * selection state has changed. + * + * @param event information about the column selection state. + */ + void columnSelectionChanged(ListSelectionEvent event); + +} diff --git a/libjava/classpath/javax/swing/event/TreeSelectionEvent.java b/libjava/classpath/javax/swing/event/TreeSelectionEvent.java index 1930677af9f..532a1dbf6d6 100644 --- a/libjava/classpath/javax/swing/event/TreeSelectionEvent.java +++ b/libjava/classpath/javax/swing/event/TreeSelectionEvent.java @@ -41,41 +41,57 @@ package javax.swing.event; import java.util.EventObject; import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; /** - * TreeSelectionEvent + * An event that carries information about a change to a + * {@link TreeSelectionModel}. + * + * @see TreeSelectionListener + * * @author Andrew Selkirk - * @version 1.0 */ -public class TreeSelectionEvent extends EventObject { +public class TreeSelectionEvent extends EventObject +{ /** - * paths + * The paths that have been added or removed from the selection. */ protected TreePath[] paths; /** - * areNew + * Flags indicating if the paths were added (<code>true</code>) or removed + * (<code>false</code>) from the selection. */ protected boolean[] areNew; /** - * oldLeadSelectionPath + * The old lead selection path (may be <code>null</code>). */ protected TreePath oldLeadSelectionPath; /** - * newLeadSelectionPath + * The new lead selection path (may be <code>null</code>). */ protected TreePath newLeadSelectionPath; /** - * Constructor TreeSelectionEvent - * @param source TODO - * @param paths TODO - * @param areNew TODO - * @param oldLeadSelectionPath TODO - * @param newLeadSelectionPath TODO + * Creates a new <code>TreeSelectionEvent</code>. + * + * @param source the source (usually a {@link TreeSelectionModel}, + * <code>null</code> not permitted). + * @param paths an array of the paths that have been added to or removed + * from the selection. + * @param areNew a flag for each path where <code>true</code> indicates the + * corresponding path has been added to the selection and + * <code>false</code> indicates the path has been removed. + * @param oldLeadSelectionPath the old lead selection path (<code>null</code> + * permitted). + * @param newLeadSelectionPath the new lead selection path (<code>null</code> + * permitted). + * + * @throws IllegalArgumentException if <code>source</code> is + * <code>null</code>. */ public TreeSelectionEvent(Object source, TreePath[] paths, boolean[] areNew, TreePath oldLeadSelectionPath, @@ -89,12 +105,21 @@ public class TreeSelectionEvent extends EventObject { } /** - * Constructor TreeSelectionEvent - * @param source TODO - * @param path TODO - * @param isNew TODO - * @param oldLeadSelectionPath TODO - * @param newLeadSelectionPath TODO + * Creates a new <code>TreeSelectionEvent</code>. + * + * @param source the event source (usually a {@link TreeSelectionModel}, + * <code>null</code> not permitted). + * @param path the path. + * @param isNew <code>true</code> indicates that <code>path</code> has been + * added to the selection, and <code>false</code> indicates that it has + * been removed. + * @param oldLeadSelectionPath the old lead selection path (<code>null</code> + * permitted). + * @param newLeadSelectionPath the new lead selection path (<code>null</code> + * permitted). + * + * @throws IllegalArgumentException if <code>source</code> is + * <code>null</code>. */ public TreeSelectionEvent(Object source, TreePath path, boolean isNew, TreePath oldLeadSelectionPath, @@ -108,7 +133,11 @@ public class TreeSelectionEvent extends EventObject { } /** - * @return the first path element + * Returns the first path element. + * + * @return The first path element. + * + * @see #getPaths() */ public TreePath getPath() { @@ -116,8 +145,11 @@ public class TreeSelectionEvent extends EventObject { } /** + * Returns an array of the paths that changed in the selection. + * + * @return The paths that changed in the selection. * - * @return the paths with selection changed + * @see #isAddedPath(TreePath) */ public TreePath[] getPaths() { @@ -125,7 +157,13 @@ public class TreeSelectionEvent extends EventObject { } /** - * @return true if the first path is added to the selection, false otherwise + * Returns <code>true</code> if the path returned by {@link #getPath()} has + * been added to the selection, and <code>false</code> if it has been + * removed. + * + * @return A boolean. + * + * @see #isAddedPath(int) */ public boolean isAddedPath() { @@ -133,21 +171,42 @@ public class TreeSelectionEvent extends EventObject { } /** - * @param path the path to check - * @return true if the path is added to the selection, false otherwise + * Returns <code>true</code> if <code>path</code> has been added to the + * selection, and <code>false</code> if the path has been removed from the + * selection. + * + * @param path the path to check. + * + * @return A flag indicating whether the path has been added to, or removed + * from, the selection. + * + * @throw IllegalArgumentException if <code>path</code> is not one of the + * paths in {@link #getPaths()}. + * + * @see #isAddedPath(int) */ public boolean isAddedPath(TreePath path) { for (int i = paths.length - 1; i >= 0; i--) if (paths[i].equals(path)) - return areNew[i]; + return areNew[i]; - return false; + throw new IllegalArgumentException("Unknown 'path' argument."); } /** - * @param index the index'th path - * @return true if the path is added to the selection, false otherwise + * Returns <code>true</code> if the path at the specified index has been + * added to the selection, and <code>false</code> if the path has been + * removed from the selection. + * + * @param index the path index. + * + * @return A flag indicating whether the path has been added to, or removed + * from, the selection. + * + * @since 1.3 + * + * @see #isAddedPath(TreePath) */ public boolean isAddedPath(int index) { @@ -155,7 +214,11 @@ public class TreeSelectionEvent extends EventObject { } /** - * @return the previous lead selection path + * Returns the old lead selection path. + * + * @return The old lead selection path (possibly <code>null</code>). + * + * @see #getNewLeadSelectionPath() */ public TreePath getOldLeadSelectionPath() { @@ -163,7 +226,11 @@ public class TreeSelectionEvent extends EventObject { } /** - * @return the current lead selection path + * Returns the new lead selection path. + * + * @return The new lead selection path (possibly <code>null</code>). + * + * @see #getOldLeadSelectionPath() */ public TreePath getNewLeadSelectionPath() { @@ -171,14 +238,20 @@ public class TreeSelectionEvent extends EventObject { } /** - * @param source the new event source - * @return a cloned event with another event source + * Creates a shallow copy of this <code>TreeSelectionEvent</code>, replacing + * the source with <code>source</code>. + * + * @param source the new event source (<code>null</code> not permitted). + * + * @return A cloned event with another event source. + * + * @throws IllegalArgumentException if <code>source</code> is + * <code>null</code>. */ public Object cloneWithSource(Object source) { - return new TreeSelectionEvent (source, paths, areNew, - oldLeadSelectionPath, - newLeadSelectionPath); + return new TreeSelectionEvent (source, paths, areNew, oldLeadSelectionPath, + newLeadSelectionPath); } } diff --git a/libjava/classpath/javax/swing/event/TreeSelectionListener.java b/libjava/classpath/javax/swing/event/TreeSelectionListener.java index b844a6e0b51..2171e39d69f 100644 --- a/libjava/classpath/javax/swing/event/TreeSelectionListener.java +++ b/libjava/classpath/javax/swing/event/TreeSelectionListener.java @@ -1,5 +1,5 @@ /* TreeSelectionListener.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,20 +37,24 @@ exception statement from your version. */ package javax.swing.event; -// Imports import java.util.EventListener; +import javax.swing.tree.TreeSelectionModel; + /** - * TreeSelectionListener public interface + * A listener that receives {@link TreeSelectionEvent} notifications from a + * source (such as a {@link TreeSelectionModel}). + * * @author Andrew Selkirk */ -public interface TreeSelectionListener extends EventListener { - - /** - * Value changed - * @param event Tree Selection Event - */ - void valueChanged(TreeSelectionEvent event); +public interface TreeSelectionListener extends EventListener +{ + /** + * Receives notification of a change to a tree selection model. + * + * @param event information about the event. + */ + void valueChanged(TreeSelectionEvent event); -} // TreeSelectionListener +} diff --git a/libjava/classpath/javax/swing/filechooser/FileFilter.java b/libjava/classpath/javax/swing/filechooser/FileFilter.java index ecfa54b5814..de11525a2bd 100644 --- a/libjava/classpath/javax/swing/filechooser/FileFilter.java +++ b/libjava/classpath/javax/swing/filechooser/FileFilter.java @@ -1,5 +1,5 @@ /* FileFilter.java -- - Copyright (C) 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -67,7 +67,7 @@ public abstract class FileFilter * * @param file the file. * - * @returns A boolean. + * @return A boolean. */ public abstract boolean accept(File file); @@ -78,7 +78,7 @@ public abstract class FileFilter * is used to select the appropriate filter (in cases where more than one * filter is available). * - * @returns A description of the filter. + * @return A description of the filter. */ public abstract String getDescription(); diff --git a/libjava/classpath/javax/swing/filechooser/FileView.java b/libjava/classpath/javax/swing/filechooser/FileView.java index ea1989f9353..8c2be32ef51 100644 --- a/libjava/classpath/javax/swing/filechooser/FileView.java +++ b/libjava/classpath/javax/swing/filechooser/FileView.java @@ -1,5 +1,5 @@ /* FileView.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. @@ -118,7 +118,7 @@ public abstract class FileView * * @param directory the directory. * - * @returns Always <code>null</code>. + * @return Always <code>null</code>. */ public Boolean isTraversable(File directory) { diff --git a/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java b/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java index c2f65965e09..96dfd2e1b1a 100644 --- a/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java +++ b/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java @@ -37,8 +37,11 @@ exception statement from your version. */ package javax.swing.filechooser; +import gnu.classpath.NotImplementedException; + import java.io.File; import java.io.IOException; + import javax.swing.Icon; @@ -110,6 +113,7 @@ class UnixFileSystemView extends FileSystemView * @return <code>null</code>. */ public String getSystemDisplayName(File f) + throws NotImplementedException { // FIXME: Implement; return null; @@ -124,6 +128,7 @@ class UnixFileSystemView extends FileSystemView * @return <code>null</code>. */ public Icon getSystemIcon(File f) + throws NotImplementedException { // FIXME: Implement; return null; @@ -138,6 +143,7 @@ class UnixFileSystemView extends FileSystemView * @return <code>null</code>. */ public String getSystemTypeDescription(File f) + throws NotImplementedException { // FIXME: Implement. return null; diff --git a/libjava/classpath/javax/swing/plaf/ComboBoxUI.java b/libjava/classpath/javax/swing/plaf/ComboBoxUI.java index 3e81ed75a6b..58f6e815cb3 100644 --- a/libjava/classpath/javax/swing/plaf/ComboBoxUI.java +++ b/libjava/classpath/javax/swing/plaf/ComboBoxUI.java @@ -1,5 +1,5 @@ /* ComboBoxUI.java -- - Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,9 +41,7 @@ import javax.swing.JComboBox; /** * An abstract base class for delegates that implement the pluggable - * look and feel for a <code>JButton</code>. - * - * @see javax.swing.JComboBox + * look and feel for a {@link JComboBox}. * * @author Andrew Selkirk * @author Sascha Brawer (brawer@dandelis.ch) @@ -57,8 +55,7 @@ public abstract class ComboBoxUI extends ComponentUI { // Nothing to do here. } - - + /** * Sets the visibility of the popup button. * @@ -70,7 +67,6 @@ public abstract class ComboBoxUI extends ComponentUI */ public abstract void setPopupVisible(JComboBox c, boolean visible); - /** * Determines whether the popup button is currently visible. * @@ -82,15 +78,15 @@ public abstract class ComboBoxUI extends ComponentUI */ public abstract boolean isPopupVisible(JComboBox c); - /** * Determines whether the combo box can receive input focus. * * @param c <code>JComboBox</code> whose focus traversability * is to be retrieved. * - * @returns <code>true</code> if <code>c</code> can receive + * @return <code>true</code> if <code>c</code> can receive * input focus, <code>false</code> otherwise. */ public abstract boolean isFocusTraversable(JComboBox c); + } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java index 1fca694519f..89e99a29a31 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java @@ -52,6 +52,7 @@ import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.ButtonModel; import javax.swing.JComponent; +import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -204,14 +205,12 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener, { AbstractButton button = (AbstractButton) e.getSource(); ButtonModel model = button.getModel(); - if (button.isRolloverEnabled()) + if (button.isRolloverEnabled() + && ! SwingUtilities.isLeftMouseButton(e)) model.setRollover(true); - - if (model.isPressed() - && (e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) + + if (model.isPressed()) model.setArmed(true); - else - model.setArmed(false); } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java index 7a63331b9c8..7dbcb91467e 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java @@ -156,7 +156,8 @@ public class BasicButtonUI extends ButtonUI LookAndFeel.installColorsAndFont(b, prefix + "background", prefix + "foreground", prefix + "font"); LookAndFeel.installBorder(b, prefix + "border"); - b.setMargin(UIManager.getInsets(prefix + "margin")); + if (b.getMargin() == null || b.getMargin() instanceof UIResource) + b.setMargin(UIManager.getInsets(prefix + "margin")); b.setIconTextGap(UIManager.getInt(prefix + "textIconGap")); b.setInputMap(JComponent.WHEN_FOCUSED, (InputMap) UIManager.get(prefix + "focusInputMap")); @@ -171,11 +172,15 @@ public class BasicButtonUI extends ButtonUI { if (b.getFont() instanceof UIResource) b.setFont(null); - b.setForeground(null); - b.setBackground(null); - b.setBorder(null); + if (b.getForeground() instanceof UIResource) + b.setForeground(null); + if (b.getBackground() instanceof UIResource) + b.setBackground(null); + if (b.getBorder() instanceof UIResource) + b.setBorder(null); b.setIconTextGap(defaultTextIconGap); - b.setMargin(null); + if (b.getMargin() instanceof UIResource) + b.setMargin(null); } protected BasicButtonListener listener; @@ -308,7 +313,7 @@ public class BasicButtonUI extends ButtonUI * @param c The component to paint the state of */ public void paint(Graphics g, JComponent c) - { + { AbstractButton b = (AbstractButton) c; Rectangle tr = new Rectangle(); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java index 831dde8c336..d8792619656 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java @@ -1,5 +1,5 @@ /* BasicComboBoxEditor.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -177,4 +177,5 @@ public class BasicComboBoxEditor extends Object implements ComboBoxEditor, // Nothing to do here. } } + } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java index 8115605b77a..48195ff293b 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java @@ -40,15 +40,13 @@ package javax.swing.plaf.basic; import java.awt.Component; import java.awt.Dimension; -import java.awt.FontMetrics; import java.io.Serializable; +import javax.swing.Icon; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.ListCellRenderer; -import javax.swing.SwingConstants; -import javax.swing.SwingUtilities; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; @@ -64,14 +62,14 @@ public class BasicComboBoxRenderer /** * A shared border instance for all renderers. */ - protected static Border noFocusBorder = new EmptyBorder(0, 0, 0, 0); + protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); /** * Creates a new <code>BasicComboBoxRenderer</code> object. */ public BasicComboBoxRenderer() { - setHorizontalAlignment(SwingConstants.LEFT); + setOpaque(true); setBorder(noFocusBorder); } @@ -103,32 +101,7 @@ public class BasicComboBoxRenderer int index, boolean isSelected, boolean cellHasFocus) { - String s = value.toString(); - - // String maybe larger than comboBox. - FontMetrics fm = getToolkit().getFontMetrics(list.getFont()); - int strWidth = SwingUtilities.computeStringWidth(fm, s); - int cbWidth = getSize().width; - if (cbWidth != 0 && strWidth > cbWidth) - { - char[] str = s.toCharArray(); - int currWidth = 0; - int i = 0; - String postStr = "... "; - cbWidth -= SwingUtilities.computeStringWidth(fm, postStr); - while (i < str.length && currWidth < cbWidth) - { - ++i; - currWidth = SwingUtilities.computeStringWidth(fm, new String(str, 0, i)); - } - setText(new String(str, 0, i) + postStr); - } - else - setText(s); - - setOpaque(true); - - if (isSelected || cellHasFocus) + if (isSelected) { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); @@ -138,9 +111,13 @@ public class BasicComboBoxRenderer setBackground(list.getBackground()); setForeground(list.getForeground()); } - - setEnabled(list.isEnabled()); setFont(list.getFont()); + + if (value instanceof Icon) + setIcon((Icon) value); + else + setText(value == null ? "" : value.toString()); + return this; } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java index 288a8d89f7e..557eea93f07 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -38,12 +38,13 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; -import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; import java.awt.LayoutManager; @@ -55,8 +56,6 @@ import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.beans.PropertyChangeEvent; @@ -66,13 +65,13 @@ import javax.accessibility.Accessible; import javax.swing.CellRendererPane; import javax.swing.ComboBoxEditor; import javax.swing.ComboBoxModel; +import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.ListCellRenderer; import javax.swing.LookAndFeel; -import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; @@ -129,11 +128,6 @@ public class BasicComboBoxUI extends ComboBoxUI protected KeyListener keyListener; /** - * A listener listening to mouse events occuring in the {@link JComboBox}. - */ - private MouseListener mouseListener; - - /** * List used when rendering selected item of the combo box. The selection * and foreground colors for combo box renderer are configured from this * list. @@ -161,36 +155,14 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected PropertyChangeListener propertyChangeListener; - /** - * The button background. - * @see #installDefaults() - */ - private Color buttonBackground; - - /** - * The button shadow. - * @see #installDefaults() - */ - private Color buttonShadow; - - /** - * The button dark shadow. - * @see #installDefaults() - */ - private Color buttonDarkShadow; - - /** - * The button highlight. - * @see #installDefaults() - */ - private Color buttonHighlight; - /* Size of the largest item in the comboBox * This is package-private to avoid an accessor method. */ - Dimension displaySize; + Dimension displaySize = new Dimension(); - // FIXME: This field isn't used anywhere at this moment. + /** + * Used to render the combo box values. + */ protected CellRendererPane currentValuePane; /** @@ -209,7 +181,8 @@ public class BasicComboBoxUI extends ComboBoxUI */ public BasicComboBoxUI() { - // Nothing to do here. + currentValuePane = new CellRendererPane(); + cachedMinimumSize = new Dimension(); } /** @@ -238,12 +211,33 @@ public class BasicComboBoxUI extends ComboBoxUI if (c instanceof JComboBox) { + isMinimumSizeDirty = true; comboBox = (JComboBox) c; - comboBox.setOpaque(true); - comboBox.setLayout(createLayoutManager()); installDefaults(); + + // Set editor and renderer for the combo box. Editor is used + // only if combo box becomes editable, otherwise renderer is used + // to paint the selected item; combobox is not editable by default. + ListCellRenderer renderer = comboBox.getRenderer(); + if (renderer == null || renderer instanceof UIResource) + comboBox.setRenderer(createRenderer()); + + ComboBoxEditor currentEditor = comboBox.getEditor(); + if (currentEditor == null || currentEditor instanceof UIResource) + { + currentEditor = createEditor(); + comboBox.setEditor(currentEditor); + } + editor = currentEditor.getEditorComponent(); + installComponents(); installListeners(); + if (arrowButton != null) + configureArrowButton(); + if (editor != null) + configureEditor(); + comboBox.setLayout(createLayoutManager()); + comboBox.setFocusable(true); installKeyboardActions(); } } @@ -257,9 +251,12 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void uninstallUI(JComponent c) { + setPopupVisible(comboBox, false); + popup.uninstallingUI(); uninstallKeyboardActions(); - uninstallListeners(); + comboBox.setLayout(null); uninstallComponents(); + uninstallListeners(); uninstallDefaults(); comboBox = null; } @@ -274,12 +271,7 @@ public class BasicComboBoxUI extends ComboBoxUI { LookAndFeel.installColorsAndFont(comboBox, "ComboBox.background", "ComboBox.foreground", "ComboBox.font"); - - // fetch the button color scheme - buttonBackground = UIManager.getColor("ComboBox.buttonBackground"); - buttonShadow = UIManager.getColor("ComboBox.buttonShadow"); - buttonDarkShadow = UIManager.getColor("ComboBox.buttonDarkShadow"); - buttonHighlight = UIManager.getColor("ComboBox.buttonHighlight"); + LookAndFeel.installBorder(comboBox, "ComboBox.border"); } /** @@ -302,12 +294,19 @@ public class BasicComboBoxUI extends ComboBoxUI keyListener = createKeyListener(); comboBox.addKeyListener(keyListener); - mouseListener = createMouseListener(); - arrowButton.addMouseListener(mouseListener); - // install listeners that listen to combo box model listDataListener = createListDataListener(); comboBox.getModel().addListDataListener(listDataListener); + + // Install mouse and key listeners from the popup. + popupMouseListener = popup.getMouseListener(); + comboBox.addMouseListener(popupMouseListener); + + popupMouseMotionListener = popup.getMouseMotionListener(); + comboBox.addMouseMotionListener(popupMouseMotionListener); + + popupKeyListener = popup.getKeyListener(); + comboBox.addKeyListener(popupKeyListener); } /** @@ -327,10 +326,7 @@ public class BasicComboBoxUI extends ComboBoxUI if (comboBox.getBackground() instanceof UIResource) comboBox.setBackground(null); - buttonBackground = null; - buttonShadow = null; - buttonDarkShadow = null; - buttonHighlight = null; + LookAndFeel.uninstallBorder(comboBox); } /** @@ -353,11 +349,20 @@ public class BasicComboBoxUI extends ComboBoxUI comboBox.removeKeyListener(keyListener); keyListener = null; - arrowButton.removeMouseListener(mouseListener); - mouseListener = null; - comboBox.getModel().removeListDataListener(listDataListener); listDataListener = null; + + if (popupMouseListener != null) + comboBox.removeMouseListener(popupMouseListener); + popupMouseListener = null; + + if (popupMouseMotionListener != null) + comboBox.removeMouseMotionListener(popupMouseMotionListener); + popupMouseMotionListener = null; + + if (popupKeyListener != null) + comboBox.removeKeyListener(popupKeyListener); + popupKeyListener = null; } /** @@ -381,17 +386,6 @@ public class BasicComboBoxUI extends ComboBoxUI } /** - * Creates a {@link MouseListener} that will listen to mouse events occurring - * in the combo box. - * - * @return the MouseListener - */ - private MouseListener createMouseListener() - { - return new MouseHandler(); - } - - /** * Creates the {@link FocusListener} that will listen to changes in this * JComboBox's focus. * @@ -453,7 +447,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected ListCellRenderer createRenderer() { - return new BasicComboBoxRenderer(); + return new BasicComboBoxRenderer.UIResource(); } /** @@ -480,25 +474,14 @@ public class BasicComboBoxUI extends ComboBoxUI popup = createPopup(); listBox = popup.getList(); - // set editor and renderer for the combo box. Editor is used - // only if combo box becomes editable, otherwise renderer is used - // to paint the selected item; combobox is not editable by default. - comboBox.setRenderer(createRenderer()); - // create and install arrow button arrowButton = createArrowButton(); - configureArrowButton(); comboBox.add(arrowButton); - ComboBoxEditor currentEditor = comboBox.getEditor(); - if (currentEditor == null || currentEditor instanceof UIResource) - { - currentEditor = createEditor(); - comboBox.setEditor(currentEditor); - } - editor = currentEditor.getEditorComponent(); + if (comboBox.isEditable()) + addEditor(); - comboBox.revalidate(); + comboBox.add(currentValuePane); } /** @@ -513,10 +496,10 @@ public class BasicComboBoxUI extends ComboBoxUI comboBox.remove(arrowButton); arrowButton = null; - listBox = null; popup = null; - comboBox.setRenderer(null); + if (comboBox.getRenderer() instanceof UIResource) + comboBox.setRenderer(null); // if the editor is not an instanceof UIResource, it was not set by the // UI delegate, so don't clear it... @@ -533,6 +516,8 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void addEditor() { + removeEditor(); + editor = comboBox.getEditor().getEditorComponent(); comboBox.add(editor); } @@ -541,7 +526,11 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void removeEditor() { - comboBox.remove(editor); + if (editor != null) + { + unconfigureEditor(); + comboBox.remove(editor); + } } /** @@ -550,8 +539,10 @@ public class BasicComboBoxUI extends ComboBoxUI protected void configureEditor() { editor.setFont(comboBox.getFont()); - comboBox.getEditor().setItem(comboBox.getSelectedItem()); - // FIXME: Need to implement. Set font and add listeners. + if (popupKeyListener != null) + editor.addKeyListener(popupKeyListener); + comboBox.configureEditor(comboBox.getEditor(), + comboBox.getSelectedItem()); } /** @@ -559,7 +550,8 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected void unconfigureEditor() { - // FIXME: Need to implement + if (popupKeyListener != null) + editor.removeKeyListener(popupKeyListener); } /** @@ -569,9 +561,15 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void configureArrowButton() { - arrowButton.setEnabled(comboBox.isEnabled()); - arrowButton.setFont(comboBox.getFont()); - arrowButton.setFocusable(false); + if (arrowButton != null) + { + arrowButton.setEnabled(comboBox.isEnabled()); + arrowButton.setFocusable(false); + if (popupMouseListener != null) + arrowButton.addMouseListener(popupMouseListener); + if (popupMouseMotionListener != null) + arrowButton.addMouseMotionListener(popupMouseMotionListener); + } } /** @@ -584,7 +582,13 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void unconfigureArrowButton() { - // Nothing to do here yet. + if (arrowButton != null) + { + if (popupMouseListener != null) + arrowButton.removeMouseListener(popupMouseListener); + if (popupMouseMotionListener != null) + arrowButton.removeMouseMotionListener(popupMouseMotionListener); + } } /** @@ -596,8 +600,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected JButton createArrowButton() { - return new BasicArrowButton(BasicArrowButton.SOUTH, buttonBackground, - buttonShadow, buttonDarkShadow, buttonHighlight); + return new BasicArrowButton(BasicArrowButton.SOUTH); } /** @@ -627,11 +630,6 @@ public class BasicComboBoxUI extends ComboBoxUI popup.show(); else popup.hide(); - - if (comboBox.isEditable()) - editor.requestFocus(); - else - comboBox.requestFocus(); } /** @@ -657,9 +655,13 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void paint(Graphics g, JComponent c) { - Rectangle rect = rectangleForCurrentValue(); - paintCurrentValueBackground(g, rect, hasFocus); - paintCurrentValue(g, rect, hasFocus); + hasFocus = comboBox.hasFocus(); + if (! comboBox.isEditable()) + { + Rectangle rect = rectangleForCurrentValue(); + paintCurrentValueBackground(g, rect, hasFocus); + paintCurrentValue(g, rect, hasFocus); + } } /** @@ -671,9 +673,6 @@ public class BasicComboBoxUI extends ComboBoxUI */ public Dimension getPreferredSize(JComponent c) { - // note: overriding getMinimumSize() (for example in the MetalComboBoxUI - // class) affects the getPreferredSize() result, so it seems logical that - // this method is implemented by delegating to the getMinimumSize() method return getMinimumSize(c); } @@ -689,18 +688,15 @@ public class BasicComboBoxUI extends ComboBoxUI { if (isMinimumSizeDirty) { - Dimension d = getDisplaySize(); - int arrowButtonWidth = d.height; - cachedMinimumSize = new Dimension(d.width + arrowButtonWidth, - d.height); - isMinimumSizeDirty = false; + Insets i = getInsets(); + Dimension d = getDisplaySize(); + d.width += i.left + i.right + d.height; + cachedMinimumSize = new Dimension(d.width, d.height + i.top + i.bottom); + isMinimumSizeDirty = false; } return new Dimension(cachedMinimumSize); } - /** The value returned by the getMaximumSize() method. */ - private static final Dimension MAXIMUM_SIZE = new Dimension(32767, 32767); - /** * Returns the maximum size for this {@link JComboBox} for this * look and feel. @@ -711,7 +707,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ public Dimension getMaximumSize(JComponent c) { - return MAXIMUM_SIZE; + return new Dimension(32767, 32767); } public int getAccessibleChildrenCount(JComponent c) @@ -779,11 +775,16 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected Rectangle rectangleForCurrentValue() { - Rectangle cbBounds = SwingUtilities.getLocalBounds(comboBox); - Rectangle abBounds = arrowButton.getBounds(); - Rectangle rectForCurrentValue = new Rectangle(cbBounds.x, cbBounds.y, - cbBounds.width - abBounds.width, cbBounds.height); - return rectForCurrentValue; + int w = comboBox.getWidth(); + int h = comboBox.getHeight(); + Insets i = comboBox.getInsets(); + int arrowSize = h - (i.top + i.bottom); + if (arrowButton != null) + { + arrowSize = arrowButton.getWidth(); + } + return new Rectangle(i.left, i.top, w - (i.left + i.right + arrowSize), + h - (i.top + i.left)); } /** @@ -793,7 +794,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected Insets getInsets() { - return new Insets(0, 0, 0, 0); + return comboBox.getInsets(); } /** @@ -807,34 +808,52 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus) { - if (! comboBox.isEditable()) + Object currentValue = comboBox.getSelectedItem(); + boolean isPressed = arrowButton.getModel().isPressed(); + + /* Gets the component to be drawn for the current value. + * If there is currently no selected item we will take an empty + * String as replacement. + */ + ListCellRenderer renderer = comboBox.getRenderer(); + if (comboBox.getSelectedIndex() != -1) { - Object currentValue = comboBox.getSelectedItem(); - boolean isPressed = arrowButton.getModel().isPressed(); - - /* Gets the component to be drawn for the current value. - * If there is currently no selected item we will take an empty - * String as replacement. - */ - Component comp = comboBox.getRenderer().getListCellRendererComponent( - listBox, (currentValue != null ? currentValue : ""), -1, - isPressed, hasFocus); - if (! comboBox.isEnabled()) + Component comp; + if (hasFocus && ! isPopupVisible(comboBox)) + { + comp = renderer.getListCellRendererComponent(listBox, + comboBox.getSelectedItem(), + -1, true, false); + } + else { - comp.setBackground(UIManager.getColor( - "ComboBox.disabledBackground")); - comp.setForeground(UIManager.getColor( - "ComboBox.disabledForeground")); - comp.setEnabled(false); + comp = renderer.getListCellRendererComponent(listBox, + comboBox.getSelectedItem(), + -1, false, false); + Color bg = UIManager.getColor("ComboBox.disabledForeground"); + comp.setBackground(bg); } - comp.setBounds(0, 0, bounds.width, bounds.height); comp.setFont(comboBox.getFont()); - comp.paint(g); - - comboBox.revalidate(); + if (hasFocus && ! isPopupVisible(comboBox)) + { + comp.setForeground(listBox.getSelectionForeground()); + comp.setBackground(listBox.getSelectionBackground()); + } + else if (comboBox.isEnabled()) + { + comp.setForeground(comboBox.getForeground()); + comp.setBackground(comboBox.getBackground()); + } + else + { + Color fg = UIManager.getColor("ComboBox.disabledForeground"); + comp.setForeground(fg); + Color bg = UIManager.getColor("ComboBox.disabledBackground"); + comp.setBackground(bg); + } + currentValuePane.paintComponent(g, comp, comboBox, bounds.x, bounds.y, + bounds.width, bounds.height); } - else - comboBox.getEditor().setItem(comboBox.getSelectedItem()); } /** @@ -850,10 +869,22 @@ public class BasicComboBoxUI extends ComboBoxUI public void paintCurrentValueBackground(Graphics g, Rectangle bounds, boolean hasFocus) { - // background is painted by renderer, so it seems that nothing - // should be done here. + Color saved = g.getColor(); + if (comboBox.isEnabled()) + { + g.setColor(UIManager.getColor("UIManager.background")); + } + else + { + g.setColor(UIManager.getColor("UIManager.disabledBackground")); + } + g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); + g.setColor(saved); } + private static final ListCellRenderer DEFAULT_RENDERER + = new DefaultListCellRenderer(); + /** * Returns the default size for the display area of a combo box that does * not contain any elements. This method returns the width and height of @@ -865,14 +896,15 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected Dimension getDefaultSize() { - // There is nothing in the spec to say how this method should be - // implemented...so I've done some guessing, written some Mauve tests, - // and written something that gives dimensions that are close to the - // reference implementation. - FontMetrics fm = comboBox.getFontMetrics(comboBox.getFont()); - int w = fm.charWidth(' ') + 2; - int h = fm.getHeight() + 2; - return new Dimension(w, h); + Component comp = DEFAULT_RENDERER.getListCellRendererComponent(listBox, + " ", -1, + false, + false); + currentValuePane.add(comp); + comp.setFont(comboBox.getFont()); + Dimension d = comp.getPreferredSize(); + currentValuePane.remove(comp); + return d; } /** @@ -883,70 +915,58 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected Dimension getDisplaySize() { - if (!comboBox.isEditable()) + Dimension dim = new Dimension(); + ListCellRenderer renderer = comboBox.getRenderer(); + if (renderer == null) + { + renderer = DEFAULT_RENDERER; + } + + Object prototype = comboBox.getPrototypeDisplayValue(); + if (prototype != null) { - Object prototype = comboBox.getPrototypeDisplayValue(); - if (prototype != null) + Component comp = renderer.getListCellRendererComponent + (listBox, prototype, -1, false, false); + currentValuePane.add(comp); + comp.setFont(comboBox.getFont()); + Dimension renderSize = comp.getPreferredSize(); + currentValuePane.remove(comp); + dim.height = renderSize.height; + dim.width = renderSize.width; + } + else + { + ComboBoxModel model = comboBox.getModel(); + int size = model.getSize(); + if (size > 0) { - // calculate result based on prototype - ListCellRenderer renderer = comboBox.getRenderer(); - Component comp = renderer.getListCellRendererComponent(listBox, - prototype, -1, false, false); - Dimension compSize = comp.getPreferredSize(); - compSize.width += 2; // add 1 pixel margin around area - compSize.height += 2; - return compSize; + for (int i = 0; i < size; ++i) + { + Component comp = renderer.getListCellRendererComponent + (listBox, model.getElementAt(i), -1, false, false); + currentValuePane.add(comp); + comp.setFont(comboBox.getFont()); + Dimension renderSize = comp.getPreferredSize(); + currentValuePane.remove(comp); + dim.width = Math.max(dim.width, renderSize.width); + dim.height = Math.max(dim.height, renderSize.height); + } } else { - ComboBoxModel model = comboBox.getModel(); - int numItems = model.getSize(); - - // if combo box doesn't have any items then simply - // return its default size - if (numItems == 0) - { - displaySize = getDefaultSize(); - return displaySize; - } - - Dimension size = new Dimension(0, 0); - - // ComboBox's display size should be equal to the - // size of the largest item in the combo box. - ListCellRenderer renderer = comboBox.getRenderer(); - - for (int i = 0; i < numItems; i++) - { - Object item = model.getElementAt(i); - Component comp = renderer.getListCellRendererComponent(listBox, - item, -1, false, false); - - Dimension compSize = comp.getPreferredSize(); - if (compSize.width + 2 > size.width) - size.width = compSize.width + 2; - if (compSize.height + 2 > size.height) - size.height = compSize.height + 2; - } - displaySize = size; - return displaySize; + dim = getDefaultSize(); + if (comboBox.isEditable()) + dim.width = 100; } } - else // an editable combo, + if (comboBox.isEditable()) { - Component comp = comboBox.getEditor().getEditorComponent(); - Dimension prefSize = comp.getPreferredSize(); - int width = prefSize.width; - int height = prefSize.height + 2; - Object prototype = comboBox.getPrototypeDisplayValue(); - if (prototype != null) - { - FontMetrics fm = comboBox.getFontMetrics(comboBox.getFont()); - width = Math.max(width, fm.stringWidth(prototype.toString()) + 2); - } - displaySize = new Dimension(width, height); - return displaySize; + Dimension editSize = editor.getPreferredSize(); + dim.width = Math.max(dim.width, editSize.width); + dim.height = Math.max(dim.height, editSize.height); } + displaySize.setSize(dim.width, dim.height); + return dim; } /** @@ -954,6 +974,7 @@ public class BasicComboBoxUI extends ComboBoxUI * by the look and feel. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement. } @@ -963,6 +984,7 @@ public class BasicComboBoxUI extends ComboBoxUI * installed by in {@link #installListeners}. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement. } @@ -1016,7 +1038,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ public Dimension preferredLayoutSize(Container parent) { - return getPreferredSize((JComponent) parent); + return parent.getPreferredSize(); } /** @@ -1028,7 +1050,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ public Dimension minimumLayoutSize(Container parent) { - return preferredLayoutSize(parent); + return parent.getMinimumSize(); } /** @@ -1043,14 +1065,15 @@ public class BasicComboBoxUI extends ComboBoxUI { // Position editor component to the left of arrow button if combo box is // editable - int arrowSize = comboBox.getHeight(); + Insets i = getInsets(); + int arrowSize = comboBox.getHeight() - (i.top + i.bottom); int editorWidth = comboBox.getBounds().width - arrowSize; - if (comboBox.isEditable()) - editor.setBounds(0, 0, editorWidth, comboBox.getBounds().height); - - arrowButton.setBounds(editorWidth, 0, arrowSize, arrowSize); - comboBox.revalidate(); + if (arrowButton != null) + arrowButton.setBounds(comboBox.getWidth() - (i.right + arrowSize), + i.top, arrowSize, arrowSize); + if (editor != null) + editor.setBounds(rectangleForCurrentValue()); } } @@ -1078,9 +1101,6 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void focusGained(FocusEvent e) { - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; - hasFocus = true; comboBox.repaint(); } @@ -1093,11 +1113,9 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void focusLost(FocusEvent e) { - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; - hasFocus = false; - setPopupVisible(comboBox, false); + if (! e.isTemporary() && comboBox.isLightWeightPopupEnabled()) + setPopupVisible(comboBox, false); comboBox.repaint(); } } @@ -1124,11 +1142,12 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void itemStateChanged(ItemEvent e) { - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; - - if (e.getStateChange() == ItemEvent.SELECTED && comboBox.isEditable()) - comboBox.getEditor().setItem(e.getItem()); + ComboBoxModel model = comboBox.getModel(); + Object v = model.getSelectedItem(); + if (editor != null) + { + comboBox.configureEditor(comboBox.getEditor(), v); + } comboBox.repaint(); } } @@ -1173,10 +1192,17 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void contentsChanged(ListDataEvent e) { - // if the item is selected or deselected - - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; + if (e.getIndex0() != -1 || e.getIndex1() != -1) + { + isMinimumSizeDirty = true; + comboBox.revalidate(); + } + if (editor != null) + { + comboBox.configureEditor(comboBox.getEditor(), + comboBox.getSelectedItem()); + } + comboBox.repaint(); } /** @@ -1186,20 +1212,51 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void intervalAdded(ListDataEvent e) { - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; - - ComboBoxModel model = comboBox.getModel(); - ListCellRenderer renderer = comboBox.getRenderer(); - - if (displaySize == null) - displaySize = getDisplaySize(); - if (displaySize.width < getDefaultSize().width) - displaySize.width = getDefaultSize().width; - if (displaySize.height < getDefaultSize().height) - displaySize.height = getDefaultSize().height; - - comboBox.repaint(); + int start = e.getIndex0(); + int end = e.getIndex1(); + if (start == 0 && comboBox.getItemCount() - (end - start + 1) == 0) + { + contentsChanged(e); + } + else if (start != -1 || end != -1) + { + ListCellRenderer renderer = comboBox.getRenderer(); + ComboBoxModel model = comboBox.getModel(); + int w = displaySize.width; + int h = displaySize.height; + // TODO: Optimize using prototype here. + for (int i = start; i <= end; ++i) + { + Component comp = + renderer.getListCellRendererComponent(listBox, + model.getElementAt(i), + -1, false, false); + currentValuePane.add(comp); + comp.setFont(comboBox.getFont()); + Dimension dim = comp.getPreferredSize(); + w = Math.max(w, dim.width); + h = Math.max(h, dim.height); + currentValuePane.remove(comp); + } + if (displaySize.width < w || displaySize.height < h) + { + if (displaySize.width < w) + { + displaySize.width = w; + } + if (displaySize.height < h) + { + displaySize.height = h; + } + comboBox.revalidate(); + if (editor != null) + { + comboBox.configureEditor(comboBox.getEditor(), + comboBox.getSelectedItem()); + } + } + } + } /** @@ -1210,12 +1267,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void intervalRemoved(ListDataEvent e) { - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; - - // recalculate display size of the JComboBox. - displaySize = getDisplaySize(); - comboBox.repaint(); + contentsChanged(e); } } @@ -1291,22 +1343,4 @@ public class BasicComboBoxUI extends ComboBoxUI } } - /** - * A handler for mouse events occurring in the combo box. An instance of - * this class is returned by the <code>createMouseListener()</code> method. - */ - private class MouseHandler extends MouseAdapter - { - /** - * Invoked when mouse is pressed over the combo box. It toggles the - * visibility of the popup list. - * - * @param e the event - */ - public void mousePressed(MouseEvent e) - { - if (comboBox.isEnabled()) - toggleOpenClose(); - } - } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java index 798101d0d85..d4eabc60264 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java @@ -38,9 +38,12 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Component; import java.awt.Dimension; +import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ItemEvent; @@ -59,13 +62,13 @@ import java.beans.PropertyChangeListener; import javax.swing.BorderFactory; import javax.swing.ComboBoxModel; import javax.swing.JComboBox; -import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPopupMenu; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; +import javax.swing.MenuSelectionManager; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.Timer; @@ -165,9 +168,17 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup public BasicComboPopup(JComboBox comboBox) { this.comboBox = comboBox; - installComboBoxListeners(); + mouseListener = createMouseListener(); + mouseMotionListener = createMouseMotionListener(); + keyListener = createKeyListener(); + + list = createList(); + configureList(); + scroller = createScroller(); + configureScroller(); configurePopup(); - setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled()); + installComboBoxListeners(); + installKeyboardActions(); } /** @@ -175,42 +186,23 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void show() { - Rectangle cbBounds = comboBox.getBounds(); - - // popup should have same width as the comboBox and should be hight anough - // to display number of rows equal to 'maximumRowCount' property - int popupHeight = getPopupHeightForRowCount(comboBox.getMaximumRowCount()); - - scroller.setPreferredSize(new Dimension(cbBounds.width, popupHeight)); - pack(); + Dimension size = comboBox.getSize(); + size.height = getPopupHeightForRowCount(comboBox.getMaximumRowCount()); + Insets i = getInsets(); + size.width -= i.left + i.right; + Rectangle bounds = computePopupBounds(0, comboBox.getBounds().height, + size.width, size.height); - // Highlight selected item in the combo box's drop down list - if (comboBox.getSelectedIndex() != -1) - list.setSelectedIndex(comboBox.getSelectedIndex()); + scroller.setMaximumSize(bounds.getSize()); + scroller.setPreferredSize(bounds.getSize()); + scroller.setMinimumSize(bounds.getSize()); + list.invalidate(); - //scroll scrollbar s.t. selected item is visible - JScrollBar scrollbar = scroller.getVerticalScrollBar(); - int selectedIndex = comboBox.getSelectedIndex(); - if (selectedIndex > comboBox.getMaximumRowCount()) - scrollbar.setValue(getPopupHeightForRowCount(selectedIndex)); - - // We put the autoclose-registration inside an InvocationEvent, so that - // the same event that triggered this show() call won't hide the popup - // immediately. - SwingUtilities.invokeLater - (new Runnable() - { - public void run() - { - // Register this popup to be autoclosed when user clicks outside the - // popup. - BasicLookAndFeel laf = (BasicLookAndFeel) UIManager.getLookAndFeel(); - laf.registerForAutoClose(BasicComboPopup.this); - }}); - - // location specified is relative to comboBox - super.show(comboBox, 0, cbBounds.height); + syncListSelection(); + list.ensureIndexIsVisible(list.getSelectedIndex()); + setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled()); + show(comboBox, bounds.x, bounds.y); } /** @@ -218,7 +210,19 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void hide() { - super.setVisible(false); + MenuSelectionManager menuSelectionManager = + MenuSelectionManager.defaultManager(); + javax.swing.MenuElement[] menuElements = + menuSelectionManager.getSelectedPath(); + for (int i = 0; i < menuElements.length; i++) + { + if (menuElements[i] == this) + { + menuSelectionManager.clearSelectedPath(); + break; + } + } + comboBox.repaint(); } /** @@ -270,7 +274,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup public void uninstallingUI() { uninstallComboBoxModelListeners(comboBox.getModel()); - uninstallListeners(); uninstallKeyboardActions(); } @@ -291,6 +294,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup * This method uninstalls keyboard actions installed by the UI. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement } @@ -446,7 +450,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup protected JList createList() { JList l = new JList(comboBox.getModel()); - l.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); return l; } @@ -456,9 +459,18 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected void configureList() { - list.setModel(comboBox.getModel()); - list.setVisibleRowCount(comboBox.getMaximumRowCount()); + list.setFont(comboBox.getFont()); + list.setForeground(comboBox.getForeground()); + list.setBackground(comboBox.getBackground()); + Color sfg = UIManager.getColor("ComboBox.selectionForeground"); + list.setSelectionForeground(sfg); + Color sbg = UIManager.getColor("ComboBox.selectionBackground"); + list.setSelectionBackground(sbg); + list.setBorder(null); + list.setCellRenderer(comboBox.getRenderer()); list.setFocusable(false); + syncListSelection(); + list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); installListListeners(); } @@ -489,7 +501,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected JScrollPane createScroller() { - return new JScrollPane(); + return new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); } /** @@ -498,8 +511,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup protected void configureScroller() { scroller.setBorder(null); - scroller.getViewport().setView(list); - scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scroller.setFocusable(false); + scroller.getVerticalScrollBar().setFocusable(false); } /** @@ -508,18 +521,11 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected void configurePopup() { + setBorderPainted(true); setBorder(BorderFactory.createLineBorder(Color.BLACK)); - // initialize list that will be used to display combo box's items - this.list = createList(); - ((JLabel) list.getCellRenderer()).setHorizontalAlignment(SwingConstants.LEFT); - configureList(); - - // initialize scroller. Add list to the scroller. - scroller = createScroller(); - configureScroller(); - - // add scroller with list inside of it to JPopupMenu - super.add(scroller); + setOpaque(false); + add(scroller); + setFocusable(false); } /* @@ -528,20 +534,14 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected void installComboBoxListeners() { - // mouse listener that listens to mouse event in combo box - mouseListener = createMouseListener(); - comboBox.addMouseListener(mouseListener); - - // mouse listener that listens to mouse dragging events in the combo box - mouseMotionListener = createMouseMotionListener(); - comboBox.addMouseMotionListener(mouseMotionListener); - // item listener listenening to selection events in the combo box itemListener = createItemListener(); comboBox.addItemListener(itemListener); propertyChangeListener = createPropertyChangeListener(); comboBox.addPropertyChangeListener(propertyChangeListener); + + installComboBoxModelListeners(comboBox.getModel()); } /** @@ -562,6 +562,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup * DOCUMENT ME! */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement } @@ -651,7 +652,10 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected void delegateFocus(MouseEvent e) { - // FIXME: Need to implement + if (comboBox.isEditable()) + comboBox.getEditor().getEditorComponent().requestFocus(); + else + comboBox.requestFocus(); } /** @@ -660,7 +664,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected void togglePopup() { - if (BasicComboPopup.this.isVisible()) + if (isVisible()) hide(); else show(); @@ -675,7 +679,14 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected MouseEvent convertMouseEvent(MouseEvent e) { - return null; + Point point = SwingUtilities.convertPoint((Component) e.getSource(), + e.getPoint(), list); + MouseEvent newEvent= new MouseEvent((Component) e.getSource(), + e.getID(), e.getWhen(), + e.getModifiers(), point.x, point.y, + e.getModifiers(), + e.isPopupTrigger()); + return newEvent; } /** @@ -707,7 +718,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup totalHeight += dim.height; } - return totalHeight; + return totalHeight == 0 ? 100 : totalHeight; } /** @@ -735,11 +746,24 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup protected void updateListBoxSelectionForEvent(MouseEvent anEvent, boolean shouldScroll) { - // TODO: We need to handle the shouldScroll parameter somehow. - int index = list.locationToIndex(anEvent.getPoint()); - // Check for valid index. - if (index >= 0) - list.setSelectedIndex(index); + Point point = anEvent.getPoint(); + if (list != null) + { + int index = list.locationToIndex(point); + if (index == -1) + { + if (point.y < 0) + index = 0; + else + index = comboBox.getModel().getSize() - 1; + } + if (list.getSelectedIndex() != index) + { + list.setSelectedIndex(index); + if (shouldScroll) + list.ensureIndexIsVisible(index); + } + } } /** @@ -769,8 +793,11 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void mousePressed(MouseEvent e) { - if (comboBox.isEnabled()) - togglePopup(); + if (SwingUtilities.isLeftMouseButton(e) && comboBox.isEnabled()) + { + delegateFocus(e); + togglePopup(); + } } /** @@ -782,28 +809,27 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void mouseReleased(MouseEvent e) { - // Get component over which mouse was released - Component src = (Component) e.getSource(); - int x = e.getX(); - int y = e.getY(); - Component releasedComponent = SwingUtilities.getDeepestComponentAt(src, - x, y); - - // if mouse was released inside the bounds of combo box then do nothing, + Component component = (Component) e.getSource(); + Dimension size = component.getSize(); + Rectangle bounds = new Rectangle(0, 0, size.width - 1, size.height - 1); + // If mouse was released inside the bounds of combo box then do nothing, // Otherwise if mouse was released inside the list of combo box items // then change selection and close popup - if (! (releasedComponent instanceof JComboBox)) + if (! bounds.contains(e.getPoint())) { - // List model contains the item over which mouse is released, - // since it is updated every time the mouse is moved over a different - // item in the list. Now that the mouse is released we need to - // update model of the combo box as well. - comboBox.setSelectedIndex(list.getSelectedIndex()); - - if (isAutoScrolling) - stopAutoScrolling(); + MouseEvent convEvent = convertMouseEvent(e); + Point point = convEvent.getPoint(); + Rectangle visRect = new Rectangle(); + list.computeVisibleRect(visRect); + if (visRect.contains(point)) + { + updateListBoxSelectionForEvent(convEvent, false); + comboBox.setSelectedIndex(list.getSelectedIndex()); + } hide(); } + hasEntered = false; + stopAutoScrolling(); } } @@ -827,58 +853,42 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void mouseDragged(MouseEvent e) { - // convert point of the drag event relative to combo box list component - // figure out over which list cell the mouse is currently being dragged - // and highlight the cell. The list model is changed but the change has - // no effect on combo box's data model. The list model is changed so - // that the appropriate item would be highlighted in the combo box's - // list. - if (BasicComboPopup.this.isVisible()) + if (isVisible()) { - int cbHeight = (int) comboBox.getPreferredSize().getHeight(); - int popupHeight = BasicComboPopup.this.getSize().height; - - // if mouse is dragged inside the the combo box's items list. - if (e.getY() > cbHeight && ! (e.getY() - cbHeight >= popupHeight)) - { - int index = list.locationToIndex(new Point(e.getX(), - (int) (e.getY() - - cbHeight))); - - int firstVisibleIndex = list.getFirstVisibleIndex(); - - // list.locationToIndex returns item's index that would - // be located at the specified point if the first item that - // is visible is item 0. However in the JComboBox it is not - // necessarily the case since list is contained in the - // JScrollPane so we need to adjust the index returned. - if (firstVisibleIndex != 0) - // FIXME: adjusted index here is off by one. I am adding one - // here to compensate for that. This should be - // index += firstVisibleIndex. Remove +1 once the bug is fixed. - index += firstVisibleIndex + 1; - - list.setSelectedIndex(index); - } - else - { - // if mouse is being dragged at the bottom of combo box's list - // of items or at the very top then scroll the list in the - // desired direction. - boolean movingUP = e.getY() < cbHeight; - boolean movingDown = e.getY() > cbHeight; - - if (movingUP) - { - scrollDirection = SCROLL_UP; - startAutoScrolling(SCROLL_UP); - } - else if (movingDown) - { - scrollDirection = SCROLL_DOWN; - startAutoScrolling(SCROLL_DOWN); - } - } + MouseEvent convEvent = convertMouseEvent(e); + Rectangle visRect = new Rectangle(); + list.computeVisibleRect(visRect); + if (convEvent.getPoint().y >= visRect.y + && (convEvent.getPoint().y <= visRect.y + visRect.height - 1)) + { + hasEntered = true; + if (isAutoScrolling) + stopAutoScrolling(); + Point point = convEvent.getPoint(); + if (visRect.contains(point)) + { + valueIsAdjusting = true; + updateListBoxSelectionForEvent(convEvent, false); + valueIsAdjusting = false; + } + } + else if (hasEntered) + { + int dir = convEvent.getPoint().y < visRect.y ? SCROLL_UP + : SCROLL_DOWN; + if (isAutoScrolling && scrollDirection != dir) + { + stopAutoScrolling(); + startAutoScrolling(dir); + } + else if (!isAutoScrolling) + startAutoScrolling(dir); + } + else if (e.getPoint().y < 0) + { + hasEntered = true; + startAutoScrolling(SCROLL_UP); + } } } } @@ -905,7 +915,13 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void itemStateChanged(ItemEvent e) { - // TODO: What should be done here? + if (e.getStateChange() == ItemEvent.SELECTED && ! valueIsAdjusting) + { + valueIsAdjusting = true; + syncListSelection(); + valueIsAdjusting = false; + list.ensureIndexIsVisible(comboBox.getSelectedIndex()); + } } } @@ -924,15 +940,12 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup public void mousePressed(MouseEvent e) { - // TODO: What should be do here? + // Nothing to do here. } public void mouseReleased(MouseEvent anEvent) { - int index = list.locationToIndex(anEvent.getPoint()); - // Check for valid index. - if (index >= 0) - comboBox.setSelectedIndex(index); + comboBox.setSelectedIndex(list.getSelectedIndex()); hide(); } } @@ -951,7 +964,15 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup public void mouseMoved(MouseEvent anEvent) { - updateListBoxSelectionForEvent(anEvent, false); + Point point = anEvent.getPoint(); + Rectangle visRect = new Rectangle(); + list.computeVisibleRect(visRect); + if (visRect.contains(point)) + { + valueIsAdjusting = true; + updateListBoxSelectionForEvent(anEvent, false); + valueIsAdjusting = false; + } } } @@ -971,15 +992,21 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { if (e.getPropertyName().equals("renderer")) { - list.setCellRenderer((ListCellRenderer) e.getNewValue()); - revalidate(); - repaint(); + list.setCellRenderer(comboBox.getRenderer()); + if (isVisible()) + hide(); } - if (e.getPropertyName().equals("dataModel")) + if (e.getPropertyName().equals("model")) { - list.setModel((ComboBoxModel) e.getNewValue()); - revalidate(); - repaint(); + ComboBoxModel oldModel = (ComboBoxModel) e.getOldValue(); + uninstallComboBoxModelListeners(oldModel); + ComboBoxModel newModel = (ComboBoxModel) e.getNewValue(); + list.setModel(newModel); + installComboBoxModelListeners(newModel); + if (comboBox.getItemCount() > 0) + comboBox.setSelectedIndex(0); + if (isVisible()) + hide(); } } } @@ -991,7 +1018,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ private void uninstallListeners() { - uninstallListListeners(); uninstallComboBoxListeners(); uninstallComboBoxModelListeners(comboBox.getModel()); } @@ -1015,12 +1041,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ private void uninstallComboBoxListeners() { - comboBox.removeMouseListener(mouseListener); - mouseListener = null; - - comboBox.removeMouseMotionListener(mouseMotionListener); - mouseMotionListener = null; - comboBox.removeItemListener(itemListener); itemListener = null; @@ -1028,6 +1048,15 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup propertyChangeListener = null; } + void syncListSelection() + { + int index = comboBox.getSelectedIndex(); + if (index == -1) + list.clearSelection(); + else + list.setSelectedIndex(index); + } + // -------------------------------------------------------------------- // The following classes are here only for backwards API compatibility // They aren't used. diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java index 30e3156b4e0..daa97708390 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java @@ -157,6 +157,21 @@ public class BasicFileChooserUI extends FileChooserUI closeDialog(); } } + else + { + File f = new File(filechooser.getCurrentDirectory(), getFileName()); + if (filechooser.isTraversable(f)) + { + filechooser.setCurrentDirectory(f); + filechooser.rescanCurrentDirectory(); + } + else + { + filechooser.setSelectedFile(f); + filechooser.approveSelection(); + closeDialog(); + } + } } } @@ -1046,9 +1061,7 @@ public class BasicFileChooserUI extends FileChooserUI */ public String getFileName() { - // FIXME: I'm thinking that this method just provides access to the - // text value in the JTextField component...but not sure yet - return null; //filename; + return entry.getText(); } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java index 56022f3331e..11980f6ca2e 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java @@ -301,27 +301,27 @@ public class BasicInternalFrameTitlePane extends JComponent { String propName = evt.getPropertyName(); if (propName.equals("closable")) - { - if (evt.getNewValue().equals(Boolean.TRUE)) - closeButton.setVisible(true); - else - closeButton.setVisible(false); - } - else if (propName.equals("iconifiable")) - { - if (evt.getNewValue().equals(Boolean.TRUE)) - iconButton.setVisible(true); - else - iconButton.setVisible(false); - } + { + if (evt.getNewValue().equals(Boolean.TRUE)) + closeButton.setVisible(true); + else + closeButton.setVisible(false); + } + else if (propName.equals("iconable")) + { + if (evt.getNewValue().equals(Boolean.TRUE)) + iconButton.setVisible(true); + else + iconButton.setVisible(false); + } else if (propName.equals("maximizable")) - { - if (evt.getNewValue().equals(Boolean.TRUE)) - maxButton.setVisible(true); - else - maxButton.setVisible(false); - } - + { + if (evt.getNewValue().equals(Boolean.TRUE)) + maxButton.setVisible(true); + else + maxButton.setVisible(false); + } + enableActions(); } } @@ -340,7 +340,7 @@ public class BasicInternalFrameTitlePane extends JComponent * * @return True if this Component can receive focus. */ - public boolean isFocusTransversable() + public boolean isFocusTraversable() { return true; } @@ -520,22 +520,22 @@ public class BasicInternalFrameTitlePane extends JComponent } /** The action command for the Close action. */ - protected static final String CLOSE_CMD = "Close"; + protected static final String CLOSE_CMD; /** The action command for the Minimize action. */ - protected static final String ICONIFY_CMD = "Minimize"; + protected static final String ICONIFY_CMD; /** The action command for the Maximize action. */ - protected static final String MAXIMIZE_CMD = "Maximize"; + protected static final String MAXIMIZE_CMD; /** The action command for the Move action. */ - protected static final String MOVE_CMD = "Move"; + protected static final String MOVE_CMD; /** The action command for the Restore action. */ - protected static final String RESTORE_CMD = "Restore"; + protected static final String RESTORE_CMD; /** The action command for the Size action. */ - protected static final String SIZE_CMD = "Size"; + protected static final String SIZE_CMD; /** The action associated with closing the JInternalFrame. */ protected Action closeAction; @@ -614,6 +614,17 @@ public class BasicInternalFrameTitlePane extends JComponent * This is package-private to avoid an accessor method. */ transient JLabel title; + + static + { + // not constants in JDK + CLOSE_CMD = "Close"; + ICONIFY_CMD = "Minimize"; + MAXIMIZE_CMD = "Maximize"; + MOVE_CMD = "Move"; + RESTORE_CMD = "Restore"; + SIZE_CMD = "Size"; + } /** * Creates a new BasicInternalFrameTitlePane object that is used in the diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java index f6cbeec8879..7ec3aa074bd 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -38,10 +38,13 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.AWTEvent; import java.awt.Color; import java.awt.Component; import java.awt.Container; +import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Insets; @@ -164,6 +167,12 @@ public class BasicInternalFrameUI extends InternalFrameUI protected class BorderListener extends MouseInputAdapter implements SwingConstants { + /** + * If true, the cursor is being already shown in the alternative "resize" + * shape. + */ + transient boolean showingResizeCursor; + /** FIXME: Use for something. */ protected final int RESIZE_NONE = 0; @@ -255,7 +264,7 @@ public class BasicInternalFrameUI extends InternalFrameUI else if (e.getSource() == titlePane) { Rectangle fBounds = frame.getBounds(); - + frame.putClientProperty("bufferedDragging", Boolean.TRUE); dm.dragFrame(frame, e.getX() - xOffset + b.x, e.getY() - yOffset + b.y); } @@ -263,25 +272,69 @@ public class BasicInternalFrameUI extends InternalFrameUI /** * This method is called when the mouse exits the JInternalFrame. - * + * * @param e The MouseEvent. */ public void mouseExited(MouseEvent e) { - // There is nothing to do when the mouse exits - // the border area. + // Reset the cursor shape. + if (showingResizeCursor) + { + frame.setCursor(Cursor.getDefaultCursor()); + showingResizeCursor = false; + } } /** - * This method is called when the mouse is moved inside the - * JInternalFrame. - * + * This method is called when the mouse is moved inside the JInternalFrame. + * * @param e The MouseEvent. */ public void mouseMoved(MouseEvent e) { - // There is nothing to do when the mouse moves - // over the border area. + // Turn off the resize cursor if we are in the frame header. + if (showingResizeCursor && e.getSource() != frame) + { + frame.setCursor(Cursor.getDefaultCursor()); + showingResizeCursor = false; + } + else if (e.getSource()==frame && frame.isResizable()) + { + int cursor; + switch (sectionOfClick(e.getX(), e.getY())) + { + case NORTH: + cursor = Cursor.N_RESIZE_CURSOR; + break; + case NORTH_EAST: + cursor = Cursor.NE_RESIZE_CURSOR; + break; + case EAST: + cursor = Cursor.E_RESIZE_CURSOR; + break; + case SOUTH_EAST: + cursor = Cursor.SE_RESIZE_CURSOR; + break; + case SOUTH: + cursor = Cursor.S_RESIZE_CURSOR; + break; + case SOUTH_WEST: + cursor = Cursor.SW_RESIZE_CURSOR; + break; + case WEST: + cursor = Cursor.W_RESIZE_CURSOR; + break; + case NORTH_WEST: + cursor = Cursor.NW_RESIZE_CURSOR; + break; + default: + cursor = Cursor.DEFAULT_CURSOR; + } + + Cursor resize = Cursor.getPredefinedCursor(cursor); + frame.setCursor(resize); + showingResizeCursor = true; + } } /** @@ -326,7 +379,10 @@ public class BasicInternalFrameUI extends InternalFrameUI if (e.getSource() == frame && frame.isResizable()) dm.endResizingFrame(frame); else if (e.getSource() == titlePane) - dm.endDraggingFrame(frame); + { + dm.endDraggingFrame(frame); + frame.putClientProperty("bufferedDragging", null); + } } /** @@ -1119,12 +1175,8 @@ public class BasicInternalFrameUI extends InternalFrameUI installComponents(); installKeyboardActions(); - ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(false); if (! frame.isSelected()) - frame.getRootPane().getGlassPane().setVisible(true); - - frame.setOpaque(true); - frame.invalidate(); + frame.getGlassPane().setVisible(true); } } @@ -1140,9 +1192,7 @@ public class BasicInternalFrameUI extends InternalFrameUI uninstallListeners(); uninstallDefaults(); - ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(true); frame.getRootPane().getGlassPane().setVisible(false); - frame = null; } @@ -1155,12 +1205,22 @@ public class BasicInternalFrameUI extends InternalFrameUI frame.setLayout(internalFrameLayout); LookAndFeel.installBorder(frame, "InternalFrame.border"); frame.setFrameIcon(UIManager.getIcon("InternalFrame.icon")); + + // Let the content pane inherit the background color from its + // frame by setting the background to null. + Component contentPane = frame.getContentPane(); + if (contentPane != null + && contentPane.getBackground() instanceof UIResource) + { + contentPane.setBackground(null); + } } /** * This method installs the keyboard actions for the JInternalFrame. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: Implement. } @@ -1243,6 +1303,7 @@ public class BasicInternalFrameUI extends InternalFrameUI * This method uninstalls the keyboard actions for the JInternalFrame. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: Implement. } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java index d0964f4733e..60e3a98684f 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java @@ -37,6 +37,8 @@ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Dimension; import java.awt.FontMetrics; @@ -372,6 +374,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener * @param l The {@link JLabel} to install keyboard actions for. */ protected void installKeyboardActions(JLabel l) + throws NotImplementedException { //FIXME: implement. } @@ -382,6 +385,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener * @param l The {@link JLabel} to uninstall keyboard actions for. */ protected void uninstallKeyboardActions(JLabel l) + throws NotImplementedException { //FIXME: implement. } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java index 19dfe21f889..d9bc0676dd9 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java @@ -1,5 +1,5 @@ /* BasicListUI.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; @@ -179,7 +181,8 @@ public class BasicListUI extends ListUI int index1 = e.getFirstIndex(); int index2 = e.getLastIndex(); Rectangle damaged = getCellBounds(list, index1, index2); - list.repaint(damaged); + if (damaged != null) + list.repaint(damaged); } } @@ -716,7 +719,8 @@ public class BasicListUI extends ListUI * @param index2 The last row to incude in the bounds * * @return A rectangle encompassing the range of rows between - * <code>index1</code> and <code>index2</code> inclusive + * <code>index1</code> and <code>index2</code> inclusive, or null + * such a rectangle couldn't be calculated for the given indexes. */ public Rectangle getCellBounds(JList l, int index1, int index2) { @@ -1023,6 +1027,7 @@ public class BasicListUI extends ListUI * Uninstalls keyboard actions for this UI in the {@link JList}. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // TODO: Implement this properly. } @@ -1182,7 +1187,7 @@ public class BasicListUI extends ListUI for (int row = startIndex; row <= endIndex; ++row) { Rectangle bounds = getCellBounds(list, row, row); - if (bounds.intersects(clip)) + if (bounds != null && bounds.intersects(clip)) paintCell(g, row, bounds, render, model, sel, lead); } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java index 3451224beeb..78c16ef08ae 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -44,6 +44,7 @@ import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; +import java.awt.SystemColor; import java.awt.Toolkit; import java.awt.event.AWTEventListener; import java.awt.event.ActionEvent; @@ -52,10 +53,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.Enumeration; -import java.util.Iterator; import java.util.ResourceBundle; -import java.util.Set; -import java.util.WeakHashMap; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; @@ -66,11 +64,9 @@ import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.BorderFactory; -import javax.swing.JPopupMenu; import javax.swing.KeyStroke; import javax.swing.LookAndFeel; import javax.swing.MenuSelectionManager; -import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.border.BevelBorder; @@ -104,11 +100,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel { /** - * Registered popups for autoclose. - */ - private WeakHashMap autoClosePopups = new WeakHashMap(); - - /** * Receives an event from the event queue. * * @param event @@ -137,46 +128,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel target = ((Container) target).findComponentAt(ev.getPoint()); if (! m.isComponentPartOfCurrentMenu(target)) m.clearSelectedPath(); - - // Handle other registered popup instances, like ComboBox popups. - autoClosePopups(ev, target); - } - - /** - * Registers Popup and its content to be autoclosed when a mouseclick - * occurs outside of the popup. - * - * @param popup the popup to be autoclosed when clicked outside - */ - void registerForAutoClose(JPopupMenu popup) - { - autoClosePopups.put(popup, null); } - /** - * Automatically closes all popups that are not 'hit' by the mouse event. - * - * @param ev the mouse event - * @param target the target of the mouse event - */ - private void autoClosePopups(MouseEvent ev, Component target) - { - if (autoClosePopups.size() != 0) - { - Set popups = autoClosePopups.keySet(); - Iterator i = popups.iterator(); - while (i.hasNext()) - { - JPopupMenu popup = (JPopupMenu) i.next(); - if (!(target == popup - || SwingUtilities.isDescendingFrom(target, popup))) - { - popup.setVisible(false); - i.remove(); - } - } - } - } } /** @@ -251,7 +204,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel */ public BasicLookAndFeel() { - // TODO + // Nothing to do here. } /** @@ -337,59 +290,138 @@ public abstract class BasicLookAndFeel extends LookAndFeel /** * Populates the <code>defaults</code> table with system color defaults. + * + * This sets up a couple of default values and passes them to + * {@link #loadSystemColors(UIDefaults, String[], boolean)}. If the + * look and feel is a native look and feel, these defaults may be overridden + * by the corresponding SystemColor constants. * * @param defaults the defaults table (<code>null</code> not permitted). */ protected void initSystemColorDefaults(UIDefaults defaults) { - Color highLight = new Color(249, 247, 246); - Color light = new Color(239, 235, 231); - Color shadow = new Color(139, 136, 134); - Color darkShadow = new Color(16, 16, 16); - - Object[] uiDefaults; - uiDefaults = new Object[] { - "activeCaption", new ColorUIResource(0, 0, 128), - "activeCaptionBorder", new ColorUIResource(Color.lightGray), - "activeCaptionText", new ColorUIResource(Color.white), - "control", new ColorUIResource(light), - "controlDkShadow", new ColorUIResource(shadow), - "controlHighlight", new ColorUIResource(highLight), - "controlLtHighlight", new ColorUIResource(highLight), - "controlShadow", new ColorUIResource(shadow), - "controlText", new ColorUIResource(darkShadow), - "desktop", new ColorUIResource(0, 92, 92), - "inactiveCaption", new ColorUIResource(Color.gray), - "inactiveCaptionBorder", new ColorUIResource(Color.lightGray), - "inactiveCaptionText", new ColorUIResource(Color.lightGray), - "info", new ColorUIResource(light), - "infoText", new ColorUIResource(darkShadow), - "menu", new ColorUIResource(light), - "menuText", new ColorUIResource(darkShadow), - "scrollbar", new ColorUIResource(light), - "text", new ColorUIResource(Color.white), - "textHighlight", new ColorUIResource(Color.black), - "textHighlightText", new ColorUIResource(Color.white), - "textInactiveText", new ColorUIResource(Color.gray), - "textText", new ColorUIResource(Color.black), - "window", new ColorUIResource(light), - "windowBorder", new ColorUIResource(Color.black), - "windowText", new ColorUIResource(darkShadow) + String[] defaultColors = new String[] { + "activeCaption", "#000080", + "activeCaptionBorder", "#C0C0C0", + "activeCaptionText", "#FFFFFF", + "control", "#C0C0C0", + "controlDkShadow", "#000000", + "controlHighlight", "#C0C0C0", + "controlLtHighlight", "#FFFFFF", + "controlShadow", "#808080", + "controlText", "#000000", + "desktop", "#005C5C", + "inactiveCaption", "#808080", + "inactiveCaptionBorder", "#C0C0C0", + "inactiveCaptionText", "#C0C0C0", + "info", "#FFFFE1", + "infoText", "#000000", + "menu", "#C0C0C0", + "menuText", "#000000", + "scrollbar", "#E0E0E0", + "text", "#C0C0C0", + "textHighlight", "#000080", + "textHighlightText", "#FFFFFF", + "textInactiveText", "#808080", + "textText", "#000000", + "window", "#FFFFFF", + "windowBorder", "#000000", + "windowText", "#000000" }; - defaults.putDefaults(uiDefaults); + loadSystemColors(defaults, defaultColors, isNativeLookAndFeel()); } /** - * Loads the system colors. This method is not implemented yet. - * + * Populates the <code>defaults</code> table with the system colors. If + * <code>useNative</code> is <code>true</code>, the table is populated + * with the constants in {@link SystemColor}, otherwise the + * <code>systemColors</code> parameter is decoded into the defaults table. + * The system colors array is made up of pairs, where the first entry is the + * name of the system color, and the second entry is a string denoting + * an RGB color value like "#C0C0C0", which is decoded using + * {@link Color#decode(String)}. + * * @param defaults the defaults table (<code>null</code> not permitted). - * @param systemColors TODO - * @param useNative TODO + * @param systemColors defaults to use when <code>useNative</code> is + * <code>false</code> + * @param useNative when <code>true</code>, installs the values of the + * SystemColor constants, when <code>false</code>, install the values + * from <code>systemColors</code> */ protected void loadSystemColors(UIDefaults defaults, String[] systemColors, boolean useNative) { - // TODO + if (useNative) + { + defaults.put("activeCaption", + new ColorUIResource(SystemColor.ACTIVE_CAPTION)); + defaults.put("activeCaptionBorder", + new ColorUIResource(SystemColor.ACTIVE_CAPTION_BORDER)); + defaults.put("activeCaptionText", + new ColorUIResource(SystemColor.ACTIVE_CAPTION_TEXT)); + defaults.put("control", + new ColorUIResource(SystemColor.CONTROL)); + defaults.put("controlDkShadow", + new ColorUIResource(SystemColor.CONTROL_DK_SHADOW)); + defaults.put("controlHighlight", + new ColorUIResource(SystemColor.CONTROL_HIGHLIGHT)); + defaults.put("controlLtHighlight", + new ColorUIResource(SystemColor.CONTROL_LT_HIGHLIGHT)); + defaults.put("controlShadow", + new ColorUIResource(SystemColor.CONTROL_SHADOW)); + defaults.put("controlText", + new ColorUIResource(SystemColor.CONTROL_TEXT)); + defaults.put("desktop", + new ColorUIResource(SystemColor.DESKTOP)); + defaults.put("inactiveCaption", + new ColorUIResource(SystemColor.INACTIVE_CAPTION)); + defaults.put("inactiveCaptionBorder", + new ColorUIResource(SystemColor.INACTIVE_CAPTION_BORDER)); + defaults.put("inactiveCaptionText", + new ColorUIResource(SystemColor.INACTIVE_CAPTION_TEXT)); + defaults.put("info", + new ColorUIResource(SystemColor.INFO)); + defaults.put("infoText", + new ColorUIResource(SystemColor.INFO_TEXT)); + defaults.put("menu", + new ColorUIResource(SystemColor.MENU)); + defaults.put("menuText", + new ColorUIResource(SystemColor.MENU_TEXT)); + defaults.put("scrollbar", + new ColorUIResource(SystemColor.SCROLLBAR)); + defaults.put("text", + new ColorUIResource(SystemColor.TEXT)); + defaults.put("textHighlight", + new ColorUIResource(SystemColor.TEXT_HIGHLIGHT)); + defaults.put("textHighlightText", + new ColorUIResource(SystemColor.TEXT_HIGHLIGHT_TEXT)); + defaults.put("textInactiveText", + new ColorUIResource(SystemColor.TEXT_INACTIVE_TEXT)); + defaults.put("textText", + new ColorUIResource(SystemColor.TEXT_TEXT)); + defaults.put("window", + new ColorUIResource(SystemColor.WINDOW)); + defaults.put("windowBorder", + new ColorUIResource(SystemColor.WINDOW_BORDER)); + defaults.put("windowText", + new ColorUIResource(SystemColor.WINDOW_TEXT)); + } + else + { + for (int i = 0; i < systemColors.length; i += 2) + { + Color color = Color.BLACK; + try + { + color = Color.decode(systemColors[i + 1]); + } + catch (NumberFormatException e) + { + e.printStackTrace(); + } + defaults.put(systemColors[i], new ColorUIResource(color)); + } + } } /** @@ -1162,6 +1194,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel "TabbedPane.shadow", new ColorUIResource(shadow), "TabbedPane.tabbedPaneContentBorderInsets", new InsetsUIResource(3, 2, 1, 2), "TabbedPane.tabbedPaneTabPadInsets", new InsetsUIResource(1, 1, 1, 1), + "TabbedPane.tabsOpaque", Boolean.TRUE, "TabbedPane.tabAreaInsets", new InsetsUIResource(3, 2, 0, 2), "TabbedPane.tabInsets", new InsetsUIResource(0, 4, 1, 4), "TabbedPane.tabRunOverlay", new Integer(2), @@ -1648,17 +1681,4 @@ public abstract class BasicLookAndFeel extends LookAndFeel toolkit.removeAWTEventListener(popupHelper); popupHelper = null; } - - /** - * Registers a JPopupMenu for autoclosing when a mouseclick occurs outside - * of the JPopupMenu. This must be called when the popup gets opened. The - * popup is unregistered from autoclosing as soon as it either got closed - * by this helper, or when it has been garbage collected. - * - * @param popup the popup menu to autoclose - */ - void registerForAutoClose(JPopupMenu popup) - { - popupHelper.registerForAutoClose(popup); - } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java index daa9b0d6b63..f258ebe3069 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Dimension; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; @@ -68,7 +70,7 @@ public class BasicMenuBarUI extends MenuBarUI protected ContainerListener containerListener; /*Property change listeners that listener to PropertyChangeEvent from menu bar*/ - protected PropertyChangeListener propertyChangeListener; + private PropertyChangeListener propertyChangeListener; /* menu bar for which this UI delegate is for*/ protected JMenuBar menuBar; @@ -176,6 +178,7 @@ public class BasicMenuBarUI extends MenuBarUI * This method installs the keyboard actions for the JMenuBar. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: implement } @@ -223,6 +226,7 @@ public class BasicMenuBarUI extends MenuBarUI * This method reverses the work done in installKeyboardActions. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: implement. } @@ -252,7 +256,7 @@ public class BasicMenuBarUI extends MenuBarUI menuBar = null; } - protected class ChangeHandler implements ChangeListener + private class ChangeHandler implements ChangeListener { public void stateChanged(ChangeEvent event) { @@ -264,7 +268,7 @@ public class BasicMenuBarUI extends MenuBarUI * This class handles ContainerEvents fired by JMenuBar. It revalidates * and repaints menu bar whenever menu is added or removed from it. */ - protected class ContainerHandler implements ContainerListener + private class ContainerHandler implements ContainerListener { /** * This method is called whenever menu is added to the menu bar @@ -292,7 +296,7 @@ public class BasicMenuBarUI extends MenuBarUI /** * This class handles PropertyChangeEvents fired from the JMenuBar */ - protected class PropertyChangeHandler implements PropertyChangeListener + private class PropertyChangeHandler implements PropertyChangeListener { /** * This method is called whenever one of the properties of the MenuBar diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java index 9166c49ee83..69c9c4507b0 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -40,6 +40,7 @@ package javax.swing.plaf.basic; import java.awt.Color; import java.awt.Component; +import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; @@ -82,6 +83,7 @@ import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentInputMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.MenuItemUI; +import javax.swing.text.View; /** * UI Delegate for JMenuItem. @@ -183,7 +185,43 @@ public class BasicMenuItemUI extends MenuItemUI /** A PropertyChangeListener to make UI updates after property changes **/ PropertyChangeHandler propertyChangeListener; - + + /** + * The view rectangle used for layout of the menu item. + */ + private Rectangle viewRect; + + /** + * The rectangle that holds the area of the label. + */ + private Rectangle textRect; + + /** + * The rectangle that holds the area of the accelerator. + */ + private Rectangle accelRect; + + /** + * The rectangle that holds the area of the icon. + */ + private Rectangle iconRect; + + /** + * The rectangle that holds the area of the icon. + */ + private Rectangle arrowIconRect; + + /** + * The rectangle that holds the area of the check icon. + */ + private Rectangle checkIconRect; + + /** + * A rectangle used for temporary storage to avoid creation of new + * rectangles. + */ + private Rectangle cachedRect; + /** * A class to handle PropertChangeEvents for the JMenuItem * @author Anthony Balkissoon abalkiss at redhat dot com. @@ -242,6 +280,15 @@ public class BasicMenuItemUI extends MenuItemUI menuKeyListener = createMenuKeyListener(menuItem); itemListener = new ItemHandler(); propertyChangeListener = new PropertyChangeHandler(); + + // Initialize rectangles for layout. + viewRect = new Rectangle(); + textRect = new Rectangle(); + iconRect = new Rectangle(); + arrowIconRect = new Rectangle(); + checkIconRect = new Rectangle(); + accelRect = new Rectangle(); + cachedRect = new Rectangle(); } /** @@ -378,50 +425,69 @@ public class BasicMenuItemUI extends MenuItemUI int defaultTextIconGap) { JMenuItem m = (JMenuItem) c; - Dimension d = BasicGraphicsUtils.getPreferredButtonSize(m, - defaultTextIconGap); - - // if menu item has accelerator then take accelerator's size into account - // when calculating preferred size. - KeyStroke accelerator = m.getAccelerator(); - Rectangle rect; - - if (accelerator != null) + String accelText = getAcceleratorString(m); + + // Layout the menu item. The result gets stored in the rectangle + // fields of this class. + layoutMenuItem(m, accelText); + + // The union of the text and icon areas is the label area. + cachedRect.setBounds(textRect); + Rectangle pref = SwingUtilities.computeUnion(iconRect.x, iconRect.y, + iconRect.width, + iconRect.height, + cachedRect); + + // Find the widest menu item text and accelerator and store it in + // client properties of the parent, so that we can align the accelerators + // properly. Of course, we only need can do this, if the parent is + // a JComponent and this menu item is not a toplevel menu. + Container parent = m.getParent(); + if (parent != null && parent instanceof JComponent + && !(m instanceof JMenu && ((JMenu) m).isTopLevelMenu())) { - rect = getAcceleratorRect( - accelerator, - m.getToolkit().getFontMetrics(acceleratorFont)); + JComponent p = (JComponent) parent; - // add width of accelerator's text - d.width += rect.width + defaultAcceleratorLabelGap; + // The widest text so far. + Integer maxTextWidth = (Integer) p.getClientProperty("maxTextWidth"); + int maxTextValue = maxTextWidth == null ? 0 : maxTextWidth.intValue(); + if (pref.width < maxTextValue) + pref.width = maxTextValue; + else + p.putClientProperty("maxTextWidth", new Integer(pref.width)); - // adjust the heigth of the preferred size if necessary - if (d.height < rect.height) - d.height = rect.height; + // The widest accelerator so far. + Integer maxAccelWidth = (Integer) p.getClientProperty("maxAccelWidth"); + int maxAccelValue = maxAccelWidth == null ? 0 + : maxAccelWidth.intValue(); + if (accelRect.width > maxAccelValue) + { + maxAccelValue = accelRect.width; + p.putClientProperty("maxAccelWidth", new Integer(accelRect.width)); + } + pref.width += maxAccelValue; + pref.width += defaultTextIconGap; } - if (checkIcon != null) + // Add arrow and check size if appropriate. + if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu())) { - d.width += checkIcon.getIconWidth() + defaultTextIconGap; - - if (checkIcon.getIconHeight() > d.height) - d.height = checkIcon.getIconHeight(); + pref.width += checkIconRect.width; + pref.width += defaultTextIconGap; + pref.width += arrowIconRect.width; + pref.width += defaultTextIconGap; } - if (arrowIcon != null && (c instanceof JMenu)) - { - int pWidth = m.getParent().getWidth(); - if (!((JMenu)c).isTopLevelMenu() && d.width < pWidth) - d.width = pWidth - - m.getInsets().left - m.getInsets().right; - else - d.width += arrowIcon.getIconWidth() + MenuGap; - - if (arrowIcon.getIconHeight() > d.height) - d.height = arrowIcon.getIconHeight(); - } - - return d; + // Add a gap ~2 times as wide as the defaultTextIconGap. + pref.width += 2 * defaultTextIconGap; + + // Respect the insets of the menu item. + Insets i = m.getInsets(); + pref.width += i.left + i.right; + pref.height += i.top + i.bottom; + + // Return a copy, so that nobody messes with our textRect. + return pref.getSize(); } /** @@ -541,7 +607,7 @@ public class BasicMenuItemUI extends MenuItemUI */ public void paint(Graphics g, JComponent c) { - paintMenuItem(g, c, checkIcon, arrowIcon, c.getBackground(), + paintMenuItem(g, c, checkIcon, arrowIcon, selectionBackground, c.getForeground(), defaultTextIconGap); } @@ -560,16 +626,18 @@ public class BasicMenuItemUI extends MenuItemUI // Menu item is considered to be highlighted when it is selected. // But we don't want to paint the background of JCheckBoxMenuItems ButtonModel mod = menuItem.getModel(); - if (menuItem.isContentAreaFilled()) + Color saved = g.getColor(); + if (mod.isArmed() || ((menuItem instanceof JMenu) && mod.isSelected())) { - if ((menuItem.isSelected() && checkIcon == null) || (mod != null && - mod.isArmed()) - && (menuItem.getParent() instanceof MenuElement)) - g.setColor(selectionBackground); - else - g.setColor(bgColor); + g.setColor(bgColor); + g.fillRect(0, 0, menuItem.getWidth(), menuItem.getHeight()); + } + else if (menuItem.isOpaque()) + { + g.setColor(menuItem.getBackground()); g.fillRect(0, 0, menuItem.getWidth(), menuItem.getHeight()); - } + } + g.setColor(saved); } /** @@ -595,87 +663,123 @@ public class BasicMenuItemUI extends MenuItemUI Color foreground, int defaultTextIconGap) { JMenuItem m = (JMenuItem) c; - Rectangle tr = new Rectangle(); // text rectangle - Rectangle ir = new Rectangle(); // icon rectangle - Rectangle vr = new Rectangle(); // view rectangle - Rectangle br = new Rectangle(); // border rectangle - Rectangle ar = new Rectangle(); // accelerator rectangle - Rectangle cr = new Rectangle(); // checkIcon rectangle - - int vertAlign = m.getVerticalAlignment(); - int horAlign = m.getHorizontalAlignment(); - int vertTextPos = m.getVerticalTextPosition(); - int horTextPos = m.getHorizontalTextPosition(); - - Font f = m.getFont(); - g.setFont(f); - FontMetrics fm = g.getFontMetrics(f); - SwingUtilities.calculateInnerArea(m, vr); + + // Fetch fonts. + Font oldFont = g.getFont(); + Font font = c.getFont(); + g.setFont(font); + FontMetrics accelFm = m.getFontMetrics(acceleratorFont); + + // Create accelerator string. + String accelText = getAcceleratorString(m); + + // Layout menu item. The result gets stored in the rectangle fields + // of this class. + layoutMenuItem(m, accelText); + + // Paint the background. paintBackground(g, m, background); - /* - * MenuItems insets are equal to menuItems margin, space between text and - * menuItems border. We need to paint insets region as well. - */ - Insets insets = m.getInsets(); - br.x -= insets.left; - br.y -= insets.top; - br.width += insets.right + insets.left; - br.height += insets.top + insets.bottom; + Color oldColor = g.getColor(); - // If this menu item is a JCheckBoxMenuItem then paint check icon + // Paint the check icon. if (checkIcon != null) { - SwingUtilities.layoutCompoundLabel(m, fm, null, checkIcon, vertAlign, - horAlign, vertTextPos, horTextPos, - vr, cr, tr, defaultTextIconGap); - checkIcon.paintIcon(m, g, cr.x, cr.y); - // We need to calculate position of the menu text and position of - // user menu icon if there exists one relative to the check icon. - // So we need to adjust view rectangle s.t. its starting point is at - // checkIcon.width + defaultTextIconGap. - vr.x = cr.x + cr.width + defaultTextIconGap; + checkIcon.paintIcon(m, g, checkIconRect.x, checkIconRect.y); + } + + // Paint the icon. + ButtonModel model = m.getModel(); + if (m.getIcon() != null) + { + // Determine icon depending on the menu item + // state (normal/disabled/pressed). + Icon icon; + if (! m.isEnabled()) + { + icon = m.getDisabledIcon(); + } + else if (model.isPressed() && model.isArmed()) + { + icon = m.getPressedIcon(); + if (icon == null) + { + icon = m.getIcon(); + } + } + else + { + icon = m.getIcon(); + } + + if (icon != null) + { + icon.paintIcon(m, g, iconRect.x, iconRect.y); + } } - // if this is a submenu, then paint arrow icon to indicate it. - if (arrowIcon != null && (c instanceof JMenu)) + // Paint the text. + String text = m.getText(); + if (text != null) { - if (!((JMenu) c).isTopLevelMenu()) + // Handle HTML. + View html = (View) m.getClientProperty(BasicHTML.propertyKey); + if (html != null) + { + html.paint(g, textRect); + } + else { - int width = arrowIcon.getIconWidth(); - int height = arrowIcon.getIconHeight(); - int offset = (vr.height - height) / 2; - arrowIcon.paintIcon(m, g, vr.width - width, vr.y + offset); + paintText(g, m, textRect, text); } } - // paint text and user menu icon if it exists - Icon i = m.getIcon(); - SwingUtilities.layoutCompoundLabel(c, fm, m.getText(), i, vertAlign, - horAlign, vertTextPos, horTextPos, vr, - ir, tr, defaultTextIconGap); - if (i != null) - i.paintIcon(c, g, ir.x, ir.y); - paintText(g, m, tr, m.getText()); + // Paint accelerator text. + if (! accelText.equals("")) + { + // Align the accelerator text. In getPreferredMenuItemSize() we + // store a client property 'maxAccelWidth' in the parent which holds + // the maximum accelerator width for the children of this parent. + // We use this here to align the accelerators properly. + int accelOffset = 0; + Container parent = m.getParent(); + if (parent != null && parent instanceof JComponent) + { + JComponent p = (JComponent) parent; + Integer maxAccelWidth = + (Integer) p.getClientProperty("maxAccelWidth"); + int maxAccelValue = maxAccelWidth == null ? 0 + : maxAccelWidth.intValue(); + accelOffset = maxAccelValue - accelRect.width; + } - // paint accelerator - String acceleratorText = ""; + g.setFont(acceleratorFont); + if (! m.isEnabled()) + { + // Paint accelerator disabled. + g.setColor(disabledForeground); + } + else + { + if (m.isArmed() || (m instanceof JMenu && m.isSelected())) + g.setColor(acceleratorSelectionForeground); + else + g.setColor(acceleratorForeground); + } + g.drawString(accelText, accelRect.x - accelOffset, + accelRect.y + accelFm.getAscent()); + } - if (m.getAccelerator() != null) + // Paint arrow. + if (arrowIcon != null + && ! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu())) { - acceleratorText = getAcceleratorText(m.getAccelerator()); - fm = g.getFontMetrics(acceleratorFont); - ar.width = fm.stringWidth(acceleratorText); - ar.x = br.width - ar.width; - vr.x = br.width - ar.width - defaultTextIconGap; - - SwingUtilities.layoutCompoundLabel(m, fm, acceleratorText, null, - vertAlign, horAlign, vertTextPos, - horTextPos, vr, ir, ar, - defaultTextIconGap); - - paintAccelerator(g, m, ar, acceleratorText); + arrowIcon.paintIcon(m, g, arrowIconRect.x, arrowIconRect.y); } + + g.setFont(oldFont); + g.setColor(oldColor); + } /** @@ -860,37 +964,6 @@ public class BasicMenuItemUI extends MenuItemUI } /** - * Paints accelerator inside menu item - * - * @param g - * The graphics context used to paint the border - * @param menuItem - * Menu item for which to draw accelerator - * @param acceleratorRect - * rectangle representing position of the accelerator relative to the - * menu item - * @param acceleratorText - * accelerator's text - */ - private void paintAccelerator(Graphics g, JMenuItem menuItem, - Rectangle acceleratorRect, - String acceleratorText) - { - g.setFont(acceleratorFont); - FontMetrics fm = g.getFontMetrics(acceleratorFont); - - if (menuItem.isEnabled()) - g.setColor(acceleratorForeground); - else - // FIXME: should fix this to use 'disabledForeground', but its - // default value in BasicLookAndFeel is null. - g.setColor(Color.gray); - - BasicGraphicsUtils.drawString(g, acceleratorText, 0, acceleratorRect.x, - acceleratorRect.y + fm.getAscent()); - } - - /** * This class handles mouse events occuring inside the menu item. Most of the * events are forwarded for processing to MenuSelectionManager of the current * menu hierarchy. @@ -1139,4 +1212,134 @@ public class BasicMenuItemUI extends MenuItemUI menuItem.repaint(); } } + + /** + * A helper method to create the accelerator string from the menu item's + * accelerator property. The returned string is empty if there is + * no accelerator defined. + * + * @param m the menu item + * + * @return the accelerator string, not null + */ + private String getAcceleratorString(JMenuItem m) + { + // Create accelerator string. + KeyStroke accel = m.getAccelerator(); + String accelText = ""; + if (accel != null) + { + int mods = accel.getModifiers(); + if (mods > 0) + { + accelText = KeyEvent.getKeyModifiersText(mods); + accelText += acceleratorDelimiter; + } + int keycode = accel.getKeyCode(); + if (keycode != 0) + accelText += KeyEvent.getKeyText(keycode); + else + accelText += accel.getKeyChar(); + } + return accelText; + } + + /** + * A helper method that lays out the menu item. The layout is stored + * in the fields of this class. + * + * @param m the menu item to layout + * @param accelText the accelerator text + */ + private void layoutMenuItem(JMenuItem m, String accelText) + { + int width = m.getWidth(); + int height = m.getHeight(); + + // Reset rectangles. + iconRect.setBounds(0, 0, 0, 0); + textRect.setBounds(0, 0, 0, 0); + accelRect.setBounds(0, 0, 0, 0); + checkIconRect.setBounds(0, 0, 0, 0); + arrowIconRect.setBounds(0, 0, 0, 0); + viewRect.setBounds(0, 0, width, height); + + // Substract insets to the view rect. + Insets insets = m.getInsets(); + viewRect.x += insets.left; + viewRect.y += insets.top; + viewRect.width -= (insets.left + insets.right); + viewRect.height -= (insets.top + insets.bottom); + + // Fetch the fonts. + Font font = m.getFont(); + FontMetrics fm = m.getFontMetrics(font); + FontMetrics accelFm = m.getFontMetrics(acceleratorFont); + + String text = m.getText(); + SwingUtilities.layoutCompoundLabel(m, fm, text, m.getIcon(), + m.getVerticalAlignment(), + m.getHorizontalAlignment(), + m.getVerticalTextPosition(), + m.getHorizontalTextPosition(), + viewRect, iconRect, textRect, + defaultTextIconGap); + + // Initialize accelerator width and height. + if (! accelText.equals("")) + { + accelRect.width = accelFm.stringWidth(accelText); + accelRect.height = accelFm.getHeight(); + } + + // Initialize check and arrow icon width and height. + if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu())) + { + if (checkIcon != null) + { + checkIconRect.width = checkIcon.getIconWidth(); + checkIconRect.height = checkIcon.getIconHeight(); + } + if (arrowIcon != null) + { + arrowIconRect.width = arrowIcon.getIconWidth(); + arrowIconRect.height = arrowIcon.getIconHeight(); + } + } + + // The union of the icon and text of the menu item is the 'label area'. + cachedRect.setBounds(textRect); + Rectangle labelRect = SwingUtilities.computeUnion(iconRect.x, + iconRect.y, + iconRect.width, + iconRect.height, + cachedRect); + textRect.x += defaultTextIconGap; + iconRect.x += defaultTextIconGap; + + // Layout accelerator rect. + accelRect.x = viewRect.x + viewRect.width - arrowIconRect.width + - defaultTextIconGap - accelRect.width; + // Layout check and arrow icons only when not in toplevel menu. + if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu())) + { + checkIconRect.x = viewRect.x + defaultTextIconGap; + textRect.x += defaultTextIconGap + checkIconRect.width; + iconRect.x += defaultTextIconGap + checkIconRect.width; + arrowIconRect.x = viewRect.x + viewRect.width - defaultTextIconGap + - arrowIconRect.width; + } + + // Align the accelerator text and all the icons vertically centered to + // the menu text. + accelRect.y = labelRect.y + (labelRect.height / 2) + - (accelRect.height / 2); + if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu())) + { + arrowIconRect.y = labelRect.y + (labelRect.height / 2) + - (arrowIconRect.height / 2); + checkIconRect.y = labelRect.y + (labelRect.height / 2) + - (checkIconRect.height / 2); + } + } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java index e638b68e1dc..f8936be5b66 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java @@ -38,10 +38,11 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Dimension; import java.awt.event.MouseEvent; -import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.JComponent; @@ -219,6 +220,7 @@ public class BasicMenuUI extends BasicMenuItemUI * */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement } @@ -263,6 +265,7 @@ public class BasicMenuUI extends BasicMenuItemUI * Basic look and feel's defaults. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement } @@ -391,7 +394,7 @@ public class BasicMenuUI extends BasicMenuItemUI /** * This class handles MenuEvents fired by the JMenu */ - protected class MenuHandler implements MenuListener + private class MenuHandler implements MenuListener { /** * This method is called when menu is cancelled. The menu is cancelled @@ -440,24 +443,7 @@ public class BasicMenuUI extends BasicMenuItemUI } /** - * This class handles PropertyChangeEvents fired from the JMenu - */ - protected class PropertyChangeHandler implements PropertyChangeListener - { - /** - * This method is called whenever one of the properties of the menu item - * changes. - * - * @param e The PropertyChangeEvent. - */ - public void propertyChange(PropertyChangeEvent e) - { - // TODO: Implement this properly. - } - } - - /** - * @deprecated + * Obsolete as of JDK1.4. */ public class ChangeHandler implements ChangeListener { @@ -501,7 +487,7 @@ public class BasicMenuUI extends BasicMenuItemUI /** * This class handles mouse dragged events occuring in the menu. */ - protected class MenuDragMouseHandler implements MenuDragMouseListener + private class MenuDragMouseHandler implements MenuDragMouseListener { /** * This method is invoked when mouse is dragged over the menu item. @@ -553,7 +539,7 @@ public class BasicMenuUI extends BasicMenuItemUI * This class handles key events occuring when menu item is visible on the * screen. */ - protected class MenuKeyHandler implements MenuKeyListener + private class MenuKeyHandler implements MenuKeyListener { /** * This method is invoked when key has been pressed diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java index 005a3b394a8..88bca3b53ce 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -1204,6 +1206,7 @@ public class BasicOptionPaneUI extends OptionPaneUI * This method installs keyboard actions for the JOptionpane. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: implement. } @@ -1336,6 +1339,7 @@ public class BasicOptionPaneUI extends OptionPaneUI * This method uninstalls keyboard actions for the JOptionPane. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: implement. } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java index 783cec473bc..4f535f653cc 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java @@ -61,11 +61,10 @@ public class BasicPanelUI extends PanelUI } } - public void installDefaults(JPanel p) + protected void installDefaults(JPanel p) { LookAndFeel.installColorsAndFont(p, "Panel.background", "Panel.foreground", "Panel.font"); - p.setOpaque(true); } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java index 6ecd06b3988..a26a5c7c46b 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -37,6 +37,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Dimension; import java.awt.event.ComponentEvent; @@ -137,6 +139,7 @@ public class BasicPopupMenuUI extends PopupMenuUI * This method installs the keyboard actions for this {@link JPopupMenu}. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement } @@ -179,6 +182,7 @@ public class BasicPopupMenuUI extends PopupMenuUI * Uninstalls any keyboard actions. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java index 66e53803722..a66fa28e610 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java @@ -45,6 +45,7 @@ import java.awt.Graphics; import java.awt.Rectangle; import javax.swing.AbstractButton; +import javax.swing.ButtonModel; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.SwingUtilities; @@ -142,14 +143,15 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI g.setFont(f); + ButtonModel m = b.getModel(); Icon currentIcon = null; - if (b.isSelected() && b.isEnabled()) + if (m.isSelected() && m.isEnabled()) currentIcon = b.getSelectedIcon(); - else if (!b.isSelected() && b.isEnabled()) + else if (! m.isSelected() && m.isEnabled()) currentIcon = b.getIcon(); - else if (b.isSelected() && !b.isEnabled()) + else if (m.isSelected() && ! m.isEnabled()) currentIcon = b.getDisabledSelectedIcon(); - else // (!b.isSelected() && !b.isEnabled()) + else // (!m.isSelected() && ! m.isEnabled()) currentIcon = b.getDisabledIcon(); SwingUtilities.calculateInnerArea(b, vr); @@ -166,7 +168,7 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI if (text != null) paintText(g, b, tr, text); // TODO: Figure out what is the size parameter? - if (b.hasFocus() && b.isFocusPainted() && b.isEnabled()) + if (b.hasFocus() && b.isFocusPainted() && m.isEnabled()) paintFocus(g, tr, null); } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java index 28e3b67c1a5..933db4c6bc2 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java @@ -38,17 +38,98 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import javax.swing.AbstractAction; +import javax.swing.ButtonModel; +import javax.swing.InputMap; +import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JRootPane; +import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.plaf.ActionMapUIResource; +import javax.swing.plaf.ComponentInputMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.RootPaneUI; public class BasicRootPaneUI extends RootPaneUI implements PropertyChangeListener { + + /** + * Performed when the user activates the default button inside the JRootPane, + * usually by pressing 'ENTER'. + */ + private class DefaultPressAction + extends AbstractAction + { + /** + * The JRootPane for which this action should be installed. + */ + private JRootPane rootPane; + + /** + * Creates a new DefaultPressAction for the specified JRootPane. + */ + DefaultPressAction(JRootPane rp) + { + rootPane = rp; + } + + /** + * Performes the action. + */ + public void actionPerformed(ActionEvent ev) + { + JButton b = rootPane.getDefaultButton(); + if (b != null) + { + ButtonModel m = b.getModel(); + m.setArmed(true); + m.setPressed(true); + } + } + } + + /** + * Performed when the user activates the default button inside the JRootPane, + * usually by releasing 'ENTER'. + */ + private class DefaultReleaseAction + extends AbstractAction + { + /** + * The JRootPane for which this action should be installed. + */ + private JRootPane rootPane; + + /** + * Creates a new DefaultReleaseAction for the specified JRootPane. + */ + DefaultReleaseAction(JRootPane rp) + { + rootPane = rp; + } + + /** + * Performes the action. + */ + public void actionPerformed(ActionEvent ev) + { + JButton b = rootPane.getDefaultButton(); + if (b != null) + { + ButtonModel m = b.getModel(); + m.setPressed(false); + m.setArmed(false); + } + } + } + public static ComponentUI createUI(JComponent x) { return new BasicRootPaneUI(); @@ -107,14 +188,43 @@ public class BasicRootPaneUI extends RootPaneUI */ protected void installKeyboardActions(JRootPane rp) { - // We currently do not install any keyboard actions here. - // This method is here anyway for compatibility and to provide - // the necessary hooks to subclasses. + // Install the keyboard actions. + ActionMapUIResource am = new ActionMapUIResource(); + am.put("press", new DefaultPressAction(rp)); + am.put("release", new DefaultReleaseAction(rp)); + SwingUtilities.replaceUIActionMap(rp, am); + + // Install the input map from the UIManager. It seems like the actual + // bindings are installed in the JRootPane only when the defaultButton + // property receives a value. So we also only install an empty + // input map here, and fill it in propertyChange. + ComponentInputMapUIResource im = new ComponentInputMapUIResource(rp); + SwingUtilities.replaceUIInputMap(rp, JComponent.WHEN_IN_FOCUSED_WINDOW, + im); } public void propertyChange(PropertyChangeEvent event) { - // TODO: Implement this properly. + JRootPane source = (JRootPane) event.getSource(); + String propertyName = event.getPropertyName(); + if (propertyName.equals("defaultButton")) + { + Object newValue = event.getNewValue(); + InputMap im = + SwingUtilities.getUIInputMap(source, + JComponent.WHEN_IN_FOCUSED_WINDOW); + if (newValue != null) + { + Object[] keybindings = + (Object[]) UIManager.get + ("RootPane.defaultButtonWindowKeyBindings"); + LookAndFeel.loadKeyBindings(im, keybindings); + } + else + { + im.clear(); + } + } } /** @@ -176,6 +286,8 @@ public class BasicRootPaneUI extends RootPaneUI */ protected void uninstallKeyboardActions(JRootPane rp) { - // We do nothing here. + SwingUtilities.replaceUIActionMap(rp, null); + SwingUtilities.replaceUIInputMap(rp, JComponent.WHEN_IN_FOCUSED_WINDOW, + null); } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java index c8713c934dd..f2448548472 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Component; import java.awt.Container; @@ -383,7 +385,7 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, * * @return Whether the thumb should keep scrolling. */ - public boolean shouldScroll(int direction) + boolean shouldScroll(int direction) { int value; if (scrollbar.getOrientation() == HORIZONTAL) @@ -763,6 +765,7 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, * This method installs the keyboard actions for the scrollbar. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: implement. } @@ -1141,6 +1144,7 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, * during install. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: implement. } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java index 71671b79943..e6a4eaf4fc1 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java @@ -38,9 +38,15 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + +import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.beans.PropertyChangeEvent; @@ -53,6 +59,8 @@ import javax.swing.JViewport; import javax.swing.LookAndFeel; import javax.swing.ScrollPaneConstants; import javax.swing.ScrollPaneLayout; +import javax.swing.Scrollable; +import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.ComponentUI; @@ -222,18 +230,149 @@ public class BasicScrollPaneUI extends ScrollPaneUI */ protected class MouseWheelHandler implements MouseWheelListener { + /** + * Use to compute the visible rectangle. + */ + final Rectangle rect = new Rectangle(); /** - * Receives notification whenever the mouse wheel is moved. - * - * @param event the mouse wheel event + * Scroll with the mouse whell. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) */ - public void mouseWheelMoved(MouseWheelEvent event) + public void mouseWheelMoved(MouseWheelEvent e) { - // TODO: Implement this properly. + if (scrollpane.getViewport().getComponentCount() == 0) + return; + + Component target = scrollpane.getViewport().getComponent(0); + JScrollBar bar = scrollpane.getVerticalScrollBar(); + Scrollable scrollable = (target instanceof Scrollable) ? (Scrollable) target + : null; + + boolean tracksHeight = scrollable != null + && scrollable.getScrollableTracksViewportHeight(); + int wheel = e.getWheelRotation() * ROWS_PER_WHEEL_CLICK; + int delta; + + // If possible, scroll vertically. + if (bar != null && ! tracksHeight) + { + if (scrollable != null) + { + bounds(target); + delta = scrollable.getScrollableUnitIncrement( + rect, SwingConstants.VERTICAL, wheel); + } + else + { + // Scroll non scrollables. + delta = wheel * SCROLL_NON_SCROLLABLES; + } + scroll(bar, delta); + } + // If not, try to scroll horizontally + else + { + bar = scrollpane.getHorizontalScrollBar(); + boolean tracksWidth = scrollable != null + && scrollable.getScrollableTracksViewportWidth(); + + if (bar != null && ! tracksWidth) + { + if (scrollable != null) + { + bounds(target); + delta = scrollable.getScrollableUnitIncrement( + rect, SwingConstants.HORIZONTAL, wheel); + } + else + { + // Scroll non scrollables. + delta = wheel * SCROLL_NON_SCROLLABLES; + } + scroll(bar, delta); + } + } } + + /** + * Place the component bounds into rect. The x and y values + * need to be reversed. + * + * @param target the target being scrolled + */ + final void bounds(Component target) + { + // Viewport bounds, translated by the scroll bar positions. + target.getParent().getBounds(rect); + rect.x = getValue(scrollpane.getHorizontalScrollBar()); + rect.y = getValue(scrollpane.getVerticalScrollBar()); + } + + /** + * Get the scroll bar value or null if there is no such scroll bar. + */ + final int getValue(JScrollBar bar) + { + return bar != null ? bar.getValue() : 0; + } + + /** + * Scroll the given distance. + * + * @param bar the scrollbar to scroll + * @param delta the distance + */ + final void scroll(JScrollBar bar, int delta) + { + int y = bar.getValue() + delta; + + if (y < bar.getMinimum()) + y = bar.getMinimum(); + if (y > bar.getMaximum()) + y = bar.getMaximum(); + bar.setValue(y); + } + } + + /** + * Adds/removes the mouse wheel listener when the component is added/removed + * to/from the scroll pane view port. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ + class ViewportContainerListener implements ContainerListener + { + /** + * Add the mouse wheel listener, allowing to scroll with the mouse. + */ + public void componentAdded(ContainerEvent e) + { + e.getChild().addMouseWheelListener(mouseWheelListener); + } + + /** + * Remove the mouse wheel listener. + */ + public void componentRemoved(ContainerEvent e) + { + e.getChild().removeMouseWheelListener(mouseWheelListener); + } } + + /** + * The number of pixels by that we should scroll the content that does + * not implement Scrollable. + */ + static int SCROLL_NON_SCROLLABLES = 10; + + /** + * The number of rows to scroll per mouse wheel click. From impression, + * Sun seems using the value 3. + */ + static int ROWS_PER_WHEEL_CLICK = 3; /** The Scrollpane for which the UI is provided by this class. */ protected JScrollPane scrollpane; @@ -262,6 +401,12 @@ public class BasicScrollPaneUI extends ScrollPaneUI * The mousewheel listener for the scrollpane. */ MouseWheelListener mouseWheelListener; + + /** + * The listener to add and remove the mouse wheel listener to/from + * the component container. + */ + ContainerListener containerListener; public static ComponentUI createUI(final JComponent c) { @@ -316,11 +461,21 @@ public class BasicScrollPaneUI extends ScrollPaneUI if (viewportChangeListener == null) viewportChangeListener = createViewportChangeListener(); - sp.getViewport().addChangeListener(viewportChangeListener); - + if (mouseWheelListener == null) mouseWheelListener = createMouseWheelListener(); - sp.addMouseWheelListener(mouseWheelListener); + + if (containerListener == null) + containerListener = new ViewportContainerListener(); + + JViewport v = sp.getViewport(); + v.addChangeListener(viewportChangeListener); + v.addContainerListener(containerListener); + + // Add mouse wheel listeners to the componets that are probably already + // in the view port. + for (int i = 0; i < v.getComponentCount(); i++) + v.getComponent(i).addMouseWheelListener(mouseWheelListener); } /** @@ -331,6 +486,7 @@ public class BasicScrollPaneUI extends ScrollPaneUI * @param sp the scrollpane to install keyboard actions on */ protected void installKeyboardActions(JScrollPane sp) + throws NotImplementedException { // TODO: Is this only a hook method or should we actually do something // here? If the latter, than figure out what and implement this. @@ -408,8 +564,14 @@ public class BasicScrollPaneUI extends ScrollPaneUI .removeChangeListener(hsbChangeListener); sp.getVerticalScrollBar().getModel() .removeChangeListener(vsbChangeListener); - sp.getViewport().removeChangeListener(viewportChangeListener); - sp.removeMouseWheelListener(mouseWheelListener); + + JViewport v = sp.getViewport(); + v.removeChangeListener(viewportChangeListener); + v.removeContainerListener(containerListener); + + for (int i = 0; i < v.getComponentCount(); i++) + v.getComponent(i).removeMouseWheelListener(mouseWheelListener); + } /** @@ -420,6 +582,7 @@ public class BasicScrollPaneUI extends ScrollPaneUI * @param sp the scrollpane to uninstall keyboard actions from */ protected void uninstallKeyboardActions(JScrollPane sp) + throws NotImplementedException { // TODO: Is this only a hook method or should we actually do something // here? If the latter, than figure out what and implement this. diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java index 26f58051902..137ab55a607 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java @@ -1,5 +1,5 @@ /* BasicSliderUI.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Component; import java.awt.ComponentOrientation; @@ -61,7 +63,9 @@ import java.util.Dictionary; import java.util.Enumeration; import javax.swing.AbstractAction; +import javax.swing.ActionMap; import javax.swing.BoundedRangeModel; +import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JSlider; @@ -72,6 +76,7 @@ import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.MouseInputAdapter; +import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.SliderUI; @@ -204,6 +209,7 @@ public class BasicSliderUI extends SliderUI * @param e A {@link FocusEvent}. */ public void focusGained(FocusEvent e) + throws NotImplementedException { // FIXME: implement. } @@ -215,6 +221,7 @@ public class BasicSliderUI extends SliderUI * @param e A {@link FocusEvent}. */ public void focusLost(FocusEvent e) + throws NotImplementedException { // FIXME: implement. } @@ -236,14 +243,16 @@ public class BasicSliderUI extends SliderUI { // Check for orientation changes. if (e.getPropertyName().equals("orientation")) - recalculateIfOrientationChanged(); + recalculateIfOrientationChanged(); else if (e.getPropertyName().equals("model")) { - BoundedRangeModel oldModel = (BoundedRangeModel) e.getOldValue(); - oldModel.removeChangeListener(changeListener); - slider.getModel().addChangeListener(changeListener); - calculateThumbLocation(); + BoundedRangeModel oldModel = (BoundedRangeModel) e.getOldValue(); + oldModel.removeChangeListener(changeListener); + slider.getModel().addChangeListener(changeListener); + calculateThumbLocation(); } + else if (e.getPropertyName().equals("paintTicks")) + calculateGeometry(); // elif the componentOrientation changes (this is a bound property, // just undocumented) we change leftToRightCache. In Sun's @@ -304,14 +313,14 @@ public class BasicSliderUI extends SliderUI { if (! trackListener.shouldScroll(direction)) { - scrollTimer.stop(); - return; + scrollTimer.stop(); + return; } if (block) - scrollByBlock(direction); + scrollByBlock(direction); else - scrollByUnit(direction); + scrollByUnit(direction); } /** @@ -364,17 +373,20 @@ public class BasicSliderUI extends SliderUI */ public void mouseDragged(MouseEvent e) { - currentMouseX = e.getX(); - currentMouseY = e.getY(); - if (slider.getValueIsAdjusting()) + if (slider.isEnabled()) { - int value; - if (slider.getOrientation() == JSlider.HORIZONTAL) - value = valueForXPosition(currentMouseX) - offset; - else - value = valueForYPosition(currentMouseY) - offset; - - slider.setValue(value); + currentMouseX = e.getX(); + currentMouseY = e.getY(); + if (slider.getValueIsAdjusting()) + { + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX) - offset; + else + value = valueForYPosition(currentMouseY) - offset; + + slider.setValue(value); + } } } @@ -399,32 +411,36 @@ public class BasicSliderUI extends SliderUI */ public void mousePressed(MouseEvent e) { - currentMouseX = e.getX(); - currentMouseY = e.getY(); - - int value; - if (slider.getOrientation() == JSlider.HORIZONTAL) - value = valueForXPosition(currentMouseX); - else - value = valueForYPosition(currentMouseY); - - if (slider.getSnapToTicks()) - value = findClosestTick(value); - - // If the thumb is hit, then we don't need to set the timers to move it. - if (! thumbRect.contains(e.getPoint())) - { - // The mouse has hit some other part of the slider. - // The value moves no matter where in the slider you hit. - if (value > slider.getValue()) - scrollDueToClickInTrack(POSITIVE_SCROLL); - else - scrollDueToClickInTrack(NEGATIVE_SCROLL); - } - else + if (slider.isEnabled()) { - slider.setValueIsAdjusting(true); - offset = value - slider.getValue(); + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (slider.getSnapToTicks()) + value = findClosestTick(value); + + // If the thumb is hit, then we don't need to set the timers to + // move it. + if (! thumbRect.contains(e.getPoint())) + { + // The mouse has hit some other part of the slider. + // The value moves no matter where in the slider you hit. + if (value > slider.getValue()) + scrollDueToClickInTrack(POSITIVE_SCROLL); + else + scrollDueToClickInTrack(NEGATIVE_SCROLL); + } + else + { + slider.setValueIsAdjusting(true); + offset = value - slider.getValue(); + } } } @@ -436,17 +452,20 @@ public class BasicSliderUI extends SliderUI */ public void mouseReleased(MouseEvent e) { - currentMouseX = e.getX(); - currentMouseY = e.getY(); - - if (slider.getValueIsAdjusting()) + if (slider.isEnabled()) { - slider.setValueIsAdjusting(false); - if (slider.getSnapToTicks()) - slider.setValue(findClosestTick(slider.getValue())); + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + if (slider.getValueIsAdjusting()) + { + slider.setValueIsAdjusting(false); + if (slider.getSnapToTicks()) + slider.setValue(findClosestTick(slider.getValue())); + } + if (scrollTimer != null) + scrollTimer.stop(); } - if (scrollTimer != null) - scrollTimer.stop(); } /** @@ -460,14 +479,14 @@ public class BasicSliderUI extends SliderUI { int value; if (slider.getOrientation() == JSlider.HORIZONTAL) - value = valueForXPosition(currentMouseX); + value = valueForXPosition(currentMouseX); else - value = valueForYPosition(currentMouseY); + value = valueForYPosition(currentMouseY); if (direction == POSITIVE_SCROLL) - return (value > slider.getValue()); + return (value > slider.getValue()); else - return (value < slider.getValue()); + return (value < slider.getValue()); } } @@ -643,35 +662,35 @@ public class BasicSliderUI extends SliderUI super.installUI(c); if (c instanceof JSlider) { - slider = (JSlider) c; + slider = (JSlider) c; - focusRect = new Rectangle(); - contentRect = new Rectangle(); - thumbRect = new Rectangle(); - trackRect = new Rectangle(); - tickRect = new Rectangle(); - labelRect = new Rectangle(); + focusRect = new Rectangle(); + contentRect = new Rectangle(); + thumbRect = new Rectangle(); + trackRect = new Rectangle(); + tickRect = new Rectangle(); + labelRect = new Rectangle(); - insetCache = slider.getInsets(); - leftToRightCache = ! slider.getInverted(); + insetCache = slider.getInsets(); + leftToRightCache = ! slider.getInverted(); - scrollTimer = new Timer(200, null); - scrollTimer.setRepeats(true); + scrollTimer = new Timer(200, null); + scrollTimer.setRepeats(true); - installDefaults(slider); - installListeners(slider); - installKeyboardActions(slider); + installDefaults(slider); + installListeners(slider); + installKeyboardActions(slider); - calculateFocusRect(); + calculateFocusRect(); - calculateContentRect(); - calculateThumbSize(); - calculateTrackBuffer(); - calculateTrackRect(); - calculateThumbLocation(); + calculateContentRect(); + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateThumbLocation(); - calculateTickRect(); - calculateLabelRect(); + calculateTickRect(); + calculateLabelRect(); } } @@ -856,7 +875,10 @@ public class BasicSliderUI extends SliderUI */ protected void installKeyboardActions(JSlider slider) { - // FIXME: implement. + InputMap keyMap = getInputMap(JComponent.WHEN_FOCUSED); + SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, keyMap); + ActionMap map = getActionMap(); + SwingUtilities.replaceUIActionMap(slider, map); } /** @@ -868,7 +890,8 @@ public class BasicSliderUI extends SliderUI */ protected void uninstallKeyboardActions(JSlider slider) { - // FIXME: implement. + SwingUtilities.replaceUIActionMap(slider, null); + SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, null); } /* XXX: This is all after experimentation with SUN's implementation. @@ -899,8 +922,7 @@ public class BasicSliderUI extends SliderUI // The width should cover all the labels (which are usually the // deciding factor of the width) int width = getWidthOfWidestLabel() * (slider.getLabelTable() == null ? 0 - : slider.getLabelTable() - .size()); + : slider.getLabelTable().size()); // If there are not enough labels. // This number is pretty much arbitrary, but it looks nice. @@ -1120,8 +1142,8 @@ public class BasicSliderUI extends SliderUI } /** - * This method calculates the size but not the position of the thumbRect. It - * must take into account the orientation of the slider. + * Sets the width and height of the <code>thumbRect</code> field, using the + * dimensions returned by {@link #getThumbSize()}. */ protected void calculateThumbSize() { @@ -1135,8 +1157,9 @@ public class BasicSliderUI extends SliderUI } /** - * This method calculates the size and position of the contentRect. This - * method does not need to be called if the orientation changes. + * Updates the <code>contentRect</code> field to an area inside the + * <code>focusRect</code>. This method does not need to be called if the + * orientation changes. */ protected void calculateContentRect() { @@ -1163,36 +1186,50 @@ public class BasicSliderUI extends SliderUI if (slider.getOrientation() == JSlider.HORIZONTAL) { - thumbRect.x = xPositionForValue(value) - thumbRect.width / 2; - thumbRect.y = trackRect.y; + thumbRect.x = xPositionForValue(value) - thumbRect.width / 2; + thumbRect.y = trackRect.y; } else { - thumbRect.x = trackRect.x; - thumbRect.y = yPositionForValue(value) - thumbRect.height / 2; + thumbRect.x = trackRect.x; + thumbRect.y = yPositionForValue(value) - thumbRect.height / 2; } } /** - * Calculates the gap size between the left edge of the contentRect and the - * left edge of the trackRect. + * Calculates the gap size between the edge of the <code>contentRect</code> + * and the edge of the <code>trackRect</code>, storing the result in the + * <code>trackBuffer</code> field. Sufficient space needs to be reserved + * for the slider thumb and/or the labels at each end of the slider track. */ protected void calculateTrackBuffer() { if (slider.getOrientation() == JSlider.HORIZONTAL) - trackBuffer = thumbRect.width / 2; + { + int w = Math.max(getWidthOfLowValueLabel(), getWidthOfHighValueLabel()); + trackBuffer = Math.max(thumbRect.width / 2, w / 2); + + } else - trackBuffer = thumbRect.height / 2; + { + int h = Math.max(getHeightOfLowValueLabel(), + getHeightOfHighValueLabel()); + trackBuffer = Math.max(thumbRect.height / 2, h / 2); + } } /** - * This method returns the size of the thumbRect. + * Returns the size of the slider's thumb. The size is hard coded to + * <code>11 x 20</code> for horizontal sliders, and <code>20 x 11</code> for + * vertical sliders. Note that a new instance of {@link Dimension} is + * returned for every call to this method (this seems wasteful, but + * {@link Dimension} instances are not immutable, so this is probably + * unavoidable). * - * @return The dimensions of the thumb. + * @return The size of the slider's thumb. */ protected Dimension getThumbSize() { - // TODO: shouldn't create new objects every time if (slider.getOrientation() == JSlider.HORIZONTAL) return new Dimension(11, 20); else @@ -1207,14 +1244,16 @@ public class BasicSliderUI extends SliderUI { if (slider.getOrientation() == JSlider.HORIZONTAL) { - trackRect.x = contentRect.x + trackBuffer; + trackRect.x = contentRect.x + trackBuffer; int h = getThumbSize().height; if (slider.getPaintTicks() && (slider.getMajorTickSpacing() > 0 || slider.getMinorTickSpacing() > 0)) h += getTickLength(); - trackRect.y = contentRect.y + (contentRect.height - h) / 2 - 1; - trackRect.width = contentRect.width - 2 * trackBuffer; - trackRect.height = thumbRect.height; + if (slider.getPaintLabels()) + h += getHeightOfTallestLabel(); + trackRect.y = contentRect.y + (contentRect.height - h) / 2 - 1; + trackRect.width = contentRect.width - 2 * trackBuffer; + trackRect.height = thumbRect.height; } else { @@ -1222,10 +1261,12 @@ public class BasicSliderUI extends SliderUI if (slider.getPaintTicks() && (slider.getMajorTickSpacing() > 0 || slider.getMinorTickSpacing() > 0)) w += getTickLength(); - trackRect.x = contentRect.x + (contentRect.width - w) / 2 - 1; - trackRect.y = contentRect.y + trackBuffer; - trackRect.width = thumbRect.width; - trackRect.height = contentRect.height - 2 * trackBuffer; + if (slider.getPaintLabels()) + w += getWidthOfWidestLabel(); + trackRect.x = contentRect.x + (contentRect.width - w) / 2 - 1; + trackRect.y = contentRect.y + trackBuffer; + trackRect.width = thumbRect.width; + trackRect.height = contentRect.height - 2 * trackBuffer; } } @@ -1252,23 +1293,23 @@ public class BasicSliderUI extends SliderUI { if (slider.getOrientation() == JSlider.HORIZONTAL) { - tickRect.x = trackRect.x; - tickRect.y = trackRect.y + trackRect.height; - tickRect.width = trackRect.width; - tickRect.height = getTickLength(); + tickRect.x = trackRect.x; + tickRect.y = trackRect.y + trackRect.height; + tickRect.width = trackRect.width; + tickRect.height = (slider.getPaintTicks() ? getTickLength() : 0); - if (tickRect.y + tickRect.height > contentRect.y + contentRect.height) - tickRect.height = contentRect.y + contentRect.height - tickRect.y; + if (tickRect.y + tickRect.height > contentRect.y + contentRect.height) + tickRect.height = contentRect.y + contentRect.height - tickRect.y; } else { - tickRect.x = trackRect.x + trackRect.width; - tickRect.y = trackRect.y; - tickRect.width = getTickLength(); - tickRect.height = trackRect.height; + tickRect.x = trackRect.x + trackRect.width; + tickRect.y = trackRect.y; + tickRect.width = (slider.getPaintTicks() ? getTickLength() : 0); + tickRect.height = trackRect.height; - if (tickRect.x + tickRect.width > contentRect.x + contentRect.width) - tickRect.width = contentRect.x + contentRect.width - tickRect.x; + if (tickRect.x + tickRect.width > contentRect.x + contentRect.width) + tickRect.width = contentRect.x + contentRect.width - tickRect.x; } } @@ -1280,17 +1321,17 @@ public class BasicSliderUI extends SliderUI { if (slider.getOrientation() == JSlider.HORIZONTAL) { - labelRect.x = contentRect.x; - labelRect.y = tickRect.y + tickRect.height; - labelRect.width = contentRect.width; - labelRect.height = contentRect.height - labelRect.y; + labelRect.x = contentRect.x; + labelRect.y = tickRect.y + tickRect.height; + labelRect.width = contentRect.width; + labelRect.height = getHeightOfTallestLabel(); } else { - labelRect.x = tickRect.x + tickRect.width; - labelRect.y = contentRect.y; - labelRect.width = contentRect.width - labelRect.x; - labelRect.height = contentRect.height; + labelRect.x = tickRect.x + tickRect.width; + labelRect.y = contentRect.y; + labelRect.width = getWidthOfWidestLabel(); + labelRect.height = contentRect.height; } } @@ -1312,13 +1353,13 @@ public class BasicSliderUI extends SliderUI for (Enumeration list = slider.getLabelTable().elements(); list.hasMoreElements();) { - Object comp = list.nextElement(); - if (! (comp instanceof Component)) - continue; - label = (Component) comp; - pref = label.getPreferredSize(); - if (pref != null && pref.width > widest) - widest = pref.width; + Object comp = list.nextElement(); + if (! (comp instanceof Component)) + continue; + label = (Component) comp; + pref = label.getPreferredSize(); + if (pref != null && pref.width > widest) + widest = pref.width; } return widest; } @@ -1340,50 +1381,54 @@ public class BasicSliderUI extends SliderUI for (Enumeration list = slider.getLabelTable().elements(); list.hasMoreElements();) { - Object comp = list.nextElement(); - if (! (comp instanceof Component)) - continue; - label = (Component) comp; - pref = label.getPreferredSize(); - if (pref != null && pref.height > tallest) - tallest = pref.height; + Object comp = list.nextElement(); + if (! (comp instanceof Component)) + continue; + label = (Component) comp; + pref = label.getPreferredSize(); + if (pref != null && pref.height > tallest) + tallest = pref.height; } return tallest; } /** - * This method returns the width of the label whose key has the highest - * value. + * Returns the width of the label whose key has the highest value, or 0 if + * there are no labels. * - * @return The width of the high value label or 0 if no label table exists. + * @return The width of the label whose key has the highest value. + * + * @see #getHighestValueLabel() */ protected int getWidthOfHighValueLabel() { Component highValueLabel = getHighestValueLabel(); if (highValueLabel != null) - return highValueLabel.getWidth(); + return highValueLabel.getPreferredSize().width; else return 0; } /** - * This method returns the width of the label whose key has the lowest - * value. + * Returns the width of the label whose key has the lowest value, or 0 if + * there are no labels. * - * @return The width of the low value label or 0 if no label table exists. + * @return The width of the label whose key has the lowest value. + * + * @see #getLowestValueLabel() */ protected int getWidthOfLowValueLabel() { Component lowValueLabel = getLowestValueLabel(); if (lowValueLabel != null) - return lowValueLabel.getWidth(); + return lowValueLabel.getPreferredSize().width; else return 0; } /** - * This method returns the height of the label whose key has the highest - * value. + * Returns the height of the label whose key has the highest value, or 0 if + * there are no labels. * * @return The height of the high value label or 0 if no label table exists. */ @@ -1391,14 +1436,14 @@ public class BasicSliderUI extends SliderUI { Component highValueLabel = getHighestValueLabel(); if (highValueLabel != null) - return highValueLabel.getHeight(); + return highValueLabel.getPreferredSize().height; else return 0; } /** - * This method returns the height of the label whose key has the lowest - * value. + * Returns the height of the label whose key has the lowest value, or 0 if + * there are no labels. * * @return The height of the low value label or 0 if no label table exists. */ @@ -1406,19 +1451,20 @@ public class BasicSliderUI extends SliderUI { Component lowValueLabel = getLowestValueLabel(); if (lowValueLabel != null) - return lowValueLabel.getHeight(); + return lowValueLabel.getPreferredSize().height; else return 0; } /** - * This method returns whether the slider is to be drawn inverted. + * Returns <code>true</code> if the slider scale is to be drawn inverted, + * and <code>false</code> if not. * - * @return True is the slider is to be drawn inverted. + * @return <code>true</code> if the slider is to be drawn inverted. */ protected boolean drawInverted() { - return ! (slider.getInverted() ^ leftToRightCache); + return slider.getInverted(); } /** @@ -1437,12 +1483,12 @@ public class BasicSliderUI extends SliderUI for (Enumeration list = labelTable.keys(); list.hasMoreElements();) { - Object value = list.nextElement(); - if (! (value instanceof Integer)) - continue; - tmpKey = (Integer) value; - if (tmpKey.intValue() < key.intValue()) - key = tmpKey; + Object value = list.nextElement(); + if (! (value instanceof Integer)) + continue; + tmpKey = (Integer) value; + if (tmpKey.intValue() < key.intValue()) + key = tmpKey; } Object comp = labelTable.get(key); if (! (comp instanceof Component)) @@ -1451,9 +1497,10 @@ public class BasicSliderUI extends SliderUI } /** - * This method returns the label whose key has the highest value. + * Returns the label whose key has the highest value. * - * @return The high value label or null if no label table exists. + * @return The label whose key has the highest value or <code>null</code> if + * no label table exists. */ protected Component getHighestValueLabel() { @@ -1466,12 +1513,12 @@ public class BasicSliderUI extends SliderUI for (Enumeration list = labelTable.keys(); list.hasMoreElements();) { - Object value = list.nextElement(); - if (! (value instanceof Integer)) - continue; - tmpKey = (Integer) value; - if (tmpKey.intValue() > key.intValue()) - key = tmpKey; + Object value = list.nextElement(); + if (! (value instanceof Integer)) + continue; + tmpKey = (Integer) value; + if (tmpKey.intValue() > key.intValue()) + key = tmpKey; } Object comp = labelTable.get(key); if (! (comp instanceof Component)) @@ -1490,7 +1537,8 @@ public class BasicSliderUI extends SliderUI public void paint(Graphics g, JComponent c) { // FIXME: Move this to propertyChangeEvent handler, when we get those. - leftToRightCache = slider.getComponentOrientation() != ComponentOrientation.RIGHT_TO_LEFT; + leftToRightCache = slider.getComponentOrientation() + != ComponentOrientation.RIGHT_TO_LEFT; // FIXME: This next line is only here because the above line is here. calculateGeometry(); @@ -1599,23 +1647,23 @@ public class BasicSliderUI extends SliderUI if (slider.getOrientation() == JSlider.HORIZONTAL) { - width = trackRect.width; - height = (thumbRect.height / 4 == 0) ? 1 : thumbRect.height / 4; + width = trackRect.width; + height = (thumbRect.height / 4 == 0) ? 1 : thumbRect.height / 4; - a.translate(0, (trackRect.height / 2) - (height / 2)); - b.translate(0, (trackRect.height / 2) + (height / 2)); - c.translate(trackRect.width, (trackRect.height / 2) + (height / 2)); - d.translate(trackRect.width, (trackRect.height / 2) - (height / 2)); + a.translate(0, (trackRect.height / 2) - (height / 2)); + b.translate(0, (trackRect.height / 2) + (height / 2)); + c.translate(trackRect.width, (trackRect.height / 2) + (height / 2)); + d.translate(trackRect.width, (trackRect.height / 2) - (height / 2)); } else { - width = (thumbRect.width / 4 == 0) ? 1 : thumbRect.width / 4; - height = trackRect.height; + width = (thumbRect.width / 4 == 0) ? 1 : thumbRect.width / 4; + height = trackRect.height; - a.translate((trackRect.width / 2) - (width / 2), 0); - b.translate((trackRect.width / 2) - (width / 2), trackRect.height); - c.translate((trackRect.width / 2) + (width / 2), trackRect.height); - d.translate((trackRect.width / 2) + (width / 2), 0); + a.translate((trackRect.width / 2) - (width / 2), 0); + b.translate((trackRect.width / 2) - (width / 2), trackRect.height); + c.translate((trackRect.width / 2) + (width / 2), trackRect.height); + d.translate((trackRect.width / 2) + (width / 2), 0); } g.setColor(Color.GRAY); g.fillRect(a.x, a.y, width, height); @@ -1647,86 +1695,42 @@ public class BasicSliderUI extends SliderUI if (majorSpace > 0) { - if (slider.getOrientation() == JSlider.HORIZONTAL) - { - double loc = tickRect.x + 0.5; - double increment = (max == min) ? 0 - : majorSpace * (double) (tickRect.width - 1) / (max - min); - if (drawInverted()) - { - loc += tickRect.width; - increment *= -1; - } + if (slider.getOrientation() == JSlider.HORIZONTAL) + { g.translate(0, tickRect.y); - for (int i = min; i <= max; i += majorSpace) - { - paintMajorTickForHorizSlider(g, tickRect, (int) loc); - loc += increment; - } + for (int i = min; i <= max; i += majorSpace) + paintMajorTickForHorizSlider(g, tickRect, xPositionForValue(i)); g.translate(0, -tickRect.y); - } - else - { - double loc = tickRect.height + tickRect.y + 0.5; - double increment = (max == min) ? 0 - : -majorSpace * (double) (tickRect.height - 1) / (max - min); - if (drawInverted()) - { - loc = tickRect.y + 0.5; - increment *= -1; - } + } + else // JSlider.VERTICAL + { g.translate(tickRect.x, 0); - for (int i = min; i <= max; i += majorSpace) - { - paintMajorTickForVertSlider(g, tickRect, (int) loc); - loc += increment; - } + for (int i = min; i <= max; i += majorSpace) + paintMajorTickForVertSlider(g, tickRect, yPositionForValue(i)); g.translate(-tickRect.x, 0); - } + } } if (minorSpace > 0) { - if (slider.getOrientation() == JSlider.HORIZONTAL) - { - double loc = tickRect.x + 0.5; - double increment = (max == min) ? 0 - : minorSpace * (double) (tickRect.width - 1) / (max - min); - if (drawInverted()) - { - loc += tickRect.width; - increment *= -1; - } + if (slider.getOrientation() == JSlider.HORIZONTAL) + { g.translate(0, tickRect.y); - for (int i = min; i <= max; i += minorSpace) - { - paintMinorTickForHorizSlider(g, tickRect, (int) loc); - loc += increment; - } + for (int i = min; i <= max; i += minorSpace) + paintMinorTickForHorizSlider(g, tickRect, xPositionForValue(i)); g.translate(0, -tickRect.y); - } - else - { - double loc = tickRect.height + tickRect.y + 0.5; - double increment = (max == min) ? 0 - : -minorSpace * (double) (tickRect.height - 1) / (max - min); - if (drawInverted()) - { - loc = tickRect.y + 0.5; - increment *= -1; - } + } + else + { g.translate(tickRect.x, 0); - for (int i = min; i <= max; i += minorSpace) - { - paintMinorTickForVertSlider(g, tickRect, (int) loc); - loc += increment; - } + for (int i = min; i <= max; i += minorSpace) + paintMinorTickForVertSlider(g, tickRect, yPositionForValue(i)); g.translate(-tickRect.x, 0); - } + } } } - /* Minor ticks start at 1/4 of the height (or width) of the tickRect and extend - to 1/2 of the tickRect. + /* Minor ticks start at 1/4 of the height (or width) of the tickRect and + extend to 1/2 of the tickRect. Major ticks start at 1/4 of the height and extend to 3/4. */ @@ -1819,45 +1823,45 @@ public class BasicSliderUI extends SliderUI { if (slider.getLabelTable() != null) { - Dictionary table = slider.getLabelTable(); - Integer tmpKey; - Object key; - Object element; - Component label; - if (slider.getOrientation() == JSlider.HORIZONTAL) - { - for (Enumeration list = table.keys(); list.hasMoreElements();) - { - key = list.nextElement(); - if (! (key instanceof Integer)) - continue; - tmpKey = (Integer) key; - element = table.get(tmpKey); - // We won't paint them if they're not - // JLabels so continue anyway - if (! (element instanceof JLabel)) - continue; - label = (Component) element; - paintHorizontalLabel(g, tmpKey.intValue(), label); - } - } - else - { - for (Enumeration list = table.keys(); list.hasMoreElements();) - { - key = list.nextElement(); - if (! (key instanceof Integer)) - continue; - tmpKey = (Integer) key; - element = table.get(tmpKey); - // We won't paint them if they're not - // JLabels so continue anyway - if (! (element instanceof JLabel)) - continue; - label = (Component) element; - paintVerticalLabel(g, tmpKey.intValue(), label); - } - } + Dictionary table = slider.getLabelTable(); + Integer tmpKey; + Object key; + Object element; + Component label; + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + for (Enumeration list = table.keys(); list.hasMoreElements();) + { + key = list.nextElement(); + if (! (key instanceof Integer)) + continue; + tmpKey = (Integer) key; + element = table.get(tmpKey); + // We won't paint them if they're not + // JLabels so continue anyway + if (! (element instanceof JLabel)) + continue; + label = (Component) element; + paintHorizontalLabel(g, tmpKey.intValue(), label); + } + } + else + { + for (Enumeration list = table.keys(); list.hasMoreElements();) + { + key = list.nextElement(); + if (! (key instanceof Integer)) + continue; + tmpKey = (Integer) key; + element = table.get(tmpKey); + // We won't paint them if they're not + // JLabels so continue anyway + if (! (element instanceof JLabel)) + continue; + label = (Component) element; + paintVerticalLabel(g, tmpKey.intValue(), label); + } + } } } @@ -1918,7 +1922,7 @@ public class BasicSliderUI extends SliderUI h = labelRect.height; label.setBounds(xpos, ypos, w, h); - javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds()); + SwingUtilities.paintComponent(g, label, null, label.getBounds()); } /** @@ -1957,7 +1961,7 @@ public class BasicSliderUI extends SliderUI w = labelRect.width; label.setBounds(xpos, ypos, w, h); - javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds()); + SwingUtilities.paintComponent(g, label, null, label.getBounds()); } /** @@ -1997,49 +2001,52 @@ public class BasicSliderUI extends SliderUI Polygon dark; // dark shadow Polygon all; - // This will be in X-dimension if the slider is inverted and y if it isn't. + // This will be in X-dimension if the slider is inverted and y if it isn't. int turnPoint; if (slider.getOrientation() == JSlider.HORIZONTAL) { - turnPoint = thumbRect.height * 3 / 4; + turnPoint = thumbRect.height * 3 / 4; - b.translate(thumbRect.width - 1, 0); - c.translate(thumbRect.width - 1, turnPoint); - d.translate(thumbRect.width / 2 - 1, thumbRect.height - 1); - e.translate(0, turnPoint); + b.translate(thumbRect.width - 1, 0); + c.translate(thumbRect.width - 1, turnPoint); + d.translate(thumbRect.width / 2 - 1, thumbRect.height - 1); + e.translate(0, turnPoint); - bright = new Polygon(new int[] { b.x - 1, a.x, e.x, d.x }, - new int[] { b.y, a.y, e.y, d.y }, 4); + bright = new Polygon(new int[] { b.x - 1, a.x, e.x, d.x }, + new int[] { b.y, a.y, e.y, d.y }, 4); - dark = new Polygon(new int[] { b.x, c.x, d.x + 1 }, - new int[] { b.y, c.y - 1, d.y }, 3); + dark = new Polygon(new int[] { b.x, c.x, d.x + 1 }, + new int[] { b.y, c.y - 1, d.y }, 3); light = new Polygon(new int[] { b.x - 1, c.x - 1, d.x + 1 }, new int[] { b.y + 1, c.y - 1, d.y - 1 }, 3); - all = new Polygon(new int[] { a.x + 1, b.x - 2, c.x - 2, d.x, e.x + 1 }, - new int[] { a.y + 1, b.y + 1, c.y - 1, d.y - 1, e.y }, 5); + all = new Polygon(new int[] { a.x + 1, b.x - 2, c.x - 2, d.x, e.x + 1 }, + new int[] { a.y + 1, b.y + 1, c.y - 1, d.y - 1, e.y }, + 5); } else { - turnPoint = thumbRect.width * 3 / 4 - 1; + turnPoint = thumbRect.width * 3 / 4 - 1; - b.translate(turnPoint, 0); - c.translate(thumbRect.width - 1, thumbRect.height / 2); - d.translate(turnPoint, thumbRect.height - 1); - e.translate(0, thumbRect.height - 1); + b.translate(turnPoint, 0); + c.translate(thumbRect.width - 1, thumbRect.height / 2); + d.translate(turnPoint, thumbRect.height - 1); + e.translate(0, thumbRect.height - 1); - bright = new Polygon(new int[] { c.x - 1, b.x, a.x, e.x }, - new int[] { c.y - 1, b.y, a.y, e.y - 1 }, 4); + bright = new Polygon(new int[] { c.x - 1, b.x, a.x, e.x }, + new int[] { c.y - 1, b.y, a.y, e.y - 1 }, 4); - dark = new Polygon(new int[] { c.x, d.x, e.x }, - new int[] { c.y, d.y, e.y }, 3); + dark = new Polygon(new int[] { c.x, d.x, e.x }, + new int[] { c.y, d.y, e.y }, 3); light = new Polygon(new int[] { c.x - 1, d.x, e.x + 1}, new int[] { c.y, d.y - 1, e.y - 1}, 3); - all = new Polygon(new int[] { a.x + 1, b.x, c.x - 2, c.x - 2, d.x, e.x + 1 }, - new int[] { a.y + 1, b.y + 1, c.y - 1, c.y, d.y - 2, e.y - 2 }, 6); + all = new Polygon(new int[] { a.x + 1, b.x, c.x - 2, c.x - 2, d.x, + e.x + 1 }, + new int[] { a.y + 1, b.y + 1, c.y - 1, c.y, d.y - 2, + e.y - 2 }, 6); } g.setColor(Color.WHITE); @@ -2071,18 +2078,22 @@ public class BasicSliderUI extends SliderUI } /** - * This method is used to move the thumb one block in the direction - * specified. If the slider snaps to ticks, this method is responsible for - * snapping it to a tick after the thumb has been moved. + * Moves the thumb one block in the direction specified (a block is 1/10th + * of the slider range). If the slider snaps to ticks, this method is + * responsible for snapping it to a tick after the thumb has been moved. * - * @param direction The direction to move in. + * @param direction the direction (positive values increment the thumb + * position by one block, zero/negative values decrement the thumb position + * by one block). */ public void scrollByBlock(int direction) { - // The direction is -1 for backwards and 1 for forwards. - int unit = direction * (slider.getMaximum() - slider.getMinimum()) / 10; - - int moveTo = slider.getValue() + unit; + int unit = (slider.getMaximum() - slider.getMinimum()) / 10; + int moveTo = slider.getValue(); + if (direction > 0) + moveTo += unit; + else + moveTo -= unit; if (slider.getSnapToTicks()) moveTo = findClosestTick(moveTo); @@ -2091,16 +2102,21 @@ public class BasicSliderUI extends SliderUI } /** - * This method is used to move the thumb one unit in the direction - * specified. If the slider snaps to ticks, this method is responsible for - * snapping it to a tick after the thumb has been moved. + * Moves the thumb one unit in the specified direction. If the slider snaps + * to ticks, this method is responsible for snapping it to a tick after the + * thumb has been moved. * - * @param direction The direction to move in. + * @param direction the direction (positive values increment the thumb + * position by one, zero/negative values decrement the thumb position by + * one). */ public void scrollByUnit(int direction) { - // The direction is -1 for backwards and 1 for forwards. - int moveTo = slider.getValue() + direction; + int moveTo = slider.getValue(); + if (direction > 0) + moveTo++; + else + moveTo--; if (slider.getSnapToTicks()) moveTo = findClosestTick(moveTo); @@ -2126,53 +2142,60 @@ public class BasicSliderUI extends SliderUI } /** - * This method returns the X coordinate for the value passed in. + * Returns the x-coordinate (relative to the component) for the given slider + * value. This method assumes that the <code>trackRect</code> field is + * set up. * - * @param value The value to calculate an x coordinate for. + * @param value the slider value. * - * @return The x coordinate for the value. + * @return The x-coordinate. */ protected int xPositionForValue(int value) { - int min = slider.getMinimum(); - int max = slider.getMaximum(); - int len = trackRect.width - 1; - - int xPos = (max == min) ? 0 : (value - min) * len / (max - min); + double min = slider.getMinimum(); + if (value < min) + value = (int) min; + double max = slider.getMaximum(); + if (value > max) + value = (int) max; + double len = trackRect.width; + if ((max - min) <= 0.0) + return 0; + int xPos = (int) ((value - min) / (max - min) * len + 0.5); - if (! drawInverted()) - xPos += trackRect.x; + if (drawInverted()) + return trackRect.x + Math.max(trackRect.width - xPos - 1, 0); else - { - xPos = len - xPos; - xPos += trackRect.x; - } - return xPos; + return trackRect.x + Math.min(xPos, trackRect.width - 1); } /** - * This method returns the y coordinate for the value passed in. + * Returns the y-coordinate (relative to the component) for the given slider + * value. This method assumes that the <code>trackRect</code> field is + * set up. * - * @param value The value to calculate a y coordinate for. + * @param value the slider value. * - * @return The y coordinate for the value. + * @return The y-coordinate. */ protected int yPositionForValue(int value) { - int min = slider.getMinimum(); - int max = slider.getMaximum(); - int len = trackRect.height - 1; + double min = slider.getMinimum(); + if (value < min) + value = (int) min; + double max = slider.getMaximum(); + if (value > max) + value = (int) max; + int len = trackRect.height; + if ((max - min) <= 0.0) + return 0; - int yPos = (max == min) ? 0 : (value - min) * len / (max - min); + int yPos = (int) ((value - min) / (max - min) * len + 0.5); if (! drawInverted()) - { - yPos = len - yPos; - yPos += trackRect.y; - } + return trackRect.y + trackRect.height - Math.max(yPos, 1); else - yPos += trackRect.y; - return yPos; + return trackRect.y + Math.min(yPos, trackRect.height - 1); } /** @@ -2279,26 +2302,26 @@ public class BasicSliderUI extends SliderUI // First check the major ticks. if (majorSpace > 0) { - int lowerBound = (value - min) / majorSpace; - int majLower = majorSpace * lowerBound + min; - int majHigher = majorSpace * (lowerBound + 1) + min; - - if (majHigher <= max && majHigher - value <= value - majLower) - major = majHigher - value; - else - major = majLower - value; + int lowerBound = (value - min) / majorSpace; + int majLower = majorSpace * lowerBound + min; + int majHigher = majorSpace * (lowerBound + 1) + min; + + if (majHigher <= max && majHigher - value <= value - majLower) + major = majHigher - value; + else + major = majLower - value; } if (minorSpace > 0) { - int lowerBound = value / minorSpace; - int minLower = minorSpace * lowerBound; - int minHigher = minorSpace * (lowerBound + 1); - - if (minHigher <= max && minHigher - value <= value - minLower) - minor = minHigher - value; - else - minor = minLower - value; + int lowerBound = value / minorSpace; + int minLower = minorSpace * lowerBound; + int minHigher = minorSpace * (lowerBound + 1); + + if (minHigher <= max && minHigher - value <= value - minLower) + minor = minHigher - value; + else + minor = minLower - value; } // Give preference to minor ticks @@ -2307,4 +2330,123 @@ public class BasicSliderUI extends SliderUI else return value + minor; } + + InputMap getInputMap(int condition) + { + if (condition == JComponent.WHEN_FOCUSED) + return (InputMap) UIManager.get("Slider.focusInputMap"); + return null; + } + + /** + * Returns the action map for the {@link JSlider}. All sliders share + * a single action map which is created the first time this method is + * called, then stored in the UIDefaults table for subsequent access. + * + * @return The shared action map. + */ + ActionMap getActionMap() + { + ActionMap map = (ActionMap) UIManager.get("Slider.actionMap"); + + if (map == null) // first time here + { + map = createActionMap(); + if (map != null) + UIManager.put("Slider.actionMap", map); + } + return map; + } + + /** + * Creates the action map shared by all {@link JSlider} instances. + * This method is called once by {@link #getActionMap()} when it + * finds no action map in the UIDefaults table...after the map is + * created, it gets added to the defaults table so that subsequent + * calls to {@link #getActionMap()} will return the same shared + * instance. + * + * @return The action map. + */ + ActionMap createActionMap() + { + ActionMap map = new ActionMapUIResource(); + map.put("positiveUnitIncrement", + new AbstractAction("positiveUnitIncrement") { + public void actionPerformed(ActionEvent event) + { + JSlider slider = (JSlider) event.getSource(); + BasicSliderUI ui = (BasicSliderUI) slider.getUI(); + if (slider.getInverted()) + ui.scrollByUnit(BasicSliderUI.NEGATIVE_SCROLL); + else + ui.scrollByUnit(BasicSliderUI.POSITIVE_SCROLL); + } + } + ); + map.put("negativeUnitIncrement", + new AbstractAction("negativeUnitIncrement") { + public void actionPerformed(ActionEvent event) + { + JSlider slider = (JSlider) event.getSource(); + BasicSliderUI ui = (BasicSliderUI) slider.getUI(); + if (slider.getInverted()) + ui.scrollByUnit(BasicSliderUI.POSITIVE_SCROLL); + else + ui.scrollByUnit(BasicSliderUI.NEGATIVE_SCROLL); + } + } + ); + map.put("positiveBlockIncrement", + new AbstractAction("positiveBlockIncrement") { + public void actionPerformed(ActionEvent event) + { + JSlider slider = (JSlider) event.getSource(); + BasicSliderUI ui = (BasicSliderUI) slider.getUI(); + if (slider.getInverted()) + ui.scrollByBlock(BasicSliderUI.NEGATIVE_SCROLL); + else + ui.scrollByBlock(BasicSliderUI.POSITIVE_SCROLL); + } + } + ); + map.put("negativeBlockIncrement", + new AbstractAction("negativeBlockIncrement") { + public void actionPerformed(ActionEvent event) + { + JSlider slider = (JSlider) event.getSource(); + BasicSliderUI ui = (BasicSliderUI) slider.getUI(); + if (slider.getInverted()) + ui.scrollByBlock(BasicSliderUI.POSITIVE_SCROLL); + else + ui.scrollByBlock(BasicSliderUI.NEGATIVE_SCROLL); + } + } + ); + map.put("minScroll", + new AbstractAction("minScroll") { + public void actionPerformed(ActionEvent event) + { + JSlider slider = (JSlider) event.getSource(); + if (slider.getInverted()) + slider.setValue(slider.getMaximum()); + else + slider.setValue(slider.getMinimum()); + } + } + ); + map.put("maxScroll", + new AbstractAction("maxScroll") { + public void actionPerformed(ActionEvent event) + { + JSlider slider = (JSlider) event.getSource(); + if (slider.getInverted()) + slider.setValue(slider.getMinimum()); + else + slider.setValue(slider.getMaximum()); + } + } + ); + return map; + } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java index 6f7a41a1d96..465374bfda9 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java @@ -41,7 +41,6 @@ package javax.swing.plaf.basic; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; -import java.awt.Font; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.event.ActionEvent; @@ -365,9 +364,9 @@ public class BasicSpinnerUI extends SpinnerUI private class DefaultLayoutManager implements LayoutManager { /** - * DOCUMENT ME! + * Layout the spinners inner parts. * - * @param parent DOCUMENT ME! + * @param parent The parent container */ public void layoutContainer(Container parent) { @@ -385,12 +384,12 @@ public class BasicSpinnerUI extends SpinnerUI Dimension e = prefSize(editor); Dimension n = prefSize(next); Dimension p = prefSize(previous); - Dimension s = spinner.getPreferredSize(); + Dimension s = parent.getSize(); int x = l2r ? i.left : i.right; int y = i.top; int w = Math.max(p.width, n.width); - int h = e.height / 2; + int h = (s.height - i.bottom) / 2; int e_width = s.width - w - i.left - i.right; if (l2r) diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java index 8a7c9d2a290..694baaddade 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Canvas; import java.awt.Color; import java.awt.Component; @@ -101,6 +103,16 @@ public class BasicSplitPaneUI extends SplitPaneUI protected int[] sizes = new int[3]; /** + * Creates a new instance. This is package private because the reference + * implementation has no public constructor either. Still, we need to + * call it from BasicVerticalLayoutManager. + */ + BasicHorizontalLayoutManager() + { + // Nothing to do here. + } + + /** * This method adds the component given to the JSplitPane. The position of * the component is given by the constraints object. * @@ -1037,6 +1049,7 @@ public class BasicSplitPaneUI extends SplitPaneUI * This method installs the keyboard actions for the JSplitPane. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: implement. } @@ -1045,6 +1058,7 @@ public class BasicSplitPaneUI extends SplitPaneUI * This method reverses the work done in installKeyboardActions. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: implement. } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java index 5b1e1ff0f60..6d9bed331cb 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Component; import java.awt.Container; @@ -130,52 +132,49 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants */ public void mousePressed(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - int tabCount = tabPane.getTabCount(); - - if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) + if (tabPane.isEnabled()) { - if (e.getSource() == incrButton) + int index = tabForCoordinate(tabPane, e.getX(), e.getY()); + if (index >= 0 && tabPane.isEnabledAt(index)) { - if (++currentScrollLocation >= tabCount) - currentScrollLocation = tabCount - 1; - - int width = 0; - for (int i = currentScrollLocation - 1; i < tabCount; i++) - width += rects[i].width; - if (width < viewport.getWidth()) - // FIXME: Still getting mouse events after the button is disabled. - // incrButton.setEnabled(false); - currentScrollLocation--; - else if (! decrButton.isEnabled()) - decrButton.setEnabled(true); - tabPane.revalidate(); - tabPane.repaint(); - return; - } - else if (e.getSource() == decrButton) - { - if (--currentScrollLocation < 0) - currentScrollLocation = 0; - if (currentScrollLocation == 0) - decrButton.setEnabled(false); - else if (! incrButton.isEnabled()) - incrButton.setEnabled(true); - tabPane.revalidate(); - tabPane.repaint(); - return; + tabPane.setSelectedIndex(index); } } + } - int index = tabForCoordinate(tabPane, x, y); + /** + * Receives notification when the mouse pointer has entered the tabbed + * pane. + * + * @param ev the mouse event + */ + public void mouseEntered(MouseEvent ev) + { + int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY()); + setRolloverTab(tabIndex); + } - // We need to check since there are areas where tabs cannot be - // e.g. in the inset area. - if (index != -1 && tabPane.isEnabledAt(index)) - tabPane.setSelectedIndex(index); - tabPane.revalidate(); - tabPane.repaint(); + /** + * Receives notification when the mouse pointer has exited the tabbed + * pane. + * + * @param ev the mouse event + */ + public void mouseExited(MouseEvent ev) + { + setRolloverTab(-1); + } + + /** + * Receives notification when the mouse pointer has moved over the tabbed + * pane. + * + * @param ev the mouse event + */ + public void mouseMoved(MouseEvent ev) + { + int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY()); + setRolloverTab(tabIndex); } } @@ -241,21 +240,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants */ public void calculateLayoutInfo() { - assureRectsCreated(tabPane.getTabCount()); - contentRect = SwingUtilities.calculateInnerArea(tabPane, contentRect); - - calculateTabRects(tabPane.getTabPlacement(), tabPane.getTabCount()); - - if (tabPane.getSelectedIndex() != -1) - { - Component visible = getVisibleComponent(); - Insets insets = getContentBorderInsets(tabPane.getTabPlacement()); - if (visible != null) - visible.setBounds(contentRect.x + insets.left, - contentRect.y + insets.top, - contentRect.width - insets.left - insets.right, - contentRect.height - insets.top - insets.bottom); - } + int count = tabPane.getTabCount(); + assureRectsCreated(count); + calculateTabRects(tabPane.getTabPlacement(), count); + tabRunsDirty = false; } /** @@ -269,45 +257,51 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants protected Dimension calculateSize(boolean minimum) { int tabPlacement = tabPane.getTabPlacement(); + int width = 0; int height = 0; - - int componentHeight = 0; - int componentWidth = 0; Component c; Dimension dims; + + // Find out the minimum/preferred size to display the largest child + // of the tabbed pane. for (int i = 0; i < tabPane.getTabCount(); i++) { c = tabPane.getComponentAt(i); if (c == null) continue; - calcRect = c.getBounds(); - dims = c.getPreferredSize(); + dims = minimum ? c.getMinimumSize() : c.getPreferredSize(); if (dims != null) { - componentHeight = Math.max(componentHeight, dims.height); - componentWidth = Math.max(componentWidth, dims.width); + height = Math.max(height, dims.height); + width = Math.max(width, dims.width); } } + + Insets tabAreaInsets = getTabAreaInsets(tabPlacement); if (tabPlacement == SwingConstants.TOP || tabPlacement == SwingConstants.BOTTOM) { int min = calculateMaxTabWidth(tabPlacement); - width = Math.max(min, componentWidth); - - int tabAreaHeight = preferredTabAreaHeight(tabPlacement, width); - height = tabAreaHeight + componentHeight; + width = Math.max(min, width); + int tabAreaHeight = preferredTabAreaHeight(tabPlacement, + width - tabAreaInsets.left + -tabAreaInsets.right); + height += tabAreaHeight; } else { int min = calculateMaxTabHeight(tabPlacement); - height = Math.max(min, componentHeight); - - int tabAreaWidth = preferredTabAreaWidth(tabPlacement, height); - width = tabAreaWidth + componentWidth; + height = Math.max(min, height); + int tabAreaWidth = preferredTabAreaWidth(tabPlacement, + height - tabAreaInsets.top + - tabAreaInsets.bottom); + width += tabAreaWidth; } - return new Dimension(width, height); + Insets tabPaneInsets = tabPane.getInsets(); + return new Dimension(width + tabPaneInsets.left + tabPaneInsets.right, + height + tabPaneInsets.top + tabPaneInsets.bottom); } // if tab placement is LEFT OR RIGHT, they share width. @@ -330,192 +324,197 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants */ protected void calculateTabRects(int tabPlacement, int tabCount) { + Insets insets = tabPane.getInsets(); + Insets tabAreaInsets = getTabAreaInsets(tabPlacement); + Dimension size = tabPane.getSize(); + + // The coordinates of the upper left corner of the tab area. + int x; + int y; + // The location at which the runs must be broken. + int breakAt; + + // Calculate the bounds for the tab area. + switch (tabPlacement) + { + case LEFT: + maxTabWidth = calculateMaxTabWidth(tabPlacement); + x = insets.left + tabAreaInsets.left; + y = insets.top + tabAreaInsets.top; + breakAt = size.height - (insets.bottom + tabAreaInsets.bottom); + break; + case RIGHT: + maxTabWidth = calculateMaxTabWidth(tabPlacement); + x = size.width - (insets.right + tabAreaInsets.right) - maxTabWidth; + y = insets.top + tabAreaInsets.top; + breakAt = size.height - (insets.bottom + tabAreaInsets.bottom); + break; + case BOTTOM: + maxTabHeight = calculateMaxTabHeight(tabPlacement); + x = insets.left + tabAreaInsets.left; + y = size.height - (insets.bottom + tabAreaInsets.bottom) + - maxTabHeight; + breakAt = size.width - (insets.right + tabAreaInsets.right); + break; + case TOP: + default: + maxTabHeight = calculateMaxTabHeight(tabPlacement); + x = insets.left + tabAreaInsets.left; + y = insets.top + tabAreaInsets.top; + breakAt = size.width - (insets.right + tabAreaInsets.right); + break; + } + if (tabCount == 0) return; FontMetrics fm = getFontMetrics(); - SwingUtilities.calculateInnerArea(tabPane, calcRect); - Insets tabAreaInsets = getTabAreaInsets(tabPlacement); - Insets insets = tabPane.getInsets(); - int max = 0; - int runs = 0; - int start = getTabRunIndent(tabPlacement, 1); + runCount = 0; + selectedRun = -1; + int selectedIndex = tabPane.getSelectedIndex(); + + Rectangle rect; + + // Go through all the tabs and build the tab runs. if (tabPlacement == SwingConstants.TOP || tabPlacement == SwingConstants.BOTTOM) { - int maxHeight = calculateMaxTabHeight(tabPlacement); - - calcRect.width -= tabAreaInsets.left + tabAreaInsets.right; - max = calcRect.width + tabAreaInsets.left + insets.left; - start += tabAreaInsets.left + insets.left; - int width = 0; - int runWidth = start; - for (int i = 0; i < tabCount; i++) { - width = calculateTabWidth(tabPlacement, i, fm); - if (runWidth + width > max) + rect = rects[i]; + if (i > 0) { - runWidth = tabAreaInsets.left + insets.left - + getTabRunIndent(tabPlacement, ++runs); - rects[i] = new Rectangle(runWidth, - insets.top + tabAreaInsets.top, - width, maxHeight); - runWidth += width; - if (runs > tabRuns.length - 1) - expandTabRunsArray(); - tabRuns[runs] = i; + rect.x = rects[i - 1].x + rects[i - 1].width; } else { - rects[i] = new Rectangle(runWidth, - insets.top + tabAreaInsets.top, - width, maxHeight); - runWidth += width; + tabRuns[0] = 0; + runCount = 1; + maxTabWidth = 0; + rect.x = x; } - } - runs++; - tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right; - tabAreaRect.height = runs * maxTabHeight - - (runs - 1) * tabRunOverlay - + tabAreaInsets.top + tabAreaInsets.bottom; - contentRect.width = tabAreaRect.width; - contentRect.height = tabPane.getHeight() - insets.top - - insets.bottom - tabAreaRect.height; - contentRect.x = insets.left; - tabAreaRect.x = insets.left; - if (tabPlacement == SwingConstants.BOTTOM) - { - contentRect.y = insets.top; - tabAreaRect.y = contentRect.y + contentRect.height; - } - else - { - tabAreaRect.y = insets.top; - contentRect.y = tabAreaRect.y + tabAreaRect.height; + rect.width = calculateTabWidth(tabPlacement, i, fm); + maxTabWidth = Math.max(maxTabWidth, rect.width); + + if (rect.x != 2 + insets.left && rect.x + rect.width > breakAt) + { + if (runCount > tabRuns.length - 1) + expandTabRunsArray(); + tabRuns[runCount] = i; + runCount++; + rect.x = x; + } + + rect.y = y; + rect.height = maxTabHeight; + if (i == selectedIndex) + selectedRun = runCount - 1; + } } else { - int maxWidth = calculateMaxTabWidth(tabPlacement); - calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom; - max = calcRect.height + tabAreaInsets.top + insets.top; - - int height = 0; - start += tabAreaInsets.top + insets.top; - int runHeight = start; - - int fontHeight = fm.getHeight(); - for (int i = 0; i < tabCount; i++) { - height = calculateTabHeight(tabPlacement, i, fontHeight); - if (runHeight + height > max) + rect = rects[i]; + if (i > 0) { - runHeight = tabAreaInsets.top + insets.top - + getTabRunIndent(tabPlacement, ++runs); - rects[i] = new Rectangle(insets.left + tabAreaInsets.left, - runHeight, maxWidth, height); - runHeight += height; - if (runs > tabRuns.length - 1) - expandTabRunsArray(); - tabRuns[runs] = i; + rect.y = rects[i - 1].y + rects[i - 1].height; } else { - rects[i] = new Rectangle(insets.left + tabAreaInsets.left, - runHeight, maxWidth, height); - runHeight += height; + tabRuns[0] = 0; + runCount = 1; + maxTabHeight = 0; + rect.y = y; } - } - runs++; + rect.height = calculateTabHeight(tabPlacement, i, + fm.getHeight()); + maxTabHeight = Math.max(maxTabHeight, rect.height); - tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay - + tabAreaInsets.left + tabAreaInsets.right; - tabAreaRect.height = tabPane.getHeight() - insets.top - - insets.bottom; - tabAreaRect.y = insets.top; - contentRect.width = tabPane.getWidth() - insets.left - insets.right - - tabAreaRect.width; - contentRect.height = tabAreaRect.height; - contentRect.y = insets.top; - if (tabPlacement == SwingConstants.LEFT) - { - tabAreaRect.x = insets.left; - contentRect.x = tabAreaRect.x + tabAreaRect.width; - } - else - { - contentRect.x = insets.left; - tabAreaRect.x = contentRect.x + contentRect.width; + if (rect.y != 2 + insets.top && rect.y + rect.height > breakAt) + { + if (runCount > tabRuns.length - 1) + expandTabRunsArray(); + tabRuns[runCount] = i; + runCount++; + rect.y = y; + } + + rect.x = x; + rect.width = maxTabWidth; + + if (i == selectedIndex) + selectedRun = runCount - 1; } } - runCount = runs; - if (runCount > tabRuns.length) - expandTabRunsArray(); - - tabRuns[0] = 0; - normalizeTabRuns(tabPlacement, tabCount, start, max); - selectedRun = getRunForTab(tabCount, tabPane.getSelectedIndex()); - if (shouldRotateTabRuns(tabPlacement)) - rotateTabRuns(tabPlacement, selectedRun); - // Need to pad the runs and move them to the correct location. - for (int i = 0; i < runCount; i++) + if (runCount > 1) { - int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1; - if (first == tabCount) - first = 0; - int last = lastTabInRun(tabCount, i); - if (shouldPadTabRun(tabPlacement, i)) - padTabRun(tabPlacement, first, last, max); - - // Done padding, now need to move it. - if (tabPlacement == SwingConstants.TOP && i > 0) + int start; + if (tabPlacement == SwingConstants.TOP + || tabPlacement == SwingConstants.BOTTOM) + start = y; + else + start = x; + normalizeTabRuns(tabPlacement, tabCount, start, breakAt); + selectedRun = getRunForTab(tabCount, selectedIndex); + if (shouldRotateTabRuns(tabPlacement)) { - for (int j = first; j <= last; j++) - rects[j].y += (runCount - i) * maxTabHeight - - (runCount - i) * tabRunOverlay; + rotateTabRuns(tabPlacement, selectedRun); } + } - if (tabPlacement == SwingConstants.BOTTOM) + // Pad the runs. + int tabRunOverlay = getTabRunOverlay(tabPlacement); + for (int i = runCount - 1; i >= 0; --i) + { + int start = tabRuns[i]; + int nextIndex; + if (i == runCount - 1) + nextIndex = 0; + else + nextIndex = i + 1; + int next = tabRuns[nextIndex]; + int end = (next != 0 ? next - 1 : tabCount - 1); + if (tabPlacement == SwingConstants.TOP + || tabPlacement == SwingConstants.BOTTOM) { - int height = tabPane.getBounds().height - insets.bottom - - tabAreaInsets.bottom; - int adjustment; - if (i == 0) - adjustment = height - maxTabHeight; + for (int j = start; j <= end; ++j) + { + rect = rects[j]; + rect.y = y; + rect.x += getTabRunIndent(tabPlacement, i); + } + if (shouldPadTabRun(tabPlacement, i)) + { + padTabRun(tabPlacement, start, end, breakAt); + } + if (tabPlacement == BOTTOM) + y -= (maxTabHeight - tabRunOverlay); else - adjustment = height - (runCount - i + 1) * maxTabHeight - - (runCount - i) * tabRunOverlay; - - for (int j = first; j <= last; j++) - rects[j].y = adjustment; - } - - if (tabPlacement == SwingConstants.LEFT && i > 0) - { - for (int j = first; j <= last; j++) - rects[j].x += (runCount - i) * maxTabWidth - - (runCount - i) * tabRunOverlay; + y += (maxTabHeight - tabRunOverlay); } - - if (tabPlacement == SwingConstants.RIGHT) + else { - int width = tabPane.getBounds().width - insets.right - - tabAreaInsets.right; - int adjustment; - if (i == 0) - adjustment = width - maxTabWidth; + for (int j = start; j <= end; ++j) + { + rect = rects[j]; + rect.x = x; + rect.y += getTabRunIndent(tabPlacement, i); + } + if (shouldPadTabRun(tabPlacement, i)) + { + padTabRun(tabPlacement, start, end, breakAt); + } + if (tabPlacement == RIGHT) + x -= (maxTabWidth - tabRunOverlay); else - adjustment = width - (runCount - i + 1) * maxTabWidth - + (runCount - i) * tabRunOverlay; - - for (int j = first; j <= last; j++) - rects[j].x = adjustment; + x += (maxTabWidth - tabRunOverlay); + } } - padSelectedTab(tabPlacement, tabPane.getSelectedIndex()); + padSelectedTab(tabPlacement, selectedIndex); } /** @@ -528,6 +527,58 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants public void layoutContainer(Container parent) { calculateLayoutInfo(); + + int tabPlacement = tabPane.getTabPlacement(); + Insets insets = tabPane.getInsets(); + int childCount = tabPane.getComponentCount(); + if (childCount > 0) + { + int compX; + int compY; + int tabAreaWidth = 0; + int tabAreaHeight = 0; + switch (tabPlacement) + { + case LEFT: + tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount, + maxTabWidth); + compX = tabAreaWidth + insets.left + contentBorderInsets.left; + compY = insets.top + contentBorderInsets.top; + break; + case RIGHT: + tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount, + maxTabWidth); + compX = insets.left + contentBorderInsets.left; + compY = insets.top + contentBorderInsets.top; + break; + case BOTTOM: + tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount, + maxTabHeight); + compX = insets.left + contentBorderInsets.left; + compY = insets.top + contentBorderInsets.top; + break; + case TOP: + default: + tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount, + maxTabHeight); + compX = insets.left + contentBorderInsets.left; + compY = tabAreaHeight + insets.top + contentBorderInsets.top; + } + Rectangle bounds = tabPane.getBounds(); + int compWidth = bounds.width - tabAreaWidth - insets.left + - insets.right - contentBorderInsets.left + - contentBorderInsets.right; + int compHeight = bounds.height - tabAreaHeight - insets.top + - insets.bottom - contentBorderInsets.top + - contentBorderInsets.bottom; + + + for (int i = 0; i < childCount; ++i) + { + Component c = tabPane.getComponent(i); + c.setBounds(compX, compY, compWidth, compHeight); + } + } } /** @@ -1288,6 +1339,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants protected int[] tabRuns; /** + * Indicates if the layout of the tab runs is ok or not. This is package + * private to avoid a synthetic accessor method. + */ + boolean tabRunsDirty; + + /** * This is the keystroke for moving down. * * @deprecated 1.3 @@ -1343,6 +1400,17 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants transient Rectangle contentRect; /** + * The index over which the mouse is currently moving. + */ + private int rolloverTab; + + /** + * Determines if tabs are painted opaque or not. This can be adjusted using + * the UIManager property 'TabbedPane.tabsOpaque'. + */ + private boolean tabsOpaque; + + /** * Creates a new BasicTabbedPaneUI object. */ public BasicTabbedPaneUI() @@ -1557,6 +1625,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants selectedTabPadInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabPadInsets"); tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets"); contentBorderInsets = UIManager.getInsets("TabbedPane.tabbedPaneContentBorderInsets"); + tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque"); calcRect = new Rectangle(); tabRuns = new int[10]; @@ -1585,9 +1654,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants lightHighlight = null; highlight = null; - tabPane.setBackground(null); - tabPane.setForeground(null); - tabPane.setFont(null); + // Install UI colors and fonts. + LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background", + "TabbedPane.foreground", + "TabbedPane.font"); } /** @@ -1666,6 +1736,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants * This method installs keyboard actions for the JTabbedPane. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: Implement. } @@ -1674,6 +1745,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants * This method uninstalls keyboard actions for the JTabbedPane. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: Implement. } @@ -1710,6 +1782,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants */ public void paint(Graphics g, JComponent c) { + if (!tabPane.isValid()) + tabPane.validate(); + if (tabPane.getTabCount() == 0) return; if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT) @@ -1735,42 +1810,26 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants // Please note: the ordering of the painting is important. // we WANT to paint the outermost run first and then work our way in. int tabCount = tabPane.getTabCount(); - int currRun = 1; - - if (tabCount < 1) - return; - - if (runCount > 1) - currRun = 0; - for (int i = 0; i < runCount; i++) + for (int i = runCount - 1; i >= 0; --i) { - int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1; - if (isScroll) - first = currentScrollLocation; - else if (first == tabCount) - first = 0; - int last = lastTabInRun(tabCount, currRun); - if (isScroll) + int start = tabRuns[i]; + int next; + if (i == runCount - 1) + next = tabRuns[0]; + else + next = tabRuns[i + 1]; + int end = (next != 0 ? next - 1 : tabCount - 1); + for (int j = start; j <= end; ++j) { - for (int k = first; k < tabCount; k++) + if (j != selectedIndex) { - if (rects[k].x + rects[k].width - rects[first].x > viewport - .getWidth()) - { - last = k; - break; - } + paintTab(g, tabPlacement, rects, j, ir, tr); } } - - for (int j = first; j <= last; j++) - { - if (j != selectedIndex || isScroll) - paintTab(g, tabPlacement, rects, j, ir, tr); - } - currRun = getPreviousTabRun(currRun); } - if (! isScroll) + + // Paint selected tab in front of every other tab. + if (selectedIndex >= 0) paintTab(g, tabPlacement, rects, selectedIndex, ir, tr); } @@ -1788,49 +1847,34 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect) { - FontMetrics fm = getFontMetrics(); - Icon icon = getIconForTab(tabIndex); - String title = tabPane.getTitleAt(tabIndex); + Rectangle rect = rects[tabIndex]; boolean isSelected = tabIndex == tabPane.getSelectedIndex(); - calcRect = getTabBounds(tabPane, tabIndex); - - int x = calcRect.x; - int y = calcRect.y; - int w = calcRect.width; - int h = calcRect.height; - if (getRunForTab(tabPane.getTabCount(), tabIndex) == 1) + // Paint background if necessary. + if (tabsOpaque || tabPane.isOpaque()) { - Insets insets = getTabAreaInsets(tabPlacement); - switch (tabPlacement) - { - case TOP: - h += insets.bottom; - break; - case LEFT: - w += insets.right; - break; - case BOTTOM: - y -= insets.top; - h += insets.top; - break; - case RIGHT: - x -= insets.left; - w += insets.left; - break; - } + paintTabBackground(g, tabPlacement, tabIndex, rect.x, rect.y, + rect.width, rect.height, isSelected); } - layoutLabel(tabPlacement, fm, tabIndex, title, icon, calcRect, iconRect, - textRect, isSelected); - paintTabBackground(g, tabPlacement, tabIndex, x, y, w, h, isSelected); - paintTabBorder(g, tabPlacement, tabIndex, x, y, w, h, isSelected); + // Paint border. + paintTabBorder(g, tabPlacement, tabIndex, rect.x, rect.y, rect.width, + rect.height, isSelected); - // FIXME: Paint little folding corner and jagged edge clipped tab. - if (icon != null) - paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected); - if (title != null && ! title.equals("")) - paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title, + + // Layout label. + FontMetrics fm = getFontMetrics(); + Icon icon = getIconForTab(tabIndex); + String title = tabPane.getTitleAt(tabIndex); + layoutLabel(tabPlacement, fm, tabIndex, title, icon, rect, iconRect, textRect, isSelected); + // Paint the text. + paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title, + textRect, isSelected); + // Paint icon if necessary. + paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected); + // Paint focus indicator. + paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect, + isSelected); } /** @@ -1902,6 +1946,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants FontMetrics metrics, int tabIndex, String title, Rectangle textRect, boolean isSelected) { + g.setFont(font); View textView = getTextViewForTab(tabIndex); if (textView != null) { @@ -1909,54 +1954,48 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants return; } - Color fg = tabPane.getForegroundAt(tabIndex); - if (fg == null) - fg = tabPane.getForeground(); - Color bg = tabPane.getBackgroundAt(tabIndex); - if (bg == null) - bg = tabPane.getBackground(); - - Color saved_color = g.getColor(); - Font f = g.getFont(); - g.setFont(font); + int ascent = metrics.getAscent(); - if (tabPane.isEnabledAt(tabIndex)) + int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex); + if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex)) { + Color fg = tabPane.getForegroundAt(tabIndex); + if (isSelected && (fg instanceof UIResource)) + { + Color selectionForeground = + UIManager.getColor("TabbedPane.selectionForeground"); + if (selectionForeground != null) + fg = selectionForeground; + } g.setColor(fg); - int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex); - if (mnemIndex != -1) BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex, textRect.x, - textRect.y - + metrics.getAscent()); + textRect.y + ascent); else - g.drawString(title, textRect.x, textRect.y + metrics.getAscent()); + g.drawString(title, textRect.x, textRect.y + ascent); } else { + Color bg = tabPane.getBackgroundAt(tabIndex); g.setColor(bg.brighter()); - - int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex); - if (mnemIndex != -1) BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex, - textRect.x, textRect.y); + textRect.x, textRect.y + + ascent); else - g.drawString(title, textRect.x, textRect.y); + g.drawString(title, textRect.x, textRect.y + ascent); g.setColor(bg.darker()); if (mnemIndex != -1) BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex, textRect.x + 1, - textRect.y + 1); + textRect.y + 1 + + ascent); else - g.drawString(title, textRect.x + 1, textRect.y + 1); + g.drawString(title, textRect.x + 1, textRect.y + 1 + ascent); } - - g.setColor(saved_color); - g.setFont(f); } /** @@ -2009,14 +2048,45 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants Rectangle iconRect, Rectangle textRect, boolean isSelected) { - Color saved = g.getColor(); - calcRect = iconRect.union(textRect); - - g.setColor(focus); - - g.drawRect(calcRect.x, calcRect.y, calcRect.width, calcRect.height); - - g.setColor(saved); + if (tabPane.hasFocus() && isSelected) + { + Rectangle rect = rects[tabIndex]; + // The focus rectangle. + int x; + int y; + int w; + int h; + + g.setColor(focus); + switch (tabPlacement) + { + case LEFT: + x = rect.x + 3; + y = rect.y + 3; + w = rect.width - 5; + h = rect.height - 6; + break; + case RIGHT: + x = rect.x + 2; + y = rect.y + 3; + w = rect.width - 6; + h = rect.height - 5; + break; + case BOTTOM: + x = rect.x + 3; + y = rect.y + 2; + w = rect.width - 6; + h = rect.height - 5; + break; + case TOP: + default: + x = rect.x + 3; + y = rect.y + 3; + w = rect.width - 6; + h = rect.height - 5; + } + BasicGraphicsUtils.drawDashedRect(g, x, y, w, h); + } } /** @@ -2109,10 +2179,44 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) { - int x = contentRect.x; - int y = contentRect.y; - int w = contentRect.width; - int h = contentRect.height; + int width = tabPane.getWidth(); + int height = tabPane.getHeight(); + Insets insets = tabPane.getInsets(); + Insets tabAreaInsets = getTabAreaInsets(tabPlacement); + + // Calculate coordinates of content area. + int x = insets.left; + int y = insets.top; + int w = width - insets.left - insets.right; + int h = height - insets.top - insets.bottom; + + switch (tabPlacement) + { + case LEFT: + x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth); + w -= (x - insets.left); + break; + case RIGHT: + w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth); + break; + case BOTTOM: + h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight); + break; + case TOP: + default: + y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight); + h -= (y - insets.top); + } + + // Fill background if necessary. + if (tabPane.isOpaque()) + { + Color bg = UIManager.getColor("TabbedPane.contentAreaColor"); + g.setColor(bg); + g.fillRect(x, y, w, h); + } + + // Paint border. paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h); paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h); paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h); @@ -2332,23 +2436,23 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants */ public int tabForCoordinate(JTabbedPane pane, int x, int y) { - Point p = new Point(x, y); + if (! tabPane.isValid()) + tabPane.validate(); + int tabCount = tabPane.getTabCount(); - int currRun = 1; - for (int i = 0; i < runCount; i++) + int index = -1; + for (int i = 0; i < tabCount; ++i) { - int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1; - if (first == tabCount) - first = 0; - int last = lastTabInRun(tabCount, currRun); - for (int j = first; j <= last; j++) + if (rects[i].contains(x, y)) { - if (getTabBounds(pane, j).contains(p)) - return j; + index = i; + break; } - currRun = getNextTabRun(currRun); } - return -1; + + // FIXME: Handle scrollable tab layout. + + return index; } /** @@ -2455,10 +2559,23 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants */ protected int lastTabInRun(int tabCount, int run) { - if (tabRuns[run] == 0) - return tabCount - 1; + int lastTab; + if (runCount == 1) + lastTab = tabCount - 1; else - return tabRuns[run] - 1; + { + int nextRun; + if (run == runCount - 1) + nextRun = 0; + else + nextRun = run + 1; + + if (tabRuns[nextRun] == 0) + lastTab = tabCount - 1; + else + lastTab = tabRuns[nextRun] - 1; + } + return lastTab; } /** @@ -2554,24 +2671,14 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants protected int calculateTabHeight(int tabPlacement, int tabIndex, int fontHeight) { - Icon icon = getIconForTab(tabIndex); - Insets insets = getTabInsets(tabPlacement, tabIndex); + // FIXME: Handle HTML somehow. - int height = 0; + int height = fontHeight; + Icon icon = getIconForTab(tabIndex); + Insets tabInsets = getTabInsets(tabPlacement, tabIndex); if (icon != null) - { - Rectangle vr = new Rectangle(); - Rectangle ir = new Rectangle(); - Rectangle tr = new Rectangle(); - layoutLabel(tabPlacement, getFontMetrics(), tabIndex, - tabPane.getTitleAt(tabIndex), icon, vr, ir, tr, - tabIndex == tabPane.getSelectedIndex()); - height = tr.union(ir).height; - } - else - height = fontHeight; - - height += insets.top + insets.bottom; + height = Math.max(height, icon.getIconHeight()); + height += tabInsets.top + tabInsets.bottom + 2; return height; } @@ -2704,9 +2811,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants */ protected Insets getTabInsets(int tabPlacement, int tabIndex) { - Insets target = new Insets(0, 0, 0, 0); - rotateInsets(tabInsets, target, tabPlacement); - return target; + return tabInsets; } /** @@ -3068,4 +3173,33 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants break; } } + + /** + * Sets the tab which should be highlighted when in rollover mode. And + * <code>index</code> of <code>-1</code> means that the rollover tab + * is deselected (i.e. the mouse is outside of the tabarea). + * + * @param index the index of the tab that is under the mouse, <code>-1</code> + * for no tab + * + * @since 1.5 + */ + protected void setRolloverTab(int index) + { + rolloverTab = index; + } + + /** + * Retunrs the index of the tab over which the mouse is currently moving, + * or <code>-1</code> for no tab. + * + * @return the index of the tab over which the mouse is currently moving, + * or <code>-1</code> for no tab + * + * @since 1.5 + */ + protected int getRolloverTab() + { + return rolloverTab; + } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java index 1e8e39f38c2..cfbebda2149 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; @@ -96,7 +98,12 @@ public class BasicTableHeaderUI extends TableHeaderUI /** * The header cell border. */ - protected Border cellBorder; + private Border cellBorder; + + /** + * Original mouse cursor prior to resizing. + */ + private Cursor originalCursor; /** * If not null, one of the columns is currently being dragged. @@ -243,6 +250,7 @@ public class BasicTableHeaderUI extends TableHeaderUI if (onBoundary) { + originalCursor = header.getCursor(); if (p < x) header.setCursor(Cursor.getPredefinedCursor (Cursor.W_RESIZE_CURSOR)); @@ -252,7 +260,7 @@ public class BasicTableHeaderUI extends TableHeaderUI } else { - header.setCursor(Cursor.getDefaultCursor()); + header.setCursor(originalCursor); header.setResizingColumn(null); } @@ -343,7 +351,7 @@ public class BasicTableHeaderUI extends TableHeaderUI showingResizeCursor = false; if (timer != null) timer.stop(); - header.setCursor(Cursor.getDefaultCursor()); + header.setCursor(originalCursor); } /** @@ -415,6 +423,7 @@ public class BasicTableHeaderUI extends TableHeaderUI } protected void installKeyboardActions() + throws NotImplementedException { // TODO: Implement this properly. } @@ -447,6 +456,7 @@ public class BasicTableHeaderUI extends TableHeaderUI } protected void uninstallKeyboardActions() + throws NotImplementedException { // TODO: Implement this properly. } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java index 8360a9ec771..ef491cbf1c6 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Component; import java.awt.ComponentOrientation; @@ -88,7 +90,7 @@ public class BasicTableUI extends TableUI protected FocusListener focusListener; protected KeyListener keyListener; - protected MouseInputListener mouseInputListener; + protected MouseInputListener mouseInputListener; protected CellRendererPane rendererPane; protected JTable table; @@ -115,6 +117,8 @@ public class BasicTableUI extends TableUI /** * Receives notification that a key has been pressed and released. + * Activates the editing session for the focused cell by pressing the + * character keys. * * @param event the key event */ @@ -122,6 +126,16 @@ public class BasicTableUI extends TableUI { // Key events should be handled through the InputMap/ActionMap mechanism // since JDK1.3. This class is only there for backwards compatibility. + + // Editor activation is a specific kind of response to ''any'' + // character key. Hence it is handled here. + if (!table.isEditing() && table.isEnabled()) + { + int r = table.getSelectedRow(); + int c = table.getSelectedColumn(); + if (table.isCellEditable(r, c)) + table.editCellAt(r, c); + } } /** @@ -509,11 +523,9 @@ public class BasicTableUI extends TableUI if (command.equals("selectPreviousRowExtendSelection")) { rowModel.setLeadSelectionIndex(Math.max(rowLead - 1, 0)); - colModel.setLeadSelectionIndex(colLead); } else if (command.equals("selectLastColumn")) { - rowModel.setSelectionInterval(rowLead, rowLead); colModel.setSelectionInterval(colMax, colMax); } else if (command.equals("startEditing")) @@ -524,53 +536,43 @@ public class BasicTableUI extends TableUI else if (command.equals("selectFirstRowExtendSelection")) { rowModel.setLeadSelectionIndex(0); - colModel.setLeadSelectionIndex(colLead); } else if (command.equals("selectFirstColumn")) { - rowModel.setSelectionInterval(rowLead, rowLead); colModel.setSelectionInterval(0, 0); } else if (command.equals("selectFirstColumnExtendSelection")) { colModel.setLeadSelectionIndex(0); - rowModel.setLeadSelectionIndex(rowLead); } else if (command.equals("selectLastRow")) { rowModel.setSelectionInterval(rowMax,rowMax); - colModel.setSelectionInterval(colLead, colLead); } else if (command.equals("selectNextRowExtendSelection")) { rowModel.setLeadSelectionIndex(Math.min(rowLead + 1, rowMax)); - colModel.setLeadSelectionIndex(colLead); } else if (command.equals("selectFirstRow")) { rowModel.setSelectionInterval(0,0); - colModel.setSelectionInterval(colLead, colLead); } else if (command.equals("selectNextColumnExtendSelection")) { colModel.setLeadSelectionIndex(Math.min(colLead + 1, colMax)); - rowModel.setLeadSelectionIndex(rowLead); } else if (command.equals("selectLastColumnExtendSelection")) { colModel.setLeadSelectionIndex(colMax); - rowModel.setLeadSelectionIndex(rowLead); } else if (command.equals("selectPreviousColumnExtendSelection")) { colModel.setLeadSelectionIndex(Math.max(colLead - 1, 0)); - rowModel.setLeadSelectionIndex(rowLead); } else if (command.equals("selectNextRow")) { rowModel.setSelectionInterval(Math.min(rowLead + 1, rowMax), Math.min(rowLead + 1, rowMax)); - colModel.setSelectionInterval(colLead,colLead); } else if (command.equals("scrollUpExtendSelection")) { @@ -589,7 +591,6 @@ public class BasicTableUI extends TableUI { rowModel.setSelectionInterval(Math.max(rowLead - 1, 0), Math.max(rowLead - 1, 0)); - colModel.setSelectionInterval(colLead,colLead); } else if (command.equals("scrollRightChangeSelection")) { @@ -606,7 +607,6 @@ public class BasicTableUI extends TableUI } else if (command.equals("selectPreviousColumn")) { - rowModel.setSelectionInterval(rowLead,rowLead); colModel.setSelectionInterval(Math.max(colLead - 1, 0), Math.max(colLead - 1, 0)); } @@ -715,7 +715,6 @@ public class BasicTableUI extends TableUI } else if (command.equals("selectNextColumn")) { - rowModel.setSelectionInterval(rowLead,rowLead); colModel.setSelectionInterval(Math.min(colLead + 1, colMax), Math.min(colLead + 1, colMax)); } @@ -903,7 +902,6 @@ public class BasicTableUI extends TableUI table.scrollRectToVisible (table.getCellRect(rowModel.getLeadSelectionIndex(), colModel.getLeadSelectionIndex(), false)); - table.repaint(); } /** @@ -1172,6 +1170,7 @@ public class BasicTableUI extends TableUI } protected void uninstallKeyboardActions() + throws NotImplementedException { // TODO: Implement this properly. } @@ -1247,16 +1246,18 @@ public class BasicTableUI extends TableUI if (rn == -1) rn = table.getRowCount() - 1; + int columnMargin = table.getColumnModel().getColumnMargin(); + int rowMargin = table.getRowMargin(); + TableColumnModel cmodel = table.getColumnModel(); int [] widths = new int[cn+1]; for (int i = c0; i <=cn ; i++) { - widths[i] = cmodel.getColumn(i).getWidth(); + widths[i] = cmodel.getColumn(i).getWidth() - columnMargin; } Rectangle bounds = table.getCellRect(r0, c0, false); - bounds.height = table.getRowHeight()+table.getRowMargin(); - + // The left boundary of the area being repainted. int left = bounds.x; @@ -1266,9 +1267,6 @@ public class BasicTableUI extends TableUI // The bottom boundary of the area being repainted. int bottom; - // The cell height. - int height = bounds.height; - // paint the cell contents Color grid = table.getGridColor(); for (int r = r0; r <= rn; ++r) @@ -1277,25 +1275,28 @@ public class BasicTableUI extends TableUI { bounds.width = widths[c]; paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c)); - bounds.x += widths[c]; + bounds.x += widths[c] + columnMargin; } - bounds.y += height; bounds.x = left; + bounds.y += table.getRowHeight(r) + rowMargin; + // Update row height for tables with custom heights. + bounds.height = table.getRowHeight(r + 1); } - bottom = bounds.y; + bottom = bounds.y - rowMargin; // paint vertical grid lines if (grid != null && table.getShowVerticalLines()) { Color save = gfx.getColor(); gfx.setColor(grid); - int x = left; - + int x = left - columnMargin; for (int c = c0; c <= cn; ++c) { + // The vertical grid is draw right from the cells, so we + // add before drawing. + x += widths[c] + columnMargin; gfx.drawLine(x, top, x, bottom); - x += widths[c]; } gfx.setColor(save); } @@ -1305,11 +1306,13 @@ public class BasicTableUI extends TableUI { Color save = gfx.getColor(); gfx.setColor(grid); - int y = top; + int y = top - rowMargin; for (int r = r0; r <= rn; ++r) { + // The horizontal grid is draw below the cells, so we + // add before drawing. + y += table.getRowHeight(r) + rowMargin; gfx.drawLine(left, y, p2.x, y); - y += height; } gfx.setColor(save); } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java index 36854e07fe0..93e119b31fa 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java @@ -1,5 +1,5 @@ /* BasicTextAreaUI.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -108,6 +108,9 @@ public class BasicTextAreaUI extends BasicTextUI JTextArea comp = (JTextArea)getComponent(); if (ev.getPropertyName() == "lineWrap" || ev.getPropertyName() == "wrapStyleWord") - modelChanged(); + { + // Changes the View (without modifying the document or it's listeners). + setView(create(textComponent.getDocument().getDefaultRootElement())); + } } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java index 4e2ca9f93df..89c4e5a7562 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java @@ -1,5 +1,5 @@ /* BasicTextFieldUI.java - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,7 @@ import java.beans.PropertyChangeEvent; import javax.swing.JComponent; import javax.swing.UIDefaults; +import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.text.Element; import javax.swing.text.FieldView; @@ -83,6 +84,9 @@ public class BasicTextFieldUI extends BasicTextUI * Receives notification whenever one of the text component's bound * properties changes. Here we check for the editable and enabled * properties and adjust the background color accordingly. + * + * <p>The colors are only changed if they are not a + * <code>ColorUIResource</code>.</p> * * @param event the property change event */ @@ -91,10 +95,11 @@ public class BasicTextFieldUI extends BasicTextUI if (event.getPropertyName().equals("editable")) { boolean editable = ((Boolean) event.getNewValue()).booleanValue(); - if (editable) - textComponent.setBackground(background); - else - textComponent.setBackground(inactiveBackground); + + // Changing the color only if the current background is an instance of + // ColorUIResource is the behavior of the RI. + if (textComponent.getBackground() instanceof ColorUIResource) + textComponent.setBackground(editable ? background : inactiveBackground); } } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java index beb1a6dfeac..3b620f04989 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java @@ -38,14 +38,20 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; +import java.awt.HeadlessException; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.beans.PropertyChangeEvent; @@ -55,7 +61,6 @@ import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JComponent; -import javax.swing.KeyStroke; import javax.swing.LookAndFeel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; @@ -63,7 +68,6 @@ import javax.swing.UIManager; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.plaf.ActionMapUIResource; -import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.TextUI; import javax.swing.plaf.UIResource; import javax.swing.text.AbstractDocument; @@ -436,6 +440,9 @@ public abstract class BasicTextUI extends TextUI */ public void changedUpdate(DocumentEvent ev) { + // Updates are forwarded to the View even if 'getVisibleEditorRect' + // method returns null. This means the View classes have to be + // aware of that possibility. rootView.changedUpdate(ev, getVisibleEditorRect(), rootView.getViewFactory()); } @@ -447,6 +454,9 @@ public abstract class BasicTextUI extends TextUI */ public void insertUpdate(DocumentEvent ev) { + // Updates are forwarded to the View even if 'getVisibleEditorRect' + // method returns null. This means the View classes have to be + // aware of that possibility. rootView.insertUpdate(ev, getVisibleEditorRect(), rootView.getViewFactory()); } @@ -458,6 +468,9 @@ public abstract class BasicTextUI extends TextUI */ public void removeUpdate(DocumentEvent ev) { + // Updates are forwarded to the View even if 'getVisibleEditorRect' + // method returns null. This means the View classes have to be + // aware of that possibility. rootView.removeUpdate(ev, getVisibleEditorRect(), rootView.getViewFactory()); } @@ -546,7 +559,6 @@ public abstract class BasicTextUI extends TextUI public void installUI(final JComponent c) { super.installUI(c); - c.setOpaque(true); textComponent = (JTextComponent) c; Document doc = textComponent.getDocument(); @@ -608,6 +620,44 @@ public abstract class BasicTextUI extends TextUI public void focusLost(FocusEvent e) { textComponent.repaint(); + + // Integrates Swing text components with the system clipboard: + // The idea is that if one wants to copy text around X11-style + // (select text and middle-click in the target component) the focus + // will move to the new component which gives the old focus owner the + // possibility to paste its selection into the clipboard. + if (!e.isTemporary() + && textComponent.getSelectionStart() + != textComponent.getSelectionEnd()) + { + SecurityManager sm = System.getSecurityManager(); + try + { + if (sm != null) + sm.checkSystemClipboardAccess(); + + Clipboard cb = Toolkit.getDefaultToolkit().getSystemSelection(); + if (cb != null) + { + StringSelection selection = new StringSelection(textComponent.getSelectedText()); + cb.setContents(selection, selection); + } + } + catch (SecurityException se) + { + // Not allowed to access the clipboard: Ignore and + // do not access it. + } + catch (HeadlessException he) + { + // There is no AWT: Ignore and do not access the + // clipboard. + } + catch (IllegalStateException ise) + { + // Clipboard is currently unavaible. + } + } } }; @@ -655,33 +705,23 @@ public abstract class BasicTextUI extends TextUI */ protected Keymap createKeymap() { - // FIXME: It seems to me that this method implementation is wrong. It seems - // to fetch the focusInputMap and transform it to the KeyBinding/Keymap - // implemenation. I would think that it should be done the other way, - // fetching the keybindings (from prefix + ".bindings") and transform - // it to the newer InputMap/ActionMap implementation. - JTextComponent.KeyBinding[] bindings = null; - String prefix = getPropertyPrefix(); - InputMapUIResource m = (InputMapUIResource) UIManager.get(prefix + ".focusInputMap"); - if (m != null) + String keymapName = getKeymapName(); + Keymap keymap = JTextComponent.getKeymap(keymapName); + if (keymap == null) { - KeyStroke[] keys = m.keys(); - int len = keys.length; - bindings = new JTextComponent.KeyBinding[len]; - for (int i = 0; i < len; i++) + Keymap parentMap = + JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP); + keymap = JTextComponent.addKeymap(keymapName, parentMap); + Object val = UIManager.get(getPropertyPrefix() + ".keyBindings"); + if (val != null && val instanceof JTextComponent.KeyBinding[]) { - KeyStroke curr = keys[i]; - bindings[i] = new JTextComponent.KeyBinding(curr, - (String) m.get(curr)); + JTextComponent.KeyBinding[] bindings = + (JTextComponent.KeyBinding[]) val; + JTextComponent.loadKeymap(keymap, bindings, + getComponent().getActions()); } } - if (bindings == null) - bindings = new JTextComponent.KeyBinding[0]; - - Keymap km = JTextComponent.addKeymap(getKeymapName(), - JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP)); - JTextComponent.loadKeymap(km, bindings, textComponent.getActions()); - return km; + return keymap; } /** @@ -689,11 +729,8 @@ public abstract class BasicTextUI extends TextUI */ protected void installKeyboardActions() { - // load key bindings for the older interface - Keymap km = JTextComponent.getKeymap(getKeymapName()); - if (km == null) - km = createKeymap(); - textComponent.setKeymap(km); + // This is only there for backwards compatibility. + textComponent.setKeymap(createKeymap()); // load any bindings for the newer InputMap / ActionMap interface SwingUtilities.replaceUIInputMap(textComponent, JComponent.WHEN_FOCUSED, @@ -794,6 +831,7 @@ public abstract class BasicTextUI extends TextUI * this UI. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: Uninstall keyboard actions here. } @@ -986,6 +1024,10 @@ public abstract class BasicTextUI extends TextUI public void damageRange(JTextComponent t, int p0, int p1, Position.Bias firstBias, Position.Bias secondBias) { + // Do nothing if the component cannot be properly displayed. + if (t.getWidth() == 0 || t.getHeight() == 0) + return; + try { // Limit p0 and p1 to sane values to prevent unfriendly @@ -1000,7 +1042,10 @@ public abstract class BasicTextUI extends TextUI Rectangle l1 = modelToView(t, p0, firstBias); Rectangle l2 = modelToView(t, p1, secondBias); if (l1.y == l2.y) - t.repaint(l1.union(l2)); + { + SwingUtilities.computeUnion(l2.x, l2.y, l2.width, l2.height, l1); + t.repaint(l1); + } else { // The two rectangles lie on different lines and we need a @@ -1023,7 +1068,11 @@ public abstract class BasicTextUI extends TextUI // we should stop searching for one. int posBelow = Utilities.getPositionBelow(t, p0, l1.x); - if (posBelow < p1 && posBelow != -1 && posBelow != p0) + int p1RowStart = Utilities.getRowStart(t, p1); + + if (posBelow != -1 + && posBelow != p0 + && Utilities.getRowStart(t, posBelow) != p1RowStart) { // Take the rectangle of the offset we just found and grow it // to the maximum width. Retain y because this is our start @@ -1034,10 +1083,15 @@ public abstract class BasicTextUI extends TextUI // Find further lines which have to be damaged completely. int nextPosBelow = posBelow; - while (nextPosBelow < p1 && nextPosBelow != -1 && posBelow != nextPosBelow) + while (nextPosBelow != -1 + && posBelow != nextPosBelow + && Utilities.getRowStart(t, nextPosBelow) != p1RowStart) { posBelow = nextPosBelow; nextPosBelow = Utilities.getPositionBelow(t, posBelow, l1.x); + + if (posBelow == nextPosBelow) + break; } // Now posBelow is an offset on the last line which has to be damaged // completely. (newPosBelow is on the same line as p1) @@ -1099,7 +1153,12 @@ public abstract class BasicTextUI extends TextUI Position.Bias[] biasRet) throws BadLocationException { - return 0; // TODO: Implement me. + // A comment in the spec of NavigationFilter.getNextVisualPositionFrom() + // suggests that this method should be implemented by forwarding the call + // the root view. + return rootView.getNextVisualPositionFrom(pos, b, + getVisibleEditorRect(), + direction, biasRet); } /** @@ -1155,7 +1214,10 @@ public abstract class BasicTextUI extends TextUI public Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias) throws BadLocationException { - return rootView.modelToView(pos, getVisibleEditorRect(), bias).getBounds(); + Rectangle r = getVisibleEditorRect(); + + return (r != null) ? rootView.modelToView(pos, r, bias).getBounds() + : null; } /** @@ -1232,8 +1294,9 @@ public abstract class BasicTextUI extends TextUI int width = textComponent.getWidth(); int height = textComponent.getHeight(); + // Return null if the component has no valid size. if (width <= 0 || height <= 0) - return new Rectangle(0, 0, 0, 0); + return null; Insets insets = textComponent.getInsets(); return new Rectangle(insets.left, insets.top, diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java index 261db687aa8..80fec6a775a 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; + import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -60,6 +62,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Hashtable; +import javax.swing.AbstractButton; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; @@ -72,8 +75,8 @@ import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.Border; +import javax.swing.border.EtchedBorder; import javax.swing.event.MouseInputListener; -import javax.swing.plaf.BorderUIResource.EtchedBorderUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ToolBarUI; import javax.swing.plaf.UIResource; @@ -307,7 +310,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected Border createNonRolloverBorder() { - return new EtchedBorderUIResource(); + return new EtchedBorder(); } /** @@ -328,7 +331,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected Border createRolloverBorder() { - return new EtchedBorderUIResource() + return new EtchedBorder() { public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) @@ -577,6 +580,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants rolloverBorder = createRolloverBorder(); borders = new Hashtable(); + setRolloverBorders(toolBar.isRollover()); fillHashtable(); } @@ -595,7 +599,6 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants floatingBorderColor = UIManager.getColor("ToolBar.floatingForeground"); floatingColor = UIManager.getColor("ToolBar.floatingBackground"); - setRolloverBorders(toolBar.isRollover()); } /** @@ -603,6 +606,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants * by the look and feel. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: implement. } @@ -707,9 +711,8 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants if (c instanceof JToolBar) { toolBar = (JToolBar) c; - toolBar.setOpaque(true); - installDefaults(); - installComponents(); + installDefaults(); + installComponents(); installListeners(); installKeyboardActions(); } @@ -754,9 +757,9 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected void setBorderToNonRollover(Component c) { - if (c instanceof JButton) + if (c instanceof AbstractButton) { - JButton b = (JButton) c; + AbstractButton b = (AbstractButton) c; b.setRolloverEnabled(false); b.setBorder(nonRolloverBorder); } @@ -875,8 +878,6 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants { installNormalBorders(toolBar); borders = null; - rolloverBorder = null; - nonRolloverBorder = null; cachedBounds = null; floatFrame = null; @@ -902,6 +903,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants * This method uninstalls keyboard actions installed by the UI. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: implement. } @@ -1231,8 +1233,8 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants public void propertyChange(PropertyChangeEvent e) { // FIXME: need name properties so can change floatFrame title. - if (e.getPropertyName().equals("rollover")) - setRolloverBorders(toolBar.isRollover()); + if (e.getPropertyName().equals("rollover") && toolBar != null) + setRolloverBorders(toolBar.isRollover()); } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java index 1c6e6c5e502..be61ccaec22 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java @@ -1,5 +1,5 @@ /* BasicTreeUI.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ package javax.swing.plaf.basic; +import gnu.javax.swing.tree.GnuPath; + import java.awt.Color; import java.awt.Component; import java.awt.Dimension; @@ -55,6 +57,7 @@ import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; +import java.awt.event.InputEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; @@ -76,7 +79,6 @@ import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JScrollBar; import javax.swing.JScrollPane; -import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.LookAndFeel; @@ -96,17 +98,16 @@ import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.TreeUI; -import javax.swing.text.Caret; import javax.swing.tree.AbstractLayoutCache; import javax.swing.tree.DefaultTreeCellEditor; import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.FixedHeightLayoutCache; import javax.swing.tree.TreeCellEditor; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; +import javax.swing.tree.VariableHeightLayoutCache; /** * A delegate providing the user interface for <code>JTree</code> according to @@ -117,16 +118,17 @@ import javax.swing.tree.TreeSelectionModel; * @author Sascha Brawer (brawer@dandelis.ch) * @author Audrius Meskauskas (audriusa@bioinformatics.org) */ -public class BasicTreeUI extends TreeUI +public class BasicTreeUI + extends TreeUI { /** * The tree cell editing may be started by the single mouse click on the * selected cell. To separate it from the double mouse click, the editing - * session starts after this time (in ms) after that single click, and only - * no other clicks were performed during that time. + * session starts after this time (in ms) after that single click, and only no + * other clicks were performed during that time. */ - static int WAIT_TILL_EDITING = 900; - + static int WAIT_TILL_EDITING = 900; + /** Collapse Icon for the tree. */ protected transient Icon collapsedIcon; @@ -251,39 +253,40 @@ public class BasicTreeUI extends TreeUI int maxHeight = 0; /** Listeners */ - private PropertyChangeListener propertyChangeListener; + PropertyChangeListener propertyChangeListener; - private FocusListener focusListener; + FocusListener focusListener; - private TreeSelectionListener treeSelectionListener; + TreeSelectionListener treeSelectionListener; - private MouseListener mouseListener; + MouseListener mouseListener; - private KeyListener keyListener; + KeyListener keyListener; - private PropertyChangeListener selectionModelPropertyChangeListener; + PropertyChangeListener selectionModelPropertyChangeListener; - private ComponentListener componentListener; + ComponentListener componentListener; CellEditorListener cellEditorListener; - private TreeExpansionListener treeExpansionListener; + TreeExpansionListener treeExpansionListener; + + TreeModelListener treeModelListener; - private TreeModelListener treeModelListener; - /** * This timer fires the editing action after about 1200 ms if not reset during - * that time. It handles the editing start with the single mouse click - * (and not the double mouse click) on the selected tree node. + * that time. It handles the editing start with the single mouse click (and + * not the double mouse click) on the selected tree node. */ Timer startEditTimer; - + /** * The special value of the mouse event is sent indicating that this is not * just the mouse click, but the mouse click on the selected node. Sending * such event forces to start the cell editing session. */ - static final MouseEvent EDIT = new MouseEvent(new Label(), 7,7,7,7,7,7, false); + static final MouseEvent EDIT = new MouseEvent(new Label(), 7, 7, 7, 7, 7, 7, + false); /** * Creates a new BasicTreeUI object. @@ -306,22 +309,21 @@ public class BasicTreeUI extends TreeUI treeExpansionListener = createTreeExpansionListener(); treeModelListener = createTreeModelListener(); - editingRow = -1; - lastSelectedRow = -1; + editingRow = - 1; + lastSelectedRow = - 1; } /** * Returns an instance of the UI delegate for the specified component. * - * @param c - * the <code>JComponent</code> for which we need a UI delegate for. + * @param c the <code>JComponent</code> for which we need a UI delegate for. * @return the <code>ComponentUI</code> for c. */ public static ComponentUI createUI(JComponent c) { return new BasicTreeUI(); } - + /** * Returns the Hash color. * @@ -335,8 +337,7 @@ public class BasicTreeUI extends TreeUI /** * Sets the Hash color. * - * @param color - * the <code>Color</code> to set the Hash to. + * @param color the <code>Color</code> to set the Hash to. */ protected void setHashColor(Color color) { @@ -347,8 +348,7 @@ public class BasicTreeUI extends TreeUI /** * Sets the left child's indent value. * - * @param newAmount - * is the new indent value for the left child. + * @param newAmount is the new indent value for the left child. */ public void setLeftChildIndent(int newAmount) { @@ -368,8 +368,7 @@ public class BasicTreeUI extends TreeUI /** * Sets the right child's indent value. * - * @param newAmount - * is the new indent value for the right child. + * @param newAmount is the new indent value for the right child. */ public void setRightChildIndent(int newAmount) { @@ -389,8 +388,7 @@ public class BasicTreeUI extends TreeUI /** * Sets the expanded icon. * - * @param newG - * is the new expanded icon. + * @param newG is the new expanded icon. */ public void setExpandedIcon(Icon newG) { @@ -410,8 +408,7 @@ public class BasicTreeUI extends TreeUI /** * Sets the collapsed icon. * - * @param newG - * is the new collapsed icon. + * @param newG is the new collapsed icon. */ public void setCollapsedIcon(Icon newG) { @@ -431,8 +428,7 @@ public class BasicTreeUI extends TreeUI /** * Updates the componentListener, if necessary. * - * @param largeModel - * sets this.largeModel to it. + * @param largeModel sets this.largeModel to it. */ protected void setLargeModel(boolean largeModel) { @@ -457,13 +453,12 @@ public class BasicTreeUI extends TreeUI /** * Sets the row height. * - * @param rowHeight - * is the height to set this.rowHeight to. + * @param rowHeight is the height to set this.rowHeight to. */ protected void setRowHeight(int rowHeight) { if (rowHeight == 0) - rowHeight = Math.max(getMaxHeight(tree), 20); + rowHeight = getMaxHeight(tree); treeState.setRowHeight(rowHeight); } @@ -474,15 +469,14 @@ public class BasicTreeUI extends TreeUI */ protected int getRowHeight() { - return treeState.getRowHeight(); + return tree.getRowHeight(); } /** * Sets the TreeCellRenderer to <code>tcr</code>. This invokes * <code>updateRenderer</code>. * - * @param tcr - * is the new TreeCellRenderer. + * @param tcr is the new TreeCellRenderer. */ protected void setCellRenderer(TreeCellRenderer tcr) { @@ -507,13 +501,13 @@ public class BasicTreeUI extends TreeUI /** * Sets the tree's model. * - * @param model - * to set the treeModel to. + * @param model to set the treeModel to. */ protected void setModel(TreeModel model) { tree.setModel(model); treeModel = tree.getModel(); + treeState.setModel(treeModel); } /** @@ -529,8 +523,7 @@ public class BasicTreeUI extends TreeUI /** * Sets the root to being visible. * - * @param newValue - * sets the visibility of the root + * @param newValue sets the visibility of the root */ protected void setRootVisible(boolean newValue) { @@ -550,8 +543,7 @@ public class BasicTreeUI extends TreeUI /** * Determines whether the node handles are to be displayed. * - * @param newValue - * sets whether or not node handles should be displayed. + * @param newValue sets whether or not node handles should be displayed. */ protected void setShowsRootHandles(boolean newValue) { @@ -571,8 +563,7 @@ public class BasicTreeUI extends TreeUI /** * Sets the cell editor. * - * @param editor - * to set the cellEditor to. + * @param editor to set the cellEditor to. */ protected void setCellEditor(TreeCellEditor editor) { @@ -593,8 +584,7 @@ public class BasicTreeUI extends TreeUI /** * Configures the receiver to allow, or not allow, editing. * - * @param newValue - * sets the receiver to allow editing if true. + * @param newValue sets the receiver to allow editing if true. */ protected void setEditable(boolean newValue) { @@ -615,8 +605,7 @@ public class BasicTreeUI extends TreeUI * Resets the selection model. The appropriate listeners are installed on the * model. * - * @param newLSM - * resets the selection model. + * @param newLSM resets the selection model. */ protected void setSelectionModel(TreeSelectionModel newLSM) { @@ -642,35 +631,23 @@ public class BasicTreeUI extends TreeUI * path will be drawn to. Will return null if any component in path is * currently valid. * - * @param tree - * is the current tree the path will be drawn to. - * @param path - * is the current path the tree to draw to. + * @param tree is the current tree the path will be drawn to. + * @param path is the current path the tree to draw to. * @return the Rectangle enclosing the label portion that the last item in the * path will be drawn to. */ public Rectangle getPathBounds(JTree tree, TreePath path) { - int row = -1; - Object cell = null; - if (path != null) - { - row = getRowForPath(tree, path); - cell = path.getLastPathComponent(); - } - return nodeDimensions.getNodeDimensions(cell, row, getLevel(cell), - tree.isExpanded(path), - new Rectangle()); + return treeState.getBounds(path, new Rectangle()); } /** * Returns the max height of all the nodes in the tree. * - * @param tree - - * the current tree + * @param tree - the current tree * @return the max height. */ - private int getMaxHeight(JTree tree) + int getMaxHeight(JTree tree) { if (maxHeight != 0) return maxHeight; @@ -692,72 +669,47 @@ public class BasicTreeUI extends TreeUI maxHeight = Math.max(maxHeight, iconHeight + gap); } - + + treeState.setRowHeight(maxHeight); return maxHeight; } /** * Returns the path for passed in row. If row is not visible null is returned. * - * @param tree - * is the current tree to return path for. - * @param row - * is the row number of the row to return. + * @param tree is the current tree to return path for. + * @param row is the row number of the row to return. * @return the path for passed in row. If row is not visible null is returned. */ public TreePath getPathForRow(JTree tree, int row) { - if (treeModel != null && currentVisiblePath != null) - { - Object[] nodes = currentVisiblePath.getPath(); - if (row < nodes.length) - return new TreePath(getPathToRoot(nodes[row], 0)); - } - return null; + return treeState.getPathForRow(row); } /** * Returns the row that the last item identified in path is visible at. Will * return -1 if any of the elments in the path are not currently visible. * - * @param tree - * is the current tree to return the row for. - * @param path - * is the path used to find the row. + * @param tree is the current tree to return the row for. + * @param path is the path used to find the row. * @return the row that the last item identified in path is visible at. Will * return -1 if any of the elments in the path are not currently * visible. */ public int getRowForPath(JTree tree, TreePath path) { - int row = 0; - Object dest = path.getLastPathComponent(); - int rowCount = getRowCount(tree); - if (currentVisiblePath != null) - { - Object[] nodes = currentVisiblePath.getPath(); - while (row < rowCount) - { - if (dest.equals(nodes[row])) - return row; - row++; - } - } - return -1; + return treeState.getRowForPath(path); } /** * Returns the number of rows that are being displayed. * - * @param tree - * is the current tree to return the number of rows for. + * @param tree is the current tree to return the number of rows for. * @return the number of rows being displayed. */ public int getRowCount(JTree tree) { - if (currentVisiblePath != null) - return currentVisiblePath.getPathCount(); - return 0; + return treeState.getRowCount(); } /** @@ -766,35 +718,21 @@ public class BasicTreeUI extends TreeUI * valid path. If you need to test if the returned object is exactly at x,y * you should get the bounds for the returned path and test x,y against that. * - * @param tree - * the tree to search for the closest path - * @param x - * is the x coordinate of the location to search - * @param y - * is the y coordinate of the location to search + * @param tree the tree to search for the closest path + * @param x is the x coordinate of the location to search + * @param y is the y coordinate of the location to search * @return the tree path closes to x,y. */ public TreePath getClosestPathForLocation(JTree tree, int x, int y) { - int row = Math.round(y / getMaxHeight(tree)); - TreePath path = getPathForRow(tree, row); - - // no row is visible at this node - while (row > 0 && path == null) - { - --row; - path = getPathForRow(tree, row); - } - - return path; + return treeState.getPathClosestTo(x, y); } /** * Returns true if the tree is being edited. The item that is being edited can * be returned by getEditingPath(). * - * @param tree - * is the tree to check for editing. + * @param tree is the tree to check for editing. * @return true if the tree is being edited. */ public boolean isEditing(JTree tree) @@ -807,8 +745,7 @@ public class BasicTreeUI extends TreeUI * being edited. Returns true if the editor allows the editing session to * stop. * - * @param tree - * is the tree to stop the editing on + * @param tree is the tree to stop the editing on * @return true if the editor allows the editing session to stop. */ public boolean stopEditing(JTree tree) @@ -818,32 +755,29 @@ public class BasicTreeUI extends TreeUI completeEditing(false, false, true); finish(); } - return !isEditing(tree); + return ! isEditing(tree); } /** * Cancels the current editing session. * - * @param tree - * is the tree to cancel the editing session on. + * @param tree is the tree to cancel the editing session on. */ public void cancelEditing(JTree tree) - { - // There is no need to send the cancel message to the editor, - // as the cancellation event itself arrives from it. This would - // only be necessary when cancelling the editing programatically. - completeEditing(false, false, false); - finish(); + { + // There is no need to send the cancel message to the editor, + // as the cancellation event itself arrives from it. This would + // only be necessary when cancelling the editing programatically. + completeEditing(false, false, false); + finish(); } /** * Selects the last item in path and tries to edit it. Editing will fail if * the CellEditor won't allow it for the selected item. * - * @param tree - * is the tree to edit on. - * @param path - * is the path in tree to edit on. + * @param tree is the tree to edit on. + * @param path is the path in tree to edit on. */ public void startEditingAtPath(JTree tree, TreePath path) { @@ -853,8 +787,7 @@ public class BasicTreeUI extends TreeUI /** * Returns the path to the element that is being editted. * - * @param tree - * is the tree to get the editing path from. + * @param tree is the tree to get the editing path from. * @return the path that is being edited. */ public TreePath getEditingPath(JTree tree) @@ -902,7 +835,8 @@ public class BasicTreeUI extends TreeUI /** * Creates an instance of NodeDimensions that is able to determine the size of - * a given node in the tree. + * a given node in the tree. The node dimensions must be created before + * configuring the layout cache. * * @return the NodeDimensions of a given node in the tree */ @@ -1018,7 +952,7 @@ public class BasicTreeUI extends TreeUI */ protected AbstractLayoutCache createLayoutCache() { - return new FixedHeightLayoutCache(); + return new VariableHeightLayoutCache(); } /** @@ -1152,8 +1086,7 @@ public class BasicTreeUI extends TreeUI * by getting the expanded descendants from the tree and forwarding to the * tree state. * - * @param path - * the path used to update the expanded states + * @param path the path used to update the expanded states */ protected void updateExpandedDescendants(TreePath path) { @@ -1165,8 +1098,7 @@ public class BasicTreeUI extends TreeUI /** * Returns a path to the last child of <code>parent</code> * - * @param parent - * is the topmost path to specified + * @param parent is the topmost path to specified * @return a path to the last child of parent */ protected TreePath getLastChildPath(TreePath parent) @@ -1212,11 +1144,13 @@ public class BasicTreeUI extends TreeUI /** * Resets the treeState instance based on the tree we're providing the look - * and feel for. + * and feel for. The node dimensions handler is required and must be created + * in advance. */ protected void configureLayoutCache() { treeState = createLayoutCache(); + treeState.setNodeDimensions(nodeDimensions); } /** @@ -1236,42 +1170,19 @@ public class BasicTreeUI extends TreeUI */ protected void updateCachedPreferredSize() { - int maxWidth = 0; - updateCurrentVisiblePath(); - boolean isLeaf = false; - if (currentVisiblePath != null) - { - Object[] path = currentVisiblePath.getPath(); - for (int i = 0; i < path.length; i++) - { - TreePath curr = new TreePath(getPathToRoot(path[i], 0)); - Rectangle bounds = getPathBounds(tree, curr); - if (treeModel != null) - isLeaf = treeModel.isLeaf(path[i]); - if (!isLeaf && hasControlIcons()) - bounds.width += getCurrentControlIcon(curr).getIconWidth(); - maxWidth = Math.max(maxWidth, bounds.x + bounds.width); - } - - maxHeight = 0; - maxHeight = getMaxHeight(tree); - preferredSize = new Dimension(maxWidth, (maxHeight * path.length)); - } - else - preferredSize = new Dimension(0, 0); - validCachedPreferredSize = true; + validCachedPreferredSize = false; } /** * Messaged from the VisibleTreeNode after it has been expanded. * - * @param path - * is the path that has been expanded. + * @param path is the path that has been expanded. */ protected void pathWasExpanded(TreePath path) { validCachedPreferredSize = false; - tree.repaint(); + treeState.setExpandedState(path, true); + tree.repaint(); } /** @@ -1280,6 +1191,7 @@ public class BasicTreeUI extends TreeUI protected void pathWasCollapsed(TreePath path) { validCachedPreferredSize = false; + treeState.setExpandedState(path, false); tree.repaint(); } @@ -1345,8 +1257,7 @@ public class BasicTreeUI extends TreeUI /** * Converts the modifiers. * - * @param mod - - * modifier to convert + * @param mod - modifier to convert * @returns the new modifier */ private int convertModifiers(int mod) @@ -1354,27 +1265,27 @@ public class BasicTreeUI extends TreeUI if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0) { mod |= KeyEvent.SHIFT_MASK; - mod &= ~KeyEvent.SHIFT_DOWN_MASK; + mod &= ~ KeyEvent.SHIFT_DOWN_MASK; } if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0) { mod |= KeyEvent.CTRL_MASK; - mod &= ~KeyEvent.CTRL_DOWN_MASK; + mod &= ~ KeyEvent.CTRL_DOWN_MASK; } if ((mod & KeyEvent.META_DOWN_MASK) != 0) { mod |= KeyEvent.META_MASK; - mod &= ~KeyEvent.META_DOWN_MASK; + mod &= ~ KeyEvent.META_DOWN_MASK; } if ((mod & KeyEvent.ALT_DOWN_MASK) != 0) { mod |= KeyEvent.ALT_MASK; - mod &= ~KeyEvent.ALT_DOWN_MASK; + mod &= ~ KeyEvent.ALT_DOWN_MASK; } if ((mod & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0) { mod |= KeyEvent.ALT_GRAPH_MASK; - mod &= ~KeyEvent.ALT_GRAPH_DOWN_MASK; + mod &= ~ KeyEvent.ALT_GRAPH_DOWN_MASK; } return mod; } @@ -1399,16 +1310,16 @@ public class BasicTreeUI extends TreeUI /** * Install the UI for the component * - * @param c - * the component to install UI for + * @param c the component to install UI for */ public void installUI(JComponent c) { tree = (JTree) c; + treeModel = tree.getModel(); + prepareForUIInstall(); super.installUI(c); installDefaults(); - installComponents(); installKeyboardActions(); installListeners(); @@ -1419,6 +1330,8 @@ public class BasicTreeUI extends TreeUI setModel(tree.getModel()); treeSelectionModel = tree.getSelectionModel(); + setRootVisible(tree.isRootVisible()); + treeState.setRootVisible(tree.isRootVisible()); completeUIInstall(); } @@ -1436,8 +1349,7 @@ public class BasicTreeUI extends TreeUI /** * Uninstall the UI for the component * - * @param c - * the component to uninstall UI for + * @param c the component to uninstall UI for */ public void uninstallUI(JComponent c) { @@ -1456,51 +1368,103 @@ public class BasicTreeUI extends TreeUI * component is being painted. Subclasses should override this method and use * the specified Graphics object to render the content of the component. * - * @param g - * the Graphics context in which to paint - * @param c - * the component being painted; this argument is often ignored, but + * @param g the Graphics context in which to paint + * @param c the component being painted; this argument is often ignored, but * might be used if the UI object is stateless and shared by multiple * components */ public void paint(Graphics g, JComponent c) { JTree tree = (JTree) c; - updateCurrentVisiblePath(); + + int rows = treeState.getRowCount(); + + if (rows == 0) + // There is nothing to do if the tree is empty. + return; Rectangle clip = g.getClipBounds(); + Insets insets = tree.getInsets(); - if (clip != null && treeModel != null && currentVisiblePath != null) + if (clip != null && treeModel != null) { int startIndex = tree.getClosestRowForLocation(clip.x, clip.y); int endIndex = tree.getClosestRowForLocation(clip.x + clip.width, clip.y + clip.height); - paintVerticalPartOfLeg(g, clip, insets, currentVisiblePath); - for (int i = startIndex; i <= endIndex; i++) + // Also paint dashes to the invisible nodes below. + // These should be painted first, otherwise they may cover + // the control icons. + if (endIndex < rows) + for (int i = endIndex + 1; i < rows; i++) + { + TreePath path = treeState.getPathForRow(i); + if (isLastChild(path)) + paintVerticalPartOfLeg(g, clip, insets, path); + } + + // The two loops are required to ensure that the lines are not + // painted over the other tree components. + + int n = endIndex - startIndex + 1; + Rectangle[] bounds = new Rectangle[n]; + boolean[] isLeaf = new boolean[n]; + boolean[] isExpanded = new boolean[n]; + TreePath[] path = new TreePath[n]; + int k; + + k = 0; + for (int i = startIndex; i <= endIndex; i++, k++) + { + path[k] = treeState.getPathForRow(i); + isLeaf[k] = treeModel.isLeaf(path[k].getLastPathComponent()); + isExpanded[k] = tree.isExpanded(path[k]); + bounds[k] = getPathBounds(tree, path[k]); + + paintHorizontalPartOfLeg(g, clip, insets, bounds[k], path[k], i, + isExpanded[k], false, isLeaf[k]); + if (isLastChild(path[k])) + paintVerticalPartOfLeg(g, clip, insets, path[k]); + } + + k = 0; + for (int i = startIndex; i <= endIndex; i++, k++) { - Object curr = currentVisiblePath.getPathComponent(i); - boolean isLeaf = treeModel.isLeaf(curr); - TreePath path = new TreePath(getPathToRoot(curr, 0)); - - boolean isExpanded = tree.isExpanded(path); - Rectangle bounds = getPathBounds(tree, path); - paintHorizontalPartOfLeg(g, clip, insets, bounds, path, i, - isExpanded, false, isLeaf); - paintRow(g, clip, insets, bounds, path, i, isExpanded, false, - isLeaf); + paintRow(g, clip, insets, bounds[k], path[k], i, isExpanded[k], + false, isLeaf[k]); } } } /** + * Check if the path is referring to the last child of some parent. + */ + private boolean isLastChild(TreePath path) + { + if (path instanceof GnuPath) + { + // Except the seldom case when the layout cache is changed, this + // optimized code will be executed. + return ((GnuPath) path).isLastChild; + } + else + { + // Non optimized general case. + TreePath parent = path.getParentPath(); + if (parent == null) + return false; + int childCount = treeState.getVisibleChildCount(parent); + int p = treeModel.getIndexOfChild(parent, path.getLastPathComponent()); + return p == childCount - 1; + } + } + + /** * Ensures that the rows identified by beginRow through endRow are visible. * - * @param beginRow - * is the first row - * @param endRow - * is the last row + * @param beginRow is the first row + * @param endRow is the last row */ protected void ensureRowsAreVisible(int beginRow, int endRow) { @@ -1514,7 +1478,7 @@ public class BasicTreeUI extends TreeUI for (int i = beginRow; i < endRow; i++) { TreePath path = getPathForRow(tree, i); - if (!tree.isVisible(path)) + if (! tree.isVisible(path)) tree.makeVisible(path); } } @@ -1522,8 +1486,7 @@ public class BasicTreeUI extends TreeUI /** * Sets the preferred minimum size. * - * @param newSize - * is the new preferred minimum size. + * @param newSize is the new preferred minimum size. */ public void setPreferredMinSize(Dimension newSize) { @@ -1537,15 +1500,17 @@ public class BasicTreeUI extends TreeUI */ public Dimension getPreferredMinSize() { - return preferredMinSize; + if (preferredMinSize == null) + return getPreferredSize(tree); + else + return preferredMinSize; } /** * Returns the preferred size to properly display the tree, this is a cover * method for getPreferredSize(c, false). * - * @param c - * the component whose preferred size is being queried; this argument + * @param c the component whose preferred size is being queried; this argument * is often ignored but might be used if the UI object is stateless * and shared by multiple components * @return the preferred size @@ -1559,17 +1524,20 @@ public class BasicTreeUI extends TreeUI * Returns the preferred size to represent the tree in c. If checkConsistancy * is true, checkConsistancy is messaged first. * - * @param c - * the component whose preferred size is being queried. - * @param checkConsistancy - * if true must check consistancy + * @param c the component whose preferred size is being queried. + * @param checkConsistancy if true must check consistancy * @return the preferred size */ public Dimension getPreferredSize(JComponent c, boolean checkConsistancy) { - // FIXME: checkConsistancy not implemented, c not used - if (!validCachedPreferredSize) - updateCachedPreferredSize(); + if (! validCachedPreferredSize) + { + Rectangle size = tree.getBounds(); + // Add the scrollbar dimensions to the preferred size. + preferredSize = new Dimension(treeState.getPreferredWidth(size), + treeState.getPreferredHeight()); + validCachedPreferredSize = true; + } return preferredSize; } @@ -1577,31 +1545,24 @@ public class BasicTreeUI extends TreeUI * Returns the minimum size for this component. Which will be the min * preferred size or (0,0). * - * @param c - * the component whose min size is being queried. + * @param c the component whose min size is being queried. * @returns the preferred size or null */ public Dimension getMinimumSize(JComponent c) { - Dimension min = getPreferredMinSize(); - if (min == null) - return new Dimension(); - return min; + return preferredMinSize = getPreferredSize(c); } /** * Returns the maximum size for the component, which will be the preferred * size if the instance is currently in JTree or (0,0). * - * @param c - * the component whose preferred size is being queried + * @param c the component whose preferred size is being queried * @return the max size or null */ public Dimension getMaximumSize(JComponent c) { - if (c instanceof JTree) - return ((JTree) c).getPreferredSize(); - return new Dimension(); + return getPreferredSize(c); } /** @@ -1622,12 +1583,9 @@ public class BasicTreeUI extends TreeUI * cancelEditing. If messageTree is true, the treeModel is messaged with * valueForPathChanged. * - * @param messageStop - * message to stop editing - * @param messageCancel - * message to cancel editing - * @param messageTree - * message to treeModel + * @param messageStop message to stop editing + * @param messageCancel message to cancel editing + * @param messageTree message to treeModel */ protected void completeEditing(boolean messageStop, boolean messageCancel, boolean messageTree) @@ -1659,25 +1617,16 @@ public class BasicTreeUI extends TreeUI * Will start editing for node if there is a cellEditor and shouldSelectCall * returns true. This assumes that path is valid and visible. * - * @param path - * is the path to start editing - * @param event - * is the MouseEvent performed on the path + * @param path is the path to start editing + * @param event is the MouseEvent performed on the path * @return true if successful */ protected boolean startEditing(TreePath path, MouseEvent event) { - // Force to recalculate the maximal row height. - maxHeight = 0; - - // Force to recalculate the cached preferred size. - validCachedPreferredSize = false; - updateCellEditor(); TreeCellEditor ed = getCellEditor(); - if (ed != null - && (event == EDIT || ed.shouldSelectCell(event)) + if (ed != null && (event == EDIT || ed.shouldSelectCell(event)) && ed.isCellEditable(event)) { Rectangle bounds = getPathBounds(tree, path); @@ -1718,12 +1667,9 @@ public class BasicTreeUI extends TreeUI * If the <code>mouseX</code> and <code>mouseY</code> are in the expand or * collapse region of the row, this will toggle the row. * - * @param path - * the path we are concerned with - * @param mouseX - * is the cursor's x position - * @param mouseY - * is the cursor's y position + * @param path the path we are concerned with + * @param mouseX is the cursor's x position + * @param mouseY is the cursor's y position */ protected void checkForClickInExpandControl(TreePath path, int mouseX, int mouseY) @@ -1737,12 +1683,9 @@ public class BasicTreeUI extends TreeUI * the area of row that is used to expand/collpse the node and the node at row * does not represent a leaf. * - * @param path - * the path we are concerned with - * @param mouseX - * is the cursor's x position - * @param mouseY - * is the cursor's y position + * @param path the path we are concerned with + * @param mouseX is the cursor's x position + * @param mouseY is the cursor's y position * @return true if the <code>mouseX</code> and <code>mouseY</code> fall in * the area of row that is used to expand/collpse the node and the * node at row does not represent a leaf. @@ -1753,7 +1696,7 @@ public class BasicTreeUI extends TreeUI boolean cntlClick = false; int row = getRowForPath(tree, path); - if (!isLeaf(row)) + if (! isLeaf(row)) { Rectangle bounds = getPathBounds(tree, path); @@ -1769,12 +1712,9 @@ public class BasicTreeUI extends TreeUI * Messaged when the user clicks the particular row, this invokes * toggleExpandState. * - * @param path - * the path we are concerned with - * @param mouseX - * is the cursor's x position - * @param mouseY - * is the cursor's y position + * @param path the path we are concerned with + * @param mouseX is the cursor's x position + * @param mouseY is the cursor's y position */ protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY) { @@ -1787,8 +1727,7 @@ public class BasicTreeUI extends TreeUI * invoked to scroll as many of the children to visible as possible (tries to * scroll to last visible descendant of path). * - * @param path - * the path we are concerned with + * @param path the path we are concerned with */ protected void toggleExpandState(TreePath path) { @@ -1800,30 +1739,40 @@ public class BasicTreeUI extends TreeUI /** * Returning true signifies a mouse event on the node should toggle the - * selection of only the row under the mouse. + * selection of only the row under the mouse. The BasisTreeUI treats the + * event as "toggle selection event" if the CTRL button was pressed while + * clicking. The event is not counted as toggle event if the associated + * tree does not support the multiple selection. * - * @param event - * is the MouseEvent performed on the row. + * @param event is the MouseEvent performed on the row. * @return true signifies a mouse event on the node should toggle the * selection of only the row under the mouse. */ protected boolean isToggleSelectionEvent(MouseEvent event) { - return (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.SINGLE_TREE_SELECTION); + return + (tree.getSelectionModel().getSelectionMode() != + TreeSelectionModel.SINGLE_TREE_SELECTION) && + ((event.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0); } /** * Returning true signifies a mouse event on the node should select from the - * anchor point. + * anchor point. The BasisTreeUI treats the event as "multiple selection + * event" if the SHIFT button was pressed while clicking. The event is not + * counted as multiple selection event if the associated tree does not support + * the multiple selection. * - * @param event - * is the MouseEvent performed on the node. + * @param event is the MouseEvent performed on the node. * @return true signifies a mouse event on the node should select from the * anchor point. */ protected boolean isMultiSelectEvent(MouseEvent event) { - return (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION); + return + (tree.getSelectionModel().getSelectionMode() != + TreeSelectionModel.SINGLE_TREE_SELECTION) && + ((event.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0); } /** @@ -1831,8 +1780,7 @@ public class BasicTreeUI extends TreeUI * the event. This is invoked after checkForClickInExpandControl, implying the * location is not in the expand (toggle) control. * - * @param event - * is the MouseEvent performed on the row. + * @param event is the MouseEvent performed on the row. * @return true indicates the row under the mouse should be toggled based on * the event. */ @@ -1846,17 +1794,19 @@ public class BasicTreeUI extends TreeUI * row. If the even is a toggle selection event, the row is either selected, * or deselected. If the event identifies a multi selection event, the * selection is updated from the anchor point. Otherwise, the row is selected, - * and if the even specified a toggle event the row is expanded/collapsed. + * and the previous selection is cleared.</p> + * + * @param path is the path selected for an event + * @param event is the MouseEvent performed on the path. * - * @param path - * is the path selected for an event - * @param event - * is the MouseEvent performed on the path. + * @see #isToggleSelectionEvent(MouseEvent) + * @see #isMultiSelectEvent(MouseEvent) */ protected void selectPathForEvent(TreePath path, MouseEvent event) { if (isToggleSelectionEvent(event)) { + // The event selects or unselects the clicked row. if (tree.isPathSelected(path)) tree.removeSelectionPath(path); else @@ -1867,6 +1817,7 @@ public class BasicTreeUI extends TreeUI } else if (isMultiSelectEvent(event)) { + // The event extends selection form anchor till the clicked row. TreePath anchor = tree.getAnchorSelectionPath(); if (anchor != null) { @@ -1877,14 +1828,17 @@ public class BasicTreeUI extends TreeUI tree.addSelectionPath(path); } else - tree.addSelectionPath(path); + { + // This is an ordinary event that just selects the clicked row. + tree.setSelectionPath(path); + tree.setAnchorSelectionPath(path); + } } /** * Returns true if the node at <code>row</code> is a leaf. * - * @param row - * is the row we are concerned with. + * @param row is the row we are concerned with. * @return true if the node at <code>row</code> is a leaf. */ protected boolean isLeaf(int row) @@ -1902,46 +1856,38 @@ public class BasicTreeUI extends TreeUI * are pressed for the JTree. The actionPerformed method is called when a key * that has been registered for the JTree is received. */ - class TreeAction extends AbstractAction + class TreeAction + extends AbstractAction { /** * What to do when this action is called. * - * @param e - * the ActionEvent that caused this action. + * @param e the ActionEvent that caused this action. */ public void actionPerformed(ActionEvent e) { + String command = e.getActionCommand(); TreePath lead = tree.getLeadSelectionPath(); - if (e.getActionCommand().equals("selectPreviousChangeLead") - || e.getActionCommand().equals("selectPreviousExtendSelection") - || e.getActionCommand().equals("selectPrevious") - || e.getActionCommand().equals("selectNext") - || e.getActionCommand().equals("selectNextExtendSelection") - || e.getActionCommand().equals("selectNextChangeLead")) + if (command.equals("selectPreviousChangeLead") + || command.equals("selectPreviousExtendSelection") + || command.equals("selectPrevious") || command.equals("selectNext") + || command.equals("selectNextExtendSelection") + || command.equals("selectNextChangeLead")) (new TreeIncrementAction(0, "")).actionPerformed(e); - else if (e.getActionCommand().equals("selectParent") - || e.getActionCommand().equals("selectChild")) + else if (command.equals("selectParent") || command.equals("selectChild")) (new TreeTraverseAction(0, "")).actionPerformed(e); - else if (e.getActionCommand().equals("selectAll")) + else if (command.equals("selectAll")) { - TreePath[] paths = new TreePath[tree.getVisibleRowCount()]; - - Object curr = getNextVisibleNode(treeModel.getRoot()); - int i = 0; - while (curr != null && i < paths.length) - { - paths[i] = new TreePath(getPathToRoot(curr, 0)); - i++; - } - + TreePath[] paths = new TreePath[treeState.getRowCount()]; + for (int i = 0; i < paths.length; i++) + paths[i] = treeState.getPathForRow(i); tree.addSelectionPaths(paths); } - else if (e.getActionCommand().equals("startEditing")) + else if (command.equals("startEditing")) tree.startEditingAtPath(lead); - else if (e.getActionCommand().equals("toggle")) + else if (command.equals("toggle")) { if (tree.isEditing()) tree.stopEditing(); @@ -1949,17 +1895,17 @@ public class BasicTreeUI extends TreeUI { Object last = lead.getLastPathComponent(); TreePath path = new TreePath(getPathToRoot(last, 0)); - if (!treeModel.isLeaf(last)) + if (! treeModel.isLeaf(last)) toggleExpandState(path); } } - else if (e.getActionCommand().equals("clearSelection")) + else if (command.equals("clearSelection")) tree.clearSelection(); - if (tree.isEditing() && !e.getActionCommand().equals("startEditing")) + if (tree.isEditing() && ! command.equals("startEditing")) tree.stopEditing(); - tree.scrollPathToVisible(lead); + tree.scrollPathToVisible(tree.getLeadSelectionPath()); } } @@ -1970,7 +1916,8 @@ public class BasicTreeUI extends TreeUI * to the true receiver after altering the actionCommand property of the * event. */ - private static class ActionListenerProxy extends AbstractAction + private static class ActionListenerProxy + extends AbstractAction { ActionListener target; @@ -1992,11 +1939,12 @@ public class BasicTreeUI extends TreeUI } } - /** + /** * Updates the preferred size when scrolling, if necessary. */ - public class ComponentHandler extends ComponentAdapter implements - ActionListener + public class ComponentHandler + extends ComponentAdapter + implements ActionListener { /** * Timer used when inside a scrollpane and the scrollbar is adjusting @@ -2017,8 +1965,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when the component's position changes. * - * @param e - * the event that occurs when moving the component + * @param e the event that occurs when moving the component */ public void componentMoved(ComponentEvent e) { @@ -2048,8 +1995,7 @@ public class BasicTreeUI extends TreeUI * Public as a result of Timer. If the scrollBar is null, or not adjusting, * this stops the timer and updates the sizing. * - * @param ae - * is the action performed + * @param ae is the action performed */ public void actionPerformed(ActionEvent ae) { @@ -2061,7 +2007,8 @@ public class BasicTreeUI extends TreeUI * Listener responsible for getting cell editing events and updating the tree * accordingly. */ - public class CellEditorHandler implements CellEditorListener + public class CellEditorHandler + implements CellEditorListener { /** * Constructor @@ -2075,8 +2022,7 @@ public class BasicTreeUI extends TreeUI * Messaged when editing has stopped in the tree. Tells the listeners * editing has stopped. * - * @param e - * is the notification event + * @param e is the notification event */ public void editingStopped(ChangeEvent e) { @@ -2087,8 +2033,7 @@ public class BasicTreeUI extends TreeUI * Messaged when editing has been canceled in the tree. This tells the * listeners the editor has canceled editing. * - * @param e - * is the notification event + * @param e is the notification event */ public void editingCanceled(ChangeEvent e) { @@ -2099,7 +2044,8 @@ public class BasicTreeUI extends TreeUI /** * Repaints the lead selection row when focus is lost/grained. */ - public class FocusHandler implements FocusListener + public class FocusHandler + implements FocusListener { /** * Constructor @@ -2111,26 +2057,38 @@ public class BasicTreeUI extends TreeUI /** * Invoked when focus is activated on the tree we're in, redraws the lead - * row. Invoked when a component gains the keyboard focus. + * row. Invoked when a component gains the keyboard focus. The method + * repaints the lead row that is shown differently when the tree is in + * focus. * - * @param e - * is the focus event that is activated + * @param e is the focus event that is activated */ public void focusGained(FocusEvent e) { - // TODO: Implement this properly. + repaintLeadRow(); } /** * Invoked when focus is deactivated on the tree we're in, redraws the lead - * row. Invoked when a component loses the keyboard focus. + * row. Invoked when a component loses the keyboard focus. The method + * repaints the lead row that is shown differently when the tree is in + * focus. * - * @param e - * is the focus event that is deactivated + * @param e is the focus event that is deactivated */ public void focusLost(FocusEvent e) { - // TODO: Implement this properly. + repaintLeadRow(); + } + + /** + * Repaint the lead row. + */ + void repaintLeadRow() + { + TreePath lead = tree.getLeadSelectionPath(); + if (lead!=null) + tree.repaint(tree.getPathBounds(lead)); } } @@ -2138,7 +2096,8 @@ public class BasicTreeUI extends TreeUI * This is used to get multiple key down events to appropriately genereate * events. */ - public class KeyHandler extends KeyAdapter + public class KeyHandler + extends KeyAdapter { /** Key code that is being generated for. */ protected Action repeatKeyAction; @@ -2160,8 +2119,7 @@ public class BasicTreeUI extends TreeUI * user. Subsequent same key presses move the keyboard focus to the next * object that starts with the same letter. * - * @param e - * the key typed + * @param e the key typed */ public void keyTyped(KeyEvent e) { @@ -2171,8 +2129,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when a key has been pressed. * - * @param e - * the key pressed + * @param e the key pressed */ public void keyPressed(KeyEvent e) { @@ -2182,8 +2139,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when a key has been released * - * @param e - * the key released + * @param e the key released */ public void keyReleased(KeyEvent e) { @@ -2195,7 +2151,9 @@ public class BasicTreeUI extends TreeUI * MouseListener is responsible for updating the selection based on mouse * events. */ - public class MouseHandler extends MouseAdapter implements MouseMotionListener + public class MouseHandler + extends MouseAdapter + implements MouseMotionListener { /** * Constructor @@ -2208,11 +2166,10 @@ public class BasicTreeUI extends TreeUI /** * Invoked when a mouse button has been pressed on a component. * - * @param e - * is the mouse event that occured + * @param e is the mouse event that occured */ public void mousePressed(MouseEvent e) - { + { // Any mouse click cancels the previous waiting edit action, initiated // by the single click on the selected node. if (startEditTimer != null) @@ -2220,7 +2177,7 @@ public class BasicTreeUI extends TreeUI startEditTimer.stop(); startEditTimer = null; } - + Point click = e.getPoint(); TreePath path = getClosestPathForLocation(tree, click.x, click.y); @@ -2228,6 +2185,11 @@ public class BasicTreeUI extends TreeUI { Rectangle bounds = getPathBounds(tree, path); int row = getRowForPath(tree, path); + + // Cancel the editing session if clicked on the different row. + if (tree.isEditing() && row != editingRow) + cancelEditing(tree); + boolean cntlClick = isLocationInExpandControl(path, click.x, click.y); boolean isLeaf = isLeaf(row); @@ -2258,35 +2220,32 @@ public class BasicTreeUI extends TreeUI if (inBounds) { TreePath currentLead = tree.getLeadSelectionPath(); - if ( - currentLead != null && - currentLead.equals(path) && - e.getClickCount() == 1 && - tree.isEditable() - ) + if (currentLead != null && currentLead.equals(path) + && e.getClickCount() == 1 && tree.isEditable()) { // Schedule the editing session. final TreePath editPath = path; - + if (startEditTimer != null) startEditTimer.stop(); - - startEditTimer = new Timer(WAIT_TILL_EDITING, - new ActionListener() - { + + startEditTimer = new Timer(WAIT_TILL_EDITING, + new ActionListener() + { public void actionPerformed(ActionEvent e) - { - startEditing(editPath, EDIT); - } + { + startEditing(editPath, EDIT); + } }); - startEditTimer.setRepeats(false); - startEditTimer.start(); + startEditTimer.setRepeats(false); + startEditTimer.start(); } else { - selectPath(tree, path); - if (e.getClickCount() == 2 && !isLeaf(row)) + if (e.getClickCount() == 2 && ! isLeaf(row)) toggleExpandState(path); + else + selectPathForEvent(path, e); } } @@ -2309,8 +2268,7 @@ public class BasicTreeUI extends TreeUI * the drag originated until the mouse button is released (regardless of * whether the mouse position is within the bounds of the component). * - * @param e - * is the mouse event that occured + * @param e is the mouse event that occured */ public void mouseDragged(MouseEvent e) { @@ -2321,8 +2279,7 @@ public class BasicTreeUI extends TreeUI * Invoked when the mouse button has been moved on a component (with no * buttons no down). * - * @param e - * the mouse event that occured + * @param e the mouse event that occured */ public void mouseMoved(MouseEvent e) { @@ -2332,8 +2289,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when a mouse button has been released on a component. * - * @param e - * is the mouse event that occured + * @param e is the mouse event that occured */ public void mouseReleased(MouseEvent e) { @@ -2346,7 +2302,8 @@ public class BasicTreeUI extends TreeUI * events, until the mouse is released to the destination it is constructed * with. */ - public class MouseInputHandler implements MouseInputListener + public class MouseInputHandler + implements MouseInputListener { /** Source that events are coming from */ protected Component source; @@ -2357,12 +2314,9 @@ public class BasicTreeUI extends TreeUI /** * Constructor * - * @param source - * that events are coming from - * @param destination - * that receives all events - * @param e - * is the event received + * @param source that events are coming from + * @param destination that receives all events + * @param e is the event received */ public MouseInputHandler(Component source, Component destination, MouseEvent e) @@ -2375,8 +2329,7 @@ public class BasicTreeUI extends TreeUI * Invoked when the mouse button has been clicked (pressed and released) on * a component. * - * @param e - * mouse event that occured + * @param e mouse event that occured */ public void mouseClicked(MouseEvent e) { @@ -2386,8 +2339,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when a mouse button has been pressed on a component. * - * @param e - * mouse event that occured + * @param e mouse event that occured */ public void mousePressed(MouseEvent e) { @@ -2397,8 +2349,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when a mouse button has been released on a component. * - * @param e - * mouse event that occured + * @param e mouse event that occured */ public void mouseReleased(MouseEvent e) { @@ -2408,8 +2359,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when the mouse enters a component. * - * @param e - * mouse event that occured + * @param e mouse event that occured */ public void mouseEntered(MouseEvent e) { @@ -2419,8 +2369,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when the mouse exits a component. * - * @param e - * mouse event that occured + * @param e mouse event that occured */ public void mouseExited(MouseEvent e) { @@ -2433,8 +2382,7 @@ public class BasicTreeUI extends TreeUI * the drag originated until the mouse button is released (regardless of * whether the mouse position is within the bounds of the component). * - * @param e - * mouse event that occured + * @param e mouse event that occured */ public void mouseDragged(MouseEvent e) { @@ -2445,8 +2393,7 @@ public class BasicTreeUI extends TreeUI * Invoked when the mouse cursor has been moved onto a component but no * buttons have been pushed. * - * @param e - * mouse event that occured + * @param e mouse event that occured */ public void mouseMoved(MouseEvent e) { @@ -2467,7 +2414,8 @@ public class BasicTreeUI extends TreeUI * BasicTreeUI method. X location does not include insets, that is handled in * getPathBounds. */ - public class NodeDimensionsHandler extends AbstractLayoutCache.NodeDimensions + public class NodeDimensionsHandler + extends AbstractLayoutCache.NodeDimensions { /** * Constructor @@ -2483,16 +2431,11 @@ public class BasicTreeUI extends TreeUI * bounds is null, a newly created Rectangle should be returned, otherwise * the value should be placed in bounds and returned. * - * @param cell - * the value to be represented - * @param row - * row being queried - * @param depth - * the depth of the row - * @param expanded - * true if row is expanded - * @param size - * a Rectangle containing the size needed to represent value + * @param cell the value to be represented + * @param row row being queried + * @param depth the depth of the row + * @param expanded true if row is expanded + * @param size a Rectangle containing the size needed to represent value * @return containing the node dimensions, or null if node has no dimension */ public Rectangle getNodeDimensions(Object cell, int row, int depth, @@ -2509,6 +2452,8 @@ public class BasicTreeUI extends TreeUI { size.x = getRowX(row, depth); size.width = SwingUtilities.computeStringWidth(fm, s); + size.width = size.width + getCurrentControlIcon(null).getIconWidth() + + gap; size.height = getMaxHeight(tree); size.y = size.height * row; } @@ -2523,17 +2468,17 @@ public class BasicTreeUI extends TreeUI */ protected int getRowX(int row, int depth) { - if (row == 0) - return 0; - return depth * rightChildIndent; + int iw = getCurrentControlIcon(null).getIconWidth(); + return depth * (rightChildIndent + iw/2); } }// NodeDimensionsHandler /** - * PropertyChangeListener for the tree. Updates the appropriate varaible, or + * PropertyChangeListener for the tree. Updates the appropriate variable, or * TreeState, based on what changes. */ - public class PropertyChangeHandler implements PropertyChangeListener + public class PropertyChangeHandler + implements PropertyChangeListener { /** @@ -2547,17 +2492,28 @@ public class BasicTreeUI extends TreeUI /** * This method gets called when a bound property is changed. * - * @param event - * A PropertyChangeEvent object describing the event source and the - * property that has changed. + * @param event A PropertyChangeEvent object describing the event source and + * the property that has changed. */ public void propertyChange(PropertyChangeEvent event) { - if ((event.getPropertyName()).equals("rootVisible")) + String property = event.getPropertyName(); + if (property.equals(JTree.ROOT_VISIBLE_PROPERTY)) { validCachedPreferredSize = false; + treeState.setRootVisible(tree.isRootVisible()); tree.repaint(); } + else if (property.equals(JTree.SELECTION_MODEL_PROPERTY)) + { + treeSelectionModel = tree.getSelectionModel(); + treeSelectionModel.setRowMapper(treeState); + } + else if (property.equals(JTree.TREE_MODEL_PROPERTY)) + { + treeModel = tree.getModel(); + treeModel.addTreeModelListener(treeModelListener); + } } } @@ -2565,8 +2521,8 @@ public class BasicTreeUI extends TreeUI * Listener on the TreeSelectionModel, resets the row selection if any of the * properties of the model change. */ - public class SelectionModelPropertyChangeHandler implements - PropertyChangeListener + public class SelectionModelPropertyChangeHandler + implements PropertyChangeListener { /** @@ -2580,9 +2536,8 @@ public class BasicTreeUI extends TreeUI /** * This method gets called when a bound property is changed. * - * @param event - * A PropertyChangeEvent object describing the event source and the - * property that has changed. + * @param event A PropertyChangeEvent object describing the event source and + * the property that has changed. */ public void propertyChange(PropertyChangeEvent event) { @@ -2593,7 +2548,8 @@ public class BasicTreeUI extends TreeUI /** * ActionListener that invokes cancelEditing when action performed. */ - public class TreeCancelEditingAction extends AbstractAction + public class TreeCancelEditingAction + extends AbstractAction { /** @@ -2607,8 +2563,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when an action occurs. * - * @param e - * event that occured + * @param e event that occured */ public void actionPerformed(ActionEvent e) { @@ -2630,7 +2585,8 @@ public class BasicTreeUI extends TreeUI /** * Updates the TreeState in response to nodes expanding/collapsing. */ - public class TreeExpansionHandler implements TreeExpansionListener + public class TreeExpansionHandler + implements TreeExpansionListener { /** @@ -2644,24 +2600,26 @@ public class BasicTreeUI extends TreeUI /** * Called whenever an item in the tree has been expanded. * - * @param event - * is the event that occured + * @param event is the event that occured */ public void treeExpanded(TreeExpansionEvent event) { validCachedPreferredSize = false; + treeState.setExpandedState(event.getPath(), true); + tree.revalidate(); tree.repaint(); } /** * Called whenever an item in the tree has been collapsed. * - * @param event - * is the event that occured + * @param event is the event that occured */ public void treeCollapsed(TreeExpansionEvent event) { validCachedPreferredSize = false; + treeState.setExpandedState(event.getPath(), false); + tree.revalidate(); tree.repaint(); } }// TreeExpansionHandler @@ -2670,7 +2628,8 @@ public class BasicTreeUI extends TreeUI * TreeHomeAction is used to handle end/home actions. Scrolls either the first * or last cell to be visible based on direction. */ - public class TreeHomeAction extends AbstractAction + public class TreeHomeAction + extends AbstractAction { /** The direction, either home or end */ @@ -2679,10 +2638,8 @@ public class BasicTreeUI extends TreeUI /** * Constructor * - * @param direction - - * it is home or end - * @param name - * is the name of the direction + * @param direction - it is home or end + * @param name is the name of the direction */ public TreeHomeAction(int direction, String name) { @@ -2692,8 +2649,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when an action occurs. * - * @param e - * is the event that occured + * @param e is the event that occured */ public void actionPerformed(ActionEvent e) { @@ -2716,7 +2672,8 @@ public class BasicTreeUI extends TreeUI * TreeIncrementAction is used to handle up/down actions. Selection is moved * up or down based on direction. */ - public class TreeIncrementAction extends AbstractAction + public class TreeIncrementAction + extends AbstractAction { /** Specifies the direction to adjust the selection by. */ @@ -2725,10 +2682,8 @@ public class BasicTreeUI extends TreeUI /** * Constructor * - * @param direction - * up or down - * @param name - * is the name of the direction + * @param direction up or down + * @param name is the name of the direction */ public TreeIncrementAction(int direction, String name) { @@ -2738,73 +2693,79 @@ public class BasicTreeUI extends TreeUI /** * Invoked when an action occurs. * - * @param e - * is the event that occured + * @param e is the event that occured */ public void actionPerformed(ActionEvent e) { - Object last = tree.getLeadSelectionPath().getLastPathComponent(); + TreePath currentPath = tree.getLeadSelectionPath(); + int currentRow; - if (e.getActionCommand().equals("selectPreviousChangeLead")) - { - Object prev = getPreviousVisibleNode(last); + if (currentPath != null) + currentRow = treeState.getRowForPath(currentPath); + else + currentRow = 0; - if (prev != null) - { - TreePath newPath = new TreePath(getPathToRoot(prev, 0)); - selectPath(tree, newPath); - tree.setLeadSelectionPath(newPath); - } - } - else if (e.getActionCommand().equals("selectPreviousExtendSelection")) + int rows = treeState.getRowCount(); + + int nextRow = currentRow + 1; + int prevRow = currentRow - 1; + boolean hasNext = nextRow < rows; + boolean hasPrev = prevRow >= 0 && rows > 0; + TreePath newPath; + String command = e.getActionCommand(); + + if (command.equals("selectPreviousChangeLead") && hasPrev) { - Object prev = getPreviousVisibleNode(last); - if (prev != null) - { - TreePath newPath = new TreePath(getPathToRoot(prev, 0)); - tree.addSelectionPath(newPath); - tree.setLeadSelectionPath(newPath); - } + newPath = treeState.getPathForRow(prevRow); + tree.setSelectionPath(newPath); + tree.setAnchorSelectionPath(newPath); + tree.setLeadSelectionPath(newPath); } - else if (e.getActionCommand().equals("selectPrevious")) + else if (command.equals("selectPreviousExtendSelection") && hasPrev) { - Object prev = getPreviousVisibleNode(last); + newPath = treeState.getPathForRow(prevRow); - if (prev != null) - { - TreePath newPath = new TreePath(getPathToRoot(prev, 0)); - selectPath(tree, newPath); - } + // If the new path is already selected, the selection shrinks, + // unselecting the previously current path. + if (tree.isPathSelected(newPath)) + tree.getSelectionModel().removeSelectionPath(currentPath); + + // This must be called in any case because it updates the model + // lead selection index. + tree.addSelectionPath(newPath); + tree.setLeadSelectionPath(newPath); } - else if (e.getActionCommand().equals("selectNext")) + else if (command.equals("selectPrevious") && hasPrev) { - Object next = getNextVisibleNode(last); - - if (next != null) - { - TreePath newPath = new TreePath(getPathToRoot(next, 0)); - selectPath(tree, newPath); - } + newPath = treeState.getPathForRow(prevRow); + tree.setSelectionPath(newPath); } - else if (e.getActionCommand().equals("selectNextExtendSelection")) + else if (command.equals("selectNext") && hasNext) { - Object next = getNextVisibleNode(last); - if (next != null) - { - TreePath newPath = new TreePath(getPathToRoot(next, 0)); - tree.addSelectionPath(newPath); - tree.setLeadSelectionPath(newPath); - } + newPath = treeState.getPathForRow(nextRow); + tree.setSelectionPath(newPath); } - else if (e.getActionCommand().equals("selectNextChangeLead")) + else if (command.equals("selectNextExtendSelection") && hasNext) { - Object next = getNextVisibleNode(last); - if (next != null) - { - TreePath newPath = new TreePath(getPathToRoot(next, 0)); - selectPath(tree, newPath); - tree.setLeadSelectionPath(newPath); - } + newPath = treeState.getPathForRow(nextRow); + + // If the new path is already selected, the selection shrinks, + // unselecting the previously current path. + if (tree.isPathSelected(newPath)) + tree.getSelectionModel().removeSelectionPath(currentPath); + + // This must be called in any case because it updates the model + // lead selection index. + tree.addSelectionPath(newPath); + + tree.setLeadSelectionPath(newPath); + } + else if (command.equals("selectNextChangeLead") && hasNext) + { + newPath = treeState.getPathForRow(nextRow); + tree.setSelectionPath(newPath); + tree.setAnchorSelectionPath(newPath); + tree.setLeadSelectionPath(newPath); } } @@ -2823,7 +2784,8 @@ public class BasicTreeUI extends TreeUI /** * Forwards all TreeModel events to the TreeState. */ - public class TreeModelHandler implements TreeModelListener + public class TreeModelHandler + implements TreeModelListener { /** * Constructor @@ -2843,12 +2805,12 @@ public class BasicTreeUI extends TreeUI * node(s). e.getChildIndices() returns the index(es) of the changed * node(s). * - * @param e - * is the event that occured + * @param e is the event that occured */ public void treeNodesChanged(TreeModelEvent e) { validCachedPreferredSize = false; + treeState.treeNodesChanged(e); tree.repaint(); } @@ -2857,12 +2819,12 @@ public class BasicTreeUI extends TreeUI * get the parent of the new node(s). e.getChildIndices() returns the * index(es) of the new node(s) in ascending order. * - * @param e - * is the event that occured + * @param e is the event that occured */ public void treeNodesInserted(TreeModelEvent e) { validCachedPreferredSize = false; + treeState.treeNodesInserted(e); tree.repaint(); } @@ -2874,12 +2836,12 @@ public class BasicTreeUI extends TreeUI * node(s). e.getChildIndices() returns, in ascending order, the index(es) * the node(s) had before being deleted. * - * @param e - * is the event that occured + * @param e is the event that occured */ public void treeNodesRemoved(TreeModelEvent e) { validCachedPreferredSize = false; + treeState.treeNodesRemoved(e); tree.repaint(); } @@ -2890,15 +2852,15 @@ public class BasicTreeUI extends TreeUI * should become the new root of the tree. Use e.getPath() to get the path * to the node. e.getChildIndices() returns null. * - * @param e - * is the event that occured + * @param e is the event that occured */ public void treeStructureChanged(TreeModelEvent e) { if (e.getPath().length == 1 - && !e.getPath()[0].equals(treeModel.getRoot())) + && ! e.getPath()[0].equals(treeModel.getRoot())) tree.expandPath(new TreePath(treeModel.getRoot())); validCachedPreferredSize = false; + treeState.treeStructureChanged(e); tree.repaint(); } }// TreeModelHandler @@ -2906,7 +2868,8 @@ public class BasicTreeUI extends TreeUI /** * TreePageAction handles page up and page down events. */ - public class TreePageAction extends AbstractAction + public class TreePageAction + extends AbstractAction { /** Specifies the direction to adjust the selection by. */ protected int direction; @@ -2914,10 +2877,8 @@ public class BasicTreeUI extends TreeUI /** * Constructor * - * @param direction - * up or down - * @param name - * is the name of the direction + * @param direction up or down + * @param name is the name of the direction */ public TreePageAction(int direction, String name) { @@ -2927,8 +2888,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when an action occurs. * - * @param e - * is the event that occured + * @param e is the event that occured */ public void actionPerformed(ActionEvent e) { @@ -2950,7 +2910,8 @@ public class BasicTreeUI extends TreeUI * Listens for changes in the selection model and updates the display * accordingly. */ - public class TreeSelectionHandler implements TreeSelectionListener + public class TreeSelectionHandler + implements TreeSelectionListener { /** * Constructor @@ -2964,26 +2925,42 @@ public class BasicTreeUI extends TreeUI * Messaged when the selection changes in the tree we're displaying for. * Stops editing, messages super and displays the changed paths. * - * @param event - * the event that characterizes the change. + * @param event the event that characterizes the change. */ public void valueChanged(TreeSelectionEvent event) { if (tree.isEditing()) - tree.stopEditing(); + tree.cancelEditing(); + + TreePath op = event.getOldLeadSelectionPath(); + TreePath np = event.getNewLeadSelectionPath(); + + // Repaint of the changed lead selection path. + if (op != np) + { + Rectangle o = treeState.getBounds(event.getOldLeadSelectionPath(), + new Rectangle()); + Rectangle n = treeState.getBounds(event.getNewLeadSelectionPath(), + new Rectangle()); + + if (o!=null) + tree.repaint(o); + if (n!=null) + tree.repaint(n); + } } }// TreeSelectionHandler /** * For the first selected row expandedness will be toggled. */ - public class TreeToggleAction extends AbstractAction + public class TreeToggleAction + extends AbstractAction { /** * Constructor * - * @param name - * is the name of <code>Action</code> field + * @param name is the name of <code>Action</code> field */ public TreeToggleAction(String name) { @@ -2993,8 +2970,7 @@ public class BasicTreeUI extends TreeUI /** * Invoked when an action occurs. * - * @param e - * the event that occured + * @param e the event that occured */ public void actionPerformed(ActionEvent e) { @@ -3016,7 +2992,8 @@ public class BasicTreeUI extends TreeUI * TreeTraverseAction is the action used for left/right keys. Will toggle the * expandedness of a node, as well as potentially incrementing the selection. */ - public class TreeTraverseAction extends AbstractAction + public class TreeTraverseAction + extends AbstractAction { /** * Determines direction to traverse, 1 means expand, -1 means collapse. @@ -3026,10 +3003,8 @@ public class BasicTreeUI extends TreeUI /** * Constructor * - * @param direction - * to traverse - * @param name - * is the name of the direction + * @param direction to traverse + * @param name is the name of the direction */ public TreeTraverseAction(int direction, String name) { @@ -3039,35 +3014,49 @@ public class BasicTreeUI extends TreeUI /** * Invoked when an action occurs. * - * @param e - * the event that occured + * @param e the event that occured */ public void actionPerformed(ActionEvent e) { - Object last = tree.getLeadSelectionPath().getLastPathComponent(); + TreePath current = tree.getLeadSelectionPath(); + if (current == null) + return; if (e.getActionCommand().equals("selectParent")) { - TreePath path = new TreePath(getPathToRoot(last, 0)); - Object p = getParent(treeModel.getRoot(), last); + if (current == null) + return; - if (!treeModel.isLeaf(last)) - toggleExpandState(path); - else if (p != null) - selectPath(tree, new TreePath(getPathToRoot(p, 0))); + if (tree.isExpanded(current)) + { + tree.collapsePath(current); + } + else + { + // If the node is not expanded (also, if it is a leaf node), + // we just select the parent. We do not select the root if it + // is not visible. + TreePath parent = current.getParentPath(); + if (parent != null && + !(parent.getPathCount()==1 && !tree.isRootVisible()) ) + tree.setSelectionPath(parent); + } } else if (e.getActionCommand().equals("selectChild")) { - TreePath path = new TreePath(getPathToRoot(last, 0)); - - if (!treeModel.isLeaf(last)) - toggleExpandState(path); + Object node = current.getLastPathComponent(); + int nc = treeModel.getChildCount(node); + if (nc == 0 || treeState.isExpanded(current)) + { + // If the node is leaf or it is already expanded, + // we just select the next row. + int nextRow = tree.getLeadSelectionRow() + 1; + if (nextRow <= tree.getRowCount()) + tree.setSelectionRow(nextRow); + } else { - Object next = getNextVisibleNode(last); - - if (next != null) - selectPath(tree, new TreePath(getPathToRoot(next, 0))); + tree.expandPath(current); } } } @@ -3113,10 +3102,8 @@ public class BasicTreeUI extends TreeUI /** * Returns the parent of the current node * - * @param root - * is the root of the tree - * @param node - * is the current node + * @param root is the root of the tree + * @param node is the current node * @return is the parent of the current node */ Object getParent(Object root, Object node) @@ -3132,15 +3119,13 @@ public class BasicTreeUI extends TreeUI /** * Recursively checks the tree for the specified node, starting at the root. * - * @param root - * is starting node to start searching at. - * @param node - * is the node to search for + * @param root is starting node to start searching at. + * @param node is the node to search for * @return the parent node of node */ private Object findNode(Object root, Object node) { - if (!treeModel.isLeaf(root) && !root.equals(node)) + if (! treeModel.isLeaf(root) && ! root.equals(node)) { int size = treeModel.getChildCount(root); for (int j = 0; j < size; j++) @@ -3158,167 +3143,20 @@ public class BasicTreeUI extends TreeUI } /** - * Get previous visible node in the tree. Package private for use in inner - * classes. - * - * @param node - - * current node - * @return the next visible node in the JTree. Return null if there are no - * more. - */ - Object getPreviousVisibleNode(Object node) - { - if (currentVisiblePath != null) - { - Object[] nodes = currentVisiblePath.getPath(); - int i = 0; - while (i < nodes.length && !node.equals(nodes[i])) - i++; - // return the next node - if (i - 1 >= 0) - return nodes[i - 1]; - } - return null; - } - - /** - * Returns the next node in the tree Package private for use in inner classes. - * - * @param curr - - * current node - * @return the next node in the tree - */ - Object getNextNode(Object curr) - { - if (!treeModel.isLeaf(curr) && treeModel.getChildCount(curr) > 0) - return treeModel.getChild(curr, 0); - - Object node = curr; - Object sibling = null; - do - { - sibling = getNextSibling(node); - node = getParent(treeModel.getRoot(), node); - } - while (sibling == null && node != null); - - return sibling; - } - - /** - * Returns the previous node in the tree Package private for use in inner - * classes. - * - * @param node - * current node - * @return the previous node in the tree - */ - Object getPreviousNode(Object node) - { - Object parent = getParent(treeModel.getRoot(), node); - if (parent == null) - return null; - - Object sibling = getPreviousSibling(node); - - if (sibling == null) - return parent; - - int size = 0; - if (!treeModel.isLeaf(sibling)) - size = treeModel.getChildCount(sibling); - while (size > 0) - { - sibling = treeModel.getChild(sibling, size - 1); - if (!treeModel.isLeaf(sibling)) - size = treeModel.getChildCount(sibling); - else - size = 0; - } - - return sibling; - } - - /** - * Returns the next sibling in the tree Package private for use in inner - * classes. - * - * @param node - - * current node - * @return the next sibling in the tree - */ - Object getNextSibling(Object node) - { - Object parent = getParent(treeModel.getRoot(), node); - if (parent == null) - return null; - - int index = treeModel.getIndexOfChild(parent, node) + 1; - - int size = 0; - if (!treeModel.isLeaf(parent)) - size = treeModel.getChildCount(parent); - if (index == 0 || index >= size) - return null; - - return treeModel.getChild(parent, index); - } - - /** - * Returns the previous sibling in the tree Package private for use in inner - * classes. - * - * @param node - - * current node - * @return the previous sibling in the tree - */ - Object getPreviousSibling(Object node) - { - Object parent = getParent(treeModel.getRoot(), node); - if (parent == null) - return null; - - int index = treeModel.getIndexOfChild(parent, node) - 1; - - int size = 0; - if (!treeModel.isLeaf(parent)) - size = treeModel.getChildCount(parent); - if (index < 0 || index >= size) - return null; - - return treeModel.getChild(parent, index); - } - - /** * Selects the specified path in the tree depending on modes. Package private * for use in inner classes. * - * @param tree - * is the tree we are selecting the path in - * @param path - * is the path we are selecting + * @param tree is the tree we are selecting the path in + * @param path is the path we are selecting */ void selectPath(JTree tree, TreePath path) { if (path != null) { - if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.SINGLE_TREE_SELECTION) - { - tree.getSelectionModel().clearSelection(); - tree.addSelectionPath(path); - tree.setLeadSelectionPath(path); - } - else if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION) - { - // TODO - } - else - { - tree.addSelectionPath(path); - tree.setLeadSelectionPath(path); - tree.getSelectionModel().setSelectionMode( - TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); - } + tree.setSelectionPath(path); + tree.setLeadSelectionPath(path); + tree.makeVisible(path); + tree.scrollPathToVisible(path); } } @@ -3326,10 +3164,8 @@ public class BasicTreeUI extends TreeUI * Returns the path from node to the root. Package private for use in inner * classes. * - * @param node - * the node to get the path to - * @param depth - * the depth of the tree to return a path for + * @param node the node to get the path to + * @param depth the depth of the tree to return a path for * @return an array of tree nodes that represent the path to node. */ Object[] getPathToRoot(Object node, int depth) @@ -3349,47 +3185,13 @@ public class BasicTreeUI extends TreeUI } /** - * Returns the level of the node in the tree. - * - * @param node - - * current node - * @return the number of the level - */ - int getLevel(Object node) - { - int count = -1; - - Object current = node; - - if (treeModel != null) - { - Object root = treeModel.getRoot(); - if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root))) - count--; - - do - { - current = getParent(root, current); - count++; - } - while (current != null); - } - return count; - } - - /** * Draws a vertical line using the given graphic context * - * @param g - * is the graphic context - * @param c - * is the component the new line will belong to - * @param x - * is the horizonal position - * @param top - * specifies the top of the line - * @param bottom - * specifies the bottom of the line + * @param g is the graphic context + * @param c is the component the new line will belong to + * @param x is the horizonal position + * @param top specifies the top of the line + * @param bottom specifies the bottom of the line */ protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, int bottom) @@ -3402,16 +3204,11 @@ public class BasicTreeUI extends TreeUI /** * Draws a horizontal line using the given graphic context * - * @param g - * is the graphic context - * @param c - * is the component the new line will belong to - * @param y - * is the vertical position - * @param left - * specifies the left point of the line - * @param right - * specifies the right point of the line + * @param g is the graphic context + * @param c is the component the new line will belong to + * @param y is the vertical position + * @param left specifies the left point of the line + * @param right specifies the right point of the line */ protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left, int right) @@ -3424,16 +3221,11 @@ public class BasicTreeUI extends TreeUI /** * Draws an icon at around a specific position * - * @param c - * is the component the new line will belong to - * @param g - * is the graphic context - * @param icon - * is the icon which will be drawn - * @param x - * is the center position in x-direction - * @param y - * is the center position in y-direction + * @param c is the component the new line will belong to + * @param g is the graphic context + * @param icon is the icon which will be drawn + * @param x is the center position in x-direction + * @param y is the center position in y-direction */ protected void drawCentered(Component c, Graphics g, Icon icon, int x, int y) { @@ -3451,14 +3243,10 @@ public class BasicTreeUI extends TreeUI /** * Draws a dashed horizontal line. * - * @param g - - * the graphics configuration. - * @param y - - * the y location to start drawing at - * @param x1 - - * the x location to start drawing at - * @param x2 - - * the x location to finish drawing at + * @param g - the graphics configuration. + * @param y - the y location to start drawing at + * @param x1 - the x location to start drawing at + * @param x2 - the x location to finish drawing at */ protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2) { @@ -3470,14 +3258,10 @@ public class BasicTreeUI extends TreeUI /** * Draws a dashed vertical line. * - * @param g - - * the graphics configuration. - * @param x - - * the x location to start drawing at - * @param y1 - - * the y location to start drawing at - * @param y2 - - * the y location to finish drawing at + * @param g - the graphics configuration. + * @param x - the x location to start drawing at + * @param y1 - the y location to start drawing at + * @param y2 - the y location to finish drawing at */ protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2) { @@ -3490,22 +3274,15 @@ public class BasicTreeUI extends TreeUI * Paints the expand (toggle) part of a row. The receiver should NOT modify * clipBounds, or insets. * - * @param g - - * the graphics configuration + * @param g - the graphics configuration * @param clipBounds - * @param insets - - * @param bounds - - * bounds of expand control - * @param path - - * path to draw control for - * @param row - - * row to draw control for - * @param isExpanded - - * is the row expanded - * @param hasBeenExpanded - - * has the row already been expanded - * @param isLeaf - - * is the path a leaf + * @param bounds - bounds of expand control + * @param path - path to draw control for + * @param row - row to draw control for + * @param isExpanded - is the row expanded + * @param hasBeenExpanded - has the row already been expanded + * @param isLeaf - is the path a leaf */ protected void paintExpandControl(Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds, @@ -3516,9 +3293,7 @@ public class BasicTreeUI extends TreeUI { Icon icon = getCurrentControlIcon(path); int iconW = icon.getIconWidth(); - int x = bounds.x - rightChildIndent + iconW / 2; - if (x + iconW > bounds.x) - x = bounds.x - rightChildIndent - gap; + int x = bounds.x - iconW - gap; icon.paintIcon(tree, g, x, bounds.y + bounds.height / 2 - icon.getIconHeight() / 2); } @@ -3529,22 +3304,15 @@ public class BasicTreeUI extends TreeUI * clipBounds, or insets. NOTE: parentRow can be -1 if the root is not * visible. * - * @param g - - * the graphics configuration + * @param g - the graphics configuration * @param clipBounds - * @param insets - - * @param bounds - - * bounds of the cell - * @param path - - * path to draw leg for - * @param row - - * row to start drawing at - * @param isExpanded - - * is the row expanded - * @param hasBeenExpanded - - * has the row already been expanded - * @param isLeaf - - * is the path a leaf + * @param bounds - bounds of the cell + * @param path - path to draw leg for + * @param row - row to start drawing at + * @param isExpanded - is the row expanded + * @param hasBeenExpanded - has the row already been expanded + * @param isLeaf - is the path a leaf */ protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds, @@ -3554,45 +3322,34 @@ public class BasicTreeUI extends TreeUI boolean isLeaf) { if (row != 0) - paintHorizontalLine(g, tree, bounds.y + bounds.height / 2, bounds.x - gap - - 2, bounds.x); + { + Icon icon = getCurrentControlIcon(path); + int iconW = icon.getIconWidth(); + paintHorizontalLine(g, tree, bounds.y + bounds.height / 2, + bounds.x - iconW/2 - gap, bounds.x - gap); + } } /** * Paints the vertical part of the leg. The receiver should NOT modify * clipBounds, insets. * - * @param g - - * the graphics configuration. + * @param g - the graphics configuration. * @param clipBounds - * @param insets - - * @param path - - * the path to draw the vertical part for. + * @param path - the path to draw the vertical part for. */ protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) { - int max = tree.getVisibleRowCount(); - for (int i = 0; i < max; i++) + Rectangle bounds = getPathBounds(tree, path); + TreePath parent = path.getParentPath(); + if (parent != null) { - Object curr = path.getPathComponent(i); - TreePath currPath = new TreePath(getPathToRoot(curr, 0)); - int numChild = treeModel.getChildCount(curr); - if (numChild > 0 && tree.isExpanded(currPath)) - { - Rectangle bounds = getPathBounds(tree, currPath); - Rectangle lastChildBounds = getPathBounds( - tree, - new TreePath( - getPathToRoot( - treeModel.getChild( - curr, - numChild - 1), - 0))); - paintVerticalLine(g, tree, bounds.x + gap + 2, bounds.y - + bounds.height - 2, - lastChildBounds.y + lastChildBounds.height / 2); - } + Rectangle parentBounds = getPathBounds(tree, parent); + paintVerticalLine(g, tree, parentBounds.x + 2* gap, + parentBounds.y + parentBounds.height / 2, + bounds.y + bounds.height / 2); } } @@ -3600,22 +3357,15 @@ public class BasicTreeUI extends TreeUI * Paints the renderer part of a row. The receiver should NOT modify * clipBounds, or insets. * - * @param g - - * the graphics configuration + * @param g - the graphics configuration * @param clipBounds - * @param insets - - * @param bounds - - * bounds of expand control - * @param path - - * path to draw control for - * @param row - - * row to draw control for - * @param isExpanded - - * is the row expanded - * @param hasBeenExpanded - - * has the row already been expanded - * @param isLeaf - - * is the path a leaf + * @param bounds - bounds of expand control + * @param path - path to draw control for + * @param row - row to draw control for + * @param isExpanded - is the row expanded + * @param hasBeenExpanded - has the row already been expanded + * @param isLeaf - is the path a leaf */ protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds, TreePath path, int row, @@ -3626,26 +3376,23 @@ public class BasicTreeUI extends TreeUI boolean hasIcons = false; Object node = path.getLastPathComponent(); - if (tree.isVisible(path)) - { - if (!validCachedPreferredSize) - updateCachedPreferredSize(); - - paintExpandControl(g, clipBounds, insets, bounds, path, row, - isExpanded, hasBeenExpanded, isLeaf); - - if (row != 0) - bounds.x += gap; - bounds.width = preferredSize.width + bounds.x; - TreeCellRenderer dtcr = tree.getCellRenderer(); - if (dtcr == null) - dtcr = createDefaultCellRenderer(); - - Component c = dtcr.getTreeCellRendererComponent(tree, node, selected, - isExpanded, isLeaf, - row, tree.hasFocus()); - rendererPane.paintComponent(g, c, c.getParent(), bounds); - } + paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded, + hasBeenExpanded, isLeaf); + + TreeCellRenderer dtcr = tree.getCellRenderer(); + if (dtcr == null) + dtcr = createDefaultCellRenderer(); + + boolean focused = false; + if (treeSelectionModel!= null) + focused = treeSelectionModel.getLeadSelectionRow() == row + && tree.isFocusOwner(); + + Component c = dtcr.getTreeCellRendererComponent(tree, node, selected, + isExpanded, isLeaf, row, + focused); + + rendererPane.paintComponent(g, c, c.getParent(), bounds); } /** @@ -3660,16 +3407,11 @@ public class BasicTreeUI extends TreeUI * Returns true if the expand (toggle) control should be drawn for the * specified row. * - * @param path - - * current path to check for. - * @param row - - * current row to check for. - * @param isExpanded - - * true if the path is expanded - * @param hasBeenExpanded - - * true if the path has been expanded already - * @param isLeaf - - * true if the row is a lead + * @param path - current path to check for. + * @param row - current row to check for. + * @param isExpanded - true if the path is expanded + * @param hasBeenExpanded - true if the path has been expanded already + * @param isLeaf - true if the row is a lead */ protected boolean shouldPaintExpandControl(TreePath path, int row, boolean isExpanded, @@ -3677,121 +3419,25 @@ public class BasicTreeUI extends TreeUI boolean isLeaf) { Object node = path.getLastPathComponent(); - return (!isLeaf && getLevel(node) != 0 && hasControlIcons()); + return (! isLeaf && hasControlIcons()); } /** - * Updates the cached current TreePath of all visible nodes in the tree. + * Finish the editing session. */ - void updateCurrentVisiblePath() - { - if (treeModel == null) - return; - - Object next = treeModel.getRoot(); - if (next == null) - return; - - TreePath rootPath = new TreePath(next); - Rectangle bounds = getPathBounds(tree, rootPath); - - // If root is not a valid size to be visible, or is - // not visible and the tree is expanded, then the next node acts - // as the root - if ((bounds.width == 0 && bounds.height == 0) - || (!isRootVisible() && tree.isExpanded(new TreePath(next)))) - { - next = getNextNode(next); - rootPath = new TreePath(next); - } - - Object root = next; - TreePath current = null; - while (next != null) - { - if (current == null) - current = rootPath; - else - current = current.pathByAddingChild(next); - - do - { - TreePath path = new TreePath(getPathToRoot(next, 0)); - if ((tree.isVisible(path) && tree.isExpanded(path)) - || treeModel.isLeaf(next)) - next = getNextNode(next); - else - { - Object pNext = next; - next = getNextSibling(pNext); - // if no next sibling, check parent's next sibling. - if (next == null) - { - Object parent = getParent(root, pNext); - while (next == null && parent != null) - { - next = getNextSibling(parent); - if (next == null) - parent = getParent(root, parent); - } - } - } - } - while (next != null - && !tree.isVisible(new TreePath(getPathToRoot(next, 0)))); - } - - currentVisiblePath = current; - tree.setVisibleRowCount(getRowCount(tree)); - - if (tree.getSelectionModel() != null && tree.getSelectionCount() == 0 - && currentVisiblePath != null) - selectPath( - tree, - new TreePath( - getPathToRoot( - currentVisiblePath.getPathComponent(0), - 0))); - } - - /** - * Get next visible node in the currentVisiblePath. Package private for use in - * inner classes. - * - * @param node - * current node - * @return the next visible node in the JTree. Return null if there are no - * more. - */ - Object getNextVisibleNode(Object node) - { - if (currentVisiblePath != null) - { - Object[] nodes = currentVisiblePath.getPath(); - int i = 0; - while (i < nodes.length && !node.equals(nodes[i])) - i++; - // return the next node - if (i + 1 < nodes.length) - return nodes[i + 1]; - } - return null; - } - - /** - * Finish the editing session. - */ void finish() { + treeState.invalidatePathBounds(treeState.getPathForRow(editingRow)); editingPath = null; - editingRow = -1; + editingRow = - 1; stopEditingInCompleteEditing = false; isEditing = false; + Rectangle bounds = editingComponent.getParent().getBounds(); tree.removeAll(); validCachedPreferredSize = false; - // Repaint the region, where was the editing component. - tree.repaint(editingComponent.getParent().getBounds()); + tree.repaint(bounds); editingComponent = null; + tree.requestFocus(); } } // BasicTreeUI diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java index 99c90acdbee..98a00ee0a0e 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java @@ -59,6 +59,7 @@ import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.border.AbstractBorder; import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; import javax.swing.plaf.BorderUIResource; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicBorders; @@ -138,24 +139,59 @@ public class MetalBorders if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) paintOceanButtonBorder(c, g, x, y, w, h); else - { - ButtonModel bmodel = null; - - if (c instanceof AbstractButton) - bmodel = ((AbstractButton) c).getModel(); + paintDefaultButtonBorder(c, g, x, y, w, h); + } - Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); - Color shadow = MetalLookAndFeel.getControlShadow(); - Color light = MetalLookAndFeel.getControlHighlight(); - Color middle = MetalLookAndFeel.getControl(); + /** + * Paints the button border for the DefaultMetalTheme. + * + * @param c the component (button) + * @param g the graphics object to use + * @param x the upper left corner of the component, X coordinate + * @param y the upper left corner of the component, Y coordinate + * @param w the width of the component + * @param h the height of the component + */ + private void paintDefaultButtonBorder(Component c, Graphics g, int x, + int y, int w, int h) + { + ButtonModel bmodel = null; - if (c.isEnabled()) - { - // draw dark border - g.setColor(darkShadow); - g.drawRect(x, y, w - 2, h - 2); + if (c instanceof AbstractButton) + bmodel = ((AbstractButton) c).getModel(); + + Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); + Color shadow = MetalLookAndFeel.getControlShadow(); + Color light = MetalLookAndFeel.getControlHighlight(); + Color middle = MetalLookAndFeel.getControl(); + + if (c.isEnabled()) + { + // draw dark border + g.setColor(darkShadow); + g.drawRect(x, y, w - 2, h - 2); - if (!bmodel.isPressed()) + // If the button is the default button, we paint a special border, + // regardless of the pressed state. + if (c instanceof JButton && ((JButton) c).isDefaultButton()) + { + g.drawRect(x + 1, y + 1, w - 4, h - 4); + // Draw white highlight. + g.setColor(light); + g.drawLine(x + 2, y + 2, x + w - 4, y + 2); + g.drawLine(x + 2, y + 2, x + 2, y + h - 4); + g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1); + g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 1); + // Draw crossing pixels. + g.setColor(middle); + g.fillRect(x + w - 2, y + 2, 1, 1); + g.fillRect(x + 2, y + h - 2, 1, 1); + } + else + { + // The normal border. This is used when the button is not + // pressed or the button is not armed. + if (! (bmodel.isPressed() && bmodel.isArmed()) ) { // draw light border g.setColor(light); @@ -166,6 +202,8 @@ public class MetalBorders g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); } + // The pressed border. This border is painted only when + // the button is both pressed and armed. else { // draw light border @@ -184,12 +222,12 @@ public class MetalBorders g.drawRect(x + w - 2, y + 1, 0, 0); } } - else - { - // draw disabled border - g.setColor(MetalLookAndFeel.getInactiveControlTextColor()); - g.drawRect(x, y, w - 2, h - 2); - } + } + else + { + // draw disabled border + g.setColor(MetalLookAndFeel.getInactiveControlTextColor()); + g.drawRect(x, y, w - 2, h - 2); } } @@ -218,11 +256,16 @@ public class MetalBorders if (c.isEnabled()) { - if (bmodel.isPressed()) + // Paint the pressed border if the button is pressed, or if + // the button is the default button. In the OceanTheme, the default + // button has the same border as a pressed button. + if (bmodel.isPressed() || ((c instanceof JButton) + && ((JButton) c).isDefaultButton())) { - // draw fat border - g.drawLine(x + 1, y + 1, x + w - 2, y + 1); - g.drawLine(x + 1, y + 1, x + 1, y + h - 2); + // Draw fat border. + g.setColor(darkShadow); + g.drawRect(x, y, w - 1, h - 1); + g.drawRect(x + 1, y + 1, w - 3, h - 3); } else if (bmodel.isRollover()) { @@ -1025,14 +1068,10 @@ public class MetalBorders public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { - boolean mouseIsOver = false; - if (c instanceof AbstractButton) - { - ButtonModel bmodel = ((AbstractButton) c).getModel(); - mouseIsOver = bmodel.isRollover(); - } - if (mouseIsOver) - super.paintBorder(c, g, x, y, w, h); + // TODO: What should be done here? Obviously the ButtonBorder already + // handles the rollover state in Sun's impl. Maybe this is only there + // for backwards compatibility. + super.paintBorder(c, g, x, y, w, h); } } @@ -1520,8 +1559,7 @@ public class MetalBorders { Border outer = new ButtonBorder(); Border inner = new RolloverMarginBorder(); - toolbarButtonBorder = new BorderUIResource.CompoundBorderUIResource - (outer, inner); + toolbarButtonBorder = new CompoundBorder(outer, inner); } return toolbarButtonBorder; } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java b/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java index e6fb22e929f..f2f778f95a7 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java @@ -41,7 +41,6 @@ package javax.swing.plaf.metal; import java.beans.PropertyChangeEvent; import javax.swing.AbstractButton; -import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicButtonListener; /** @@ -70,17 +69,6 @@ class MetalButtonListener extends BasicButtonListener public void propertyChange(PropertyChangeEvent e) { super.propertyChange(e); - if (e.getPropertyName().equals( - AbstractButton.ROLLOVER_ENABLED_CHANGED_PROPERTY)) - { - AbstractButton b = (AbstractButton) e.getSource(); - if (b.getBorder() instanceof UIResource) - { - if (Boolean.TRUE.equals(e.getNewValue())) - b.setBorder(MetalBorders.getRolloverBorder()); - else if (Boolean.FALSE.equals(e.getNewValue())) - b.setBorder(MetalBorders.getButtonBorder()); - } - } + // TODO: What should be done here? } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java index 10e51117329..83cd3366215 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java @@ -45,6 +45,7 @@ import java.awt.Graphics; import java.awt.Rectangle; import javax.swing.AbstractButton; +import javax.swing.ButtonModel; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.SwingConstants; @@ -160,8 +161,8 @@ public class MetalButtonUI } /** - * Paints the background of the button to indicate that it is in the "pressed" - * state. + * Paints the background of the button to indicate that it is in the + * "pressed" state. * * @param g the graphics context. * @param b the button. @@ -234,8 +235,12 @@ public class MetalButtonUI public void update(Graphics g, JComponent c) { AbstractButton b = (AbstractButton) c; - if (b.isOpaque() && UIManager.get(getPropertyPrefix() + "gradient") != null - && !b.getModel().isPressed() && b.isEnabled()) + ButtonModel m = b.getModel(); + if (b.isContentAreaFilled() + && (UIManager.get(getPropertyPrefix() + "gradient") != null) + && ! m.isPressed() && ! m.isArmed() + && b.isEnabled() + && (b.getBackground() instanceof UIResource)) { MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(), SwingConstants.VERTICAL, diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java index 6993e18e9b9..3787a98c3a9 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java @@ -38,22 +38,25 @@ exception statement from your version. */ package javax.swing.plaf.metal; +import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Insets; -import java.awt.Rectangle; import javax.swing.CellRendererPane; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JList; -import javax.swing.SwingUtilities; +import javax.swing.ListCellRenderer; +import javax.swing.UIManager; /** * A button used by the {@link MetalComboBoxUI} class. */ -public class MetalComboBoxButton extends JButton { +public class MetalComboBoxButton + extends JButton +{ /** A reference to the JComboBox that the button belongs to. */ protected JComboBox comboBox; @@ -61,7 +64,9 @@ public class MetalComboBoxButton extends JButton { /** A reference to the JList. */ protected JList listBox; - /** ??? */ + /** + * Used for rendering the selected item. + */ protected CellRendererPane rendererPane; /** The button icon. */ @@ -91,7 +96,7 @@ public class MetalComboBoxButton extends JButton { * @param cb the combo that the button is used for (<code>null</code> not * permitted). * @param i the icon displayed on the button. - * @parma onlyIcon a flag that specifies whether the button displays only an + * @param onlyIcon a flag that specifies whether the button displays only an * icon, or text as well. * @param pane the rendering pane. * @param list the list. @@ -107,6 +112,9 @@ public class MetalComboBoxButton extends JButton { iconOnly = onlyIcon; listBox = list; rendererPane = pane; + setRolloverEnabled(false); + setEnabled(comboBox.isEnabled()); + setFocusable(comboBox.isEnabled()); } /** @@ -191,8 +199,16 @@ public class MetalComboBoxButton extends JButton { public void setEnabled(boolean enabled) { super.setEnabled(enabled); - // TODO: figure out what this might need to be used for - // perhaps it has something to do with the button's icon and/or border? + if (enabled) + { + setBackground(comboBox.getBackground()); + setForeground(comboBox.getForeground()); + } + else + { + setBackground(UIManager.getColor("ComboBox.disabledBackground")); + setForeground(UIManager.getColor("ComboBox.disabledForeground")); + } } /** @@ -203,39 +219,75 @@ public class MetalComboBoxButton extends JButton { public void paintComponent(Graphics g) { super.paintComponent(g); - if (iconOnly) - { - Rectangle bounds = getBounds(); - int x = (bounds.width - comboIcon.getIconWidth()) / 2; - int y = (bounds.height - comboIcon.getIconHeight()) / 2; - comboIcon.paintIcon(comboBox, g, x, y); - } - else + Insets insets = this.getInsets(); + int w = getWidth() - (insets.left + insets.right); + int h = getHeight() - (insets.top + insets.bottom); + if (h > 0 && w > 0) { - Object selected = comboBox.getModel().getSelectedItem(); - if (selected == null) - selected = ""; - Rectangle bounds = comboBox.getBounds(); - Rectangle innerArea = SwingUtilities.calculateInnerArea(this, null); - Insets insets = comboBox.getInsets(); - Rectangle renderArea = new Rectangle(innerArea.x, innerArea.y, - innerArea.width - comboIcon.getIconWidth() - 4, innerArea.height); - Component cellRenderer - = comboBox.getRenderer().getListCellRendererComponent(this.listBox, - selected, comboBox.getSelectedIndex(), false, false); - cellRenderer.setBackground(comboBox.getBackground()); - cellRenderer.setEnabled(comboBox.isEnabled()); - rendererPane.paintComponent(g, cellRenderer, this, renderArea); - if (comboBox.hasFocus()) + int x1 = insets.left; + int y1 = insets.top; + int x2 = x1 + (w - 1); + int y2 = y1 + (h - 1); + int iconWidth = 0; + int iconX = x2; + if (comboIcon != null) + { + iconWidth = comboIcon.getIconWidth(); + int iconHeight = comboIcon.getIconHeight(); + int iconY; + if (iconOnly) + { + iconX = getWidth() / 2 - iconWidth / 2; + iconY = getHeight() / 2 - iconHeight / 2; + } + else + { + iconX = x1 + (w - 1) - iconWidth; + iconY = y1 + (y2 - y1) / 2 - iconHeight / 2; + } + comboIcon.paintIcon(this, g, iconX, iconY); + if (this.hasFocus()) + { + g.setColor(MetalLookAndFeel.getFocusColor()); + g.drawRect(x1 - 1, y1 - 1, w + 3, h + 1); + } + } + if (! iconOnly && comboBox != null) { - g.setColor(MetalLookAndFeel.getFocusColor()); - g.drawRect(innerArea.x, innerArea.y - 1, innerArea.width - 1, - innerArea.height); + ListCellRenderer renderer = comboBox.getRenderer(); + boolean pressed = this.getModel().isPressed(); + Component comp= renderer.getListCellRendererComponent(listBox, + comboBox.getSelectedItem(), + -1, false, false); + comp.setFont(rendererPane.getFont()); + if (model.isArmed() && model.isPressed()) + { + if (isOpaque()) + { + comp.setBackground(UIManager.getColor("Button.select")); + comp.setForeground(comboBox.getForeground()); + } + } + else if (! comboBox.isEnabled()) + { + if (this.isOpaque()) + { + Color dbg = + UIManager.getColor("ComboBox.disabledBackground"); + comp.setBackground(dbg); + Color dfg = + UIManager.getColor("ComboBox.disabledForeground"); + comp.setForeground(dfg); + } + } + else + { + comp.setForeground(comboBox.getForeground()); + comp.setBackground(comboBox.getBackground()); + } + int wr = w - (insets.right + iconWidth); + rendererPane.paintComponent(g, comp, this, x1, y1, wr, h); } - int iconX = bounds.width - insets.right - comboIcon.getIconWidth() - 7; - int iconY = insets.top - + (bounds.height - comboIcon.getIconHeight()) / 2; - comboIcon.paintIcon(comboBox, g, iconX, iconY); } } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java index a531079cb1d..11e41510377 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java @@ -38,15 +38,15 @@ exception statement from your version. */ package javax.swing.plaf.metal; -import java.awt.Color; import java.awt.Component; +import java.awt.Dimension; import java.awt.Graphics; import java.awt.Insets; import javax.swing.JTextField; +import javax.swing.border.AbstractBorder; import javax.swing.plaf.basic.BasicComboBoxEditor; import javax.swing.plaf.metal.MetalLookAndFeel; -import javax.swing.plaf.metal.MetalBorders.Flush3DBorder; /** * An editor used by the {@link MetalComboBoxUI} class. @@ -56,7 +56,7 @@ public class MetalComboBoxEditor extends BasicComboBoxEditor /** * A border used for the {@link JTextField} component. */ - static class MetalComboBoxEditorBorder extends Flush3DBorder + static class MetalComboBoxEditorBorder extends AbstractBorder { /** * Creates a new border instance. @@ -78,20 +78,34 @@ public class MetalComboBoxEditor extends BasicComboBoxEditor */ public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) - { - Color savedColor = g.getColor(); - if (c.isEnabled()) - g.setColor(MetalLookAndFeel.getControlDarkShadow()); + { + g.translate(x, y); + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, w - 1, 0); + g.drawLine(0, 0, 0, h - 1); + g.drawLine(0, h - 1, w - 1, h - 1); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(1, 1, w - 2, 1); + g.drawLine(1, 1, 1, h - 2); + g.drawLine(1, h - 2, w - 1, h - 2); + g.drawLine(w - 1, 1, w - 1, h - 2); + } else - g.setColor(MetalLookAndFeel.getControlShadow()); - g.drawLine(x, y, x + w - 1, y); - g.drawLine(x, y, x, y + h - 2); - g.drawLine(x + 2, y + h - 2, x + w - 1, y + h - 2); - g.setColor(MetalLookAndFeel.getControl()); - g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); - g.setColor(MetalLookAndFeel.getWhite()); - g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); - g.setColor(savedColor); + { + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + g.drawLine(0, 0, w - 1, 0); + g.drawLine(0, 0, 0, h - 2); + g.drawLine(0, h - 2, w - 1, h - 2); + g.setColor(MetalLookAndFeel.getControlHighlight()); + g.drawLine(1, 1, w - 1, 1); + g.drawLine(1, 1, 1, h - 1); + g.drawLine(1, h - 1, w - 1, h - 1); + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(1, h - 2, 1, h - 2); + } + g.translate(-x, -y); } /** @@ -127,16 +141,49 @@ public class MetalComboBoxEditor extends BasicComboBoxEditor // Nothing to do here. } } - + + /** + * A special textfield implementation for the MetalComboBoxEditor. + */ + private class EditorTextField extends JTextField + { + EditorTextField(String s, int columns) + { + super(s, columns); + } + + /** + * Tests seem to show that the textfield in MetalComboBoxEditors have + * a height + 4. + */ + public Dimension getPreferredSize() + { + Dimension size = super.getPreferredSize(); + size.height += 4; + return size; + } + + /** + * Tests seem to show that the textfield in MetalComboBoxEditors have + * a height + 4. + */ + public Dimension getMinimumSize() + { + Dimension size = super.getMinimumSize(); + size.height += 4; + return size; + } + } + /** The editor's border insets. */ - protected static Insets editorBorderInsets = new Insets(4, 2, 4, 0); + protected static Insets editorBorderInsets = new Insets(2, 2, 2, 0); /** * Creates a new editor. */ public MetalComboBoxEditor() { - super(); + editor = new EditorTextField("", 9); editor.setBorder(new MetalComboBoxEditorBorder()); } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java index 0006b78fee3..c24c0850560 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java @@ -38,12 +38,12 @@ exception statement from your version. */ package javax.swing.plaf.metal; +import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Insets; import java.awt.LayoutManager; -import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -88,14 +88,7 @@ public class MetalComboBoxUI extends BasicComboBoxUI */ public void layoutContainer(Container parent) { - JComboBox cb = (JComboBox) parent; - if (!cb.isEditable()) - { - Rectangle bounds = parent.getBounds(); - arrowButton.setBounds(0, 0, bounds.width, bounds.height); - } - else - superLayout(parent); + layoutComboBox(parent, this); } /** @@ -134,9 +127,31 @@ public class MetalComboBoxUI extends BasicComboBoxUI */ public void propertyChange(PropertyChangeEvent e) { - if (e.getPropertyName().equals("editable")) - editablePropertyChanged(e); super.propertyChange(e); + String name = e.getPropertyName(); + if (name.equals("editable")) + editablePropertyChanged(e); + else if (name.equals("enabled")) + { + if (arrowButton instanceof MetalComboBoxButton) + { + arrowButton.setFocusable(!comboBox.isEditable() + && comboBox.isEnabled()); + comboBox.repaint(); + } + } + else if (name.equals("background")) + { + Color c = (Color) e.getNewValue(); + arrowButton.setBackground(c); + listBox.setBackground(c); + } + else if (name.equals("foreground")) + { + Color c = (Color) e.getNewValue(); + arrowButton.setForeground(c); + listBox.setForeground(c); + } } } @@ -247,22 +262,8 @@ public class MetalComboBoxUI extends BasicComboBoxUI { MetalComboBoxButton b = (MetalComboBoxButton) arrowButton; b.setIconOnly(comboBox.isEditable()); - } - if (comboBox.isEditable()) - { - arrowButton.setText(null); - if (editor != null) - editor.setVisible(true); - } - else - { - String text = ""; - Object selected = comboBox.getSelectedItem(); - if (selected != null) - text = selected.toString(); - arrowButton.setText(text); - if (editor != null) - editor.setVisible(true); + b.setFocusable(!comboBox.isEditable() && comboBox.isEnabled()); + comboBox.repaint(); } } @@ -295,22 +296,39 @@ public class MetalComboBoxUI extends BasicComboBoxUI */ public Dimension getMinimumSize(JComponent c) { - Dimension d = getDisplaySize(); - MetalComboBoxButton b = (MetalComboBoxButton) arrowButton; - Insets insets = b.getInsets(); - int insetsH = insets.top + insets.bottom; - int insetsW = insets.left + insets.right; - if (!comboBox.isEditable()) + if (!isMinimumSizeDirty) + return new Dimension(cachedMinimumSize); + + Dimension d; + if (!comboBox.isEditable() && arrowButton != null + && arrowButton instanceof MetalComboBoxButton) { + MetalComboBoxButton b = (MetalComboBoxButton) arrowButton; + d = getDisplaySize(); + Insets insets = b.getInsets(); + Insets arrowInsets = b.getInsets(); + Insets comboInsets = comboBox.getInsets(); Icon icon = b.getComboIcon(); - int iconWidth = icon.getIconWidth() + 6; - return new Dimension(d.width + insetsW + iconWidth, d.height + insetsH); + d.width += comboInsets.left + comboInsets.right; + d.width += arrowInsets.left + arrowInsets.right; + d.width += arrowInsets.right + icon.getIconWidth(); + d.height += comboInsets.top + comboInsets.bottom; + d.height += arrowInsets.top + arrowInsets.bottom; + } + else if (comboBox.isEditable() && arrowButton != null && editor != null) + { + d = super.getMinimumSize(c); + Insets arrowMargin = arrowButton.getMargin(); + d.height += arrowMargin.top + arrowMargin.bottom; + d.width += arrowMargin.left + arrowMargin.right; } else - // FIXME: the following dimensions pass most of the Mauve tests, but - // I don't yet understand the logic behind this...it is probably wrong - return new Dimension(d.width + insetsW + (d.height + insetsH) - 4, - d.height + insetsH + 1); + { + d = super.getMinimumSize(c); + } + cachedMinimumSize.setSize(d.width, d.height); + isMinimumSizeDirty = false; + return new Dimension(cachedMinimumSize); } /** @@ -318,27 +336,21 @@ public class MetalComboBoxUI extends BasicComboBoxUI */ public void configureEditor() { - ComboBoxEditor cbe = comboBox.getEditor(); - if (cbe != null) - { - cbe.getEditorComponent().setFont(comboBox.getFont()); - cbe.setItem(comboBox.getSelectedItem()); - cbe.addActionListener(comboBox); - } + super.configureEditor(); + if (popupKeyListener != null) + editor.removeKeyListener(popupKeyListener); + if (focusListener != null) + editor.addFocusListener(focusListener); } - + /** * Unconfigures the editor for this combo box. */ public void unconfigureEditor() { - ComboBoxEditor cbe = comboBox.getEditor(); - if (cbe != null) - { - cbe.getEditorComponent().setFont(null); - cbe.setItem(null); - cbe.removeActionListener(comboBox); - } + super.unconfigureEditor(); + if (focusListener != null) + editor.removeFocusListener(focusListener); } /** @@ -347,6 +359,16 @@ public class MetalComboBoxUI extends BasicComboBoxUI public void layoutComboBox(Container parent, MetalComboBoxUI.MetalComboBoxLayoutManager manager) { - manager.layoutContainer(parent); + if (comboBox.isEditable()) + manager.superLayout(parent); + else if (arrowButton != null) + { + Insets comboInsets = comboBox.getInsets(); + int width = comboBox.getWidth(); + int height = comboBox.getHeight(); + arrowButton.setBounds(comboInsets.left, comboInsets.top, + width - (comboInsets.left + comboInsets.right), + height - (comboInsets.top + comboInsets.bottom)); + } } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java index ecbb76e6e7a..0c1163a8e29 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java @@ -1,5 +1,5 @@ /* MetalDesktopIconUI.java - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -50,10 +50,6 @@ public class MetalDesktopIconUI extends BasicDesktopIconUI { - // FIXME: maybe replace by a Map of instances when this becomes stateful - /** The shared UI instance for MetalDesktopIcons */ - private static MetalDesktopIconUI instance = null; - /** * Constructs a new instance of <code>MetalDesktopIconUI</code>. */ @@ -63,16 +59,14 @@ public class MetalDesktopIconUI } /** - * Returns a shared instance of <code>MetalDesktopIconUI</code>. + * Returns a new <code>MetalDesktopIconUI</code> instance. * - * @param component the component for which we return an UI instance + * @param component the component (ignored). * - * @return A shared instance of <code>MetalDesktopIconUI</code>. + * @return A new <code>MetalDesktopIconUI</code> instance. */ public static ComponentUI createUI(JComponent component) { - if (instance == null) - instance = new MetalDesktopIconUI(); - return instance; + return new MetalDesktopIconUI(); } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java b/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java index 0b644f30037..d24a0526232 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java @@ -756,6 +756,17 @@ public class MetalIconFactory implements Serializable { /** + * This is used as a mask when painting the gradient. See + * {@link MetalUtils#paintGradient(java.awt.Graphics, int, int, int, int, + * float, float, java.awt.Color, java.awt.Color, java.awt.Color, int, + * int[][])} for details. + */ + private static int[][] gradientMask = new int[][] {{3, 7}, {1, 9}, {1, 9}, + {0, 10}, {0, 10}, {0, 10}, + {0, 10}, {1, 9}, {1, 9}, + {3, 7}}; + + /** * Returns the width of the icon in pixels. * * @return the width of the icon in pixels @@ -788,12 +799,13 @@ public class MetalIconFactory implements Serializable public void paintIcon(Component c, Graphics g, int x, int y) { if (UIManager.get("RadioButton.gradient") != null) - MetalUtils.paintGradient(g, x, y, getIconWidth(), getIconHeight(), - SwingConstants.VERTICAL, "RadioButton.gradient"); + MetalUtils.paintGradient(g, x + 2, y + 2, 8, 8, + SwingConstants.VERTICAL, "RadioButton.gradient", + gradientMask); Color savedColor = g.getColor(); JRadioButton b = (JRadioButton) c; - + // draw outer circle if (b.isEnabled()) g.setColor(MetalLookAndFeel.getControlDarkShadow()); @@ -951,6 +963,14 @@ public class MetalIconFactory implements Serializable { /** + * This mask is used to paint the gradient in the shape of the thumb. + */ + int[][] gradientMask = new int[][] { {0, 12}, {0, 12}, {0, 12}, {0, 12}, + {0, 12}, {0, 12}, {0, 12}, {1, 12}, + {2, 10}, {3, 9}, {4, 8}, {5, 7}, + {6, 6}}; + + /** * Creates a new instance. */ public HorizontalSliderThumbIcon() @@ -1008,21 +1028,37 @@ public class MetalIconFactory implements Serializable g.drawLine(x + 6, y + 14, x, y + 8); g.drawLine(x, y + 7, x, y + 1); - // fill the icon - if (focus) - g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + // Fill the icon. + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme + && enabled) + { + String gradient; + if (focus) + gradient = "Slider.focusGradient"; + else + gradient = "Slider.gradient"; + MetalUtils.paintGradient(g, x + 1, y + 2, 12, 13, + SwingConstants.VERTICAL, gradient, + gradientMask); + } else - g.setColor(MetalLookAndFeel.getControl()); - g.fillRect(x + 1, y + 2, 13, 7); - g.drawLine(x + 2, y + 9, x + 12, y + 9); - g.drawLine(x + 3, y + 10, x + 11, y + 10); - g.drawLine(x + 4, y + 11, x + 10, y + 11); - g.drawLine(x + 5, y + 12, x + 9, y + 12); - g.drawLine(x + 6, y + 13, x + 8, y + 13); - g.drawLine(x + 7, y + 14, x + 7, y + 14); - - // if the slider is enabled, draw dots and highlights - if (c.isEnabled()) + { + if (focus) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x + 1, y + 2, 13, 7); + g.drawLine(x + 2, y + 9, x + 12, y + 9); + g.drawLine(x + 3, y + 10, x + 11, y + 10); + g.drawLine(x + 4, y + 11, x + 10, y + 11); + g.drawLine(x + 5, y + 12, x + 9, y + 12); + g.drawLine(x + 6, y + 13, x + 8, y + 13); + g.drawLine(x + 7, y + 14, x + 7, y + 14); + } + + // If the slider is enabled, draw dots and highlights. + if (c.isEnabled() + && !(MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)) { if (focus) g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); @@ -1039,7 +1075,7 @@ public class MetalIconFactory implements Serializable g.drawLine(x + 7, y + 7, x + 7, y + 7); g.drawLine(x + 11, y + 7, x + 11, y + 7); - // draw highlights + // Draw highlights if (focus) g.setColor(MetalLookAndFeel.getPrimaryControl()); else @@ -1583,6 +1619,14 @@ public class MetalIconFactory implements Serializable private static class VerticalSliderThumbIcon implements Icon, Serializable { /** + * This mask is used to paint the gradient in the shape of the thumb. + */ + int[][] gradientMask = new int[][] { {0, 12}, {0, 12}, {0, 12}, {0, 12}, + {0, 12}, {0, 12}, {0, 12}, {1, 12}, + {2, 10}, {3, 9}, {4, 8}, {5, 7}, + {6, 6}}; + + /** * Creates a new instance. */ public VerticalSliderThumbIcon() @@ -1641,21 +1685,37 @@ public class MetalIconFactory implements Serializable g.drawLine(x + 8, y + 14, x + 1, y + 14); g.drawLine(x, y + 13, x, y + 1); - // fill the icon - if (focus) - g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + // Fill the icon. + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme + && enabled) + { + String gradient; + if (focus) + gradient = "Slider.focusGradient"; + else + gradient = "Slider.gradient"; + MetalUtils.paintGradient(g, x + 2, y + 1, 13, 12, + SwingConstants.HORIZONTAL, gradient, + gradientMask); + } else - g.setColor(MetalLookAndFeel.getControl()); - g.fillRect(x + 2, y + 1, 7, 13); - g.drawLine(x + 9, y + 2, x + 9, y + 12); - g.drawLine(x + 10, y + 3, x + 10, y + 11); - g.drawLine(x + 11, y + 4, x + 11, y + 10); - g.drawLine(x + 12, y + 5, x + 12, y + 9); - g.drawLine(x + 13, y + 6, x + 13, y + 8); - g.drawLine(x + 14, y + 7, x + 14, y + 7); - + { + if (focus) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x + 2, y + 1, 7, 13); + g.drawLine(x + 9, y + 2, x + 9, y + 12); + g.drawLine(x + 10, y + 3, x + 10, y + 11); + g.drawLine(x + 11, y + 4, x + 11, y + 10); + g.drawLine(x + 12, y + 5, x + 12, y + 9); + g.drawLine(x + 13, y + 6, x + 13, y + 8); + g.drawLine(x + 14, y + 7, x + 14, y + 7); + } + // if the slider is enabled, draw dots and highlights - if (enabled) + if (enabled + && ! (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)) { if (focus) g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java b/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java index 2cf5f67d55d..f74828e566e 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java @@ -93,7 +93,11 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane public void propertyChange(PropertyChangeEvent e) { String propName = e.getPropertyName(); - if (propName.equals("JInternalFrame.isPalette")) + if (e.getPropertyName().equals(JInternalFrame.FRAME_ICON_PROPERTY)) + { + title.setIcon( frame.getFrameIcon() ); + } + else if (propName.equals("JInternalFrame.isPalette")) { if (e.getNewValue().equals(Boolean.TRUE)) setPalette(true); @@ -262,7 +266,7 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane paletteTitleHeight = UIManager.getInt("InternalFrame.paletteTitleHeight"); paletteCloseIcon = UIManager.getIcon("InternalFrame.paletteCloseIcon"); minIcon = MetalIconFactory.getInternalFrameAltMaximizeIcon(16); - + title = new JLabel(frame.getTitle(), MetalIconFactory.getInternalFrameDefaultMenuIcon(), SwingConstants.LEFT); @@ -329,9 +333,10 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane } /** - * Creates a new instance of {@link MetalTitlePaneLayout}. + * Creates a new instance of <code>MetalTitlePaneLayout</code> (not part of + * the public API). * - * @return A new instance of {@link MetalTitlePaneLayout}. + * @return A new instance of <code>MetalTitlePaneLayout</code>. */ protected LayoutManager createLayout() { @@ -382,8 +387,8 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane paintPalette(g); else { - paintTitleBackground(g); - paintChildren(g); + paintTitleBackground(g); + paintChildren(g); Dimension d = getSize(); if (frame.isSelected()) g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java index e84644615ce..7a973d46eef 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -1,5 +1,5 @@ /* MetalLookAndFeel.java - Copyright (C) 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -90,7 +90,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel protected void createDefaultTheme() { if (theme == null) - setCurrentTheme(new DefaultMetalTheme()); + setCurrentTheme(new OceanTheme()); } /** @@ -899,7 +899,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel "CheckBoxMenuItem.acceleratorForeground", getAcceleratorForeground(), "CheckBoxMenuItem.acceleratorSelectionForeground", getAcceleratorSelectedForeground(), "CheckBoxMenuItem.background", getMenuBackground(), - "CheckBoxMenuItem.borderPainted", new Boolean(true), + "CheckBoxMenuItem.borderPainted", Boolean.TRUE, "CheckBoxMenuItem.commandSound", "sounds/MenuItemCommand.wav", "CheckBoxMenuItem.checkIcon", MetalIconFactory.getCheckBoxMenuItemIcon(), "CheckBoxMenuItem.disabledForeground", getMenuDisabledForeground(), @@ -1204,7 +1204,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel "Table.focusCellForeground", getControlTextColor(), "Table.foreground", getControlTextColor(), "Table.focusCellHighlightBorder", - new BorderUIResource.LineBorderUIResource(getControlShadow()), + new BorderUIResource.LineBorderUIResource(getFocusColor()), "Table.focusCellBackground", getWindowBackground(), "Table.gridColor", getControlDarkShadow(), "Table.selectionBackground", new ColorUIResource(204, 204, 255), diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java index 23051e9bcea..6cabc7e8691 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java @@ -47,11 +47,11 @@ import java.awt.Graphics; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.LayoutManager2; +import java.awt.Point; import java.awt.Rectangle; import java.awt.Window; import java.awt.event.ActionEvent; -import java.awt.event.WindowEvent; -import java.awt.event.WindowFocusListener; +import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import javax.swing.AbstractAction; @@ -70,6 +70,7 @@ import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.AbstractBorder; +import javax.swing.event.MouseInputAdapter; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicRootPaneUI; @@ -191,6 +192,50 @@ public class MetalRootPaneUI */ private static class MetalTitlePane extends JComponent { + + /** + * Handles dragging of the title pane and moves the window accordingly. + */ + private class MouseHandler + extends MouseInputAdapter + { + /** + * The point where the dragging started. + */ + Point lastDragLocation; + + /** + * Receives notification when the mouse gets pressed on the title pane. + * This updates the lastDragLocation. + * + * @param ev the mouse event + */ + public void mousePressed(MouseEvent ev) + { + lastDragLocation = ev.getPoint(); + } + + /** + * Receives notification when the mouse is dragged on the title pane. + * This will move the nearest window accordingly. + * + * @param ev the mouse event + */ + public void mouseDragged(MouseEvent ev) + { + Point dragLocation = ev.getPoint(); + int deltaX = dragLocation.x - lastDragLocation.x; + int deltaY = dragLocation.y - lastDragLocation.y; + Window window = SwingUtilities.getWindowAncestor(rootPane); + Point loc = window.getLocation(); + window.setLocation(loc.x + deltaX, loc.y + deltaY); + // Note that we do not update the lastDragLocation. This is because + // we move the underlying window while dragging the component, which + // results in having the same lastDragLocation under the mouse while + // dragging. + } + } + /** * The Action responsible for closing the JInternalFrame. */ @@ -255,6 +300,45 @@ public class MetalRootPaneUI } /** + * This action is performed when the iconify button is pressed. + */ + private class IconifyAction + extends AbstractAction + { + + public void actionPerformed(ActionEvent event) + { + Window w = SwingUtilities.getWindowAncestor(rootPane); + if (w instanceof Frame) + { + Frame f = (Frame) w; + int state = f.getExtendedState(); + f.setExtendedState(Frame.ICONIFIED); + } + } + + } + + /** + * This action is performed when the maximize button is pressed. + */ + private class MaximizeAction + extends AbstractAction + { + + public void actionPerformed(ActionEvent event) + { + Window w = SwingUtilities.getWindowAncestor(rootPane); + if (w instanceof Frame) + { + Frame f = (Frame) w; + int state = f.getExtendedState(); + f.setExtendedState(Frame.MAXIMIZED_BOTH); + } + } + } + + /** * This helper class is used to create the minimize, maximize and close * buttons in the top right corner of the Title Pane. These buttons are * special since they cannot be given focus and have no border. @@ -499,23 +583,16 @@ public class MetalRootPaneUI private void installListeners() { - Window window = SwingUtilities.getWindowAncestor(rootPane); - window.addWindowFocusListener(new WindowFocusListener() - { - public void windowGainedFocus(WindowEvent ev) - { - repaint(); - } - public void windowLostFocus(WindowEvent ev) - { - repaint(); - } - }); + MouseInputAdapter mouseHandler = new MouseHandler(); + addMouseListener(mouseHandler); + addMouseMotionListener(mouseHandler); } private void createActions() { closeAction = new CloseAction(); + iconifyAction = new IconifyAction(); + maximizeAction = new MaximizeAction(); } private void assembleSystemMenu() @@ -699,6 +776,21 @@ public class MetalRootPaneUI */ private Dimension prefSize; + /** + * The title pane for l&f decorated frames. + */ + private MetalTitlePane titlePane; + + /** + * Creates a new MetalRootLayout. + * + * @param tp the title pane + */ + MetalRootLayout(MetalTitlePane tp) + { + titlePane = tp; + } + public void addLayoutComponent(Component component, Object constraints) { // Nothing to do here. @@ -747,12 +839,8 @@ public class MetalRootPaneUI { JRootPane rp = (JRootPane) parent; JLayeredPane layeredPane = rp.getLayeredPane(); - Component contentPane = layeredPane.getComponent(0); - Component titlePane = layeredPane.getComponent(1); - Component menuBar = null; - if (layeredPane.getComponentCount() > 2 - && layeredPane.getComponent(2) instanceof JMenuBar) - menuBar = layeredPane.getComponent(2); + Component contentPane = rp.getContentPane(); + Component menuBar = rp.getJMenuBar(); // We must synchronize here, otherwise we cannot guarantee that the // prefSize is still non-null when returning. @@ -789,12 +877,8 @@ public class MetalRootPaneUI { JRootPane rp = (JRootPane) parent; JLayeredPane layeredPane = rp.getLayeredPane(); - Component contentPane = layeredPane.getComponent(0); - Component titlePane = layeredPane.getComponent(1); - Component menuBar = null; - if (layeredPane.getComponentCount() > 2 - && layeredPane.getComponent(2) instanceof JMenuBar) - menuBar = layeredPane.getComponent(2); + Component contentPane = rp.getContentPane(); + Component menuBar = rp.getJMenuBar(); Component glassPane = rp.getGlassPane(); if (glassPaneBounds == null || layeredPaneBounds == null @@ -937,6 +1021,7 @@ public class MetalRootPaneUI */ public void propertyChange(PropertyChangeEvent ev) { + super.propertyChange(ev); String propertyName = ev.getPropertyName(); if (propertyName.equals("windowDecorationStyle")) { @@ -958,12 +1043,14 @@ public class MetalRootPaneUI private void installWindowDecorations(JRootPane rp) { rp.setBorder(new MetalFrameBorder()); - rp.setLayout(new MetalRootLayout()); + MetalTitlePane titlePane = new MetalTitlePane(rp); + rp.setLayout(new MetalRootLayout(titlePane)); // We should have a contentPane already. - assert rp.getLayeredPane().getComponentCount() == 1 + assert rp.getLayeredPane().getComponentCount() > 0 : "We should have a contentPane already"; - rp.getLayeredPane().add(new MetalTitlePane(rp), - JLayeredPane.FRAME_CONTENT_LAYER); + + rp.getLayeredPane().add(titlePane, + JLayeredPane.FRAME_CONTENT_LAYER, 1); } /** @@ -975,6 +1062,14 @@ public class MetalRootPaneUI private void uninstallWindowDecorations(JRootPane rp) { rp.setBorder(null); - rp.getLayeredPane().remove(1); + JLayeredPane lp = rp.getLayeredPane(); + for (int i = lp.getComponentCount() - 1; i >= 0; --i) + { + if (lp.getComponent(i) instanceof MetalTitlePane) + { + lp.remove(i); + break; + } + } } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java index 155bb814689..c7dfd11e48c 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java @@ -349,10 +349,15 @@ public class MetalScrollBarUI extends BasicScrollBarUI else paintThumbVertical(g, c, thumbBounds); - // draw the pattern - MetalUtils.fillMetalPattern(c, g, thumbBounds.x + 3, thumbBounds.y + 3, - thumbBounds.width - 6, thumbBounds.height - 6, - thumbHighlightColor, thumbLightShadowColor); + // Draw the pattern when the theme is not Ocean. + if (! (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)) + { + MetalUtils.fillMetalPattern(c, g, thumbBounds.x + 3, thumbBounds.y + 3, + thumbBounds.width - 6, + thumbBounds.height - 6, + thumbHighlightColor, + thumbLightShadowColor); + } } /** @@ -370,13 +375,24 @@ public class MetalScrollBarUI extends BasicScrollBarUI int w = thumbBounds.width; int h = thumbBounds.height; - // first we fill the background - g.setColor(thumbColor); - if (isFreeStanding) - g.fillRect(x, y, w, h - 1); + // First we fill the background. + MetalTheme theme = MetalLookAndFeel.getCurrentTheme(); + if (theme instanceof OceanTheme + && UIManager.get("ScrollBar.gradient") != null) + { + MetalUtils.paintGradient(g, x + 2, y + 2, w - 4, h - 2, + SwingConstants.VERTICAL, + "ScrollBar.gradient"); + } else - g.fillRect(x, y, w, h); - + { + g.setColor(thumbColor); + if (isFreeStanding) + g.fillRect(x, y, w, h - 1); + else + g.fillRect(x, y, w, h); + } + // then draw the dark box g.setColor(thumbLightShadowColor); if (isFreeStanding) @@ -405,6 +421,19 @@ public class MetalScrollBarUI extends BasicScrollBarUI g.setColor(UIManager.getColor("ScrollBar.shadow")); g.drawLine(x + w, y + 1, x + w, y + h - 1); + // For the OceanTheme, draw the 3 lines in the middle. + if (theme instanceof OceanTheme) + { + g.setColor(thumbLightShadowColor); + int middle = x + w / 2; + g.drawLine(middle - 2, y + 4, middle - 2, y + h - 5); + g.drawLine(middle, y + 4, middle, y + h - 5); + g.drawLine(middle + 2, y + 4, middle + 2, y + h - 5); + g.setColor(UIManager.getColor("ScrollBar.highlight")); + g.drawLine(middle - 1, y + 5, middle - 1, y + h - 4); + g.drawLine(middle + 1, y + 5, middle + 1, y + h - 4); + g.drawLine(middle + 3, y + 5, middle + 3, y + h - 4); + } } /** @@ -422,13 +451,24 @@ public class MetalScrollBarUI extends BasicScrollBarUI int w = thumbBounds.width; int h = thumbBounds.height; - // first we fill the background - g.setColor(thumbColor); - if (isFreeStanding) - g.fillRect(x, y, w - 1, h); + // First we fill the background. + MetalTheme theme = MetalLookAndFeel.getCurrentTheme(); + if (theme instanceof OceanTheme + && UIManager.get("ScrollBar.gradient") != null) + { + MetalUtils.paintGradient(g, x + 2, y + 2, w - 2, h - 4, + SwingConstants.HORIZONTAL, + "ScrollBar.gradient"); + } else - g.fillRect(x, y, w, h); - + { + g.setColor(thumbColor); + if (isFreeStanding) + g.fillRect(x, y, w - 1, h); + else + g.fillRect(x, y, w, h); + } + // then draw the dark box g.setColor(thumbLightShadowColor); if (isFreeStanding) @@ -456,6 +496,20 @@ public class MetalScrollBarUI extends BasicScrollBarUI // draw the shadow line g.setColor(UIManager.getColor("ScrollBar.shadow")); g.drawLine(x + 1, y + h, x + w - 2, y + h); + + // For the OceanTheme, draw the 3 lines in the middle. + if (theme instanceof OceanTheme) + { + g.setColor(thumbLightShadowColor); + int middle = y + h / 2; + g.drawLine(x + 4, middle - 2, x + w - 5, middle - 2); + g.drawLine(x + 4, middle, x + w - 5, middle); + g.drawLine(x + 4, middle + 2, x + w - 5, middle + 2); + g.setColor(UIManager.getColor("ScrollBar.highlight")); + g.drawLine(x + 5, middle - 1, x + w - 4, middle - 1); + g.drawLine(x + 5, middle + 1, x + w - 4, middle + 1); + g.drawLine(x + 5, middle + 3, x + w - 4, middle + 3); + } } /** diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java index 08fb99d216c..f97717f31e0 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java @@ -1,5 +1,5 @@ /* MetalSliderUI.java - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -210,7 +210,7 @@ public class MetalSliderUI extends BasicSliderUI { int trackX = trackRect.x; int trackY = trackRect.y + (trackRect.height - getTrackWidth()) / 2; - int trackW = trackRect.width - 1; + int trackW = trackRect.width; int trackH = getTrackWidth(); // draw border @@ -224,29 +224,47 @@ public class MetalSliderUI extends BasicSliderUI } // fill track (if required) - if (filledSlider) - { - int xPos = xPositionForValue(slider.getValue()); - int x = (slider.getInverted() ? xPos : trackRect.x); - int w = (slider.getInverted() ? trackX + trackW - xPos - : xPos - trackRect.x); - g.setColor(MetalLookAndFeel.getControlShadow()); - g.fillRect(x + 1, trackY + 1, w - 3, getTrackWidth() - 3); - if (slider.isEnabled()) - { - g.setColor(MetalLookAndFeel.getControl()); - g.drawLine(x + 1, trackY + 1, x + w - 3, trackY + 1); - g.drawLine(x + 1, trackY + 1, x + 1, - trackY + getTrackWidth() - 3); - } - } + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + { + if (slider.isEnabled()) + { + int xPos = xPositionForValue(slider.getValue()); + int x = (slider.getInverted() ? xPos : trackRect.x); + int w = (slider.getInverted() ? trackX + trackW - xPos + : xPos - trackRect.x); + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 1, trackY + 1, x + w - 3, trackY + 1); + g.setColor(UIManager.getColor("Slider.altTrackColor")); + g.drawLine(x + 1, trackY + 2, x + w - 3, trackY + 2); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x + 1, trackY + 3, x + w - 3, trackY + 3); + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + g.drawLine(x + 1, trackY + 4, x + w - 3, trackY + 4); + } + } + else if (filledSlider) + { + int xPos = xPositionForValue(slider.getValue()); + int x = (slider.getInverted() ? xPos : trackRect.x); + int w = (slider.getInverted() ? trackX + trackW - xPos + : xPos - trackRect.x); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.fillRect(x + 1, trackY + 1, w - 3, getTrackWidth() - 3); + if (slider.isEnabled()) + { + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(x + 1, trackY + 1, x + w - 3, trackY + 1); + g.drawLine(x + 1, trackY + 1, x + 1, + trackY + getTrackWidth() - 3); + } + } } else { int trackX = trackRect.x + (trackRect.width - getTrackWidth()) / 2; int trackY = trackRect.y; int trackW = getTrackWidth(); - int trackH = trackRect.height - 1; + int trackH = trackRect.height; if (slider.isEnabled()) BasicGraphicsUtils.drawEtchedRect(g, trackX, trackY, trackW, trackH, darkShadowColor, shadowColor, darkShadowColor, highlightColor); @@ -255,8 +273,28 @@ public class MetalSliderUI extends BasicSliderUI g.setColor(MetalLookAndFeel.getControlShadow()); g.drawRect(trackX, trackY, trackW - 2, trackH - 2); } - - if (filledSlider) + + // Fill track if necessary. + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + { + if (slider.isEnabled()) + { + int yPos = yPositionForValue(slider.getValue()); + int y = (slider.getInverted() ? trackY : yPos); + int h = (slider.getInverted() ? yPos - trackY + : trackY + trackH - yPos); + + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(trackX + 1, y + 1, trackX + 1, y + h - 3); + g.setColor(UIManager.getColor("Slider.altTrackColor")); + g.drawLine(trackX + 2, y + 1, trackX + 2, y + h - 3); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(trackX + 3, y + 1, trackX + 3, y + h - 3); + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + g.drawLine(trackX + 4, y + 1, trackX + 4, y + h - 3); + } + } + else if (filledSlider) { int yPos = yPositionForValue(slider.getValue()); int y = (slider.getInverted() ? trackY : yPos); diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java index c6c46ffe614..39dec3d663f 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java @@ -47,6 +47,7 @@ import javax.swing.JComponent; import javax.swing.JTabbedPane; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicTabbedPaneUI; /** @@ -101,6 +102,17 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI // do nothing, because the selected tab does not have extra padding in // the MetalLookAndFeel } + + /** + * Overridden because tab runs are only normalized for TOP and BOTTOM + * tab placement in the Metal L&F. + */ + protected void normalizeTabRuns(int tabPlacement, int tabCount, int start, + int max) + { + if (tabPlacement == TOP || tabPlacement == BOTTOM) + super.normalizeTabRuns(tabPlacement, tabCount, start, max); + } } /** @@ -125,7 +137,12 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI /** The graphics to draw the highlight below the tab. */ private Graphics hg; - + + /** + * Indicates if the tabs are having their background filled. + */ + private boolean tabsOpaque; + /** * Constructs a new instance of MetalTabbedPaneUI. */ @@ -153,7 +170,7 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI */ protected LayoutManager createLayoutManager() { - return super.createLayoutManager(); + return new TabbedPaneLayout(); } /** @@ -172,16 +189,24 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { - if (tabPlacement == TOP) - paintTopTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected); - else if (tabPlacement == LEFT) - paintLeftTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected); - else if (tabPlacement == BOTTOM) - paintBottomTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected); - else if (tabPlacement == RIGHT) - paintRightTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected); - else - throw new AssertionError("Unrecognised 'tabPlacement' argument."); + int bottom = y + h - 1; + int right = x + w - 1; + + switch (tabPlacement) + { + case LEFT: + paintLeftTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected); + break; + case BOTTOM: + paintBottomTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected); + break; + case RIGHT: + paintRightTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected); + break; + case TOP: + default: + paintTopTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected); + } } /** @@ -194,35 +219,90 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI * @param y the y-coordinate for the tab's bounding rectangle. * @param w the width for the tab's bounding rectangle. * @param h the height for the tab's bounding rectangle. - * @param btm ??? - * @param rght ??? + * @param btm the y coordinate of the bottom border + * @param rght the x coordinate of the right border * @param isSelected indicates whether the tab is selected. */ protected void paintTopTabBorder(int tabIndex, Graphics g, int x, int y, int w, int h, int btm, int rght, boolean isSelected) { - int currentRun = getRunForTab(tabPane.getTabCount(), tabIndex); + int tabCount = tabPane.getTabCount(); + int currentRun = getRunForTab(tabCount, tabIndex); + int right = w - 1; + int bottom = h - 1; + + // Paint gap. if (shouldFillGap(currentRun, tabIndex, x, y)) { g.translate(x, y); - g.setColor(getColorForGap(currentRun, x, y)); + g.setColor(getColorForGap(currentRun, x, y + 1)); g.fillRect(1, 0, 5, 3); g.fillRect(1, 3, 2, 2); g.translate(-x, -y); } - - if (isSelected) - { - g.setColor(MetalLookAndFeel.getControlHighlight()); - g.drawLine(x + 1, y + h, x + 1, y + 6); - g.drawLine(x + 1, y + 6, x + 6, y + 1); - g.drawLine(x + 6, y + 1, x + w - 1, y + 1); - } - g.setColor(MetalLookAndFeel.getControlDarkShadow()); - g.drawLine(x, y + h - 1, x, y + 6); - g.drawLine(x, y + 6, x + 6, y); - g.drawLine(x + 6, y, x + w, y); - g.drawLine(x + w, y, x + w, y + h - 1); + + g.translate(x, y); + + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + if (isOcean && isSelected) + g.setColor(oceanSelectedBorder); + else + g.setColor(darkShadow); + + // Slant + g.drawLine(1, 5, 6, 0); + // Top. + g.drawLine(6, 0, right, 0); + // Right. + int lastIndex = lastTabInRun(tabCount, currentRun); + if (tabIndex == lastIndex) + g.drawLine(right, 1, right, bottom); + // Left. + int selectedIndex = tabPane.getSelectedIndex(); + if (isOcean && tabIndex - 1 == selectedIndex + && currentRun == getRunForTab(tabCount, selectedIndex)) + { + g.setColor(oceanSelectedBorder); + } + if (tabIndex != tabRuns[runCount - 1]) + { + if (isOcean && isSelected) + { + g.drawLine(0, 6, 0, bottom); + g.setColor(darkShadow); + g.drawLine(0, 0, 0, 5); + } + else + { + g.drawLine(0, 0, 0, bottom); + } + } + else + { + g.drawLine(0, 6, 0, bottom); + } + + // Paint the highlight. + g.setColor(isSelected ? selectHighlight : highlight); + // Slant. + g.drawLine(1, 6, 6, 1); + // Top. + g.drawLine(6, 1, right, 1); + // Left. + g.drawLine(1, 6, 1, bottom); + int firstIndex = tabRuns[currentRun]; + if (tabIndex == firstIndex && tabIndex != tabRuns[runCount - 1]) + { + if (tabPane.getSelectedIndex() == tabRuns[currentRun + 1]) + g.setColor(selectHighlight); + else + g.setColor(highlight); + g.drawLine(1, 0, 1, 4); + } + + g.translate(-x, -y); } /** @@ -242,18 +322,115 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI protected void paintLeftTabBorder(int tabIndex, Graphics g, int x, int y, int w, int h, int btm, int rght, boolean isSelected) { - if (isSelected) - { - g.setColor(MetalLookAndFeel.getControlHighlight()); - g.drawLine(x + 1, y + h, x + 1, y + 6); - g.drawLine(x + 1, y + 6, x + 6, y + 1); - g.drawLine(x + 6, y + 1, x + w - 1, y + 1); - } - g.setColor(MetalLookAndFeel.getControlDarkShadow()); - g.drawLine(x, y + h, x, y + 6); - g.drawLine(x, y + 6, x + 6, y); - g.drawLine(x + 6, y, x + w - 1, y); - g.drawLine(x, y + h, x + w - 1, y + h); + g.translate(x, y); + int bottom = h - 1; + int right = w - 1; + + + int tabCount = tabPane.getTabCount(); + int currentRun = getRunForTab(tabCount, tabIndex); + int firstIndex = tabRuns[currentRun]; + + // Paint the part of the above tab. + if (tabIndex != firstIndex && tabIndex > 0 && tabsOpaque) + { + Color c; + if (tabPane.getSelectedIndex() == tabIndex - 1) + c = selectColor; + else + c = getUnselectedBackground(tabIndex - 1); + g.setColor(c); + g.fillRect(2, 0, 4, 3); + g.drawLine(2, 3, 2, 3); + } + + // Paint the highlight. + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + if (isOcean) + { + g.setColor(isSelected ? selectHighlight : MetalLookAndFeel.getWhite()); + } + else + { + g.setColor(isSelected ? selectHighlight : highlight); + } + // Slant. + g.drawLine(1, 6, 6, 1); + // Left. + g.drawLine(1, 6, 1, bottom); + // Top. + g.drawLine(6, 1, right, 1); + if (tabIndex != firstIndex) + { + if (isOcean) + { + g.setColor(MetalLookAndFeel.getWhite()); + } + g.drawLine(1, 0, 1, 4); + } + + // Paint border. + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + if (isOcean && isSelected) + { + g.setColor(oceanSelectedBorder); + } + else + { + g.setColor(darkShadow); + } + + // Slant. + g.drawLine(1, 5, 6, 0); + // Top. + g.drawLine(6, 0, right, 0); + // Bottom. + int lastIndex = lastTabInRun(tabCount, currentRun); + if (tabIndex == lastIndex) + { + g.drawLine(0, bottom, right, bottom); + } + // Left. + if (isOcean) + { + if (tabPane.getSelectedIndex() == tabIndex - 1) + { + g.drawLine(0, 5, 0, bottom); + g.setColor(oceanSelectedBorder); + g.drawLine(0, 0, 0, 5); + } + else if (isSelected) + { + g.drawLine(0, 5, 0, bottom); + if (tabIndex != 0) + { + g.setColor(darkShadow); + g.drawLine(0, 0, 0, 5); + } + } + else if (tabIndex != firstIndex) + { + g.drawLine(0, 0, 0, bottom); + } + else + { + g.drawLine(0, 6, 0, bottom); + } + } + else + { + if (tabIndex != firstIndex) + { + g.drawLine(0, 0, 0, bottom); + } + else + { + g.drawLine(0, 6, 0, bottom); + } + } + + g.translate(-x, -y); } /** @@ -273,17 +450,92 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI protected void paintRightTabBorder(int tabIndex, Graphics g, int x, int y, int w, int h, int btm, int rght, boolean isSelected) { - if (isSelected) - { - g.setColor(MetalLookAndFeel.getControlHighlight()); - g.drawLine(x, y + 1, x + w - 7, y + 1); - g.drawLine(x + w - 7, y + 1, x + w - 1, y + 7); - } - g.setColor(MetalLookAndFeel.getControlDarkShadow()); - g.drawLine(x, y, x + w - 7, y); - g.drawLine(x + w - 7, y, x + w - 1, y + 6); - g.drawLine(x + w - 1, y + 6, x + w - 1, y + h - 1); - g.drawLine(x + w - 1, y + h, x, y + h); + g.translate(x, y); + int bottom = h - 1; + int right = w - 1; + + int tabCount = tabPane.getTabCount(); + int currentRun = getRunForTab(tabCount, tabIndex); + int firstIndex = tabRuns[currentRun]; + + // Paint part of the above tab. + if (tabIndex != firstIndex && tabIndex > 0 && tabsOpaque) + { + Color c; + if (tabPane.getSelectedIndex() == tabIndex - 1) + c = UIManager.getColor("TabbedPane.tabAreaBackground"); + else + c = getUnselectedBackground(tabIndex - 1); + g.fillRect(right - 5, 0, 5, 3); + g.fillRect(right - 2, 3, 2, 2); + } + + // Paint highlight. + g.setColor(isSelected ? selectHighlight : highlight); + + // Slant. + g.drawLine(right - 6, 1, right - 1, 6); + // Top. + g.drawLine(0, 1, right - 6, 1); + // Left. + if (! isSelected) + { + g.drawLine(0, 1, 0, bottom); + } + + // Paint border. + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + if (isOcean && isSelected) + { + g.setColor(oceanSelectedBorder); + } + else + { + g.setColor(darkShadow); + } + + // Bottom. + int lastIndex = lastTabInRun(tabCount, currentRun); + if (tabIndex == lastIndex) + { + g.drawLine(0, bottom, right, bottom); + } + // Slant. + if (isOcean && tabPane.getSelectedIndex() == tabIndex - 1) + { + g.setColor(oceanSelectedBorder); + } + g.drawLine(right - 6, 0, right, 6); + // Top. + g.drawLine(0, 0, right - 6, 0); + // Right. + if (isOcean && isSelected) + { + g.drawLine(right, 6, right, bottom); + if (tabIndex != firstIndex) + { + g.setColor(darkShadow); + g.drawLine(right, 0, right, 5); + } + } + else if (isOcean && tabPane.getSelectedIndex() == tabIndex - 1) + { + g.setColor(oceanSelectedBorder); + g.drawLine(right, 0, right, 6); + g.setColor(darkShadow); + g.drawLine(right, 6, right, bottom); + } + else if (tabIndex != firstIndex) + { + g.drawLine(right, 0, right, bottom); + } + else + { + g.drawLine(right, 6, right, bottom); + } + g.translate(-x, -y); } /** @@ -303,27 +555,94 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI protected void paintBottomTabBorder(int tabIndex, Graphics g, int x, int y, int w, int h, int btm, int rght, boolean isSelected) { - int currentRun = getRunForTab(tabPane.getTabCount(), tabIndex); + int bottom = h - 1; + int right = w - 1; + + int tabCount = tabPane.getTabCount(); + int currentRun = getRunForTab(tabCount, tabIndex); + // Paint gap if necessary. if (shouldFillGap(currentRun, tabIndex, x, y)) { g.translate(x, y); g.setColor(getColorForGap(currentRun, x, y)); - g.fillRect(1, h - 5, 3, 5); - g.fillRect(4, h - 2, 2, 2); + g.fillRect(1, bottom - 4, 3, 5); + g.fillRect(4, bottom - 1, 2, 2); g.translate(-x, -y); } - - if (isSelected) - { - g.setColor(MetalLookAndFeel.getControlHighlight()); - g.drawLine(x + 1, y, x + 1, y + h - 7); - g.drawLine(x + 1, y + h - 7, x + 7, y + h - 1); - } - g.setColor(MetalLookAndFeel.getControlDarkShadow()); - g.drawLine(x, y, x, y + h - 7); - g.drawLine(x, y + h - 7, x + 6, y + h - 1); - g.drawLine(x + 6, y + h - 1, x + w, y + h - 1); - g.drawLine(x + w, y + h - 1, x + w, y); + + g.translate(x, y); + + // Paint border. + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + if (isOcean && isSelected) + { + g.setColor(oceanSelectedBorder); + } + else + { + g.setColor(darkShadow); + } + // Slant. + g.drawLine(1, bottom - 5, 6, bottom); + // Bottom. + g.drawLine(6, bottom, right, bottom); + // Right. + int lastIndex = lastTabInRun(tabCount, currentRun); + if (tabIndex == lastIndex) + { + g.drawLine(right, 0, right, bottom); + } + // Left. + if (isOcean && isSelected) + { + g.drawLine(0, 0, 0, bottom - 5); + if ((currentRun == 0 && tabIndex != 0) + || (currentRun > 0 && tabIndex != tabRuns[currentRun - 1])) + { + g.setColor(darkShadow); + g.drawLine(0, bottom - 5, 0, bottom); + } + } + else + { + if (isOcean && tabIndex == tabPane.getSelectedIndex()+ 1) + { + g.setColor(oceanSelectedBorder); + } + if (tabIndex != tabRuns[runCount- 1]) + { + g.drawLine(0, 0, 0, bottom); + } + else + { + g.drawLine(0, 0, 0, bottom - 6); + } + } + + // Paint highlight. + g.setColor(isSelected ? selectHighlight : highlight); + // Slant. + g.drawLine(1, bottom - 6, 6, bottom - 1); + // Left. + g.drawLine(1, 0, 1, bottom - 6); + + int firstIndex = tabRuns[currentRun]; + if (tabIndex == firstIndex && tabIndex != tabRuns[runCount - 1]) + { + if (tabPane.getSelectedIndex() == tabRuns[currentRun + 1]) + { + g.setColor(selectHighlight); + } + else + { + g.setColor(highlight); + } + g.drawLine(1, bottom - 4, 1, bottom); + } + + g.translate(-x, -y); } /** @@ -343,42 +662,29 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI int tabIndex, int x, int y, int w, int h, boolean isSelected) { if (isSelected) - g.setColor(UIManager.getColor("TabbedPane.selected")); + g.setColor(selectColor); else - { - // This is only present in the OceanTheme, so we must check if it - // is actually there - Color background = UIManager.getColor("TabbedPane.unselectedBackground"); - if (background == null) - background = UIManager.getColor("TabbedPane.background"); - g.setColor(background); - } - int[] px, py; - if (tabPlacement == TOP) - { - px = new int[] {x + 6, x + w - 1, x + w -1, x + 2, x + 2}; - py = new int[] {y + 2, y + 2, y + h - 1, y + h -1, y + 6}; - } - else if (tabPlacement == LEFT) - { - px = new int[] {x + 6, x + w - 1, x + w -1, x + 2, x + 2}; - py = new int[] {y + 2, y + 2, y + h - 1, y + h -1, y + 6}; - } - else if (tabPlacement == BOTTOM) - { - px = new int[] {x + 2, x + w - 1, x + w -1, x + 8, x + 2}; - py = new int[] {y, y, y + h - 1, y + h -1, y + h - 7}; - } - else if (tabPlacement == RIGHT) - { - px = new int[] {x + 2, x + w - 7, x + w - 1, x + w - 1, x + 2}; - py = new int[] {y + 2, y + 2, y + 7, y + h -1, y + h - 1}; - } - else - throw new AssertionError("Unrecognised 'tabPlacement' argument."); - g.fillPolygon(px, py, 5); - hg = g; - paintHighlightBelowTab(); + g.setColor(getUnselectedBackground(tabIndex)); + + switch (tabPlacement) + { + case LEFT: + g.fillRect(x + 5, y + 1, w - 5, h - 1); + g.fillRect(x + 2, y + 4, 3, h - 4); + break; + case BOTTOM: + g.fillRect(x + 2, y, w - 2, h - 3); + g.fillRect(x + 5, y + h - 4, w - 5, 3); + break; + case RIGHT: + g.fillRect(x, y + 1, w - 4, h - 1); + g.fillRect(x + w - 4, y + 5, 3, h - 5); + break; + case TOP: + default: + g.fillRect(x + 4, y + 2, w - 4, h - 2); + g.fillRect(x + 2, y + 5, 2, h - 5); + } } /** @@ -408,6 +714,7 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI selectColor = UIManager.getColor("TabbedPane.selected"); selectHighlight = UIManager.getColor("TabbedPane.selectHighlight"); tabAreaBackground = UIManager.getColor("TabbedPane.tabAreaBackground"); + tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque"); minTabWidth = 0; } @@ -487,4 +794,354 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI // false because tab runs are not rotated in the MetalLookAndFeel return false; } + + protected int calculateMaxTabHeight(int tabPlacement) + { + // FIXME: Why is this overridden? + return super.calculateMaxTabHeight(tabPlacement); + } + + /** + * Returns the amount of overlay among the tabs. In + * the Metal L&F the overlay for LEFT and RIGHT placement + * is half of the maxTabHeight. For TOP and BOTTOM placement + * the tabs do not overlay. + * + * @param tabPlacement the placement + * + * @return the amount of overlay among the tabs + */ + protected int getTabRunOverlay(int tabPlacement) + { + int overlay = 0; + if (tabPlacement == LEFT || tabPlacement == RIGHT) + { + int maxHeight = calculateMaxTabHeight(tabPlacement); + overlay = maxTabHeight / 2; + } + return overlay; + } + + /** + * Paints the upper edge of the content border. + * + * @param g the graphics to use for painting + * @param tabPlacement the tab placement + * @param selectedIndex the index of the selected tab + * @param x the upper left coordinate of the content area + * @param y the upper left coordinate of the content area + * @param w the width of the content area + * @param h the height of the content area + */ + protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + if (isOcean) + { + g.setColor(oceanSelectedBorder); + } + else + { + g.setColor(selectHighlight); + } + + Rectangle rect = selectedIndex < 0 ? null : + getTabBounds(selectedIndex, calcRect); + + // If tabs are not placed on TOP, or if the selected tab is not in the + // run directly above the content or the selected tab is not visible, + // then we draw an unbroken line. + if (tabPlacement != TOP || selectedIndex < 0 + || rect.y + rect.height + 1 < y || rect.x < x ||rect.x > x + w) + { + g.drawLine(x, y, x + w - 2, y); + if (isOcean && tabPlacement == TOP) + { + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x, y + 1, x + w - 2, y + 1); + } + } + else + { + boolean isLast = isLastTabInRun(selectedIndex); + if (isLast) + { + g.drawLine(x, y, rect.x + 1, y); + } + else + { + g.drawLine(x, y, rect.x, y); + } + + int right = x + w - 1; + if (rect.x + rect.width < right - 1) + { + if (isLast) + { + g.drawLine(rect.x + rect.width - 1, y, right - 1, y); + } + else + { + g.drawLine(rect.x + rect.width, y, right - 1, y); + } + } + else + { + g.setColor(shadow); + g.drawLine(x + w - 2, y, x + w - 2, y); + } + + // When in OceanTheme, draw another white line. + if (isOcean) + { + g.setColor(MetalLookAndFeel.getWhite()); + if (isLast) + { + g.drawLine(x, y + 1, rect.x + 1, y + 1); + } + else + { + g.drawLine(x, y + 1, rect.x, y + 1); + } + + if (rect.x + rect.width < right - 1) + { + if (isLast) + { + g.drawLine(rect.x + rect.width - 1, y + 1, right - 1, + y + 1); + } + else + { + g.drawLine(rect.x + rect.width, y + 1, right - 1, y + 1); + } + } + else + { + g.setColor(shadow); + g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1); + } + } + } + } + + /** + * Paints the lower edge of the content border. + * + * @param g the graphics to use for painting + * @param tabPlacement the tab placement + * @param selectedIndex the index of the selected tab + * @param x the upper left coordinate of the content area + * @param y the upper left coordinate of the content area + * @param w the width of the content area + * @param h the height of the content area + */ + protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + g.setColor(darkShadow); + + // If tabs are not placed on BOTTOM, or if the selected tab is not in the + // run directly below the content or the selected tab is not visible, + // then we draw an unbroken line. + Rectangle rect = selectedIndex < 0 ? null : + getTabBounds(selectedIndex, calcRect); + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + if (tabPlacement != BOTTOM || selectedIndex < 0 || rect.y - 1 > h + || rect.x < x || rect.x > x + w) + { + if (isOcean && tabPlacement == BOTTOM) + { + g.setColor(oceanSelectedBorder); + } + g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); + } + else + { + boolean isLast = isLastTabInRun(selectedIndex); + if (isOcean) + { + g.setColor(oceanSelectedBorder); + } + + int bottom = y + h - 1; + int right = x + w - 1; + if (isLast) + { + g.drawLine(x, bottom, rect.x, bottom); + } + else + { + g.drawLine(x, bottom, rect.x - 1, bottom); + } + + if (rect.x + rect.width < x + w - 2) + { + if (isLast) + { + g.drawLine(rect.x + rect.width - 1, bottom, right, bottom); + } + else + { + g.drawLine(rect.x + rect.width, bottom, right, bottom); + } + } + } + } + + /** + * Paints the left edge of the content border. + * + * @param g the graphics to use for painting + * @param tabPlacement the tab placement + * @param selectedIndex the index of the selected tab + * @param x the upper left coordinate of the content area + * @param y the upper left coordinate of the content area + * @param w the width of the content area + * @param h the height of the content area + */ + protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + Rectangle rect = selectedIndex < 0 ? null : + getTabBounds(selectedIndex, calcRect); + + if (isOcean) + { + g.setColor(oceanSelectedBorder); + } + else + { + g.setColor(selectHighlight); + } + + // If tabs are not placed on LEFT, or if the selected tab is not in the + // run directly left to the content or the selected tab is not visible, + // then we draw an unbroken line. + if (tabPlacement != LEFT || selectedIndex < 0 + || rect.x + rect.width + 1 < x || rect.y < y || rect.y > y + h) + { + g.drawLine(x, y + 1, x, y + h - 2); + if (isOcean && tabPlacement == LEFT) + { + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x, y + 1, x, y + h - 2); + } + } + else + { + g.drawLine(x, y, x, rect.y + 1); + if (rect.y + rect.height < y + h - 2) + { + g.drawLine(x, rect.y + rect.height + 1, x, y + h + 2); + } + if (isOcean) + { + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 1, y + 1, x + 1, rect.y + 1); + if (rect.y + rect.height < y + h - 2) + { + g.drawLine(x + y, rect.y + rect.height + 1, x + 1, y + h + 2); + } + } + } + + } + + /** + * Paints the right edge of the content border. + * + * @param g the graphics to use for painting + * @param tabPlacement the tab placement + * @param selectedIndex the index of the selected tab + * @param x the upper left coordinate of the content area + * @param y the upper left coordinate of the content area + * @param w the width of the content area + * @param h the height of the content area + */ + protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + g.setColor(darkShadow); + Rectangle rect = selectedIndex < 0 ? null : + getTabBounds(selectedIndex, calcRect); + boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme; + Color oceanSelectedBorder = + UIManager.getColor("TabbedPane.borderHightlightColor"); + + // If tabs are not placed on RIGHT, or if the selected tab is not in the + // run directly right to the content or the selected tab is not visible, + // then we draw an unbroken line. + if (tabPlacement != RIGHT || selectedIndex < 0 || rect.x - 1 > w + || rect.y < y || rect.y > y + h) + { + if (isOcean && tabPlacement == RIGHT) + { + g.setColor(oceanSelectedBorder); + } + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); + } + else + { + if (isOcean) + { + g.setColor(oceanSelectedBorder); + } + g.drawLine(x + w - 1, y, x + w - 1, rect.y); + + if (rect.y + rect.height < y + h - 2) + { + g.drawLine(x + w - 1, rect.y + rect.height, x + w - 1, y + h - 2); + } + } + } + + /** + * Determines if the specified tab is the last tab in its tab run. + * + * @param tabIndex the index of the tab + * + * @return if the specified tab is the last tab in its tab run + */ + private boolean isLastTabInRun(int tabIndex) + { + int count = tabPane.getTabCount(); + int run = getRunForTab(count, tabIndex); + int lastIndex = lastTabInRun(count, run); + return tabIndex == lastIndex; + } + + /** + * Returns the background for an unselected tab. This first asks the + * JTabbedPane for the background at the specified tab index, if this + * is an UIResource (that means, it is inherited from the JTabbedPane) + * and the TabbedPane.unselectedBackground UI property is not null, + * this returns the value of the TabbedPane.unselectedBackground property, + * otherwise the value returned by the JTabbedPane. + * + * @param tabIndex the index of the tab for which we query the background + * + * @return the background for an unselected tab + */ + private Color getUnselectedBackground(int tabIndex) + { + Color bg = tabPane.getBackgroundAt(tabIndex); + Color unselectedBackground = + UIManager.getColor("TabbedPane.unselectedBackground"); + if (bg instanceof UIResource && unselectedBackground != null) + bg = unselectedBackground; + return bg; + } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java index 0b56d591442..8c7a46e3a86 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java @@ -45,12 +45,14 @@ import java.awt.Graphics; import java.awt.Rectangle; import javax.swing.AbstractButton; +import javax.swing.ButtonModel; import javax.swing.JComponent; import javax.swing.JToggleButton; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicButtonUI; import javax.swing.plaf.basic.BasicToggleButtonUI; @@ -157,13 +159,15 @@ public class MetalToggleButtonUI /** * Paints the text for the button. * + * As of JDK 1.4 this method is obsolete. + * Use {@link BasicButtonUI#paintText(java.awt.Graphics, + * javax.swing.AbstractButton, java.awt.Rectangle, java.lang.String)}. + * * @param g the graphics device. * @param c the component. * @param textRect the bounds for the text. * @param text the text. * - * @deprecated 1.4 Use {@link BasicButtonUI#paintText(java.awt.Graphics, - * javax.swing.AbstractButton, java.awt.Rectangle, java.lang.String)}. */ protected void paintText(Graphics g, JComponent c, Rectangle textRect, String text) @@ -207,7 +211,12 @@ public class MetalToggleButtonUI */ public void update(Graphics g, JComponent c) { - if (c.isOpaque() && UIManager.get(getPropertyPrefix() + "gradient") != null) + AbstractButton b = (AbstractButton) c; + ButtonModel m = b.getModel(); + if (b.getBackground() instanceof UIResource + && b.isContentAreaFilled() + && b.isEnabled() && ! m.isArmed() && ! m.isPressed() + && UIManager.get(getPropertyPrefix() + "gradient") != null) { MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(), SwingConstants.VERTICAL, diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java index 16e22ac5286..1848c1f162d 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java @@ -38,6 +38,7 @@ exception statement from your version. */ package javax.swing.plaf.metal; +import java.awt.Graphics; import java.awt.Point; import java.awt.event.ContainerListener; import java.awt.event.MouseEvent; @@ -46,6 +47,8 @@ import java.beans.PropertyChangeListener; import javax.swing.JComponent; import javax.swing.JToolBar; +import javax.swing.SwingConstants; +import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.event.MouseInputListener; import javax.swing.plaf.ComponentUI; @@ -225,4 +228,71 @@ public class MetalToolBarUI extends BasicToolBarUI super.mouseDragged(e); } } + + /** + * Installs the UI on the toolbar. This calls super and sets the rollover + * property according to the <code>UIManager</code> property + * "ToolBar.isRollover". + * + * @param c the component to install the UI on + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JToolBar) + { + JToolBar tb = (JToolBar) c; + tb.setRollover(UIManager.getBoolean("ToolBar.isRollover")); + } + } + + /** + * Uninstalls the UI from the toolbar. This calls super and resets the + * rollover property. + * + * @param c the component to uninstall the UI from + */ + public void uninstallUI(JComponent c) + { + if (c instanceof JToolBar) + { + JToolBar tb = (JToolBar) c; + tb.setRollover(false); + } + super.uninstallUI(c); + } + + /** + * Paints the background of the component if necessary and then calls + * <code>paint(g, c)</code>. + * + * This is overridden to implement the OceanTheme gradient when an OceanTheme + * is installed. + * + * @param g the graphics to use + * @param c the component to paint. + * + * @since 1.5 + */ + public void update(Graphics g, JComponent c) + { + // TODO: Sun's implementation uses the MenuBar.gradient here. + // I would consider this a bug, but implement it like this + // for compatibility. + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme + && UIManager.get("MenuBar.gradient") != null) + { + if (c.isOpaque()) + { + MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(), + SwingConstants.VERTICAL, + "MenuBar.gradient"); + } + paint(g, c); + } + else + { + super.update(g, c); + } + } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java index 24432a2b5f6..3ea37c82f18 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.metal; +import gnu.classpath.NotImplementedException; + import java.awt.Graphics; import java.awt.Insets; import java.awt.Rectangle; @@ -133,6 +135,7 @@ public class MetalTreeUI extends BasicTreeUI * @param lineStyleFlag - String representation */ protected void decodeLineStyle(Object lineStyleFlag) + throws NotImplementedException { // FIXME: not implemented } @@ -176,6 +179,7 @@ public class MetalTreeUI extends BasicTreeUI * @param c - the current component to draw */ protected void paintHorizontalSeparators(Graphics g, JComponent c) + throws NotImplementedException { // FIXME: not implemented } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java index b9d5ea76434..03617aa4099 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java @@ -91,7 +91,7 @@ class MetalUtils Color light, Color dark) { if (g instanceof Graphics2D - && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") != null) + && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null) fillMetalPattern2D((Graphics2D) g, x, y, w, h, light, dark); else { @@ -161,14 +161,35 @@ class MetalUtils /** * Paints the typical Metal gradient. See {@link #paintGradient(Graphics, - * int, int, int, int, double, double, Color, Color, Color, int)} + * int, int, int, int, float, float, Color, Color, Color, int, int[][])} + * for more details. + * + * This variant paints a gradient without a mask. + * + * @param g the graphics context to use + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param dir the direction of the gradient, either + * @param uiProp the key of the UIManager property that has the parameters + */ + static void paintGradient(Graphics g, int x, int y, int w, int h, + int dir, String uiProp) + { + paintGradient(g, x, y, w, h, dir, uiProp, null); + } + + /** + * Paints the typical Metal gradient. See {@link #paintGradient(Graphics, + * int, int, int, int, float, float, Color, Color, Color, int, int[][])} * for more details. * * The parameters are fetched from the UIManager using the key * <code>uiProp</code>. The value is expected to be a {@link List} that * contains 4 values: two {@link Double}s and 3 {@link Color} object that * together make up the parameters passed to the painting method. - * + * * @param g the graphics context to use * @param x the X coordinate of the upper left corner of the rectangle * @param y the Y coordinate of the upper left corner of the rectangle @@ -176,17 +197,19 @@ class MetalUtils * @param h the height of the rectangle * @param dir the direction of the gradient, either * @param uiProp the key of the UIManager property that has the parameters + * @param mask the mask that should be used when painting the gradient as + * described above */ static void paintGradient(Graphics g, int x, int y, int w, int h, - int dir, String uiProp) + int dir, String uiProp, int[][] mask) { List params = (List) UIManager.get(uiProp); - double g1 = ((Double) params.get(0)).doubleValue(); - double g2 = ((Double) params.get(1)).doubleValue(); + float g1 = ((Float) params.get(0)).floatValue(); + float g2 = ((Float) params.get(1)).floatValue(); Color c1 = (Color) params.get(2); Color c2 = (Color) params.get(3); Color c3 = (Color) params.get(4); - paintGradient(g, x, y, w, h, g1, g2, c1, c2, c3, dir); + paintGradient(g, x, y, w, h, g1, g2, c1, c2, c3, dir, mask); } /** @@ -209,6 +232,33 @@ class MetalUtils * <li>A gradient from color 2 to color 1 with the relative width specified * by <code>g1</code></li> * + * The <code>mask</code> parameter is an array if int arrays, where the first + * index specifies the row (in the gradient direction), and the second index + * is the starting and end offset of that line. This way you can specify a + * mask that should be laid over the gradient for paintint non-rectangular + * gradients. The following example should demonstrate this for painting + * a circular shaped gradient (note that the first and last line should not + * be drawn at all, they are only here to show the circular shape more + * clearly). Everything <em>inside</code> the surrounded area is filled by + * the gradient: + * + * <pre> + * 012345678 + * xxx + * 0 x x { {4, 7}, + * 1 x x {3, 8}, + * 2 x x {3, 8}, + * 3 x x {3, 8}, + * 4 x x {4, 7} } + * xxx + * </pre> + * + * The <code>mask</code> array is expected to have <code>w</code> or + * <code>h</code> array elements, depending on the direction. + * + * If the <code>mask</code> parameter is null, then the gradient is painted + * without a mask. + * * @param g the graphics context to use * @param x the X coordinate of the upper left corner of the rectangle * @param y the Y coordinate of the upper left corner of the rectangle @@ -221,19 +271,23 @@ class MetalUtils * @param c3 the color 3 * @param dir the direction of the gradient, either * {@link SwingConstants#HORIZONTAL} or {@link SwingConstants#VERTICAL} + * @param mask the mask that should be used when painting the gradient as + * described above */ - static void paintGradient(Graphics g, int x, int y, int w, int h, double g1, - double g2, Color c1, Color c2, Color c3, int dir) + static void paintGradient(Graphics g, int x, int y, int w, int h, float g1, + float g2, Color c1, Color c2, Color c3, int dir, + int[][] mask) { if (dir == SwingConstants.HORIZONTAL) - paintHorizontalGradient(g, x, y, w, h, g1, g2, c1, c2, c3); + paintHorizontalGradient(g, x, y, w, h, g1, g2, c1, c2, c3, mask); else - paintVerticalGradient(g, x, y, w, h, g1, g2, c1, c2, c3); + paintVerticalGradient(g, x, y, w, h, g1, g2, c1, c2, c3, mask); } /** * Paints a horizontal gradient. See {@link #paintGradient(Graphics, int, - * int, int, int, double, double, Color, Color, Color, int)} for details. + * int, int, int, float, float, Color, Color, Color, int, int[][])} + * for details. * * @param x the X coordinate of the upper left corner of the rectangle * @param y the Y coordinate of the upper left corner of the rectangle @@ -244,12 +298,16 @@ class MetalUtils * @param c1 the color 1 * @param c2 the color 2 * @param c3 the color 3 + * @param mask the mask that should be used when painting the gradient as + * described above */ static void paintHorizontalGradient(Graphics g, int x, int y, int w, int h, - double g1, double g2, Color c1, Color c2, - Color c3) + float g1, float g2, Color c1, Color c2, + Color c3, int[][] mask) { // Calculate the coordinates. + int y0 = y; + int y1 = y + h; // The size of the first gradient area (c1->2). int w1 = (int) (w * g1); // The size of the solid c2 area. @@ -276,11 +334,28 @@ class MetalUtils + c1.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(xc, y, xc, y + h); + if (mask != null) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + } + g.drawLine(xc, y0, xc, y1); } // Paint solid c2 area. g.setColor(c2); - g.fillRect(x1, y, x2 - x1, h); + if (mask == null) + { + g.fillRect(x1, y, x2 - x1, h); + } + else + { + for (xc = x1; xc < x2; xc++) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + g.drawLine(xc, y0, xc, y1); + } + } // Paint second gradient area (c2->c1). for (xc = x2; xc < x3; xc++) @@ -297,7 +372,12 @@ class MetalUtils + c2.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(xc, y, xc, y + h); + if (mask != null) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + } + g.drawLine(xc, y0, xc, y1); } // Paint third gradient area (c1->c3). @@ -315,13 +395,18 @@ class MetalUtils + c1.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(xc, y, xc, y + h); + if (mask != null) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + } + g.drawLine(xc, y0, xc, y1); } } /** * Paints a vertical gradient. See {@link #paintGradient(Graphics, int, int, - * int, int, double, double, Color, Color, Color, int)} for details. + * int, int, float, float, Color, Color, Color, int, int[][])} for details. * * @param x the X coordinate of the upper left corner of the rectangle * @param y the Y coordinate of the upper left corner of the rectangle @@ -332,12 +417,16 @@ class MetalUtils * @param c1 the color 1 * @param c2 the color 2 * @param c3 the color 3 + * @param mask the mask that should be used when painting the gradient as + * described above */ static void paintVerticalGradient(Graphics g, int x, int y, int w, int h, double g1, double g2, Color c1, Color c2, - Color c3) + Color c3, int[][] mask) { // Calculate the coordinates. + int x0 = x; + int x1 = x + w; // The size of the first gradient area (c1->2). int w1 = (int) (h * g1); // The size of the solid c2 area. @@ -364,11 +453,28 @@ class MetalUtils + c1.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(x, yc, x + w, yc); + if (mask != null) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + } + g.drawLine(x0, yc, x1, yc); } // Paint solid c2 area. g.setColor(c2); - g.fillRect(x, y1, w, y2 - y1); + if (mask == null) + { + g.fillRect(x, y1, w, y2 - y1); + } + else + { + for (yc = y1; yc < y2; yc++) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + g.drawLine(x0, yc, x1, yc); + } + } // Paint second gradient area (c2->c1). for (yc = y2; yc < y3; yc++) @@ -385,7 +491,12 @@ class MetalUtils + c2.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(x, yc, x + w, yc); + if (mask != null) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + } + g.drawLine(x0, yc, x1, yc); } // Paint third gradient area (c1->c3). @@ -403,7 +514,12 @@ class MetalUtils + c1.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(x, yc, x + w, yc); + if (mask != null) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + } + g.drawLine(x0, yc, x1, yc); } } } diff --git a/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java b/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java index d1fc4cfecde..9d76ff7e808 100644 --- a/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java +++ b/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java @@ -38,10 +38,12 @@ exception statement from your version. */ package javax.swing.plaf.metal; import java.awt.Color; +import java.awt.Insets; import java.util.Arrays; import javax.swing.UIDefaults; import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.BorderUIResource.LineBorderUIResource; /** * A modern theme for the Metal Look & Feel. @@ -207,41 +209,108 @@ public class OceanTheme extends DefaultMetalTheme */ public void addCustomEntriesToTable(UIDefaults defaults) { + // Gradients. defaults.put("Button.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("CheckBox.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("CheckBoxMenuItem.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("MenuBar.gradient", Arrays.asList(new Object[] - {new Double(1.0), new Double(0.0), new ColorUIResource(Color.WHITE), + {new Float(1.0), new Float(0.0), new ColorUIResource(Color.WHITE), new ColorUIResource(218, 218, 218), new ColorUIResource(218, 218, 218)})); defaults.put("RadioButton.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("RadioButtonMenuItem.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("ScrollBar.gradient", Arrays.asList(new Object[] - {new Double(1.0), new Double(0.0), new ColorUIResource(Color.WHITE), - new ColorUIResource(218, 218, 218), new ColorUIResource(218, 218, 218)})); + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("Slider.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.2), new ColorUIResource(200, 221, 242), + {new Float(0.3), new Float(0.2), new ColorUIResource(200, 221, 242), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("Slider.focusGradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.2), new ColorUIResource(200, 221, 242), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("ToggleButton.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("InternalFrame.activeTitleGradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); - + // Colors. + ColorUIResource c1 = new ColorUIResource(200, 221, 242); + ColorUIResource c2 = new ColorUIResource(153, 153, 153); + ColorUIResource c3 = new ColorUIResource(204, 204, 204); + ColorUIResource c4 = new ColorUIResource(210, 226, 239); + ColorUIResource c5 = new ColorUIResource(218, 218, 218); + defaults.put("Button.disabledToolBarBorderBackground", c3); + defaults.put("Button.toolBarBorderBackground", c2); + defaults.put("Label.disabledForeground", c2); + defaults.put("MenuBar.borderColor", c3); + defaults.put("Slider.altTrackColor", c4); + defaults.put("SplitPane.dividerFocusColor", c1); + defaults.put("TabbedPane.contentAreaColor", c1); + defaults.put("TabbedPane.borderHightlightColor", PRIMARY1); + defaults.put("TabbedPane.selected", c1); + defaults.put("TabbedPane.tabAreaBackground", c5); + defaults.put("TabbedPane.unselectedBackground", SECONDARY3); + defaults.put("Table.gridColor", SECONDARY1); + defaults.put("ToolBar.borderColor", c3); + defaults.put("Tree.selectionBorderColor", PRIMARY1); + + // Borders. + defaults.put("Table.focusCellHighlightBorder", + new LineBorderUIResource(getPrimary1())); + + // Insets. + defaults.put("TabbedPane.contentBorderInsets", new Insets(4, 2, 3, 3)); + defaults.put("TabbedPane.tabAreaInsets", new Insets(2, 2, 0, 6)); + + // Flags. + defaults.put("SplitPane.oneTouchButtonsOpaque", Boolean.FALSE); + defaults.put("Menu.opaque", Boolean.FALSE); + defaults.put("ToolBar.isRollover", Boolean.TRUE); + defaults.put("RadioButton.rollover", Boolean.TRUE); + defaults.put("CheckBox.rollover", Boolean.TRUE); defaults.put("Button.rollover", Boolean.TRUE); - defaults.put("TabbedPane.selected", new ColorUIResource(200, 221, 242)); - defaults.put("TabbedPane.unselectedBackground", SECONDARY3); + // Icons. + // FIXME: Add OceanTheme icons. +// defaults.put("Tree.leafIcon", XXX); +// defaults.put("Tree.expandedIcon", XXX); +// defaults.put("Tree.openIcon", XXX); +// defaults.put("Tree.closedIcon", XXX); +// defaults.put("Tree.collapsedIcon", XXX); +// defaults.put("FileChooser.newFolderIcon", XXX); +// defaults.put("FileChooser.homeFolderIcon", XXX); +// defaults.put("FileChooser.upFolderIcon", XXX); +// defaults.put("FileView.hardDriveIcon", XXX); +// defaults.put("FileView.floppyDriveIcon", XXX); +// defaults.put("FileView.fileIcon", XXX); +// defaults.put("FileView.computerIcon", XXX); +// defaults.put("FileView.directoryIcon", XXX); +// defaults.put("OptionPane.questionIcon", XXX); +// defaults.put("OptionPane.errorIcon", XXX); +// defaults.put("OptionPane.warningIcon", XXX); +// defaults.put("OptionPane.informationIcon", XXX); +// defaults.put("InternalFrame.icon", XXX); +// defaults.put("InternalFrame.closeIcon", XXX); +// defaults.put("InternalFrame.iconifyIcon", XXX); +// defaults.put("InternalFrame.minimizeIcon", XXX); +// defaults.put("InternalFrame.maximizeIcon", XXX); +// defaults.put("InternalFrame.paletteCloseIcon", XXX); + + // UI classes. + defaults.put("MenuBarUI", "javax.swing.plaf.metal.MetalMenuBarUI"); + + // Others. + defaults.put("Button.rolloverIconType", "ocean"); } } diff --git a/libjava/classpath/javax/swing/plaf/synth/ColorType.java b/libjava/classpath/javax/swing/plaf/synth/ColorType.java index 954e309e1d6..ced1efc0210 100644 --- a/libjava/classpath/javax/swing/plaf/synth/ColorType.java +++ b/libjava/classpath/javax/swing/plaf/synth/ColorType.java @@ -78,7 +78,12 @@ public class ColorType /** * The maximum number of color types. */ - public static final int MAX_COUNT = 5; + public static final int MAX_COUNT; + static + { + // This is not a constant in the JDK. + MAX_COUNT = 5; + } /** * A counter used to assign an ID to the created color types. diff --git a/libjava/classpath/javax/swing/plaf/synth/Region.java b/libjava/classpath/javax/swing/plaf/synth/Region.java index 7ede65fc87b..25d1a11d5e7 100644 --- a/libjava/classpath/javax/swing/plaf/synth/Region.java +++ b/libjava/classpath/javax/swing/plaf/synth/Region.java @@ -108,13 +108,13 @@ public class Region /** * Specifies the region of a file chooser. */ - public static final Region FILECHOOSER = + public static final Region FILE_CHOOSER = new Region("FileChooser", "FileChooserUI", false); /** * Specifies the region of a formatted text field. */ - public static final Region FormattedTextField = + public static final Region FORMATTED_TEXT_FIELD = new Region("FormattedTextField", "FormattedTextFieldUI", false); /** diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java b/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java index a68b6f6ec2f..1907d754f63 100644 --- a/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java +++ b/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.synth; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Dimension; import java.awt.Font; @@ -159,6 +161,7 @@ public class SynthGraphicsUtils Icon icon, int hAlign, int vAlign, int hTextPosition,int vTextPosition, int iconTextGap,int mnemonicIndex) + throws NotImplementedException { // FIXME: Implement this correctly. return new Dimension(0, 0); @@ -187,6 +190,7 @@ public class SynthGraphicsUtils Icon icon, int hAlign, int vAlign, int hTextPosition,int vTextPosition, int iconTextGap,int mnemonicIndex) + throws NotImplementedException { // FIXME: Implement this correctly. return new Dimension(0, 0); @@ -215,6 +219,7 @@ public class SynthGraphicsUtils Icon icon, int hAlign, int vAlign, int hTextPosition,int vTextPosition, int iconTextGap,int mnemonicIndex) + throws NotImplementedException { // FIXME: Implement this correctly. return new Dimension(0, 0); @@ -277,6 +282,7 @@ public class SynthGraphicsUtils int hAlign, int vAlign, int hTextPosition, int vTextPosition, int iconTextGap, int mnemonicIndex, int textOffset) + throws NotImplementedException { // FIXME: Implement this correctly. } diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java b/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java index 8d0596d416e..1a2489e7ea6 100644 --- a/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java +++ b/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.synth; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.io.InputStream; import java.text.ParseException; @@ -119,6 +121,7 @@ public class SynthLookAndFeel * @param c the componenent for which to update the style */ public static void updateStyles(Component c) + throws NotImplementedException { // FIXME: Implement this properly. } @@ -131,6 +134,7 @@ public class SynthLookAndFeel * @return the region for a given Swing component */ public static Region getRegion(JComponent c) + throws NotImplementedException { // FIXME: This can be implemented as soon as we have the component UI // classes in place, since this region will be matched via the UI classes. @@ -147,6 +151,7 @@ public class SynthLookAndFeel * component */ public static ComponentUI createUI(JComponent c) + throws NotImplementedException { // FIXME: This can be implemented as soon as we have the component UI // classes in place. @@ -157,6 +162,7 @@ public class SynthLookAndFeel * Initializes this look and feel. */ public void initialize() + throws NotImplementedException { super.initialize(); // TODO: Implement at least the following here: @@ -168,6 +174,7 @@ public class SynthLookAndFeel * Uninitializes the look and feel. */ public void uninitialize() + throws NotImplementedException { super.uninitialize(); // TODO: What to do here? @@ -179,6 +186,7 @@ public class SynthLookAndFeel * @return the UI defaults of this look and feel */ public UIDefaults getDefaults() + throws NotImplementedException { // FIXME: This is certainly wrong. The defaults should be fetched/merged // from the file from which the l&f is loaded. @@ -191,6 +199,7 @@ public class SynthLookAndFeel * @return FIXME */ public boolean shouldUpdateStyleOnAncestorChanged() + throws NotImplementedException { return false; } @@ -210,14 +219,14 @@ public class SynthLookAndFeel // FIXME: The signature in the JDK has a Class<?> here. Should be fixed as // soon as we switch to the generics branch. public void load(InputStream in, Class resourceBase) - throws ParseException, IllegalArgumentException + throws ParseException, IllegalArgumentException, NotImplementedException { // FIXME: Implement this correctly. } /** * Returns a textual description of the Synth look and feel. This returns - * "Synt look and feel". + * "Synth look and feel". * * @return a textual description of the Synth look and feel */ @@ -238,7 +247,7 @@ public class SynthLookAndFeel /** * Returns the name of the Synth look and feel. This returns - * "Synt look and feel". + * "Synth look and feel". * * @return the name of the Synth look and feel */ diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java b/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java index 0d63c6db76f..fa1f6f572ce 100644 --- a/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java +++ b/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java @@ -62,6 +62,117 @@ public abstract class SynthPainter } /** + * Paints the foreground of an arrow button. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param dir the orientation of the arrow + */ + public void paintArrowButtonForeground(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int dir) + { + // Nothing to do here. + } + + /** + * Paints the foreground of a progress bar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param dir the orientation of the progress bar + */ + public void paintProgressBarForeground(SynthContext ctx, Graphics g, + int x, int y, int w, int h, + int dir) + { + // Nothing to do here. + } + + /** + * Paints the foreground of a separator. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param dir the orientation of the separator + */ + public void paintSeparatorForeground(SynthContext ctx, Graphics g, + int x, int y, int w, int h, + int dir) + { + // Nothing to do here. + } + + /** + * Paints the foreground of a split pane's divider. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param dir the orientation of the divider + */ + public void paintSplitPaneDividerForeground(SynthContext ctx, Graphics g, + int x, int y, int w, int h, + int dir) + { + // Nothing to do here. + } + + /** + * Paints a split pane's divider, when it is being dragged. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param dir the orientation of the divider + */ + public void paintSplitPaneDragDivider(SynthContext ctx, Graphics g, + int x, int y, int w, int h, + int dir) + { + // Nothing to do here. + } + + /** + * Paints the indicator for a tree cell which has the focus. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTreeCellFocus(SynthContext ctx, Graphics g, + int x, int y, int w, int h) + { + // Nothing to do here. + } + + /** * Paints the background of an arrow button. * * @param ctx the synth context identifying the component and region for @@ -73,7 +184,1815 @@ public abstract class SynthPainter * @param h the height of the area to paint */ public void paintArrowButtonBackground(SynthContext ctx, Graphics g, int x, - int y, int w, int h) + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of an arrow button. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintArrowButtonBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a button. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintButtonBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a button. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintButtonBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a check box. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintCheckBoxBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a check box. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintCheckBoxBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a check box menu item. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintCheckBoxMenuItemBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a check box menu item. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintCheckBoxMenuItemBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a color chooser. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintColorChooserBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a color chooser. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintColorChooserBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a combo box. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintComboBoxBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a combo box. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintComboBoxBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a desktop icon. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintDesktopIconBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a desktop icon. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintDesktopIconBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a desktop pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintDesktopPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a desktop pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintDesktopPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of an editor pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintEditorPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of an editor pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintEditorPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a file chooser. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintFileChooserBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a file chooser. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintFileChooserBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a formatted text field. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintFormattedTextFieldBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a formatted text field. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintFormattedTextFieldBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of an internal frame. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintInternalFrameBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of an internal frame. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintInternalFrameBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of an internal frame's title pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintInternalFrameTitlePaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of an internal frame's title pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintInternalFrameTitlePaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a label. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintLabelBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a label. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintLabelBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a list. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintListBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a list. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintListBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a menu. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintMenuBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a menu. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintMenuBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a menu bar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintMenuBarBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a menu bar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintMenuBarBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a menu item. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintMenuItemBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a menu item. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintMenuItemBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of an option pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintOptionPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of an option pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintOptionPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a panel. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintPanelBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a panel. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintPanelBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a password field. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintPasswordFieldBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a password field. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintPasswordFieldBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a popup menu. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintPopupMenuBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a popup menu. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintPopupMenuBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a progress bar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintProgressBarBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a progress bar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintProgressBarBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a radio button. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintRadioButtonBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a radio button. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintRadioButtonBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a radio button menu item. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintRadioButtonMenuItemBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a radio button menu item. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintRadioButtonMenuItemBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a root pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintRootPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a root pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintRootPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a scrollbar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintScrollBarBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a scrollbar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintScrollBarBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a scrollbar's thumb. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param orientation orientation of the scrollbar + */ + public void paintScrollBarThumbBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int orientation) + { + // Nothing to do here. + } + + /** + * Paints the border of a scrollbar's thumb. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param orientation orientation of the scrollbar + */ + public void paintScrollBarThumbBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int orientation) + { + // Nothing to do here. + } + + /** + * Paints the background of a scrollbar's track. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintScrollBarTrackBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a scrollbar's track. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintScrollBarTrackBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a scroll pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintScrollPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a scroll pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintScrollPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a separator. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSeparatorBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a separator. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSeparatorBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a slider. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSliderBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a slider. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSliderBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a slider's thumb. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param orientation orientation of the slider + */ + public void paintSliderThumbBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int orientation) + { + // Nothing to do here. + } + + /** + * Paints the border of a slider's thumb. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param orientation orientation of the slider + */ + public void paintSliderThumbBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int orientation) + { + // Nothing to do here. + } + + /** + * Paints the background of a slider's track. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSliderTrackBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a slider's track. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSliderTrackBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a spinner. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSpinnerBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a spinner. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSpinnerBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a split pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSplitPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a split pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSplitPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a split pane's divider. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintSplitPaneDividerBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a tabbed pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTabbedPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a tabbed pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTabbedPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of the contents of a tabbed pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTabbedPaneContentBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of the contents of a tabbed pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTabbedPaneContentBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of the tab area of a tabbed pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTabbedPaneTabAreaBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of the tab area of a tabbed pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTabbedPaneTabAreaBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a tab of a tabbed pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param index the index of the tab to paint + */ + public void paintTabbedPaneTabBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int index) + { + // Nothing to do here. + } + + /** + * Paints the border of a tab of a tabbed pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + * @param index the index of the tab to paint + */ + public void paintTabbedPaneTabBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int index) + { + // Nothing to do here. + } + + /** + * Paints the background of a table. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTableBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a table. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTableBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a table's header. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTableHeaderBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a table's header. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTableHeaderBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a text area. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTextAreaBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a text area. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTextAreaBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a text field. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTextFieldBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a text field. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTextFieldBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a text pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTextPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a text pane. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTextPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a toggle button. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintToggleButtonBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a toggle button. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintToggleButtonBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a toolbar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintToolBarBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a toolbar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintToolBarBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of the contents of a toolbar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintToolBarContentBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of the contents of a toolbar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintToolBarContentBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of the window of a detached toolbar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintToolBarDragWindowBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of the window of a detached toolbar. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintToolBarDragWindowBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a tool tip. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintToolTipBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a tool tip. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintToolTipBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a tree. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTreeBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a tree. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTreeBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a cell in a tree. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTreeCellBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a cell in a tree. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintTreeCellBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a viewport. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintViewportBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a viewport. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintViewportBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) { // Nothing to do here. } diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java b/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java index e0a8dbcc7b9..f5ab3df3b5b 100644 --- a/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java +++ b/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.plaf.synth; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Font; import java.awt.Insets; @@ -58,87 +60,144 @@ public abstract class SynthStyle * Creates a new <code>SynthStyle</code> object. */ public SynthStyle() + throws NotImplementedException { // FIXME: Implement this correctly. } public SynthGraphicsUtils getGraphicsUtils(SynthContext ctx) + throws NotImplementedException { // FIXME: Implement this correctly. return null; } public Color getColor(SynthContext ctx, ColorType type) + throws NotImplementedException { // FIXME: Implement this correctly. return null; } - public abstract Color getColorForState(SynthContext ctx, ColorType type); + protected abstract Color getColorForState(SynthContext ctx, ColorType type); public Font getFont(SynthContext ctx) + throws NotImplementedException { // FIXME: Implement this correctly. return null; } - public abstract Font getFontForState(SynthContext ctx); + protected abstract Font getFontForState(SynthContext ctx); - public Insets getInsets(SynthContext ctx) + public Insets getInsets(SynthContext ctx, Insets result) + throws NotImplementedException { // FIXME: Implement this correctly. return null; } - public SynthPainter getPainted(SynthContext ctx) + public SynthPainter getPainter(SynthContext ctx) + throws NotImplementedException { // FIXME: Implement this correctly. return null; } public boolean isOpaque(SynthContext ctx) + throws NotImplementedException { // FIXME: Implement this correctly. return true; } public Object get(SynthContext ctx, Object key) + throws NotImplementedException { // FIXME: Implement this correctly. return null; } public void installDefaults(SynthContext ctx) + throws NotImplementedException { // FIXME: Implement this correctly. } public void uninstallDefaults(SynthContext ctx) + throws NotImplementedException { // FIXME: Implement this correctly. } + /** + * A convenience method to fetch an integer property. + * If the property's value is a {@link Number}, then the + * integer value is returned. Otherwise, the default value + * is returned. + * @param ctx the context + * @param key the key to fetch + * @param defaultValue the default value + * @return the integer value of the property, or the default value + */ public int getInt(SynthContext ctx, Object key, int defaultValue) { - // FIXME: Implement this correctly. - return -1; + Object obj = get(ctx, key); + if (obj instanceof Number) + return ((Number) obj).intValue(); + return defaultValue; } - public boolean getBoolean(SynthContext ctx, Object key, boolean defaultValue) + /** + * A convenience method to fetch an integer property. + * If the property's value is a {@link Boolean}, then the + * value is returned. Otherwise, the default value + * is returned. + * @param ctx the context + * @param key the key to fetch + * @param defaultValue the default value + * @return the boolean value of the property, or the default value + */ + public boolean getBoolean(SynthContext ctx, Object key, + boolean defaultValue) { - // FIXME: Implement this correctly. - return false; + Object obj = get(ctx, key); + if (obj instanceof Boolean) + return ((Boolean) obj).booleanValue(); + return defaultValue; } + /** + * A convenience method to fetch an Icon-valued property. + * If the property's value is an {@link Icon}, then the + * value is returned. Otherwise, null is returned. + * @param ctx the context + * @param key the key to fetch + * @return the icon, or null + */ public Icon getIcon(SynthContext ctx, Object key) { - // FIXME: Implement this correctly. + Object obj = get(ctx, key); + if (key instanceof Icon) + return (Icon) obj; return null; } + /** + * A convenience method to fetch a String property. + * If the property's value is a {@link String}, then the + * value is returned. Otherwise, the default value + * is returned. + * @param ctx the context + * @param key the key to fetch + * @param defaultValue the default value + * @return the String value of the property, or the default value + */ public String getString(SynthContext ctx, Object key, String defaultValue) { - // FIXME: Implement this correctly. - return null; + Object obj = get(ctx, key); + if (obj instanceof String) + return (String) obj; + return defaultValue; } } diff --git a/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java b/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java index 0d9b62567f6..a9bbe9a7848 100644 --- a/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java +++ b/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java @@ -1,5 +1,5 @@ /* DefaultTableCellRenderer.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. @@ -49,7 +49,6 @@ import javax.swing.JTable; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; -import javax.swing.JTextField; /** * Class to display every cells. @@ -59,7 +58,7 @@ public class DefaultTableCellRenderer extends JLabel { static final long serialVersionUID = 7878911414715528324L; - protected static Border noFocusBorder = new EmptyBorder(0, 0, 0, 0); + protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); public static class UIResource extends DefaultTableCellRenderer implements javax.swing.plaf.UIResource @@ -164,17 +163,17 @@ public class DefaultTableCellRenderer extends JLabel super.setForeground(table.getForeground()); } + Border b = null; if (hasFocus) { - setBorder(UIManager.getBorder("Table.focusCellHighlightBorder")); - if (table.isCellEditable(row, column)) - { - super.setBackground(UIManager.getColor("Table.focusCellBackground")); - super.setForeground(UIManager.getColor("Table.focusCellForeground")); - } + if (isSelected) + b = UIManager.getBorder("Table.focusSelectedCellHighlightBorder"); + if (b == null) + b = UIManager.getBorder("Table.focusCellHighlightBorder"); } else - setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + b = noFocusBorder; + setBorder(b); setFont(table.getFont()); diff --git a/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java b/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java index 10871770de5..24ac8fc9c39 100644 --- a/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java +++ b/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java @@ -1,5 +1,5 @@ /* DefaultTableColumnModel.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. @@ -46,6 +46,7 @@ import java.util.EventListener; import java.util.Vector; import javax.swing.DefaultListSelectionModel; +import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.event.ChangeEvent; import javax.swing.event.EventListenerList; @@ -55,9 +56,11 @@ import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; /** - * DefaultTableColumnModel + * A model that stores information about the columns used in a {@link JTable}. + * + * @see JTable#setColumnModel(TableColumnModel) + * * @author Andrew Selkirk - * @version 1.0 */ public class DefaultTableColumnModel implements TableColumnModel, PropertyChangeListener, ListSelectionListener, @@ -66,88 +69,116 @@ public class DefaultTableColumnModel private static final long serialVersionUID = 6580012493508960512L; /** - * Columns that this model keeps track of. + * Storage for the table columns. */ protected Vector tableColumns; /** - * Selection Model that keeps track of columns selection + * A selection model that keeps track of column selections. */ protected ListSelectionModel selectionModel; /** - * Space between two columns. By default it is set to 1 + * The space between the columns (the default value is <code>1</code>). */ protected int columnMargin; /** - * listenerList keeps track of all listeners registered with this model + * Storage for the listeners registered with the model. */ protected EventListenerList listenerList = new EventListenerList(); /** - * changeEvent is fired when change occurs in one of the columns properties + * A change event used when notifying listeners of a change to the + * <code>columnMargin</code> field. This single event is reused for all + * notifications. */ + // FIXME: use lazy instantiation protected transient ChangeEvent changeEvent = new ChangeEvent(this); /** - * Indicates whether columns can be selected + * A flag that indicates whether or not columns can be selected. */ protected boolean columnSelectionAllowed; /** - * Total width of all the columns in this model + * The total width of all the columns in this model. */ protected int totalColumnWidth; /** - * Constructor DefaultTableColumnModel + * Creates a new table column model with zero columns. A default column + * selection model is created by calling {@link #createSelectionModel()}. + * The default value for <code>columnMargin</code> is <code>1</code> and + * the default value for <code>columnSelectionAllowed</code> is + * <code>false</code>. */ public DefaultTableColumnModel() { tableColumns = new Vector(); - setSelectionModel(createSelectionModel()); + selectionModel = createSelectionModel(); + selectionModel.addListSelectionListener(this); columnMargin = 1; columnSelectionAllowed = false; } /** - * addColumn adds column to the model. This method fires ColumnAdded - * event to model's registered TableColumnModelListeners. + * Adds a column to the model then calls + * {@link #fireColumnAdded(TableColumnModelEvent)} to notify the registered + * listeners. The model registers itself with the column as a + * {@link PropertyChangeListener} so that changes to the column width will + * invalidate the cached {@link #totalColumnWidth} value. * - * @param col column to add + * @param column the column (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>column</code> is + * <code>null</code>. + * + * @see #removeColumn(TableColumn) */ - public void addColumn(TableColumn col) + public void addColumn(TableColumn column) { - if (col == null) + if (column == null) throw new IllegalArgumentException("Null 'col' argument."); - tableColumns.add(col); + tableColumns.add(column); + column.addPropertyChangeListener(this); invalidateWidthCache(); - fireColumnAdded(new TableColumnModelEvent(this, 0, tableColumns.size() - 1)); + fireColumnAdded(new TableColumnModelEvent(this, 0, + tableColumns.size() - 1)); } /** - * removeColumn removes table column from the model. This method fires - * ColumnRemoved event to model's registered TableColumnModelListeners. + * Removes a column from the model then calls + * {@link #fireColumnRemoved(TableColumnModelEvent)} to notify the registered + * listeners. If the specified column does not belong to the model, or is + * <code>null</code>, this method does nothing. * - * @param col column to be removed + * @param column the column to be removed (<code>null</code> permitted). + * + * @see #addColumn(TableColumn) */ - public void removeColumn(TableColumn col) + public void removeColumn(TableColumn column) { - int index = this.tableColumns.indexOf(col); + int index = this.tableColumns.indexOf(column); if (index < 0) return; + tableColumns.remove(column); fireColumnRemoved(new TableColumnModelEvent(this, index, 0)); - tableColumns.remove(col); + column.removePropertyChangeListener(this); invalidateWidthCache(); } /** - * moveColumn moves column at index i to index j. This method fires - * ColumnMoved event to model's registered TableColumnModelListeners. + * Moves the column at index i to the position specified by index j, then + * calls {@link #fireColumnMoved(TableColumnModelEvent)} to notify registered + * listeners. * - * @param i index of the column that will be moved - * @param j index of column's new location + * @param i index of the column that will be moved. + * @param j index of the column's new location. + * + * @throws IllegalArgumentException if <code>i</code> or <code>j</code> are + * outside the range <code>0</code> to <code>N-1</code>, where + * <code>N</code> is the column count. */ public void moveColumn(int i, int j) { @@ -158,22 +189,27 @@ public class DefaultTableColumnModel throw new IllegalArgumentException("Index 'j' out of range."); Object column = tableColumns.remove(i); tableColumns.add(j, column); - fireColumnAdded(new TableColumnModelEvent(this, i, j)); + fireColumnMoved(new TableColumnModelEvent(this, i, j)); } /** - * setColumnMargin sets margin of the columns. - * @param m new column margin + * Sets the column margin then calls {@link #fireColumnMarginChanged()} to + * notify the registered listeners. + * + * @param margin the column margin. + * + * @see #getColumnMargin() */ - public void setColumnMargin(int m) + public void setColumnMargin(int margin) { - columnMargin = m; + columnMargin = margin; fireColumnMarginChanged(); } /** - * getColumnCount returns number of columns in the model - * @return int number of columns in the model + * Returns the number of columns in the model. + * + * @return The column count. */ public int getColumnCount() { @@ -181,8 +217,9 @@ public class DefaultTableColumnModel } /** - * getColumns - * @return Enumeration + * Returns an enumeration of the columns in the model. + * + * @return An enumeration of the columns in the model. */ public Enumeration getColumns() { @@ -214,18 +251,28 @@ public class DefaultTableColumnModel } /** - * getColumn returns column at the specified index - * @param i index of the column - * @return TableColumn column at the specified index + * Returns the column at the specified index. + * + * @param columnIndex the column index (in the range from <code>0</code> to + * <code>N-1</code>, where <code>N</code> is the number of columns in + * the model). + * + * @return The column at the specified index. + * + * @throws ArrayIndexOutOfBoundsException if <code>i</code> is not within + * the specified range. */ - public TableColumn getColumn(int i) + public TableColumn getColumn(int columnIndex) { - return (TableColumn) tableColumns.get(i); + return (TableColumn) tableColumns.get(columnIndex); } /** - * getColumnMargin returns column margin - * @return int column margin + * Returns the column margin. + * + * @return The column margin. + * + * @see #setColumnMargin(int) */ public int getColumnMargin() { @@ -233,16 +280,26 @@ public class DefaultTableColumnModel } /** - * getColumnIndexAtX returns column that contains specified x-coordinate. - * @param x x-coordinate that column should contain - * @return int index of the column that contains specified x-coordinate relative - * to this column model + * Returns the index of the column that contains the specified x-coordinate. + * This method assumes that: + * <ul> + * <li>column zero begins at position zero;</li> + * <li>all columns appear in order;</li> + * <li>individual column widths are taken into account, but the column margin + * is ignored.</li> + * </ul> + * If no column contains the specified position, this method returns + * <code>-1</code>. + * + * @param x the x-position. + * + * @return The column index, or <code>-1</code>. */ public int getColumnIndexAtX(int x) { for (int i = 0; i < tableColumns.size(); ++i) { - int w = ((TableColumn)tableColumns.get(i)).getWidth(); + int w = ((TableColumn) tableColumns.get(i)).getWidth(); if (0 <= x && x < w) return i; else @@ -252,10 +309,10 @@ public class DefaultTableColumnModel } /** - * getTotalColumnWidth returns total width of all the columns including - * column's margins. + * Returns total width of all the columns in the model, ignoring the + * {@link #columnMargin}. * - * @return total width of all the columns + * @return The total width of all the columns. */ public int getTotalColumnWidth() { @@ -265,24 +322,32 @@ public class DefaultTableColumnModel } /** - * setSelectionModel sets selection model that will be used by this ColumnTableModel - * to keep track of currently selected columns + * Sets the selection model that will be used to keep track of the selected + * columns. * - * @param model new selection model - * @exception IllegalArgumentException if model is null + * @param model the selection model (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>model</code> is + * <code>null</code>. + * + * @see #getSelectionModel() */ public void setSelectionModel(ListSelectionModel model) { if (model == null) throw new IllegalArgumentException(); + selectionModel.removeListSelectionListener(this); selectionModel = model; selectionModel.addListSelectionListener(this); } /** - * getSelectionModel returns selection model - * @return ListSelectionModel selection model + * Returns the selection model used to track table column selections. + * + * @return The selection model. + * + * @see #setSelectionModel(ListSelectionModel) */ public ListSelectionModel getSelectionModel() { @@ -290,10 +355,11 @@ public class DefaultTableColumnModel } /** - * setColumnSelectionAllowed sets whether column selection is allowed - * or not. + * Sets the flag that indicates whether or not column selection is allowed. * - * @param flag true if column selection is allowed and false otherwise + * @param flag the new flag value. + * + * @see #getColumnSelectionAllowed() */ public void setColumnSelectionAllowed(boolean flag) { @@ -301,10 +367,12 @@ public class DefaultTableColumnModel } /** - * getColumnSelectionAllowed indicates whether column selection is - * allowed or not. + * Returns <code>true</code> if column selection is allowed, and + * <code>false</code> if column selection is not allowed. * - * @return boolean true if column selection is allowed and false otherwise. + * @return A boolean. + * + * @see #setColumnSelectionAllowed(boolean) */ public boolean getColumnSelectionAllowed() { @@ -312,10 +380,9 @@ public class DefaultTableColumnModel } /** - * getSelectedColumns returns array containing indexes of currently - * selected columns + * Returns an array containing the indices of the selected columns. * - * @return int[] array containing indexes of currently selected columns + * @return An array containing the indices of the selected columns. */ public int[] getSelectedColumns() { @@ -356,8 +423,11 @@ public class DefaultTableColumnModel } /** - * getSelectedColumnCount returns number of currently selected columns - * @return int number of currently selected columns + * Returns the number of selected columns in the model. + * + * @return The selected column count. + * + * @see #getSelectionModel() */ public int getSelectedColumnCount() { @@ -395,10 +465,10 @@ public class DefaultTableColumnModel } /** - * addColumnModelListener adds specified listener to the model's - * listener list + * Registers a listener with the model, so that it will receive + * {@link TableColumnModelEvent} notifications. * - * @param listener the listener to add + * @param listener the listener (<code>null</code> ignored). */ public void addColumnModelListener(TableColumnModelListener listener) { @@ -406,10 +476,10 @@ public class DefaultTableColumnModel } /** - * removeColumnModelListener removes specified listener from the model's - * listener list. + * Deregisters a listener so that it no longer receives notification of + * changes to this model. * - * @param listener the listener to remove + * @param listener the listener to remove */ public void removeColumnModelListener(TableColumnModelListener listener) { @@ -417,6 +487,13 @@ public class DefaultTableColumnModel } /** + * Returns an array containing the listeners that are registered with the + * model. If there are no listeners, an empty array is returned. + * + * @return An array containing the listeners that are registered with the + * model. + * + * @see #addColumnModelListener(TableColumnModelListener) * @since 1.4 */ public TableColumnModelListener[] getColumnModelListeners() @@ -426,78 +503,97 @@ public class DefaultTableColumnModel } /** - * fireColumnAdded fires TableColumnModelEvent to registered - * TableColumnModelListeners to indicate that column was added - * - * @param e TableColumnModelEvent + * Sends the specified {@link TableColumnModelEvent} to all registered + * listeners, to indicate that a column has been added to the model. The + * event's <code>toIndex</code> attribute should contain the index of the + * added column. + * + * @param e the event. + * + * @see #addColumn(TableColumn) */ protected void fireColumnAdded(TableColumnModelEvent e) { TableColumnModelListener[] listeners = getColumnModelListeners(); - for (int i=0; i< listeners.length; i++) + for (int i = 0; i < listeners.length; i++) listeners[i].columnAdded(e); } /** - * fireColumnAdded fires TableColumnModelEvent to registered - * TableColumnModelListeners to indicate that column was removed - * - * @param e TableColumnModelEvent + * Sends the specified {@link TableColumnModelEvent} to all registered + * listeners, to indicate that a column has been removed from the model. The + * event's <code>fromIndex</code> attribute should contain the index of the + * removed column. + * + * @param e the event. + * + * @see #removeColumn(TableColumn) */ protected void fireColumnRemoved(TableColumnModelEvent e) { TableColumnModelListener[] listeners = getColumnModelListeners(); - for (int i=0; i< listeners.length; i++) + for (int i = 0; i < listeners.length; i++) listeners[i].columnRemoved(e); } /** - * fireColumnAdded fires TableColumnModelEvent to registered - * TableColumnModelListeners to indicate that column was moved - * - * @param e TableColumnModelEvent + * Sends the specified {@link TableColumnModelEvent} to all registered + * listeners, to indicate that a column in the model has been moved. The + * event's <code>fromIndex</code> attribute should contain the old column + * index, and the <code>toIndex</code> attribute should contain the new + * column index. + * + * @param e the event. + * + * @see #moveColumn(int, int) */ protected void fireColumnMoved(TableColumnModelEvent e) { TableColumnModelListener[] listeners = getColumnModelListeners(); - for (int i=0; i< listeners.length; i++) + for (int i = 0; i < listeners.length; i++) listeners[i].columnMoved(e); } /** - * fireColumnSelectionChanged fires TableColumnModelEvent to model's - * registered TableColumnModelListeners to indicate that different column - * was selected. + * Sends the specified {@link ListSelectionEvent} to all registered listeners, + * to indicate that the column selections have changed. * - * @param evt ListSelectionEvent + * @param e the event. + * + * @see #valueChanged(ListSelectionEvent) */ - protected void fireColumnSelectionChanged(ListSelectionEvent evt) + protected void fireColumnSelectionChanged(ListSelectionEvent e) { EventListener [] listeners = getListeners(TableColumnModelListener.class); for (int i = 0; i < listeners.length; ++i) - ((TableColumnModelListener)listeners[i]).columnSelectionChanged(evt); + ((TableColumnModelListener) listeners[i]).columnSelectionChanged(e); } /** - * fireColumnMarginChanged fires TableColumnModelEvent to model's - * registered TableColumnModelListeners to indicate that column margin - * was changed. + * Sends a {@link ChangeEvent} to the model's registered listeners to + * indicate that the column margin was changed. + * + * @see #setColumnMargin(int) */ protected void fireColumnMarginChanged() { EventListener [] listeners = getListeners(TableColumnModelListener.class); for (int i = 0; i < listeners.length; ++i) - ((TableColumnModelListener)listeners[i]).columnMarginChanged(changeEvent); + ((TableColumnModelListener) listeners[i]).columnMarginChanged(changeEvent); } /** - * getListeners returns currently registered listeners with this model. - * @param listenerType type of listeners to return + * Returns an array containing the listeners (of the specified type) that + * are registered with this model. + * + * @param listenerType the listener type (must indicate a subclass of + * {@link EventListener}, <code>null</code> not permitted). * - * @return EventListener[] array of model's listeners of the specified type + * @return An array containing the listeners (of the specified type) that + * are registered with this model. */ public EventListener[] getListeners(Class listenerType) { @@ -505,20 +601,26 @@ public class DefaultTableColumnModel } /** - * propertyChange handles changes occuring in the properties of the - * model's columns. + * Receives notification of property changes for the columns in the model. + * If the <code>width</code> property for any column changes, we invalidate + * the {@link #totalColumnWidth} value here. * - * @param evt PropertyChangeEvent + * @param event the event. */ - public void propertyChange(PropertyChangeEvent evt) + public void propertyChange(PropertyChangeEvent event) { - if (evt.getPropertyName().equals(TableColumn.COLUMN_WIDTH_PROPERTY)) - invalidateWidthCache(); + if (event.getPropertyName().equals("width")) + invalidateWidthCache(); } /** - * valueChanged handles changes in the selectionModel. - * @param e ListSelectionEvent + * Receives notification of the change to the list selection model, and + * responds by calling + * {@link #fireColumnSelectionChanged(ListSelectionEvent)}. + * + * @param e the list selection event. + * + * @see #getSelectionModel() */ public void valueChanged(ListSelectionEvent e) { @@ -526,10 +628,11 @@ public class DefaultTableColumnModel } /** - * createSelectionModel creates selection model that will keep track - * of currently selected column(s) + * Creates a default selection model to track the currently selected + * column(s). This method is called by the constructor and returns a new + * instance of {@link DefaultListSelectionModel}. * - * @return ListSelectionModel selection model of the columns + * @return A new default column selection model. */ protected ListSelectionModel createSelectionModel() { @@ -537,9 +640,10 @@ public class DefaultTableColumnModel } /** - * recalcWidthCache calculates total width of the columns. - * If the current cache of the total width is in invalidated state, - * then width is recalculated. Otherwise nothing is done. + * Recalculates the total width of the columns, if the cached value is + * <code>-1</code>. Otherwise this method does nothing. + * + * @see #getTotalColumnWidth() */ protected void recalcWidthCache() { @@ -548,13 +652,15 @@ public class DefaultTableColumnModel totalColumnWidth = 0; for (int i = 0; i < tableColumns.size(); ++i) { - totalColumnWidth += ((TableColumn)tableColumns.get(i)).getWidth(); + totalColumnWidth += ((TableColumn) tableColumns.get(i)).getWidth(); } } } /** - * invalidateWidthCache + * Sets the {@link #totalColumnWidth} field to <code>-1</code>. + * + * @see #recalcWidthCache() */ private void invalidateWidthCache() { diff --git a/libjava/classpath/javax/swing/table/DefaultTableModel.java b/libjava/classpath/javax/swing/table/DefaultTableModel.java index c281caa0791..09be2f75239 100644 --- a/libjava/classpath/javax/swing/table/DefaultTableModel.java +++ b/libjava/classpath/javax/swing/table/DefaultTableModel.java @@ -294,12 +294,7 @@ public class DefaultTableModel extends AbstractTableModel else { int rowsToAdd = rowCount - existingRowCount; - for (int i = 0; i < rowsToAdd; i++) - { - Vector tmp = new Vector(); - tmp.setSize(columnIdentifiers.size()); - dataVector.add(tmp); - } + addExtraRows(rowsToAdd, columnIdentifiers.size()); fireTableRowsInserted(existingRowCount,rowCount-1); } } @@ -366,12 +361,7 @@ public class DefaultTableModel extends AbstractTableModel if (columnData.length > dataVector.size()) { int rowsToAdd = columnData.length - dataVector.size(); - for (int i = 0; i < rowsToAdd; i++) - { - Vector tmp = new Vector(); - tmp.setSize(columnIdentifiers.size()); - dataVector.add(tmp); - } + addExtraRows(rowsToAdd, columnIdentifiers.size()); } else if (columnData.length < dataVector.size()) { @@ -502,7 +492,8 @@ public class DefaultTableModel extends AbstractTableModel else { if (column < getColumnCount()) - { + { + checkSize(); Object id = columnIdentifiers.get(column); if (id != null) result = id.toString(); @@ -588,4 +579,41 @@ public class DefaultTableModel extends AbstractTableModel vector.add(convertToVector(data[i])); return vector; } + + /** + * This method adds some rows to <code>dataVector</code>. + * + * @param rowsToAdd number of rows to add + * @param nbColumns size of the added rows + */ + private void addExtraRows(int rowsToAdd, int nbColumns) + { + for (int i = 0; i < rowsToAdd; i++) + { + Vector tmp = new Vector(); + tmp.setSize(columnIdentifiers.size()); + dataVector.add(tmp); + } + } + + /** + * Checks the real columns/rows sizes against the ones returned by + * <code>getColumnCount()</code> and <code>getRowCount()</code>. + * If the supposed one are bigger, then we grow <code>columIdentifiers</code> + * and <code>dataVector</code> to their expected size. + */ + private void checkSize() + { + int columnCount = getColumnCount(); + int rowCount = getRowCount(); + + if (columnCount > columnIdentifiers.size()) + columnIdentifiers.setSize(columnCount); + + if (rowCount > dataVector.size()) + { + int rowsToAdd = rowCount - dataVector.size(); + addExtraRows(rowsToAdd, columnCount); + } + } } diff --git a/libjava/classpath/javax/swing/table/JTableHeader.java b/libjava/classpath/javax/swing/table/JTableHeader.java index 4e8dcd7b7ef..f7c1e1cd589 100644 --- a/libjava/classpath/javax/swing/table/JTableHeader.java +++ b/libjava/classpath/javax/swing/table/JTableHeader.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.table; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; @@ -80,232 +82,278 @@ public class JTableHeader extends JComponent protected class AccessibleJTableHeaderEntry extends AccessibleContext implements Accessible, AccessibleComponent { - public AccessibleJTableHeaderEntry(int c, JTableHeader p, JTable t) + public AccessibleJTableHeaderEntry(int c, JTableHeader p, JTable t) + throws NotImplementedException { throw new Error("not implemented"); } public void addFocusListener(FocusListener l) + throws NotImplementedException { throw new Error("not implemented"); } public void addPropertyChangeListener(PropertyChangeListener l) + throws NotImplementedException { throw new Error("not implemented"); } public boolean contains(Point p) + throws NotImplementedException { throw new Error("not implemented"); } public AccessibleAction getAccessibleAction() + throws NotImplementedException { throw new Error("not implemented"); } public Accessible getAccessibleAt(Point p) + throws NotImplementedException { throw new Error("not implemented"); } public Accessible getAccessibleChild(int i) + throws NotImplementedException { throw new Error("not implemented"); } public int getAccessibleChildrenCount() + throws NotImplementedException { throw new Error("not implemented"); } public AccessibleComponent getAccessibleComponent() + throws NotImplementedException { throw new Error("not implemented"); } public AccessibleContext getAccessibleContext() + throws NotImplementedException { throw new Error("not implemented"); } public String getAccessibleDescription() + throws NotImplementedException { throw new Error("not implemented"); } public int getAccessibleIndexInParent() + throws NotImplementedException { throw new Error("not implemented"); } public String getAccessibleName() + throws NotImplementedException { throw new Error("not implemented"); } public AccessibleRole getAccessibleRole() + throws NotImplementedException { throw new Error("not implemented"); } public AccessibleSelection getAccessibleSelection() + throws NotImplementedException { throw new Error("not implemented"); } public AccessibleStateSet getAccessibleStateSet() + throws NotImplementedException { throw new Error("not implemented"); } public AccessibleText getAccessibleText() + throws NotImplementedException { throw new Error("not implemented"); } public AccessibleValue getAccessibleValue() + throws NotImplementedException { throw new Error("not implemented"); } public Color getBackground() + throws NotImplementedException { throw new Error("not implemented"); } public Rectangle getBounds() + throws NotImplementedException { throw new Error("not implemented"); } public Cursor getCursor() + throws NotImplementedException { throw new Error("not implemented"); } public Font getFont() + throws NotImplementedException { throw new Error("not implemented"); } public FontMetrics getFontMetrics(Font f) + throws NotImplementedException { throw new Error("not implemented"); } public Color getForeground() + throws NotImplementedException { throw new Error("not implemented"); } public Locale getLocale() + throws NotImplementedException { throw new Error("not implemented"); } public Point getLocation() + throws NotImplementedException { throw new Error("not implemented"); } public Point getLocationOnScreen() + throws NotImplementedException { throw new Error("not implemented"); } public Dimension getSize() + throws NotImplementedException { throw new Error("not implemented"); } public boolean isEnabled() + throws NotImplementedException { throw new Error("not implemented"); } public boolean isFocusTraversable() + throws NotImplementedException { throw new Error("not implemented"); } public boolean isShowing() + throws NotImplementedException { throw new Error("not implemented"); } public boolean isVisible() + throws NotImplementedException { throw new Error("not implemented"); } public void removeFocusListener(FocusListener l) + throws NotImplementedException { throw new Error("not implemented"); } public void removePropertyChangeListener(PropertyChangeListener l) + throws NotImplementedException { throw new Error("not implemented"); } public void requestFocus() + throws NotImplementedException { throw new Error("not implemented"); } public void setAccessibleDescription(String s) + throws NotImplementedException { throw new Error("not implemented"); } public void setAccessibleName(String s) + throws NotImplementedException { throw new Error("not implemented"); } public void setBackground(Color c) + throws NotImplementedException { throw new Error("not implemented"); } public void setBounds(Rectangle r) + throws NotImplementedException { throw new Error("not implemented"); } public void setCursor(Cursor c) + throws NotImplementedException { throw new Error("not implemented"); } public void setEnabled(boolean b) + throws NotImplementedException { throw new Error("not implemented"); } public void setFont(Font f) + throws NotImplementedException { throw new Error("not implemented"); } public void setForeground(Color c) + throws NotImplementedException { throw new Error("not implemented"); } public void setLocation(Point p) + throws NotImplementedException { throw new Error("not implemented"); } public void setSize(Dimension d) + throws NotImplementedException { throw new Error("not implemented"); } public void setVisible(boolean b) + throws NotImplementedException { throw new Error("not implemented"); } diff --git a/libjava/classpath/javax/swing/table/TableColumn.java b/libjava/classpath/javax/swing/table/TableColumn.java index 9f06c5b7fcc..fbb877d977d 100644 --- a/libjava/classpath/javax/swing/table/TableColumn.java +++ b/libjava/classpath/javax/swing/table/TableColumn.java @@ -1,5 +1,5 @@ /* TableColumn.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.table; +import java.awt.Component; +import java.awt.Dimension; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.Serializable; @@ -49,7 +51,6 @@ import javax.swing.event.SwingPropertyChangeSupport; * width, minimum width, preferred width and maximum width. * * @author Andrew Selkirk - * @version 1.0 */ public class TableColumn implements Serializable @@ -57,8 +58,9 @@ public class TableColumn static final long serialVersionUID = -6113660025878112608L; /** - * The name for the <code>columnWidth</code> property. Note that the typo - * in the name value is deliberate, to match the specification. + * The name for the <code>columnWidth</code> property (this field is + * obsolete and no longer used). Note also that the typo in the value + * string is deliberate, to match the specification. */ public static final String COLUMN_WIDTH_PROPERTY = "columWidth"; @@ -88,47 +90,48 @@ public class TableColumn protected Object identifier; /** - * The width. + * The current width for the column. */ protected int width; /** - * The minimum width. + * The minimum width for the column. */ protected int minWidth = 15; /** - * The preferred width. + * The preferred width for the column. */ private int preferredWidth; /** - * The maximum width. + * The maximum width for the column. */ protected int maxWidth = Integer.MAX_VALUE; /** - * headerRenderer + * The renderer for the column header. */ protected TableCellRenderer headerRenderer; /** - * The header value. + * The value for the column header. */ protected Object headerValue; /** - * cellRenderer + * The renderer for the regular cells in this column. */ protected TableCellRenderer cellRenderer; /** - * cellEditor + * An editor for the regular cells in this column. */ protected TableCellEditor cellEditor; /** - * isResizable + * A flag that determines whether or not the column is resizable (the default + * is <code>true</code>). */ protected boolean isResizable = true; @@ -140,7 +143,7 @@ public class TableColumn protected transient int resizedPostingDisableCount; /** - * changeSupport + * A storage and notification mechanism for property change listeners. */ private SwingPropertyChangeSupport changeSupport = new SwingPropertyChangeSupport(this); @@ -200,60 +203,31 @@ public class TableColumn } /** - * firePropertyChange - * - * @param property the name of the property - * @param oldValue the old value - * @param newValue the new value - */ - private void firePropertyChange(String property, Object oldValue, - Object newValue) - { - changeSupport.firePropertyChange(property, oldValue, newValue); - } - - /** - * firePropertyChange - * - * @param property the name of the property - * @param oldValue the old value - * @param newValue the new value - */ - private void firePropertyChange(String property, int oldValue, int newValue) - { - firePropertyChange(property, new Integer(oldValue), new Integer(newValue)); - } - - /** - * firePropertyChange - * - * @param property the name of the property - * @param oldValue the old value - * @param newValue the new value - */ - private void firePropertyChange(String property, boolean oldValue, - boolean newValue) - { - firePropertyChange(property, Boolean.valueOf(oldValue), - Boolean.valueOf(newValue)); - } - - /** * Sets the index of the column in the related {@link TableModel} that this - * <code>TableColumn</code> maps to. + * <code>TableColumn</code> maps to, and sends a {@link PropertyChangeEvent} + * (with the property name 'modelIndex') to all registered listeners. * * @param modelIndex the column index in the model. + * + * @see #getModelIndex() */ public void setModelIndex(int modelIndex) { - this.modelIndex = modelIndex; + if (this.modelIndex != modelIndex) + { + int oldValue = this.modelIndex; + this.modelIndex = modelIndex; + changeSupport.firePropertyChange("modelIndex", oldValue, modelIndex); + } } /** * Returns the index of the column in the related {@link TableModel} that * this <code>TableColumn</code> maps to. * - * @return the model index + * @return the model index. + * + * @see #setModelIndex(int) */ public int getModelIndex() { @@ -261,13 +235,21 @@ public class TableColumn } /** - * Sets the identifier for the column. + * Sets the identifier for the column and sends a {@link PropertyChangeEvent} + * (with the property name 'identifier') to all registered listeners. + * + * @param identifier the identifier (<code>null</code> permitted). * - * @param identifier the identifier + * @see #getIdentifier() */ public void setIdentifier(Object identifier) { - this.identifier = identifier; + if (this.identifier != identifier) + { + Object oldValue = this.identifier; + this.identifier = identifier; + changeSupport.firePropertyChange("identifier", oldValue, identifier); + } } /** @@ -285,11 +267,12 @@ public class TableColumn } /** - * Sets the header value and sends a {@link PropertyChangeEvent} to all - * registered listeners. The header value property uses the name - * {@link #HEADER_VALUE_PROPERTY}. + * Sets the header value and sends a {@link PropertyChangeEvent} (with the + * property name {@link #HEADER_VALUE_PROPERTY}) to all registered listeners. * - * @param headerValue the value of the header + * @param headerValue the value of the header (<code>null</code> permitted). + * + * @see #getHeaderValue() */ public void setHeaderValue(Object headerValue) { @@ -298,13 +281,16 @@ public class TableColumn Object oldValue = this.headerValue; this.headerValue = headerValue; - firePropertyChange(HEADER_VALUE_PROPERTY, oldValue, headerValue); + changeSupport.firePropertyChange(HEADER_VALUE_PROPERTY, oldValue, + headerValue); } /** * Returns the header value. * - * @return the value of the header + * @return the value of the header. + * + * @see #getHeaderValue() */ public Object getHeaderValue() { @@ -312,9 +298,13 @@ public class TableColumn } /** - * setHeaderRenderer + * Sets the renderer for the column header and sends a + * {@link PropertyChangeEvent} (with the property name + * {@link #HEADER_RENDERER_PROPERTY}) to all registered listeners. + * + * @param renderer the header renderer (<code>null</code> permitted). * - * @param renderer the renderer to use + * @see #getHeaderRenderer() */ public void setHeaderRenderer(TableCellRenderer renderer) { @@ -323,13 +313,16 @@ public class TableColumn TableCellRenderer oldRenderer = headerRenderer; headerRenderer = renderer; - firePropertyChange(HEADER_RENDERER_PROPERTY, - oldRenderer, headerRenderer); + changeSupport.firePropertyChange(HEADER_RENDERER_PROPERTY, oldRenderer, + headerRenderer); } /** - * getHeaderRenderer - * @return TableCellRenderer + * Returns the renderer for the column header. + * + * @return The renderer for the column header (possibly <code>null</code>). + * + * @see #setHeaderRenderer(TableCellRenderer) */ public TableCellRenderer getHeaderRenderer() { @@ -338,9 +331,12 @@ public class TableColumn /** * Sets the renderer for cells in this column and sends a - * {@link PropertyChangeEvent} to all registered listeners. + * {@link PropertyChangeEvent} (with the property name + * {@link #CELL_RENDERER_PROPERTY}) to all registered listeners. * * @param renderer the cell renderer (<code>null</code> permitted). + * + * @see #getCellRenderer() */ public void setCellRenderer(TableCellRenderer renderer) { @@ -349,14 +345,16 @@ public class TableColumn TableCellRenderer oldRenderer = cellRenderer; cellRenderer = renderer; - firePropertyChange(CELL_RENDERER_PROPERTY, - oldRenderer, cellRenderer); + changeSupport.firePropertyChange(CELL_RENDERER_PROPERTY, oldRenderer, + cellRenderer); } /** * Returns the renderer for the table cells in this column. * - * @return The cell renderer. + * @return The cell renderer (possibly <code>null</code>). + * + * @see #setCellRenderer(TableCellRenderer) */ public TableCellRenderer getCellRenderer() { @@ -364,19 +362,30 @@ public class TableColumn } /** - * setCellEditor + * Sets the cell editor for the column and sends a {@link PropertyChangeEvent} + * (with the property name 'cellEditor') to all registered listeners. + * + * @param cellEditor the cell editor (<code>null</code> permitted). * - * @param cellEditor the cell editor + * @see #getCellEditor() */ public void setCellEditor(TableCellEditor cellEditor) { - this.cellEditor = cellEditor; + if (this.cellEditor != cellEditor) + { + TableCellEditor oldValue = this.cellEditor; + this.cellEditor = cellEditor; + changeSupport.firePropertyChange("cellEditor", oldValue, cellEditor); + } } /** - * getCellEditor + * Returns the cell editor for the column (the default value is + * <code>null</code>). + * + * @return The cell editor (possibly <code>null</code>). * - * @return the cell editor + * @see #setCellEditor(TableCellEditor) */ public TableCellEditor getCellEditor() { @@ -384,9 +393,14 @@ public class TableColumn } /** - * setWidth + * Sets the width for the column and sends a {@link PropertyChangeEvent} + * (with the property name 'width') to all registered listeners. If the new + * width falls outside the range getMinWidth() to getMaxWidth() it is + * adjusted to the appropriate boundary value. + * + * @param newWidth the width. * - * @param newWidth the width + * @see #getWidth() */ public void setWidth(int newWidth) { @@ -406,13 +420,15 @@ public class TableColumn // however, tests show that the actual fired property name is 'width' // and even Sun's API docs say that this constant field is obsolete and // not used. - firePropertyChange("width", oldWidth, width); + changeSupport.firePropertyChange("width", oldWidth, width); } /** - * getWidth + * Returns the width for the column (the default value is <code>75</code>). * - * @return int + * @return The width. + * + * @see #setWidth(int) */ public int getWidth() { @@ -420,9 +436,15 @@ public class TableColumn } /** - * setPreferredWidth + * Sets the preferred width for the column and sends a + * {@link PropertyChangeEvent} (with the property name 'preferredWidth') to + * all registered listeners. If necessary, the supplied value will be + * adjusted to fit in the range {@link #getMinWidth()} to + * {@link #getMaxWidth()}. + * + * @param preferredWidth the preferred width. * - * @param preferredWidth the preferred width + * @see #getPreferredWidth() */ public void setPreferredWidth(int preferredWidth) { @@ -435,13 +457,17 @@ public class TableColumn else this.preferredWidth = preferredWidth; - firePropertyChange("preferredWidth", oldPrefWidth, this.preferredWidth); + changeSupport.firePropertyChange("preferredWidth", oldPrefWidth, + this.preferredWidth); } /** - * getPreferredWidth + * Returns the preferred width for the column (the default value is + * <code>75</code>). + * + * @return The preferred width. * - * @return the preferred width + * @see #setPreferredWidth(int) */ public int getPreferredWidth() { @@ -449,22 +475,39 @@ public class TableColumn } /** - * Sets the minimum width for the column and, if necessary, updates the - * <code>width</code> and <code>preferredWidth</code>. + * Sets the minimum width for the column and sends a + * {@link PropertyChangeEvent} (with the property name 'minWidth') to all + * registered listeners. If the current <code>width</code> and/or + * <code>preferredWidth</code> are less than the new minimum width, they are + * adjusted accordingly. * - * @param minWidth the minimum width + * @param minWidth the minimum width (negative values are treated as 0). + * + * @see #getMinWidth() */ public void setMinWidth(int minWidth) { - this.minWidth = minWidth; - setWidth(getWidth()); - setPreferredWidth(getPreferredWidth()); + if (minWidth < 0) + minWidth = 0; + if (this.minWidth != minWidth) + { + if (width < minWidth) + setWidth(minWidth); + if (preferredWidth < minWidth) + setPreferredWidth(minWidth); + int oldValue = this.minWidth; + this.minWidth = minWidth; + changeSupport.firePropertyChange("minWidth", oldValue, minWidth); + } } /** - * Returns the <code>TableColumn</code>'s minimum width. + * Returns the <code>TableColumn</code>'s minimum width (the default value + * is <code>15</code>). * * @return The minimum width. + * + * @see #setMinWidth(int) */ public int getMinWidth() { @@ -472,22 +515,37 @@ public class TableColumn } /** - * Sets the maximum width and, if necessary, updates the <code>width</code> - * and <code>preferredWidth</code>. + * Sets the maximum width for the column and sends a + * {@link PropertyChangeEvent} (with the property name 'maxWidth') to all + * registered listeners. If the current <code>width</code> and/or + * <code>preferredWidth</code> are greater than the new maximum width, they + * are adjusted accordingly. + * + * @param maxWidth the maximum width. * - * @param maxWidth the maximum width + * @see #getMaxWidth() */ public void setMaxWidth(int maxWidth) { - this.maxWidth = maxWidth; - setWidth(getWidth()); - setPreferredWidth(getPreferredWidth()); + if (this.maxWidth != maxWidth) + { + if (width > maxWidth) + setWidth(maxWidth); + if (preferredWidth > maxWidth) + setPreferredWidth(maxWidth); + int oldValue = this.maxWidth; + this.maxWidth = maxWidth; + changeSupport.firePropertyChange("maxWidth", oldValue, maxWidth); + } } /** - * Returns the maximum width. + * Returns the maximum width for the column (the default value is + * {@link Integer#MAX_VALUE}). * - * @return The maximum width. + * @return The maximum width for the column. + * + * @see #setMaxWidth(int) */ public int getMaxWidth() { @@ -495,21 +553,32 @@ public class TableColumn } /** - * setResizable + * Sets the flag that controls whether or not the column is resizable, and + * sends a {@link PropertyChangeEvent} (with the property name 'isResizable') + * to all registered listeners. * * @param isResizable <code>true</code> if this column is resizable, - * <code>false</code> otherwise + * <code>false</code> otherwise. + * + * @see #getResizable() */ public void setResizable(boolean isResizable) { - this.isResizable = isResizable; + if (this.isResizable != isResizable) + { + this.isResizable = isResizable; + changeSupport.firePropertyChange("isResizable", !this.isResizable, + isResizable); + } } /** - * getResizable + * Returns the flag that controls whether or not the column is resizable. * * @return <code>true</code> if this column is resizable, - * <code>false</code> otherwise + * <code>false</code> otherwise. + * + * @see #setResizable(boolean) */ public boolean getResizable() { @@ -517,11 +586,23 @@ public class TableColumn } /** - * sizeWidthToFit + * Sets the minimum, maximum, preferred and current width to match the + * minimum, maximum and preferred width of the header renderer component. + * If there is no header renderer component, this method does nothing. */ public void sizeWidthToFit() { - // TODO + if (headerRenderer == null) + return; + Component c = headerRenderer.getTableCellRendererComponent(null, + getHeaderValue(), false, false, 0, 0); + Dimension min = c.getMinimumSize(); + Dimension max = c.getMaximumSize(); + Dimension pref = c.getPreferredSize(); + setMinWidth(min.width); + setMaxWidth(max.width); + setPreferredWidth(pref.width); + setWidth(pref.width); } /** @@ -543,26 +624,55 @@ public class TableColumn } /** - * Adds a property change listener. + * Adds a listener so that it receives {@link PropertyChangeEvent} + * notifications from this column. The properties defined by the column are: + * <ul> + * <li><code>width</code> - see {@link #setWidth(int)};</li> + * <li><code>preferredWidth</code> - see {@link #setPreferredWidth(int)};</li> + * <li><code>minWidth</code> - see {@link #setMinWidth(int)};</li> + * <li><code>maxWidth</code> - see {@link #setMaxWidth(int)};</li> + * <li><code>modelIndex</code> - see {@link #setModelIndex(int)};</li> + * <li><code>isResizable</code> - see {@link #setResizable(boolean)};</li> + * <li><code>cellRenderer</code> - see + * {@link #setCellRenderer(TableCellRenderer)};</li> + * <li><code>cellEditor</code> - see + * {@link #setCellEditor(TableCellEditor)};</li> + * <li><code>headerRenderer</code> - see + * {@link #setHeaderRenderer(TableCellRenderer)};</li> + * <li><code>headerValue</code> - see {@link #setHeaderValue(Object)};</li> + * <li><code>identifier</code> - see {@link #setIdentifier(Object)}.</li> + * </ul> + * + * @param listener the listener to add (<code>null</code> is ignored). * - * @param listener the listener to add + * @see #removePropertyChangeListener(PropertyChangeListener) */ - public synchronized void addPropertyChangeListener(PropertyChangeListener listener) + public synchronized void addPropertyChangeListener( + PropertyChangeListener listener) { changeSupport.addPropertyChangeListener(listener); } /** - * removePropertyChangeListener - * @param listener the listener to remove + * Removes a listener so that it no longer receives + * {@link PropertyChangeEvent} notifications from this column. If + * <code>listener</code> is not registered with the column, or is + * <code>null</code>, this method does nothing. + * + * @param listener the listener to remove (<code>null</code> is ignored). */ - public synchronized void removePropertyChangeListener(PropertyChangeListener listener) + public synchronized void removePropertyChangeListener( + PropertyChangeListener listener) { changeSupport.removePropertyChangeListener(listener); } /** * Returns the property change listeners for this <code>TableColumn</code>. + * An empty array is returned if there are currently no listeners registered. + * + * @return The property change listeners registered with this column. + * * @since 1.4 */ public PropertyChangeListener[] getPropertyChangeListeners() @@ -571,8 +681,10 @@ public class TableColumn } /** - * createDefaultHeaderRenderer - * @return TableCellRenderer + * Creates and returns a default renderer for the column header (in this case, + * a new instance of {@link DefaultTableCellRenderer}). + * + * @return A default renderer for the column header. */ protected TableCellRenderer createDefaultHeaderRenderer() { diff --git a/libjava/classpath/javax/swing/table/TableColumnModel.java b/libjava/classpath/javax/swing/table/TableColumnModel.java index b006f9ad4bb..986c0253323 100644 --- a/libjava/classpath/javax/swing/table/TableColumnModel.java +++ b/libjava/classpath/javax/swing/table/TableColumnModel.java @@ -1,5 +1,5 @@ /* TableColumnModel.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. @@ -42,6 +42,8 @@ import java.util.Enumeration; import javax.swing.JTable; import javax.swing.ListSelectionModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; /** @@ -50,7 +52,6 @@ import javax.swing.event.TableColumnModelListener; * * @author Andrew Selkirk */ -// FIXME: The API documentation in this class is incomplete. public interface TableColumnModel { /** @@ -80,21 +81,26 @@ public interface TableColumnModel void moveColumn(int columnIndex, int newIndex); /** - * setColumnMargin - * @param margin Margin of column + * Sets the column margin and sends a {@link ChangeEvent} to all registered + * {@link TableColumnModelListener}s registered with the model. + * + * @param margin the column margin. + * + * @see #getColumnMargin() */ void setColumnMargin(int margin); /** * Returns the number of columns in the model. * - * @return The column count + * @return The column count. */ int getColumnCount(); /** - * getColumns - * @return Enumeration of columns + * Returns an enumeration of the columns in the model. + * + * @return An enumeration of the columns in the model. */ Enumeration getColumns(); @@ -123,30 +129,53 @@ public interface TableColumnModel * Returns the column margin. * * @return The column margin. + * + * @see #setColumnMargin(int) */ int getColumnMargin(); /** - * getColumnIndexAtX - * @return Column index as position x + * Returns the index of the column that contains the specified x-coordinate, + * assuming that: + * <ul> + * <li>column zero begins at position zero;</li> + * <li>all columns appear in order;</li> + * <li>individual column widths are taken into account, but the column margin + * is ignored.</li> + * </ul> + * If no column contains the specified position, this method returns + * <code>-1</code>. + * + * @param xPosition the x-position. + * + * @return The column index, or <code>-1</code>. */ int getColumnIndexAtX(int xPosition); /** - * getTotalColumnWidth - * @return Total column width + * Returns total width of all the columns in the model, ignoring the + * column margin (see {@link #getColumnMargin()}). + * + * @return The total width of all the columns. */ int getTotalColumnWidth(); /** - * setColumnSelectionAllowed - * @param value Set column selection + * Sets the flag that indicates whether or not column selection is allowed. + * + * @param allowed the new flag value. + * + * @see #getColumnSelectionAllowed() */ - void setColumnSelectionAllowed(boolean value); + void setColumnSelectionAllowed(boolean allowed); /** - * getColumnSelectionAllowed - * @return true if column selection allowed, false otherwise + * Returns <code>true</code> if column selection is allowed, and + * <code>false</code> if column selection is not allowed. + * + * @return A boolean. + * + * @see #setColumnSelectionAllowed(boolean) */ boolean getColumnSelectionAllowed(); @@ -157,31 +186,47 @@ public interface TableColumnModel int[] getSelectedColumns(); /** - * getSelectedColumnCount - * @return Count of selected columns + * Returns the number of selected columns in the model. + * + * @return The selected column count. + * + * @see #getSelectionModel() */ int getSelectedColumnCount(); /** - * setSelectionModel - * @param model ListSelectionModel + * Sets the selection model that will be used to keep track of the selected + * columns. + * + * @param model the selection model (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>model</code> is + * <code>null</code>. */ void setSelectionModel(ListSelectionModel model); /** - * getSelectionModel + * Returns the selection model used to track table column selections. + * + * @return The selection model. + * + * @see #setSelectionModel(ListSelectionModel) */ ListSelectionModel getSelectionModel(); /** - * addColumnModelListener - * @param listener TableColumnModelListener + * Registers a listener with the model, so that it will receive + * {@link TableColumnModelEvent} notifications. + * + * @param listener the listener (<code>null</code> ignored). */ void addColumnModelListener(TableColumnModelListener listener); /** - * removeColumnModelListener - * @param listener TableColumnModelListener + * Deregisters a listener, so that it will no longer receive + * {@link TableColumnModelEvent} notifications. + * + * @param listener the listener. */ void removeColumnModelListener(TableColumnModelListener listener); } diff --git a/libjava/classpath/javax/swing/text/AbstractDocument.java b/libjava/classpath/javax/swing/text/AbstractDocument.java index a3e8c463bd3..1ef81732fed 100644 --- a/libjava/classpath/javax/swing/text/AbstractDocument.java +++ b/libjava/classpath/javax/swing/text/AbstractDocument.java @@ -51,6 +51,7 @@ import javax.swing.event.DocumentListener; import javax.swing.event.EventListenerList; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; +import javax.swing.text.DocumentFilter; import javax.swing.tree.TreeNode; import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.CompoundEdit; @@ -148,6 +149,11 @@ public abstract class AbstractDocument implements Document, Serializable */ Object documentCV = new Object(); + /** An instance of a DocumentFilter.FilterBypass which allows calling + * the insert, remove and replace method without checking for an installed + * document filter. + */ + DocumentFilter.FilterBypass bypass; /** * Creates a new <code>AbstractDocument</code> with the specified @@ -180,6 +186,19 @@ public abstract class AbstractDocument implements Document, Serializable content = doc; context = ctx; } + + /** Returns the DocumentFilter.FilterBypass instance for this + * document and create it if it does not exist yet. + * + * @return This document's DocumentFilter.FilterBypass instance. + */ + private DocumentFilter.FilterBypass getBypass() + { + if (bypass == null) + bypass = new Bypass(); + + return bypass; + } /** * Returns the paragraph {@link Element} that holds the specified position. @@ -329,7 +348,7 @@ public abstract class AbstractDocument implements Document, Serializable * * @return the {@link AttributeContext} used in this <code>Document</code> */ - protected AttributeContext getAttributeContext() + protected final AttributeContext getAttributeContext() { return context; } @@ -366,7 +385,7 @@ public abstract class AbstractDocument implements Document, Serializable * @return the thread that currently modifies this <code>Document</code> * if there is one, otherwise <code>null</code> */ - protected Thread getCurrentWriter() + protected final Thread getCurrentWriter() { return currentWriter; } @@ -392,7 +411,7 @@ public abstract class AbstractDocument implements Document, Serializable * @return a {@link Position} which will always mark the end of the * <code>Document</code> */ - public Position getEndPosition() + public final Position getEndPosition() { // FIXME: Properly implement this by calling Content.createPosition(). return new Position() @@ -437,7 +456,7 @@ public abstract class AbstractDocument implements Document, Serializable * @return the property for <code>key</code> or <code>null</code> if there * is no such property stored */ - public Object getProperty(Object key) + public final Object getProperty(Object key) { // FIXME: make me thread-safe Object value = null; @@ -470,7 +489,7 @@ public abstract class AbstractDocument implements Document, Serializable * @return a {@link Position} which will always mark the beginning of the * <code>Document</code> */ - public Position getStartPosition() + public final Position getStartPosition() { // FIXME: Properly implement this using Content.createPosition(). return new Position() @@ -521,6 +540,13 @@ public abstract class AbstractDocument implements Document, Serializable /** * Inserts a String into this <code>Document</code> at the specified * position and assigning the specified attributes to it. + * + * <p>If a {@link DocumentFilter} is installed in this document, the + * corresponding method of the filter object is called.</p> + * + * <p>The method has no effect when <code>text</code> is <code>null</code> + * or has a length of zero.</p> + * * * @param offset the location at which the string should be inserted * @param text the content to be inserted @@ -532,6 +558,19 @@ public abstract class AbstractDocument implements Document, Serializable public void insertString(int offset, String text, AttributeSet attributes) throws BadLocationException { + // Bail out if we have a bogus insertion (Behavior observed in RI). + if (text == null || text.length() == 0) + return; + + if (documentFilter == null) + insertStringImpl(offset, text, attributes); + else + documentFilter.insertString(getBypass(), offset, text, attributes); + } + + void insertStringImpl(int offset, String text, AttributeSet attributes) + throws BadLocationException + { // Just return when no text to insert was given. if (text == null || text.length() == 0) return; @@ -589,7 +628,7 @@ public abstract class AbstractDocument implements Document, Serializable * @param key the key of the property to be stored * @param value the value of the property to be stored */ - public void putProperty(Object key, Object value) + public final void putProperty(Object key, Object value) { // FIXME: make me thread-safe if (properties == null) @@ -602,7 +641,7 @@ public abstract class AbstractDocument implements Document, Serializable * Blocks until a read lock can be obtained. Must block if there is * currently a writer modifying the <code>Document</code>. */ - public void readLock() + public final void readLock() { if (currentWriter != null && currentWriter.equals(Thread.currentThread())) return; @@ -627,7 +666,7 @@ public abstract class AbstractDocument implements Document, Serializable * Releases the read lock. If this was the only reader on this * <code>Document</code>, writing may begin now. */ - public void readUnlock() + public final void readUnlock() { // Note we could have a problem here if readUnlock was called without a // prior call to readLock but the specs simply warn users to ensure that @@ -673,7 +712,16 @@ public abstract class AbstractDocument implements Document, Serializable /** * Removes a piece of content from this <code>Document</code>. - * + * + * <p>If a {@link DocumentFilter} is installed in this document, the + * corresponding method of the filter object is called. The + * <code>DocumentFilter</code> is called even if <code>length</code> + * is zero. This is different from {@link #replace}.</p> + * + * <p>Note: When <code>length</code> is zero or below the call is not + * forwarded to the underlying {@link AbstractDocument.Content} instance + * of this document and no exception is thrown.</p> + * * @param offset the start offset of the fragment to be removed * @param length the length of the fragment to be removed * @@ -683,6 +731,18 @@ public abstract class AbstractDocument implements Document, Serializable */ public void remove(int offset, int length) throws BadLocationException { + if (documentFilter == null) + removeImpl(offset, length); + else + documentFilter.remove(getBypass(), offset, length); + } + + void removeImpl(int offset, int length) throws BadLocationException + { + // Prevent some unneccessary method invocation (observed in the RI). + if (length <= 0) + return; + DefaultDocumentEvent event = new DefaultDocumentEvent(offset, length, DocumentEvent.EventType.REMOVE); @@ -707,6 +767,13 @@ public abstract class AbstractDocument implements Document, Serializable /** * Replaces a piece of content in this <code>Document</code> with * another piece of content. + * + * <p>If a {@link DocumentFilter} is installed in this document, the + * corresponding method of the filter object is called.</p> + * + * <p>The method has no effect if <code>length</code> is zero (and + * only zero) and, at the same time, <code>text</code> is + * <code>null</code> or has zero length.</p> * * @param offset the start offset of the fragment to be removed * @param length the length of the fragment to be removed @@ -720,11 +787,36 @@ public abstract class AbstractDocument implements Document, Serializable * @since 1.4 */ public void replace(int offset, int length, String text, + AttributeSet attributes) + throws BadLocationException + { + // Bail out if we have a bogus replacement (Behavior observed in RI). + if (length == 0 + && (text == null || text.length() == 0)) + return; + + if (documentFilter == null) + { + // It is important to call the methods which again do the checks + // of the arguments and the DocumentFilter because subclasses may + // have overridden these methods and provide crucial behavior + // which would be skipped if we call the non-checking variants. + // An example for this is PlainDocument where insertString can + // provide a filtering of newlines. + remove(offset, length); + insertString(offset, text, attributes); + } + else + documentFilter.replace(getBypass(), offset, length, text, attributes); + + } + + void replaceImpl(int offset, int length, String text, AttributeSet attributes) throws BadLocationException { - remove(offset, length); - insertString(offset, text, attributes); + removeImpl(offset, length); + insertStringImpl(offset, text, attributes); } /** @@ -854,7 +946,7 @@ public abstract class AbstractDocument implements Document, Serializable * Blocks until a write lock can be obtained. Must wait if there are * readers currently reading or another thread is currently writing. */ - protected void writeLock() + protected final void writeLock() { if (currentWriter != null && currentWriter.equals(Thread.currentThread())) return; @@ -881,7 +973,7 @@ public abstract class AbstractDocument implements Document, Serializable * Releases the write lock. This allows waiting readers or writers to * obtain the lock. */ - protected void writeUnlock() + protected final void writeUnlock() { synchronized (documentCV) { @@ -2239,4 +2331,37 @@ public abstract class AbstractDocument implements Document, Serializable + getStartOffset() + "," + getEndOffset() + "\n"); } } + + /** A class whose methods delegate to the insert, remove and replace methods + * of this document which do not check for an installed DocumentFilter. + */ + class Bypass extends DocumentFilter.FilterBypass + { + + public Document getDocument() + { + return AbstractDocument.this; + } + + public void insertString(int offset, String string, AttributeSet attr) + throws BadLocationException + { + AbstractDocument.this.insertStringImpl(offset, string, attr); + } + + public void remove(int offset, int length) + throws BadLocationException + { + AbstractDocument.this.removeImpl(offset, length); + } + + public void replace(int offset, int length, String string, + AttributeSet attrs) + throws BadLocationException + { + AbstractDocument.this.replaceImpl(offset, length, string, attrs); + } + + } + } diff --git a/libjava/classpath/javax/swing/text/AsyncBoxView.java b/libjava/classpath/javax/swing/text/AsyncBoxView.java index 1988bbadcc8..90447f86e6a 100644 --- a/libjava/classpath/javax/swing/text/AsyncBoxView.java +++ b/libjava/classpath/javax/swing/text/AsyncBoxView.java @@ -1030,7 +1030,7 @@ public class AsyncBoxView * * @since 1.4 */ - public void setEstimatedMajorSpan(boolean estimated) + protected void setEstimatedMajorSpan(boolean estimated) { estimatedMajorSpan = estimated; } @@ -1045,7 +1045,7 @@ public class AsyncBoxView * * @since 1.4 */ - public boolean getEstimatedMajorSpan() + protected boolean getEstimatedMajorSpan() { return estimatedMajorSpan; } @@ -1367,7 +1367,7 @@ public class AsyncBoxView /** * Updates the layout for this view. This is implemented to trigger - * {link ChildLocator#childChanged} for the changed view, if there is + * {@link ChildLocator#childChanged} for the changed view, if there is * any. * * @param ec the element change, may be <code>null</code> if there were diff --git a/libjava/classpath/javax/swing/text/BoxView.java b/libjava/classpath/javax/swing/text/BoxView.java index b5907dcbbe6..a184a813152 100644 --- a/libjava/classpath/javax/swing/text/BoxView.java +++ b/libjava/classpath/javax/swing/text/BoxView.java @@ -1,5 +1,5 @@ /* BoxView.java -- An composite view - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -591,9 +591,12 @@ public class BoxView for (int i = 0; i < count; ++i) { copy.setBounds(r); - childAllocation(i, r); + // The next call modifies copy. + childAllocation(i, copy); if (copy.contains(x, y)) { + // Modify r on success. + r.setBounds(copy); result = getView(i); break; } @@ -919,7 +922,7 @@ public class BoxView return super.viewToModel(x, y, a, bias); } - protected boolean flipEastAndWestEnds(int position, Position.Bias bias) + protected boolean flipEastAndWestAtEnds(int position, Position.Bias bias) { // FIXME: What to do here? return super.flipEastAndWestAtEnds(position, bias); diff --git a/libjava/classpath/javax/swing/text/CompositeView.java b/libjava/classpath/javax/swing/text/CompositeView.java index a10aca7e625..17f13dbedd6 100644 --- a/libjava/classpath/javax/swing/text/CompositeView.java +++ b/libjava/classpath/javax/swing/text/CompositeView.java @@ -1,5 +1,5 @@ /* CompositeView.java -- An abstract view that manages child views - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -218,21 +218,24 @@ public abstract class CompositeView throws BadLocationException { int childIndex = getViewIndex(pos, bias); + if (childIndex == -1) + throw new BadLocationException("Position " + pos + " is not represented by view.", pos); + Shape ret = null; - if (childIndex != -1) - { - View child = getView(childIndex); - Shape childAlloc = getChildAllocation(childIndex, a); - if (childAlloc == null) - ret = createDefaultLocation(a, bias); - Shape result = child.modelToView(pos, childAlloc, bias); - if (result != null) - ret = result; - else - ret = createDefaultLocation(a, bias); - } - else + + View child = getView(childIndex); + Shape childAlloc = getChildAllocation(childIndex, a); + + if (childAlloc == null) ret = createDefaultLocation(a, bias); + + Shape result = child.modelToView(pos, childAlloc, bias); + + if (result != null) + ret = result; + else + ret = createDefaultLocation(a, bias); + return ret; } @@ -301,7 +304,7 @@ public abstract class CompositeView { Rectangle r = getInsideAllocation(a); View view = getViewAtPoint((int) x, (int) y, r); - return view.viewToModel(x, y, a, b); + return view.viewToModel(x, y, r, b); } return 0; } @@ -630,8 +633,51 @@ public abstract class CompositeView Position.Bias[] biasRet) throws BadLocationException { - // FIXME: Implement this correctly. - return pos; + // TODO: It is unknown to me how this method has to be implemented and + // there is no specification telling me how to do it properly. Therefore + // the implementation was done for cases that are known. + // + // If this method ever happens to act silly for your particular case then + // it is likely that it is a cause of not knowing about your case when it + // was implemented first. You are free to fix the behavior. + // + // Here are the assumptions that lead to the implementation: + // If direction is NORTH chose the View preceding the one that contains the + // offset 'pos' (imagine the views are stacked on top of each other where + // the top is 0 and the bottom is getViewCount()-1. + // Consecutively when the direction is SOUTH the View following the one + // the offset 'pos' lies in is questioned. + // + // This limitation is described as PR 27345. + int index = getViewIndex(pos, b); + View v = null; + + if (index == -1) + return pos; + + switch (direction) + { + case NORTH: + // If we cannot calculate a proper offset return the one that was + // provided. + if (index <= 0) + return pos; + + v = getView(index - 1); + break; + case SOUTH: + // If we cannot calculate a proper offset return the one that was + // provided. + if (index >= getViewCount() - 1) + return pos; + + v = getView(index + 1); + break; + default: + throw new IllegalArgumentException(); + } + + return v.getNextVisualPositionFrom(pos, b, a, direction, biasRet); } /** @@ -664,8 +710,55 @@ public abstract class CompositeView Position.Bias[] biasRet) throws BadLocationException { - // FIXME: Implement this correctly. - return pos; + // TODO: It is unknown to me how this method has to be implemented and + // there is no specification telling me how to do it properly. Therefore + // the implementation was done for cases that are known. + // + // If this method ever happens to act silly for your particular case then + // it is likely that it is a cause of not knowing about your case when it + // was implemented first. You are free to fix the behavior. + // + // Here are the assumptions that lead to the implementation: + // If direction is EAST increase the offset by one and ask the View to + // which that index belong to calculate the 'next visual position'. + // If the direction is WEST do the same with offset 'pos' being decreased + // by one. + // This behavior will fail in a right-to-left or bidi environment! + // + // This limitation is described as PR 27346. + int index; + + View v = null; + + switch (direction) + { + case EAST: + index = getViewIndex(pos + 1, b); + // If we cannot calculate a proper offset return the one that was + // provided. + if (index == -1) + return pos; + + v = getView(index); + break; + case WEST: + index = getViewIndex(pos - 1, b); + // If we cannot calculate a proper offset return the one that was + // provided. + if (index == -1) + return pos; + + v = getView(index); + break; + default: + throw new IllegalArgumentException(); + } + + return v.getNextVisualPositionFrom(pos, + b, + a, + direction, + biasRet); } /** diff --git a/libjava/classpath/javax/swing/text/DefaultCaret.java b/libjava/classpath/javax/swing/text/DefaultCaret.java index f2a68c00db1..c9369af2089 100644 --- a/libjava/classpath/javax/swing/text/DefaultCaret.java +++ b/libjava/classpath/javax/swing/text/DefaultCaret.java @@ -59,17 +59,48 @@ import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.EventListenerList; +import javax.swing.text.Position.Bias; /** * The default implementation of the {@link Caret} interface. * - * @author orgininal author unknown + * @author original author unknown * @author Roman Kennke (roman@kennke.org) */ public class DefaultCaret extends Rectangle implements Caret, FocusListener, MouseListener, MouseMotionListener { + + /** A text component in the current VM which currently has a + * text selection or <code>null</code>. + */ + static JTextComponent componentWithSelection; + + /** An implementation of NavigationFilter.FilterBypass which delegates + * to the corresponding methods of the <code>DefaultCaret</code>. + * + * @author Robert Schuster (robertschuster@fsfe.org) + */ + class Bypass extends NavigationFilter.FilterBypass + { + + public Caret getCaret() + { + return DefaultCaret.this; + } + public void moveDot(int dot, Bias bias) + { + DefaultCaret.this.moveDotImpl(dot); + } + + public void setDot(int dot, Bias bias) + { + DefaultCaret.this.setDotImpl(dot); + } + + } + /** * Controls the blinking of the caret. * @@ -294,12 +325,29 @@ public class DefaultCaret extends Rectangle private BlinkTimerListener blinkListener; /** + * A <code>NavigationFilter.FilterBypass</code> instance which + * is provided to the a <code>NavigationFilter</code> to + * unconditionally set or move the caret. + */ + NavigationFilter.FilterBypass bypass; + + /** * Creates a new <code>DefaultCaret</code> instance. */ public DefaultCaret() { // Nothing to do here. } + + /** Returns the caret's <code>NavigationFilter.FilterBypass</code> instance + * and creates it if it does not yet exist. + * + * @return The caret's <code>NavigationFilter.FilterBypass</code> instance. + */ + private NavigationFilter.FilterBypass getBypass() + { + return (bypass == null) ? bypass = new Bypass() : bypass; + } /** * Sets the Caret update policy. @@ -346,7 +394,8 @@ public class DefaultCaret extends Rectangle */ public void mouseDragged(MouseEvent event) { - moveCaret(event); + if (event.getButton() == MouseEvent.BUTTON1) + moveCaret(event); } /** @@ -379,7 +428,7 @@ public class DefaultCaret extends Rectangle { int count = event.getClickCount(); - if (count >= 2) + if (event.getButton() == MouseEvent.BUTTON1 && count >= 2) { int newDot = getComponent().viewToModel(event.getPoint()); JTextComponent t = getComponent(); @@ -387,29 +436,42 @@ public class DefaultCaret extends Rectangle try { if (count == 3) - t.select(Utilities.getRowStart(t, newDot), Utilities.getRowEnd(t, newDot)); + { + setDot(Utilities.getRowStart(t, newDot)); + moveDot( Utilities.getRowEnd(t, newDot)); + } else { - int nextWord = Utilities.getNextWord(t, newDot); + int wordStart = Utilities.getWordStart(t, newDot); // When the mouse points at the offset of the first character // in a word Utilities().getPreviousWord will not return that // word but we want to select that. We have to use - // Utilities.nextWord() to get it. - if (newDot == nextWord) - t.select(nextWord, Utilities.getNextWord(t, nextWord)); + // Utilities.getWordStart() to get it. + if (newDot == wordStart) + { + setDot(wordStart); + moveDot(Utilities.getWordEnd(t, wordStart)); + } else { + int nextWord = Utilities.getNextWord(t, newDot); int previousWord = Utilities.getPreviousWord(t, newDot); int previousWordEnd = Utilities.getWordEnd(t, previousWord); // If the user clicked in the space between two words, // then select the space. if (newDot >= previousWordEnd && newDot <= nextWord) - t.select(previousWordEnd, nextWord); + { + setDot(previousWordEnd); + moveDot(nextWord); + } // Otherwise select the word under the mouse pointer. else - t.select(previousWord, previousWordEnd); + { + setDot(previousWord); + moveDot(previousWordEnd); + } } } } @@ -417,8 +479,6 @@ public class DefaultCaret extends Rectangle { // TODO: Swallowing ok here? } - - dot = newDot; } } @@ -455,10 +515,35 @@ public class DefaultCaret extends Rectangle */ public void mousePressed(MouseEvent event) { - if (event.isShiftDown()) - moveCaret(event); - else - positionCaret(event); + int button = event.getButton(); + + // The implementation assumes that consuming the event makes the AWT event + // mechanism forget about this event instance and not transfer focus. + // By observing how the RI reacts the following behavior has been + // 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 + // on a text component is ignored + // - a middle-click positions the caret and pastes the clipboard + // contents. + // - a middle-click when shift is held down is ignored + + if (button == MouseEvent.BUTTON1) + if (event.isShiftDown()) + moveCaret(event); + else + positionCaret(event); + else if(button == MouseEvent.BUTTON2) + if (event.isShiftDown()) + event.consume(); + else + { + positionCaret(event); + textComponent.paste(); + } + else + event.consume(); } /** @@ -636,10 +721,13 @@ public class DefaultCaret extends Rectangle { try { - if (highlightEntry == null) - highlightEntry = highlighter.addHighlight(0, 0, getSelectionPainter()); - else + if (highlightEntry != null) highlighter.changeHighlight(highlightEntry, 0, 0); + + // Free the global variable which stores the text component with an active + // selection. + if (componentWithSelection == textComponent) + componentWithSelection = null; } catch (BadLocationException e) { @@ -675,6 +763,17 @@ public class DefaultCaret extends Rectangle highlightEntry = highlighter.addHighlight(p0, p1, getSelectionPainter()); else highlighter.changeHighlight(highlightEntry, p0, p1); + + // If another component currently has a text selection clear that selection + // first. + if (componentWithSelection != null) + if (componentWithSelection != textComponent) + { + Caret c = componentWithSelection.getCaret(); + c.setDot(c.getDot()); + } + componentWithSelection = textComponent; + } catch (BadLocationException e) { @@ -776,7 +875,7 @@ public class DefaultCaret extends Rectangle if (visible) { g.setColor(textComponent.getCaretColor()); - g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height); + g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height - 1); } } @@ -888,12 +987,24 @@ public class DefaultCaret extends Rectangle * Moves the <code>dot</code> location without touching the * <code>mark</code>. This is used when making a selection. * + * <p>If the underlying text component has a {@link NavigationFilter} + * installed the caret will call the corresponding method of that object.</p> + * * @param dot the location where to move the dot * * @see #setDot(int) */ public void moveDot(int dot) { + NavigationFilter filter = textComponent.getNavigationFilter(); + if (filter != null) + filter.moveDot(getBypass(), dot, Bias.Forward); + else + moveDotImpl(dot); + } + + void moveDotImpl(int dot) + { if (dot >= 0) { Document doc = textComponent.getDocument(); @@ -902,8 +1013,8 @@ public class DefaultCaret extends Rectangle this.dot = Math.max(this.dot, 0); handleHighlight(); - adjustVisibility(this); appear(); + adjustVisibility(this); } } @@ -912,12 +1023,24 @@ public class DefaultCaret extends Rectangle * <code>Document</code>. This also sets the <code>mark</code> to the new * location. * + * <p>If the underlying text component has a {@link NavigationFilter} + * installed the caret will call the corresponding method of that object.</p> + * * @param dot * the new position to be set * @see #moveDot(int) */ public void setDot(int dot) { + NavigationFilter filter = textComponent.getNavigationFilter(); + if (filter != null) + filter.setDot(getBypass(), dot, Bias.Forward); + else + setDotImpl(dot); + } + + void setDotImpl(int dot) + { if (dot >= 0) { Document doc = textComponent.getDocument(); @@ -927,8 +1050,8 @@ public class DefaultCaret extends Rectangle this.mark = this.dot; clearHighlight(); - adjustVisibility(this); appear(); + adjustVisibility(this); } } @@ -1043,7 +1166,16 @@ public class DefaultCaret extends Rectangle // must set a valid value here, since otherwise the painting mechanism // sets a zero clip and never calls paint. if (height <= 0) - height = getComponent().getHeight(); + try + { + height = textComponent.modelToView(dot).height; + } + catch (BadLocationException ble) + { + // Should not happen. + throw new InternalError("Caret location not within document range."); + } + repaint(); } @@ -1068,4 +1200,5 @@ public class DefaultCaret extends Rectangle blinkTimer = new Timer(getBlinkRate(), blinkListener); blinkTimer.setRepeats(true); } + } diff --git a/libjava/classpath/javax/swing/text/DefaultEditorKit.java b/libjava/classpath/javax/swing/text/DefaultEditorKit.java index c0056963c78..1b686182b6a 100644 --- a/libjava/classpath/javax/swing/text/DefaultEditorKit.java +++ b/libjava/classpath/javax/swing/text/DefaultEditorKit.java @@ -63,6 +63,663 @@ import javax.swing.Action; */ public class DefaultEditorKit extends EditorKit { + static class SelectionPreviousWordAction + extends TextAction + { + SelectionPreviousWordAction() + { + super(selectionPreviousWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getPreviousWord(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.moveDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class SelectionNextWordAction + extends TextAction + { + SelectionNextWordAction() + { + super(selectionNextWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getNextWord(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.moveDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class PreviousWordAction + extends TextAction + { + PreviousWordAction() + { + super(previousWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getPreviousWord(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.setDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class NextWordAction + extends TextAction + { + NextWordAction() + { + super(nextWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getNextWord(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.setDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class SelectAllAction + extends TextAction + { + SelectAllAction() + { + super(selectAllAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + int offs = t.getDocument().getLength(); + Caret c = t.getCaret(); + c.setDot(0); + c.moveDot(offs); + + try + { + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class SelectionBeginAction + extends TextAction + { + SelectionBeginAction() + { + super(selectionBeginAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + Caret c = t.getCaret(); + c.moveDot(0); + try + { + c.setMagicCaretPosition(t.modelToView(0).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class SelectionEndAction + extends TextAction + { + SelectionEndAction() + { + super(selectionEndAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + int offs = t.getDocument().getLength(); + Caret c = t.getCaret(); + c.moveDot(offs); + try + { + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class SelectionEndLineAction + extends TextAction + { + SelectionEndLineAction() + { + super(selectionEndLineAction); + } + + 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 + } + } + } + + static class SelectionBeginLineAction + extends TextAction + { + SelectionBeginLineAction() + { + super(selectionBeginLineAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + + 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. + } + } + } + + static class SelectionDownAction + extends TextAction + { + SelectionDownAction() + { + super(selectionDownAction); + } + + 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 x = (mcp != null) ? mcp.x : 0; + int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x); + + if (pos > -1) + t.moveCaretPosition(pos); + } + } + catch(BadLocationException ble) + { + // FIXME: Swallowing allowed? + } + } + } + + static class SelectionUpAction + extends TextAction + { + SelectionUpAction() + { + super(selectionUpAction); + } + + 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 x = (mcp != null) ? mcp.x : 0; + int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x); + + if (pos > -1) + t.moveCaretPosition(pos); + } + } + catch(BadLocationException ble) + { + // FIXME: Swallowing allowed? + } + } + } + + static class SelectionForwardAction + extends TextAction + { + SelectionForwardAction() + { + super(selectionForwardAction); + } + + public void actionPerformed(ActionEvent event) + { + 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. + } + } + } + } + } + + static class SelectionBackwardAction + extends TextAction + { + SelectionBackwardAction() + { + super(selectionBackwardAction); + } + + public void actionPerformed(ActionEvent event) + { + 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. + } + } + } + } + } + + static class DownAction + extends TextAction + { + DownAction() + { + super(downAction); + } + + 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 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? + } + } + } + + static class UpAction + extends TextAction + { + UpAction() + { + super(upAction); + } + + 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 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? + } + } + } + + static class ForwardAction + extends TextAction + { + ForwardAction() + { + super(forwardAction); + } + + public void actionPerformed(ActionEvent event) + { + 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. + } + } + } + + } + } + + static class BackwardAction + extends TextAction + { + BackwardAction() + { + super(backwardAction); + } + + public void actionPerformed(ActionEvent event) + { + 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. + } + } + } + } + } + + static class DeletePrevCharAction + extends TextAction + { + DeletePrevCharAction() + { + super(deletePrevCharAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + if (t != null) + { + try + { + int pos = t.getSelectionStart(); + int len = t.getSelectionEnd() - pos; + + if (len > 0) + t.getDocument().remove(pos, len); + else if (pos > 0) + { + pos--; + t.getDocument().remove(pos, 1); + Caret c = t.getCaret(); + c.setDot(pos); + c.setMagicCaretPosition(t.modelToView(pos).getLocation()); + } + } + catch (BadLocationException e) + { + // FIXME: we're not authorized to throw this.. swallow it? + } + } + } + } + + static class DeleteNextCharAction + extends TextAction + { + DeleteNextCharAction() + { + super(deleteNextCharAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + if (t != null) + { + try + { + int pos = t.getSelectionStart(); + int len = t.getSelectionEnd() - pos; + + if (len > 0) + t.getDocument().remove(pos, len); + else if (pos < t.getDocument().getLength()) + t.getDocument().remove(pos, 1); + + Caret c = t.getCaret(); + c.setDot(pos); + c.setMagicCaretPosition(t.modelToView(pos).getLocation()); + } + catch (BadLocationException e) + { + // FIXME: we're not authorized to throw this.. swallow it? + } + } + } + } + + static class EndLineAction + extends TextAction + { + EndLineAction() + { + super(endLineAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + int offs = Utilities.getRowEnd(t, t.getCaretPosition()); + + if (offs > -1) + { + Caret c = t.getCaret(); + c.setDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch (BadLocationException ble) + { + // Nothing to do here + } + } + } + + static class BeginLineAction + extends TextAction + { + BeginLineAction() + { + super(beginLineAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + int offs = Utilities.getRowStart(t, t.getCaretPosition()); + + if (offs > -1) + { + Caret c = t.getCaret(); + c.setDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch (BadLocationException ble) + { + // Do nothing here. + } + } + } + /** * Creates a beep on the PC speaker. * @@ -692,6 +1349,7 @@ public class DefaultEditorKit extends EditorKit // to handle this. private static Action[] defaultActions = new Action[] { + // These classes are public because they are so in the RI. new BeepAction(), new CopyAction(), new CutAction(), @@ -700,404 +1358,38 @@ public class DefaultEditorKit extends EditorKit new InsertContentAction(), new InsertTabAction(), new PasteAction(), - new TextAction(beginLineAction) - { - public void actionPerformed(ActionEvent event) - { - JTextComponent t = getTextComponent(event); - try - { - int offs = Utilities.getRowStart(t, t.getCaretPosition()); - - if (offs > -1) - { - Caret c = t.getCaret(); - c.setDot(offs); - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - } - catch (BadLocationException ble) - { - // Do nothing here. - } - } - }, - new TextAction(endLineAction) - { - public void actionPerformed(ActionEvent event) - { - JTextComponent t = getTextComponent(event); - try - { - int offs = Utilities.getRowEnd(t, t.getCaretPosition()); - - if (offs > -1) - { - Caret c = t.getCaret(); - c.setDot(offs); - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - } - catch (BadLocationException ble) - { - // Nothing to do here - } - } - }, - new TextAction(deleteNextCharAction) - { - public void actionPerformed(ActionEvent event) - { - JTextComponent t = getTextComponent(event); - if (t != null) - { - try - { - int pos = t.getSelectionStart(); - int len = t.getSelectionEnd() - pos; - - if (len > 0) - t.getDocument().remove(pos, len); - else if (pos < t.getDocument().getLength()) - t.getDocument().remove(pos, 1); - - Caret c = t.getCaret(); - c.setDot(pos); - c.setMagicCaretPosition(t.modelToView(pos).getLocation()); - } - catch (BadLocationException e) - { - // FIXME: we're not authorized to throw this.. swallow it? - } - } - } - }, - new TextAction(deletePrevCharAction) - { - public void actionPerformed(ActionEvent event) - { - JTextComponent t = getTextComponent(event); - if (t != null) - { - try - { - int pos = t.getSelectionStart(); - int len = t.getSelectionEnd() - pos; - - if (len > 0) - t.getDocument().remove(pos, len); - else if (pos > 0) - { - pos--; - t.getDocument().remove(pos, 1); - Caret c = t.getCaret(); - c.setDot(pos); - c.setMagicCaretPosition(t.modelToView(pos).getLocation()); - } - } - catch (BadLocationException e) - { - // FIXME: we're not authorized to throw this.. swallow it? - } - } - } - }, - new TextAction(backwardAction) - { - public void actionPerformed(ActionEvent event) - { - 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. - } - } - } - } - }, - new TextAction(forwardAction) - { - public void actionPerformed(ActionEvent event) - { - 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. - } - } - } - - } - }, - new TextAction(upAction) - { - 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 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? - } - } - }, - new TextAction(downAction) - { - 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 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? - } - } - }, - new TextAction(selectionBackwardAction) - { - public void actionPerformed(ActionEvent event) - { - 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. - } - } - } - } - }, - new TextAction(selectionForwardAction) - { - public void actionPerformed(ActionEvent event) - { - 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. - } - } - } - } - }, - new TextAction(selectionUpAction) - { - 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 x = (mcp != null) ? mcp.x : 0; - int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x); - - if (pos > -1) - t.moveCaretPosition(pos); - } - } - catch(BadLocationException ble) - { - // FIXME: Swallowing allowed? - } - } - }, - new TextAction(selectionDownAction) - { - 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 x = (mcp != null) ? mcp.x : 0; - int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x); - - if (pos > -1) - t.moveCaretPosition(pos); - } - } - catch(BadLocationException ble) - { - // FIXME: Swallowing allowed? - } - } - }, - new TextAction(selectionBeginLineAction) - { - public void actionPerformed(ActionEvent event) - { - JTextComponent t = getTextComponent(event); - - 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. - } - } - }, - new TextAction(selectionEndLineAction) - { - 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 - } - } - }, - new TextAction(selectionEndAction) - { - public void actionPerformed(ActionEvent event) - { - JTextComponent t = getTextComponent(event); - int offs = t.getDocument().getLength(); - Caret c = t.getCaret(); - c.moveDot(offs); - try - { - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - catch(BadLocationException ble) - { - // Can't happen. - } - } - }, - new TextAction(selectionBeginAction) - { - public void actionPerformed(ActionEvent event) - { - JTextComponent t = getTextComponent(event); - Caret c = t.getCaret(); - c.moveDot(0); - try - { - c.setMagicCaretPosition(t.modelToView(0).getLocation()); - } - catch(BadLocationException ble) - { - // Can't happen. - } - } - } + + // These are (package-)private inner classes. + new DeleteNextCharAction(), + new DeletePrevCharAction(), + + new BeginLineAction(), + new SelectionBeginLineAction(), + + new EndLineAction(), + new SelectionEndLineAction(), + + new BackwardAction(), + new SelectionBackwardAction(), + + new ForwardAction(), + new SelectionForwardAction(), + + new UpAction(), + new SelectionUpAction(), + + new DownAction(), + new SelectionDownAction(), + + new NextWordAction(), + new SelectionNextWordAction(), + + new PreviousWordAction(), + new SelectionPreviousWordAction(), + + new SelectionBeginAction(), + new SelectionEndAction(), + new SelectAllAction(), }; /** diff --git a/libjava/classpath/javax/swing/text/DefaultHighlighter.java b/libjava/classpath/javax/swing/text/DefaultHighlighter.java index 33b5fcab8bf..59f77316e87 100644 --- a/libjava/classpath/javax/swing/text/DefaultHighlighter.java +++ b/libjava/classpath/javax/swing/text/DefaultHighlighter.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.text; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Graphics; import java.awt.Insets; @@ -45,6 +47,7 @@ import java.awt.Rectangle; import java.awt.Shape; import java.util.ArrayList; +import javax.swing.SwingUtilities; import javax.swing.plaf.TextUI; public class DefaultHighlighter extends LayeredHighlighter @@ -71,60 +74,102 @@ public class DefaultHighlighter extends LayeredHighlighter } public void paint(Graphics g, int p0, int p1, Shape bounds, - JTextComponent c) + JTextComponent t) { - Rectangle r0 = null; - Rectangle r1 = null; - Rectangle rect = bounds.getBounds(); - - try - { - r0 = c.modelToView(p0); - r1 = c.modelToView(p1); - } - catch (BadLocationException e) - { - // This should never occur. - return; - } + if (p0 == p1) + return; - if (r0 == null || r1 == null) - return; + Rectangle rect = bounds.getBounds(); if (color == null) - g.setColor(c.getSelectionColor()); + g.setColor(t.getSelectionColor()); else - g.setColor(color); - - // Check if only one line to highlight. - if (r0.y == r1.y) - { - r0.width = r1.x - r0.x; - paintHighlight(g, r0); - return; - } - - // First line, from p0 to end-of-line. - r0.width = rect.x + rect.width - r0.x; - paintHighlight(g, r0); - - // FIXME: All the full lines in between, if any (assumes that all lines - // have the same height -- not a good assumption with JEditorPane/JTextPane). - r0.y += r0.height; - r0.x = rect.x; - r0.width = rect.width; + g.setColor(color); + + TextUI ui = t.getUI(); - while (r0.y < r1.y) - { - paintHighlight(g, r0); - r0.y += r0.height; - } - - // Last line, from beginning-of-line to p1. - // The "-1" is neccessary else we would paint one pixel column more - // than in the case where the selection is only on one line. - r0.width = r1.x + r1.width - 1; - paintHighlight(g, r0); + try + { + + Rectangle l0 = ui.modelToView(t, p0, null); + Rectangle l1 = ui.modelToView(t, p1, null); + + // Note: The computed locations may lie outside of the allocation + // area if the text is scrolled. + + if (l0.y == l1.y) + { + SwingUtilities.computeUnion(l0.x, l0.y, l0.width, l0.height, l1); + + // Paint only inside the allocation area. + SwingUtilities.computeIntersection(rect.x, rect.y, rect.width, rect.height, l1); + + paintHighlight(g, l1); + } + else + { + // 1. The line of p0 is painted from the position of p0 + // to the right border. + // 2. All lines between the ones where p0 and p1 lie on + // are completely highlighted. The allocation area is used to find + // out the bounds. + // 3. The final line is painted from the left border to the + // position of p1. + + // Highlight first line until the end. + // If rect.x is non-zero the calculation will properly adjust the + // area to be painted. + l0.x -= rect.x; + l0.width = rect.width - l0.x - rect.x; + + paintHighlight(g, l0); + + int posBelow = Utilities.getPositionBelow(t, p0, l0.x); + int p1RowStart = Utilities.getRowStart(t, p1); + if (posBelow != -1 + && posBelow != p0 + && Utilities.getRowStart(t, posBelow) + != p1RowStart) + { + Rectangle grow = ui.modelToView(t, posBelow); + grow.x = rect.x; + grow.width = rect.width; + + // Find further lines which have to be highlighted completely. + int nextPosBelow = posBelow; + while (nextPosBelow != -1 + && Utilities.getRowStart(t, nextPosBelow) != p1RowStart) + { + posBelow = nextPosBelow; + nextPosBelow = Utilities.getPositionBelow(t, posBelow, l0.x); + + if (nextPosBelow == posBelow) + break; + } + // Now posBelow is an offset on the last line which has to be painted + // completely. (newPosBelow is on the same line as p1) + + // Retrieve the rectangle of posBelow and use its y and height + // value to calculate the final height of the multiple line + // spanning rectangle. + Rectangle end = ui.modelToView(t, posBelow); + grow.height = end.y + end.height - grow.y; + + paintHighlight(g, grow); + } + + // Paint last line from its beginning to the position of p1. + l1.width = l1.x + l1.width - rect.x; + l1.x = rect.x; + paintHighlight(g, l1); + } + } + catch (BadLocationException ex) + { + AssertionError err = new AssertionError("Unexpected bad location exception"); + err.initCause(ex); + throw err; + } } public Shape paintLayer(Graphics g, int p0, int p1, Shape bounds, @@ -330,6 +375,7 @@ public class DefaultHighlighter extends LayeredHighlighter public void paintLayeredHighlights(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor, View view) + throws NotImplementedException { // TODO: Implement this properly. } diff --git a/libjava/classpath/javax/swing/text/FieldView.java b/libjava/classpath/javax/swing/text/FieldView.java index 2496418444e..0c2f0fef156 100644 --- a/libjava/classpath/javax/swing/text/FieldView.java +++ b/libjava/classpath/javax/swing/text/FieldView.java @@ -1,5 +1,5 @@ /* FieldView.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,20 +39,86 @@ exception statement from your version. */ package javax.swing.text; import java.awt.Component; -import java.awt.ComponentOrientation; +import java.awt.Container; import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Insets; import java.awt.Rectangle; import java.awt.Shape; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.BoundedRangeModel; import javax.swing.JTextField; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; public class FieldView extends PlainView { + BoundedRangeModel horizontalVisibility; + + /** Caches the preferred span of the X axis. It is invalidated by + * setting it to -1f. This is done when text in the document + * is inserted, removed or changed. The value is corrected as + * soon as calculateHorizontalSpan() is called. + */ + float cachedSpan = -1f; + public FieldView(Element elem) { super(elem); + + } + + /** Checks whether the given container is a JTextField. If so + * it retrieves the textfield's horizontalVisibility instance. + * + * <p>This method should be only called when the view's container + * is valid. Naturally that would be the setParent() method however + * that method is not overridden in the RI and that is why we chose + * paint() instead.</p> + */ + private void checkContainer() + { + Container c = getContainer(); + + if (c instanceof JTextField) + { + horizontalVisibility = ((JTextField) c).getHorizontalVisibility(); + + // Provokes a repaint when the BoundedRangeModel's values change + // (which is what the RI does). + horizontalVisibility.addChangeListener(new ChangeListener(){ + public void stateChanged(ChangeEvent event) { + getContainer().repaint(); + }; + }); + + // It turned out that the span calculated at this point is wrong + // and needs to be recalculated (e.g. a different font setting is + // not taken into account). + calculateHorizontalSpan(); + + // Initializes the BoundedRangeModel properly. + updateVisibility(); + } + + } + + private void updateVisibility() + { + JTextField tf = (JTextField) getContainer(); + Insets insets = tf.getInsets(); + + int width = tf.getWidth() - insets.left - insets.right; + + horizontalVisibility.setMaximum(Math.max((int) ((cachedSpan != -1f) + ? cachedSpan + : calculateHorizontalSpan()), + width)); + + horizontalVisibility.setExtent(width - 1); } protected FontMetrics getFontMetrics() @@ -72,41 +138,47 @@ public class FieldView extends PlainView */ protected Shape adjustAllocation(Shape shape) { + // Return null when the original allocation is null (like the RI). + if (shape == null) + return null; + Rectangle rectIn = shape.getBounds(); // vertical adjustment int height = (int) getPreferredSpan(Y_AXIS); int y = rectIn.y + (rectIn.height - height) / 2; // horizontal adjustment JTextField textField = (JTextField) getContainer(); - int halign = textField.getHorizontalAlignment(); - int width = (int) getPreferredSpan(X_AXIS); + int width = (int) ((cachedSpan != -1f) ? cachedSpan : calculateHorizontalSpan()); int x; - ComponentOrientation orientation = textField.getComponentOrientation(); - switch (halign) - { - case JTextField.CENTER: - x = rectIn.x + (rectIn.width - width) / 2; - break; - case JTextField.RIGHT: - x = rectIn.x + (rectIn.width - width); - break; - case JTextField.TRAILING: - if (orientation.isLeftToRight()) - x = rectIn.x + (rectIn.width - width); - else - x = rectIn.x; - break; - case JTextField.LEADING: - if (orientation.isLeftToRight()) + if (horizontalVisibility != null && horizontalVisibility.getExtent() < width) + x = rectIn.x - horizontalVisibility.getValue(); + else + switch (textField.getHorizontalAlignment()) + { + case JTextField.CENTER: + x = rectIn.x + (rectIn.width - width) / 2; + break; + case JTextField.RIGHT: + x = rectIn.x + (rectIn.width - width - 1); + break; + case JTextField.TRAILING: + if (textField.getComponentOrientation().isLeftToRight()) + x = rectIn.x + (rectIn.width - width - 1); + else + x = rectIn.x; + break; + case JTextField.LEADING: + if (textField.getComponentOrientation().isLeftToRight()) + x = rectIn.x; + else + x = rectIn.x + (rectIn.width - width - 1); + break; + case JTextField.LEFT: + default: x = rectIn.x; - else - x = rectIn.x + (rectIn.width - width); - break; - case JTextField.LEFT: - default: - x = rectIn.x; - break; - } + break; + } + return new Rectangle(x, y, width, height); } @@ -115,18 +187,31 @@ public class FieldView extends PlainView if (axis != X_AXIS && axis != Y_AXIS) throw new IllegalArgumentException(); - FontMetrics fm = getFontMetrics(); if (axis == Y_AXIS) return super.getPreferredSpan(axis); - String text; + if (cachedSpan != -1f) + return cachedSpan; + + return calculateHorizontalSpan(); + } + + /** Calculates and sets the horizontal span and stores the value + * in cachedSpan. + */ + private float calculateHorizontalSpan() + { + Segment s = getLineBuffer(); Element elem = getElement(); try { - text = elem.getDocument().getText(elem.getStartOffset(), - elem.getEndOffset()); + elem.getDocument().getText(elem.getStartOffset(), + elem.getEndOffset() - 1, + s); + + return cachedSpan = Utilities.getTabbedTextWidth(s, getFontMetrics(), 0, this, s.offset); } catch (BadLocationException e) { @@ -135,8 +220,6 @@ public class FieldView extends PlainView ae.initCause(e); throw ae; } - - return fm.stringWidth(text); } public int getResizeWeight(int axis) @@ -153,19 +236,39 @@ public class FieldView extends PlainView public void paint(Graphics g, Shape s) { + if (horizontalVisibility == null) + checkContainer(); + 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); super.paint(g, newAlloc); + g.setClip(clip); } public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) { + cachedSpan = -1f; + + if (horizontalVisibility != null) + updateVisibility(); + Shape newAlloc = adjustAllocation(shape); + super.insertUpdate(ev, newAlloc, vf); getContainer().repaint(); } public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) { + cachedSpan = -1f; + + if (horizontalVisibility != null) + updateVisibility(); + Shape newAlloc = adjustAllocation(shape); super.removeUpdate(ev, newAlloc, vf); getContainer().repaint(); @@ -173,14 +276,19 @@ public class FieldView extends PlainView public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) { + cachedSpan = -1f; + + if (horizontalVisibility != null) + updateVisibility(); + Shape newAlloc = adjustAllocation(shape); - super.removeUpdate(ev, newAlloc, vf); + super.changedUpdate(ev, newAlloc, vf); getContainer().repaint(); } public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) { - return super.viewToModel(fx, fy, a, bias); + return super.viewToModel(fx, fy, adjustAllocation(a), bias); } } diff --git a/libjava/classpath/javax/swing/text/FlowView.java b/libjava/classpath/javax/swing/text/FlowView.java index 8be8f41e939..8ca55d8347a 100644 --- a/libjava/classpath/javax/swing/text/FlowView.java +++ b/libjava/classpath/javax/swing/text/FlowView.java @@ -433,7 +433,7 @@ public abstract class FlowView extends BoxView /** * Loads the children of this view. The <code>FlowView</code> does not * directly load its children. Instead it creates a logical view - * (@{link #layoutPool}) which is filled by the logical child views. + * ({@link #layoutPool}) which is filled by the logical child views. * The real children are created at layout time and each represent one * row. * diff --git a/libjava/classpath/javax/swing/text/GapContent.java b/libjava/classpath/javax/swing/text/GapContent.java index 28d1d6ee01f..219accb4056 100644 --- a/libjava/classpath/javax/swing/text/GapContent.java +++ b/libjava/classpath/javax/swing/text/GapContent.java @@ -289,6 +289,7 @@ public class GapContent */ public GapContent(int size) { + size = Math.max(size, 2); buffer = (char[]) allocateArray(size); gapStart = 1; gapEnd = size; @@ -351,7 +352,7 @@ public class GapContent throw new BadLocationException("The where argument cannot be smaller" + " than the zero", where); - if (where >= length) + if (where > length) throw new BadLocationException("The where argument cannot be greater" + " than the content length", where); @@ -375,14 +376,11 @@ public class GapContent { // check arguments int length = length(); - - if (where >= length) - throw new BadLocationException("the where argument cannot be greater" - + " than the content length", where); - if ((where + nitems) > length) + + if ((where + nitems) >= length) throw new BadLocationException("where + nitems cannot be greater" + " than the content length", where + nitems); - + String removedText = getString(where, nitems); replace(where, nitems, null, 0); @@ -439,6 +437,8 @@ public class GapContent { // check arguments int length = length(); + if (where < 0) + throw new BadLocationException("the where argument may not be below zero", where); if (where >= length) throw new BadLocationException("the where argument cannot be greater" + " than the content length", where); @@ -642,6 +642,10 @@ public class GapContent if (addItems != null) { System.arraycopy(addItems, 0, buffer, gapStart, addSize); + + + resetMarksAtZero(); + gapStart += addSize; } } diff --git a/libjava/classpath/javax/swing/text/InternationalFormatter.java b/libjava/classpath/javax/swing/text/InternationalFormatter.java index ba3cffaba5b..8db435c18f3 100644 --- a/libjava/classpath/javax/swing/text/InternationalFormatter.java +++ b/libjava/classpath/javax/swing/text/InternationalFormatter.java @@ -350,7 +350,7 @@ public class InternationalFormatter * There is no such method in the whole API! So we just call * super.getActions here. */ - public Action[] getActions() + protected Action[] getActions() { return super.getActions(); } diff --git a/libjava/classpath/javax/swing/text/JTextComponent.java b/libjava/classpath/javax/swing/text/JTextComponent.java index 6b8348ceaf5..1103de9b473 100644 --- a/libjava/classpath/javax/swing/text/JTextComponent.java +++ b/libjava/classpath/javax/swing/text/JTextComponent.java @@ -1138,6 +1138,7 @@ public abstract class JTextComponent extends JComponent setFocusable(true); setEditable(true); enableEvents(AWTEvent.KEY_EVENT_MASK); + setOpaque(true); updateUI(); } @@ -1190,6 +1191,7 @@ public abstract class JTextComponent extends JComponent catch (BadLocationException e) { // This can never happen. + throw (InternalError) new InternalError().initCause(e); } } diff --git a/libjava/classpath/javax/swing/text/PlainView.java b/libjava/classpath/javax/swing/text/PlainView.java index 4bb3a8eda33..18818c0bad3 100644 --- a/libjava/classpath/javax/swing/text/PlainView.java +++ b/libjava/classpath/javax/swing/text/PlainView.java @@ -59,6 +59,18 @@ public class PlainView extends View implements TabExpander * The color that is used to draw disabled text fields. */ Color disabledColor; + + /** + * While painting this is the textcomponent's current start index + * of the selection. + */ + int selectionStart; + + /** + * While painting this is the textcomponent's current end index + * of the selection. + */ + int selectionEnd; Font font; @@ -150,12 +162,47 @@ public class PlainView extends View implements TabExpander { try { - metrics = g.getFontMetrics(); - // FIXME: Selected text are not drawn yet. Element line = getElement().getElement(lineIndex); - drawUnselectedText(g, x, y, line.getStartOffset(), - line.getEndOffset() - 1); - //drawSelectedText(g, , , , ); + int startOffset = line.getStartOffset(); + int endOffset = line.getEndOffset() - 1; + + if (selectionStart <= startOffset) + // Selection starts before the line ... + if (selectionEnd <= startOffset) + { + // end ends before the line: Draw completely unselected text. + drawUnselectedText(g, x, y, startOffset, endOffset); + } + else if (selectionEnd <= endOffset) + { + // and ends within the line: First part is selected, + // second is not. + x = drawSelectedText(g, x, y, startOffset, selectionEnd); + drawUnselectedText(g, x, y, selectionEnd, endOffset); + } + else + // and ends behind the line: Draw completely selected text. + drawSelectedText(g, x, y, startOffset, endOffset); + else if (selectionStart < endOffset) + // Selection starts within the line .. + if (selectionEnd < endOffset) + { + // and ends within it: First part unselected, second part + // selected, third part unselected. + x = drawUnselectedText(g, x, y, startOffset, selectionStart); + x = drawSelectedText(g, x, y, selectionStart, selectionEnd); + drawUnselectedText(g, x, y, selectionEnd, endOffset); + } + else + { + // and ends behind the line: First part unselected, second + // part selected. + x = drawUnselectedText(g, x, y, startOffset, selectionStart); + drawSelectedText(g, x, y, selectionStart, endOffset); + } + else + // Selection is behind this line: Draw completely unselected text. + drawUnselectedText(g, x, y, startOffset, endOffset); } catch (BadLocationException e) { @@ -171,7 +218,7 @@ public class PlainView extends View implements TabExpander g.setColor(selectedColor); Segment segment = getLineBuffer(); getDocument().getText(p0, p1 - p0, segment); - return Utilities.drawTabbedText(segment, x, y, g, this, 0); + return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset); } /** @@ -212,6 +259,8 @@ public class PlainView extends View implements TabExpander selectedColor = textComponent.getSelectedTextColor(); unselectedColor = textComponent.getForeground(); disabledColor = textComponent.getDisabledTextColor(); + selectionStart = textComponent.getSelectionStart(); + selectionEnd = textComponent.getSelectionEnd(); Rectangle rect = s.getBounds(); @@ -219,11 +268,13 @@ public class PlainView extends View implements TabExpander Document document = textComponent.getDocument(); Element root = document.getDefaultRootElement(); int y = rect.y + metrics.getAscent(); + int height = metrics.getHeight(); - for (int i = 0; i < root.getElementCount(); i++) + int count = root.getElementCount(); + for (int i = 0; i < count; i++) { drawLine(i, g, rect.x, y); - y += metrics.getHeight(); + y += height; } } @@ -274,7 +325,7 @@ public class PlainView extends View implements TabExpander { Element child = el.getElement(i); int start = child.getStartOffset(); - int end = child.getEndOffset(); + int end = child.getEndOffset() - 1; try { el.getDocument().getText(start, end - start, seg); @@ -386,6 +437,11 @@ public class PlainView extends View implements TabExpander */ protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f) { + // Return early and do no updates if the allocation area is null + // (like the RI). + if (a == null) + return; + float oldMaxLineLength = maxLineLength; Rectangle alloc = a.getBounds(); Element el = getElement(); @@ -467,7 +523,7 @@ public class PlainView extends View implements TabExpander { Element child = newElements[i]; int start = child.getStartOffset(); - int end = child.getEndOffset(); + int end = child.getEndOffset() - 1; try { el.getDocument().getText(start, end - start, seg); @@ -586,7 +642,7 @@ public class PlainView extends View implements TabExpander * @returna {@link Segment} object, that can be used to fetch text from * the document */ - protected Segment getLineBuffer() + protected final Segment getLineBuffer() { if (lineBuffer == null) lineBuffer = new Segment(); diff --git a/libjava/classpath/javax/swing/text/Position.java b/libjava/classpath/javax/swing/text/Position.java index a9d3d09d764..bb1449e187a 100644 --- a/libjava/classpath/javax/swing/text/Position.java +++ b/libjava/classpath/javax/swing/text/Position.java @@ -40,7 +40,7 @@ package javax.swing.text; public interface Position { - static class Bias + static final class Bias { public static final Bias Backward = new Bias("backward"); public static final Bias Forward = new Bias("forward"); diff --git a/libjava/classpath/javax/swing/text/Segment.java b/libjava/classpath/javax/swing/text/Segment.java index 875d9966c1f..d2364e05a10 100644 --- a/libjava/classpath/javax/swing/text/Segment.java +++ b/libjava/classpath/javax/swing/text/Segment.java @@ -245,7 +245,8 @@ public class Segment implements Cloneable, CharacterIterator || position > getEndIndex()) throw new IllegalArgumentException("position: " + position + ", beginIndex: " + getBeginIndex() - + ", endIndex: " + getEndIndex()); + + ", endIndex: " + getEndIndex() + + ", text: " + toString()); current = position; @@ -264,7 +265,7 @@ public class Segment implements Cloneable, CharacterIterator */ public String toString() { - return new String(array, offset, count); + return (array != null) ? new String(array, offset, count) : ""; } /** diff --git a/libjava/classpath/javax/swing/text/StyleContext.java b/libjava/classpath/javax/swing/text/StyleContext.java index e2643a2aacd..8ef34400d29 100644 --- a/libjava/classpath/javax/swing/text/StyleContext.java +++ b/libjava/classpath/javax/swing/text/StyleContext.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.text; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; @@ -711,35 +713,37 @@ public class StyleContext // have left incomplete; I'm not sure I understand the intent properly. public static Object getStaticAttribute(Object key) + throws NotImplementedException { throw new InternalError("not implemented"); } public static Object getStaticAttributeKey(Object key) + throws NotImplementedException { throw new InternalError("not implemented"); } public static void readAttributeSet(ObjectInputStream in, MutableAttributeSet a) - throws ClassNotFoundException, IOException + throws ClassNotFoundException, IOException, NotImplementedException { throw new InternalError("not implemented"); } public static void writeAttributeSet(ObjectOutputStream out, AttributeSet a) - throws IOException + throws IOException, NotImplementedException { throw new InternalError("not implemented"); } public void readAttributes(ObjectInputStream in, MutableAttributeSet a) - throws ClassNotFoundException, IOException + throws ClassNotFoundException, IOException, NotImplementedException { throw new InternalError("not implemented"); } public void writeAttributes(ObjectOutputStream out, AttributeSet a) - throws IOException + throws IOException, NotImplementedException { throw new InternalError("not implemented"); } diff --git a/libjava/classpath/javax/swing/text/Utilities.java b/libjava/classpath/javax/swing/text/Utilities.java index d109a4a950f..f154e55aac0 100644 --- a/libjava/classpath/javax/swing/text/Utilities.java +++ b/libjava/classpath/javax/swing/text/Utilities.java @@ -1,5 +1,5 @@ /* Utilities.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. @@ -48,6 +48,7 @@ import java.text.BreakIterator; * inside this package. * * @author Roman Kennke (roman@ontographics.com) + * @author Robert Schuster (robertschuster@fsfe.org) */ public class Utilities { @@ -99,8 +100,10 @@ public class Utilities int pixelWidth = 0; int pos = s.offset; int len = 0; + + int end = s.offset + s.count; - for (int offset = s.offset; offset < (s.offset + s.count); ++offset) + for (int offset = s.offset; offset < end; ++offset) { char c = buffer[offset]; if (c == '\t' || c == '\n') @@ -140,7 +143,7 @@ public class Utilities if (len > 0) g.drawChars(buffer, pos, len, pixelX, pixelY + ascent); - return pixelX; + return pixelX + pixelWidth; } /** @@ -236,35 +239,39 @@ public class Utilities // At the end of the for loop, this holds the requested model location int pos; int currentX = x0; - + int width = 0; + for (pos = 0; pos < s.count; pos++) { char nextChar = s.array[s.offset+pos]; if (nextChar == 0) - { - if (! round) - pos--; break; - } + if (nextChar != '\t') - currentX += fm.charWidth(nextChar); + width = fm.charWidth(nextChar); else { if (te == null) - currentX += fm.charWidth(' '); + width = fm.charWidth(' '); else - currentX = (int) te.nextTabStop(currentX, pos); + width = ((int) te.nextTabStop(currentX, pos)) - currentX; } - if (currentX > x) + if (round) { - if (! round) - pos--; - break; + if (currentX + (width>>1) > x) + break; + } + else + { + if (currentX + width > x) + break; } + + currentX += width; } - + return pos + p0; } @@ -315,21 +322,31 @@ public class Utilities String text = c.getText(); BreakIterator wb = BreakIterator.getWordInstance(); wb.setText(text); + int last = wb.following(offs); int current = wb.next(); + int cp; + while (current != BreakIterator.DONE) { for (int i = last; i < current; i++) { - // FIXME: Should use isLetter(int) and text.codePointAt(int) - // instead, but isLetter(int) isn't implemented yet - if (Character.isLetter(text.charAt(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.next(); } - return BreakIterator.DONE; + + throw new BadLocationException("no more word", offs); } /** @@ -358,9 +375,7 @@ public class Utilities { for (int i = last; i < offs; i++) { - // FIXME: Should use isLetter(int) and text.codePointAt(int) - // instead, but isLetter(int) isn't implemented yet - if (Character.isLetter(text.charAt(i))) + if (Character.isLetter(text.codePointAt(i))) return last; } last = current; @@ -510,24 +525,28 @@ public class Utilities int x0, int x, TabExpander e, int startOffset) { - int mark = Utilities.getTabbedTextOffset(s, metrics, x0, x, e, startOffset); + int mark = Utilities.getTabbedTextOffset(s, metrics, x0, x, e, startOffset, false); BreakIterator breaker = BreakIterator.getWordInstance(); breaker.setText(s); - // If mark is equal to the end of the string, just use that position - if (mark == s.count + s.offset) + // If startOffset and s.offset differ then we need to use + // that difference two convert the offset between the two metrics. + int shift = startOffset - s.offset; + + // If mark is equal to the end of the string, just use that position. + if (mark >= shift + s.count) return mark; // Try to find a word boundary previous to the mark at which we - // can break the text - int preceding = breaker.preceding(mark + 1); + // can break the text. + int preceding = breaker.preceding(mark + 1 - shift); if (preceding != 0) - return preceding; - else - // If preceding is 0 we couldn't find a suitable word-boundary so - // just break it on the character boundary - return mark; + return preceding + shift; + + // If preceding is 0 we couldn't find a suitable word-boundary so + // just break it on the character boundary + return mark; } /** @@ -619,8 +638,22 @@ public class Utilities if(offs == -1) return -1; - // Effectively calculates the y value of the previous line. - Point pt = c.modelToView(offs+1).getLocation(); + Point pt = null; + + // Note: Some views represent the position after the last + // typed character others do not. Converting offset 3 in "a\nb" + // in a PlainView will return a valid rectangle while in a + // WrappedPlainView this will throw a BadLocationException. + // This behavior has been observed in the RI. + try + { + // Effectively calculates the y value of the next line. + pt = c.modelToView(offs+1).getLocation(); + } + catch(BadLocationException ble) + { + return offset; + } pt.x = x; diff --git a/libjava/classpath/javax/swing/text/View.java b/libjava/classpath/javax/swing/text/View.java index 2feaf29a4f9..d8ad5f5858e 100644 --- a/libjava/classpath/javax/swing/text/View.java +++ b/libjava/classpath/javax/swing/text/View.java @@ -1,5 +1,5 @@ /* View.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. @@ -733,23 +733,38 @@ public abstract class View implements SwingConstants throws BadLocationException { int ret = pos; + Rectangle r; + View parent; + switch (d) { - case WEST: - ret = pos - 1; - break; case EAST: - ret = pos + 1; + // TODO: take component orientation into account? + // Note: If pos is below zero the implementation will return + // pos + 1 regardless of whether that value is a correct offset + // in the document model. However this is what the RI does. + ret = Math.min(pos + 1, getEndOffset()); + break; + case WEST: + // TODO: take component orientation into account? + ret = Math.max(pos - 1, getStartOffset()); break; case NORTH: - // TODO: Implement this + // Try to find a suitable offset by examining the area above. + parent = getParent(); + r = parent.modelToView(pos, a, b).getBounds(); + ret = parent.viewToModel(r.x, r.y - 1, a, biasRet); break; case SOUTH: - // TODO: Implement this + // Try to find a suitable offset by examining the area below. + parent = getParent(); + r = parent.modelToView(pos, a, b).getBounds(); + ret = parent.viewToModel(r.x + r.width, r.y + r.height, a, biasRet); break; default: throw new IllegalArgumentException("Illegal value for d"); } + return ret; } } diff --git a/libjava/classpath/javax/swing/text/WrappedPlainView.java b/libjava/classpath/javax/swing/text/WrappedPlainView.java index e2790a05ca0..a6c369a4c25 100644 --- a/libjava/classpath/javax/swing/text/WrappedPlainView.java +++ b/libjava/classpath/javax/swing/text/WrappedPlainView.java @@ -1,5 +1,5 @@ /* WrappedPlainView.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,7 +45,6 @@ import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; -import javax.swing.SwingConstants; import javax.swing.event.DocumentEvent; import javax.swing.text.Position.Bias; @@ -64,8 +63,11 @@ public class WrappedPlainView extends BoxView implements TabExpander /** The color for disabled components **/ Color disabledColor; - /** Stores the font metrics **/ - protected FontMetrics metrics; + /** + * Stores the font metrics. This is package private to avoid synthetic + * accessor method. + */ + FontMetrics metrics; /** Whether or not to wrap on word boundaries **/ boolean wordWrap; @@ -79,6 +81,9 @@ public class WrappedPlainView extends BoxView implements TabExpander /** The end of the selected text **/ int selectionEnd; + /** The height of the line (used while painting) **/ + int lineHeight; + /** * The instance returned by {@link #getLineBuffer()}. */ @@ -270,8 +275,20 @@ public class WrappedPlainView extends BoxView implements TabExpander protected int calculateBreakPosition(int p0, int p1) { Container c = getContainer(); - Rectangle alloc = new Rectangle(0, 0, getWidth(), getHeight()); + + int li = getLeftInset(); + int ti = getTopInset(); + + Rectangle alloc = new Rectangle(li, ti, + getWidth()-getRightInset()-li, + getHeight()-getBottomInset()-ti); + + // Mimic a behavior observed in the RI. + if (alloc.isEmpty()) + return 0; + updateMetrics(); + try { getDocument().getText(p0, p1 - p0, getLineBuffer()); @@ -279,18 +296,16 @@ public class WrappedPlainView extends BoxView implements TabExpander catch (BadLocationException ble) { // this shouldn't happen + throw new InternalError("Invalid offsets p0: " + p0 + " - p1: " + p1); } - // FIXME: Should we account for the insets of the container? + if (wordWrap) - return p0 - + Utilities.getBreakLocation(lineBuffer, metrics, alloc.x, - alloc.x + alloc.width, this, 0); + return Utilities.getBreakLocation(lineBuffer, metrics, alloc.x, + alloc.x + alloc.width, this, p0); else - { - return p0 - + Utilities.getTabbedTextOffset(lineBuffer, metrics, alloc.x, - alloc.x + alloc.width, this, 0); - } + return p0 + Utilities.getTabbedTextOffset(lineBuffer, metrics, alloc.x, + alloc.x + alloc.width, this, 0, + true); } void updateMetrics() @@ -336,8 +351,8 @@ public class WrappedPlainView extends BoxView implements TabExpander public void insertUpdate (DocumentEvent e, Shape a, ViewFactory f) { super.insertUpdate(e, a, viewFactory); - // FIXME: could improve performance by repainting only the necessary area - getContainer().repaint(); + + // No repaint needed, as this is done by the WrappedLine instances. } /** @@ -347,8 +362,8 @@ public class WrappedPlainView extends BoxView implements TabExpander public void removeUpdate (DocumentEvent e, Shape a, ViewFactory f) { super.removeUpdate(e, a, viewFactory); - // FIXME: could improve performance by repainting only the necessary area - getContainer().repaint(); + + // No repaint needed, as this is done by the WrappedLine instances. } /** @@ -359,8 +374,8 @@ public class WrappedPlainView extends BoxView implements TabExpander public void changedUpdate (DocumentEvent e, Shape a, ViewFactory f) { super.changedUpdate(e, a, viewFactory); - // FIXME: could improve performance by repainting only the necessary area - getContainer().repaint(); + + // No repaint needed, as this is done by the WrappedLine instances. } class WrappedLineCreator implements ViewFactory @@ -383,9 +398,19 @@ public class WrappedPlainView extends BoxView implements TabExpander public void paint(Graphics g, Shape a) { JTextComponent comp = (JTextComponent)getContainer(); + // Ensure metrics are up-to-date. + updateMetrics(); + selectionStart = comp.getSelectionStart(); selectionEnd = comp.getSelectionEnd(); - updateMetrics(); + + selectedColor = comp.getSelectedTextColor(); + unselectedColor = comp.getForeground(); + disabledColor = comp.getDisabledTextColor(); + selectedColor = comp.getSelectedTextColor(); + lineHeight = metrics.getHeight(); + g.setFont(comp.getFont()); + super.paint(g, a); } @@ -404,7 +429,7 @@ public class WrappedPlainView extends BoxView implements TabExpander class WrappedLine extends View { /** Used to cache the number of lines for this View **/ - int numLines; + int numLines = 1; public WrappedLine(Element elem) { @@ -418,48 +443,47 @@ public class WrappedPlainView extends BoxView implements TabExpander */ public void paint(Graphics g, Shape s) { - // Ensure metrics are up-to-date. - updateMetrics(); - JTextComponent textComponent = (JTextComponent) getContainer(); - - g.setFont(textComponent.getFont()); - selectedColor = textComponent.getSelectedTextColor(); - unselectedColor = textComponent.getForeground(); - disabledColor = textComponent.getDisabledTextColor(); - - // FIXME: this is a hack, for some reason textComponent.getSelectedColor - // was returning black, which is not visible against a black background - selectedColor = Color.WHITE; - Rectangle rect = s.getBounds(); - int lineHeight = metrics.getHeight(); int end = getEndOffset(); int currStart = getStartOffset(); - int currEnd; + int currEnd; + int count = 0; while (currStart < end) { currEnd = calculateBreakPosition(currStart, end); - drawLine(currStart, currEnd, g, rect.x, rect.y); + + drawLine(currStart, currEnd, g, rect.x, rect.y + metrics.getAscent()); + rect.y += lineHeight; if (currEnd == currStart) currStart ++; else - currStart = currEnd; + currStart = currEnd; + + count++; + } + + if (count != numLines) + { + numLines = count; + preferenceChanged(this, false, true); + } + } /** - * Determines the number of logical lines that the Element - * needs to be displayed - * @return the number of lines needed to display the Element + * Calculates the number of logical lines that the Element + * needs to be displayed and updates the variable numLines + * accordingly. */ - int determineNumLines() + void determineNumLines() { numLines = 0; int end = getEndOffset(); if (end == 0) - return 0; + return; int breakPoint; for (int i = getStartOffset(); i < end;) @@ -468,12 +492,17 @@ public class WrappedPlainView extends BoxView implements TabExpander // careful: check that there's no off-by-one problem here // depending on which position calculateBreakPosition returns breakPoint = calculateBreakPosition(i, end); + + if (breakPoint == 0) + return; + + // If breakPoint is equal to the current index no further + // line is needed and we can end the loop. if (breakPoint == i) - i ++; + break; else i = breakPoint; } - return numLines; } /** @@ -489,7 +518,11 @@ public class WrappedPlainView extends BoxView implements TabExpander if (axis == X_AXIS) return getWidth(); else if (axis == Y_AXIS) - return numLines * metrics.getHeight(); + { + if (metrics == null) + updateMetrics(); + return numLines * metrics.getHeight(); + } throw new IllegalArgumentException("Invalid axis for getPreferredSpan: " + axis); @@ -509,9 +542,15 @@ public class WrappedPlainView extends BoxView implements TabExpander public Shape modelToView(int pos, Shape a, Bias b) throws BadLocationException { + Rectangle rect = a.getBounds(); + + // Throwing a BadLocationException is an observed behavior of the RI. + if (rect.isEmpty()) + throw new BadLocationException("Unable to calculate view coordinates " + + "when allocation area is empty.", 5); + Segment s = getLineBuffer(); int lineHeight = metrics.getHeight(); - Rectangle rect = a.getBounds(); // Return a rectangle with width 1 and height equal to the height // of the text @@ -530,7 +569,7 @@ public class WrappedPlainView extends BoxView implements TabExpander // If pos is between currLineStart and currLineEnd then just find // the width of the text from currLineStart to pos and add that // to rect.x - if (pos >= currLineStart && pos < currLineEnd || pos == end - 1) + if (pos >= currLineStart && pos < currLineEnd) { try { @@ -574,68 +613,93 @@ public class WrappedPlainView extends BoxView implements TabExpander Segment s = getLineBuffer(); Rectangle rect = a.getBounds(); int currLineStart = getStartOffset(); + + // Although calling modelToView with the last possible offset will + // cause a BadLocationException in CompositeView it is allowed + // to return that offset in viewToModel. int end = getEndOffset(); + int lineHeight = metrics.getHeight(); if (y < rect.y) return currLineStart; + if (y > rect.y + rect.height) - return end - 1; + return end; + + // Note: rect.x and rect.width do not represent the width of painted + // text but the area where text *may* be painted. This means the width + // is most of the time identical to the component's width. - while (true) + while (currLineStart != end) { int currLineEnd = calculateBreakPosition(currLineStart, end); + // If we're at the right y-position that means we're on the right // logical line and we should look for the character if (y >= rect.y && y < rect.y + lineHeight) { - // Check if the x position is to the left or right of the text - if (x < rect.x) - return currLineStart; - if (x > rect.x + rect.width) - return currLineEnd - 1; - try { - getDocument().getText(currLineStart, end - currLineStart, s); + getDocument().getText(currLineStart, currLineEnd - currLineStart, s); } catch (BadLocationException ble) { // Shouldn't happen } - int mark = Utilities.getTabbedTextOffset(s, metrics, rect.x, - (int) x, - WrappedPlainView.this, - currLineStart); - return currLineStart + mark; + + int offset = Utilities.getTabbedTextOffset(s, metrics, rect.x, + (int) x, + WrappedPlainView.this, + currLineStart); + // If the calculated offset is the end of the line (in the + // document (= start of the next line) return the preceding + // offset instead. This makes sure that clicking right besides + // the last character in a line positions the cursor after the + // last character and not in the beginning of the next line. + return (offset == currLineEnd) ? offset - 1 : offset; } // Increment rect.y so we're checking the next logical line rect.y += lineHeight; // Increment currLineStart to the model position of the start - // of the next logical line - if (currLineEnd == currLineStart) - currLineStart = end; - else - currLineStart = currLineEnd; + // of the next logical line. + currLineStart = currLineEnd; + } + + return end; } /** - * This method is called from insertUpdate and removeUpdate. - * If the number of lines in the document has changed, just repaint + * <p>This method is called from insertUpdate and removeUpdate.</p> + * + * <p>If the number of lines in the document has changed, just repaint * the whole thing (note, could improve performance by not repainting * anything above the changes). If the number of lines hasn't changed, - * just repaint the given Rectangle. + * just repaint the given Rectangle.</p> + * + * <p>Note that the <code>Rectangle</code> argument may be <code>null</code> + * when the allocation area is empty.</code> + * * @param a the Rectangle to repaint if the number of lines hasn't changed */ void updateDamage (Rectangle a) { - int newNumLines = determineNumLines(); - if (numLines != newNumLines) + // If the allocation area is empty we can't do anything useful. + // As determining the number of lines is impossible in that state we + // reset it to an invalid value which can then be recalculated at a + // later point. + if (a == null || a.isEmpty()) { - numLines = newNumLines; - getContainer().repaint(); + numLines = 1; + return; } + + int oldNumLines = numLines; + determineNumLines(); + + if (numLines != oldNumLines) + preferenceChanged(this, false, true); else getContainer().repaint(a.x, a.y, a.width, a.height); } @@ -663,6 +727,15 @@ public class WrappedPlainView extends BoxView implements TabExpander */ public void removeUpdate (DocumentEvent changes, Shape a, ViewFactory f) { + // Note: This method is not called when characters from the + // end of the document are removed. The reason for this + // can be found in the implementation of View.forwardUpdate: + // The document event will denote offsets which do not exist + // any more, getViewIndex() will therefore return -1 and this + // makes View.forwardUpdate() skip this method call. + // However this seems to cause no trouble and as it reduces the + // number of method calls it can stay this way. + updateDamage((Rectangle)a); } } diff --git a/libjava/classpath/javax/swing/text/html/FormView.java b/libjava/classpath/javax/swing/text/html/FormView.java index b85c6943404..d54021066d0 100644 --- a/libjava/classpath/javax/swing/text/html/FormView.java +++ b/libjava/classpath/javax/swing/text/html/FormView.java @@ -39,8 +39,11 @@ exception statement from your version. */ package javax.swing.text.html; import java.awt.Component; +import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -83,6 +86,24 @@ public class FormView implements ActionListener { + protected class MouseEventListener + extends MouseAdapter + { + /** + * Creates a new <code>MouseEventListener</code>. + */ + protected MouseEventListener() + { + // Nothing to do here. + } + + public void mouseReleased(MouseEvent ev) + { + String data = getImageData(ev.getPoint()); + imageSubmit(data); + } + } + /** * If the value attribute of an <code><input type="submit">> * tag is not specified, then this string is used. @@ -227,4 +248,28 @@ public class FormView { // FIXME: Implement this. } + + /** + * Determines the image data that should be submitted in response to a + * mouse click on a image. This is either 'x=<p.x>&y=<p.y>' if the name + * attribute of the element is null or '' or + * <name>.x=<p.x>&<name>.y=<p.y>' when the name attribute is not empty. + * + * @param p the coordinates of the mouseclick + */ + String getImageData(Point p) + { + String name = (String) getElement().getAttributes() + .getAttribute(HTML.Attribute.NAME); + String data; + if (name == null || name.equals("")) + { + data = "x=" + p.x + "&y=" + p.y; + } + else + { + data = name + ".x=" + p.x + "&" + name + ".y=" + p.y; + } + return data; + } } diff --git a/libjava/classpath/javax/swing/text/html/HTML.java b/libjava/classpath/javax/swing/text/html/HTML.java index 2b521cd22b4..2c908f6fc6e 100644 --- a/libjava/classpath/javax/swing/text/html/HTML.java +++ b/libjava/classpath/javax/swing/text/html/HTML.java @@ -292,7 +292,7 @@ public class HTML /** * The media attribute */ - public static final Attribute MEDIA = new Attribute("media"); + static final Attribute MEDIA = new Attribute("media"); /** * The method attribute @@ -758,7 +758,7 @@ public class HTML /** * The <nobr> tag */ - public static final Tag NOBR = new Tag("nobr"); + static final Tag NOBR = new Tag("nobr"); /** * The <noframes> tag , breaks flow, block tag. diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java index 2a96953ee91..fba6cad12e9 100644 --- a/libjava/classpath/javax/swing/text/html/HTMLDocument.java +++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.text.html; +import gnu.classpath.NotImplementedException; + import java.io.IOException; import java.net.URL; import java.util.HashMap; @@ -667,6 +669,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("FormAction.start not implemented"); @@ -677,6 +680,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("FormAction.end not implemented"); @@ -690,6 +694,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("HiddenAction.start not implemented"); @@ -700,6 +705,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("HiddenAction.end not implemented"); @@ -713,6 +719,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("IsindexAction.start not implemented"); @@ -723,6 +730,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("IsindexAction.end not implemented"); @@ -759,6 +767,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("PreAction.start not implemented"); @@ -769,6 +778,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("PreAction.end not implemented"); @@ -782,6 +792,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("SpecialAction.start not implemented"); @@ -792,6 +803,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("SpecialAction.end not implemented"); @@ -805,6 +817,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("AreaAction.start not implemented"); @@ -815,6 +828,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("AreaAction.end not implemented"); @@ -828,6 +842,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("BaseAction.start not implemented"); @@ -838,6 +853,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("BaseAction.end not implemented"); @@ -851,6 +867,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("HeadAction.start not implemented: "+t); @@ -862,6 +879,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("HeadAction.end not implemented: "+t); @@ -876,6 +894,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("LinkAction.start not implemented"); @@ -886,6 +905,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("LinkAction.end not implemented"); @@ -899,6 +919,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("MapAction.start not implemented"); @@ -909,6 +930,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("MapAction.end not implemented"); @@ -922,6 +944,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("MetaAction.start not implemented"); @@ -932,6 +955,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("MetaAction.end not implemented"); @@ -945,6 +969,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("StyleAction.start not implemented"); @@ -955,6 +980,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("StyleAction.end not implemented"); @@ -968,6 +994,7 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement. print ("TitleAction.start not implemented"); @@ -978,6 +1005,7 @@ public class HTMLDocument extends DefaultStyledDocument * with this Action. */ public void end(HTML.Tag t) + throws NotImplementedException { // FIXME: Implement. print ("TitleAction.end not implemented"); @@ -1253,6 +1281,7 @@ public class HTMLDocument extends DefaultStyledDocument * @since 1.3 */ public void handleEndOfLineString(String eol) + throws NotImplementedException { // FIXME: Implement. print ("HTMLReader.handleEndOfLineString not implemented yet"); @@ -1265,6 +1294,7 @@ public class HTMLDocument extends DefaultStyledDocument * @param data the text to add to the textarea */ protected void textAreaContent(char[] data) + throws NotImplementedException { // FIXME: Implement. print ("HTMLReader.textAreaContent not implemented yet"); @@ -1276,6 +1306,7 @@ public class HTMLDocument extends DefaultStyledDocument * @param data the text */ protected void preContent(char[] data) + throws NotImplementedException { // FIXME: Implement print ("HTMLReader.preContent not implemented yet"); @@ -1447,6 +1478,7 @@ public class HTMLDocument extends DefaultStyledDocument * @param a the attribute set specifying the special content */ protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a) + throws NotImplementedException { // FIXME: Implement print ("HTMLReader.addSpecialElement not implemented yet"); @@ -1550,7 +1582,7 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if an HTMLEditorKit.Parser has not been set */ public void setInnerHTML(Element elem, String htmlText) - throws BadLocationException, IOException + throws BadLocationException, IOException, NotImplementedException { if (elem.isLeaf()) throw new IllegalArgumentException("Element is a leaf"); @@ -1574,7 +1606,7 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if parser is not set */ public void setOuterHTML(Element elem, String htmlText) - throws BadLocationException, IOException + throws BadLocationException, IOException, NotImplementedException { if (parser == null) throw new IllegalStateException("Parser has not been set"); @@ -1593,7 +1625,7 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if parser has not been set */ public void insertBeforeStart(Element elem, String htmlText) - throws BadLocationException, IOException + throws BadLocationException, IOException, NotImplementedException { if (parser == null) throw new IllegalStateException("Parser has not been set"); @@ -1613,7 +1645,7 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if parser is not set */ public void insertBeforeEnd(Element elem, String htmlText) - throws BadLocationException, IOException + throws BadLocationException, IOException, NotImplementedException { if (parser == null) throw new IllegalStateException("Parser has not been set"); @@ -1632,7 +1664,7 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if parser is not set */ public void insertAfterEnd(Element elem, String htmlText) - throws BadLocationException, IOException + throws BadLocationException, IOException, NotImplementedException { if (parser == null) throw new IllegalStateException("Parser has not been set"); @@ -1651,7 +1683,7 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if parser is not set */ public void insertAfterStart(Element elem, String htmlText) - throws BadLocationException, IOException + throws BadLocationException, IOException, NotImplementedException { if (parser == null) throw new IllegalStateException("Parser has not been set"); @@ -1676,6 +1708,7 @@ public class HTMLDocument extends DefaultStyledDocument */ public void setParagraphAttributes(int offset, int length, AttributeSet s, boolean replace) + throws NotImplementedException { // FIXME: Not implemented. System.out.println("setParagraphAttributes not implemented"); @@ -1688,6 +1721,7 @@ public class HTMLDocument extends DefaultStyledDocument * @param e - the Document event */ protected void fireChangedUpdate(DocumentEvent e) + throws NotImplementedException { // FIXME: Not implemented. System.out.println("fireChangedUpdate not implemented"); diff --git a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java index 2d5d1eb79da..92d9de938eb 100644 --- a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java +++ b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java @@ -39,6 +39,8 @@ exception statement from your version. */ package javax.swing.text.html; +import gnu.classpath.NotImplementedException; + import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -298,6 +300,7 @@ public class HTMLEditorKit Element insertElement, String html, HTML.Tag parentTag, HTML.Tag addTag) + throws NotImplementedException { /* As its name implies, this protected method is used when HTML is inserted at a diff --git a/libjava/classpath/javax/swing/text/html/ListView.java b/libjava/classpath/javax/swing/text/html/ListView.java new file mode 100644 index 00000000000..c07d3598c92 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/ListView.java @@ -0,0 +1,131 @@ +/* ListView.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 java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; + +import javax.swing.text.Element; + +/** + * A View to render HTML lists, like the <code><ul></code> and + * <code><ol></code> tags. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class ListView + extends BlockView +{ + + /** + * The painter used to paint the list items. + */ + private StyleSheet.ListPainter painter; + + /** + * Creates a new <code>ListView</code> for the specified element. + * + * @param el the element to create a list view for + */ + public ListView(Element el) + { + super(el, Y_AXIS); + } + + /** + * Returns the alignment of this view along the specified axis. + * + * This returns <code>0.5</code> unconditionally. + * + * @param axis the axis + * + * @return the alignment of this view along the specified axis + */ + public float getAlignment(int axis) + { + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Illegal axis parameter: " + axis); + + return 0.5F; + } + + /** + * Paints the <code>ListView</code>. + * + * @param g the graphics context to use for painting + * @param allocation the allocation given to this view + */ + public void paint(Graphics g, Shape allocation) + { + super.paint(g, allocation); + // FIXME: Why is this overridden? I think that painting would be done + // by the superclass and the stylesheet... Maybe find out when this + // stuff is implemented properly. + } + + /** + * Paints the child with the specified index into the specified allocation. + * + * This implementation forwards to the list painter fetched from the + * {@link StyleSheet} and then calls + * <code>super.paintChild(g, a, index)</code>. + * + * @param g the graphics context to use + * @param a the allocation for the child + * @param index the child index + */ + protected void paintChild(Graphics g, Rectangle a, int index) + { + painter.paint(g, a.x, a.y, a.width, a.height, this, index); + super.paintChild(g, a, index); + } + + /** + * Fetches this view's properties from the style attributes of this view's + * element. + * + * This forwards to super and then fetches a {@link StyleSheet.ListPainter} + * from the stylesheet suitable for painting the list. + */ + protected void setPropertiesFromAttributes() + { + super.setPropertiesFromAttributes(); + painter = getStyleSheet().getListPainter(getAttributes()); + } +} diff --git a/libjava/classpath/javax/swing/text/html/NullView.java b/libjava/classpath/javax/swing/text/html/NullView.java index 4b66c5ad87e..86ce0c10f0f 100644 --- a/libjava/classpath/javax/swing/text/html/NullView.java +++ b/libjava/classpath/javax/swing/text/html/NullView.java @@ -52,8 +52,8 @@ import javax.swing.text.Position.Bias; * * @author Roman Kennke (kennke@aicas.com) */ -public class NullView - extends View +class NullView + extends View { /** diff --git a/libjava/classpath/javax/swing/text/html/parser/Entity.java b/libjava/classpath/javax/swing/text/html/parser/Entity.java index 766984f9c79..cf294c748db 100644 --- a/libjava/classpath/javax/swing/text/html/parser/Entity.java +++ b/libjava/classpath/javax/swing/text/html/parser/Entity.java @@ -54,7 +54,7 @@ import java.io.Serializable; * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) */ public final class Entity - implements DTDConstants, Serializable + implements DTDConstants { /** * Package level mapper between type names and they string values. diff --git a/libjava/classpath/javax/swing/text/rtf/package.html b/libjava/classpath/javax/swing/text/rtf/package.html new file mode 100644 index 00000000000..c695aef6c47 --- /dev/null +++ b/libjava/classpath/javax/swing/text/rtf/package.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.text.rtf package. + 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. --> + +<html> +<head><title>GNU Classpath - javax.swing.text.rtf</title></head> + +<body> +<p>Provides support for Rich Text Format (RTF) data to be used with the +{@link JEditorPane} component. +</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/tree/AbstractLayoutCache.java b/libjava/classpath/javax/swing/tree/AbstractLayoutCache.java index adece101deb..8dbdd2f5e58 100644 --- a/libjava/classpath/javax/swing/tree/AbstractLayoutCache.java +++ b/libjava/classpath/javax/swing/tree/AbstractLayoutCache.java @@ -38,10 +38,13 @@ exception statement from your version. */ package javax.swing.tree; +import gnu.classpath.NotImplementedException; + import java.awt.Rectangle; import java.util.Enumeration; import javax.swing.event.TreeModelEvent; +import javax.swing.tree.VariableHeightLayoutCache.NodeRecord; /** * class AbstractLayoutCache @@ -49,361 +52,397 @@ import javax.swing.event.TreeModelEvent; * @author Andrew Selkirk */ public abstract class AbstractLayoutCache - implements RowMapper + implements RowMapper { - /** - * class NodeDimensions - */ - public abstract static class NodeDimensions - { - /** - * Creates <code>NodeDimensions</code> object. - */ - public NodeDimensions() - { - // Do nothing here. - } - - /** - * getNodeDimensions - * - * @param value0 TODO - * @param value1 TODO - * @param value2 TODO - * @param value3 TODO - * @param value4 TODO - * @return Rectangle - */ - public abstract Rectangle getNodeDimensions(Object value0, int value1, - int value2, boolean value3, Rectangle value4); - } - - /** - * nodeDimensions - */ - protected NodeDimensions nodeDimensions; - - /** - * treeModel - */ - protected TreeModel treeModel; - - /** - * treeSelectionModel - */ - protected TreeSelectionModel treeSelectionModel; - - /** - * rootVisible - */ - protected boolean rootVisible; - - /** - * rowHeight - */ - protected int rowHeight; - - /** - * Constructor AbstractLayoutCache - */ - public AbstractLayoutCache() - { - // Do nothing here. - } - - /** - * setNodeDimensions - * - * @param dimensions TODO - */ - public void setNodeDimensions(NodeDimensions dimensions) - { - nodeDimensions = dimensions; - } - - /** - * getNodeDimensions - * - * @return NodeDimensions - */ - public NodeDimensions getNodeDimensions() - { - return nodeDimensions; - } - - /** - * getNodeDimensions - * - * @param value TODO - * @param row TODO - * @param depth TODO - * @param expanded TODO - * @param bounds TODO - * - * @return Rectangle - */ - protected Rectangle getNodeDimensions(Object value, int row, int depth, - boolean expanded, Rectangle bounds) - { - if (bounds == null) - return new Rectangle(); - return null; - // TODO - } - - /** - * Sets the model that provides the tree data. - * - * @param model the model - */ - public void setModel(TreeModel model) - { - treeModel = model; - } - - /** - * Returns the model that provides the tree data. - * - * @return the model - */ - public TreeModel getModel() - { - return treeModel; - } - - /** - * setRootVisible - * - * @param visible <code>true</code> if root should be visible, - * <code>false</code> otherwise - */ - public void setRootVisible(boolean visible) - { - rootVisible = visible; - } - - /** - * isRootVisible - * - * @return <code>true</code> if root is visible, - * <code>false</code> otherwise - */ - public boolean isRootVisible() - { - return rootVisible; - } - - /** - * setRowHeight - * - * @param height the row height - */ - public void setRowHeight(int height) - { - rowHeight = height; - } - - /** - * getRowHeight - * - * @return the row height - */ - public int getRowHeight() - { - return rowHeight; - } - - /** - * setSelectionModel - * - * @param model the model - */ - public void setSelectionModel(TreeSelectionModel model) - { - treeSelectionModel = model; - } - - /** - * getSelectionModel - * - * @return the model - */ - public TreeSelectionModel getSelectionModel() - { - return treeSelectionModel; - } - - /** - * getPreferredHeight - * - * @return int - */ - public int getPreferredHeight() - { - return 0; // TODO - } - - /** - * getPreferredWidth - * - * @param value0 TODO - * - * @return int - */ - public int getPreferredWidth(Rectangle value0) - { - return 0; // TODO - } - - /** - * isExpanded - * - * @param value0 TODO - * - * @return boolean - */ - public abstract boolean isExpanded(TreePath value0); - - /** - * getBounds - * - * @param value0 TODO - * @param value1 TODO - * - * @return Rectangle - */ - public abstract Rectangle getBounds(TreePath value0, Rectangle value1); - - /** - * getPathForRow - * - * @param row the row - * - * @return the tree path - */ - public abstract TreePath getPathForRow(int row); - - /** - * getRowForPath - * - * @param path the tree path - * - * @return the row - */ - public abstract int getRowForPath(TreePath path); - - /** - * getPathClosestTo - * - * @param value0 TODO - * @param value1 TODO - * - * @return the tree path - */ - public abstract TreePath getPathClosestTo(int value0, int value1); - - /** - * getVisiblePathsFrom - * - * @param path the tree path - * - * @return Enumeration - */ - public abstract Enumeration getVisiblePathsFrom(TreePath path); - - /** - * getVisibleChildCount - * - * @param path the tree path - * - * @return int - */ - public abstract int getVisibleChildCount(TreePath path); - - /** - * setExpandedState - * - * @param value0 TODO - * - * @param value1 TODO - */ - public abstract void setExpandedState(TreePath value0, boolean value1); - - /** - * getExpandedState - * - * @param path the tree path - * - * @return boolean - */ - public abstract boolean getExpandedState(TreePath path); - - /** - * getRowCount - * - * @return the number of rows - */ - public abstract int getRowCount(); - - /** - * invalidateSizes - */ - public abstract void invalidateSizes(); - - /** - * invalidatePathBounds - * - * @param path the tree path - */ - public abstract void invalidatePathBounds(TreePath path); - - /** - * treeNodesChanged - * - * @param event the event to send - */ - public abstract void treeNodesChanged(TreeModelEvent event); - - /** - * treeNodesInserted - * - * @param event the event to send - */ - public abstract void treeNodesInserted(TreeModelEvent event); - - /** - * treeNodesRemoved - * - * @param event the event to send - */ - public abstract void treeNodesRemoved(TreeModelEvent event); - - /** - * treeStructureChanged - * - * @param event the event to send - */ - public abstract void treeStructureChanged(TreeModelEvent event); - - /** - * getRowsForPaths - * - * @param paths the tree paths - * - * @return an array of rows - */ - public int[] getRowsForPaths(TreePath[] paths) - { - return null; // TODO - } - - /** - * isFixedRowHeight - * - * @return boolean - */ - protected boolean isFixedRowHeight() - { - return false; // TODO - } + /** + * class NodeDimensions + */ + public abstract static class NodeDimensions + { + /** + * Creates <code>NodeDimensions</code> object. + */ + public NodeDimensions() + { + // Do nothing here. + } + + /** + * Get the node dimensions. The NodeDimensions property must be set (unless + * the method is overridden, like if {@link FixedHeightLayoutCache}. If the + * method is not overridden and the property is not set, the InternalError is + * thrown. + * + * @param value the last node in the path + * @param row the node row + * @param depth the indentation depth + * @param expanded true if this node is expanded, false otherwise + * @param bounds the area where the tree is displayed + */ + public abstract Rectangle getNodeDimensions(Object value, int row, + int depth, boolean expanded, + Rectangle bounds); + } + + /** + * nodeDimensions + */ + protected NodeDimensions nodeDimensions; + + /** + * treeModel + */ + protected TreeModel treeModel; + + /** + * treeSelectionModel + */ + protected TreeSelectionModel treeSelectionModel; + + /** + * rootVisible + */ + protected boolean rootVisible; + + /** + * rowHeight + */ + protected int rowHeight; + + /** + * Constructor AbstractLayoutCache + */ + public AbstractLayoutCache() + { + // Do nothing here. + } + + /** + * setNodeDimensions + * + * @param dimensions TODO + */ + public void setNodeDimensions(NodeDimensions dimensions) + { + nodeDimensions = dimensions; + } + + /** + * getNodeDimensions + * + * @return NodeDimensions + */ + public NodeDimensions getNodeDimensions() + { + return nodeDimensions; + } + + /** + * Get the node dimensions. The NodeDimensions property must be set + * (unless the method is overridden, like if + * {@link FixedHeightLayoutCache}. If the method is not overridden and + * the property is not set, the InternalError is thrown. + * + * @param value the last node in the path + * @param row the node row + * @param depth the indentation depth + * @param expanded true if this node is expanded, false otherwise + * @param bounds the area where the tree is displayed + */ + protected Rectangle getNodeDimensions(Object value, int row, int depth, + boolean expanded, Rectangle bounds) + { + if (nodeDimensions == null) + throw new InternalError("The NodeDimensions are not set"); + return nodeDimensions.getNodeDimensions(value, row, depth, expanded, bounds); + } + + /** + * Sets the model that provides the tree data. + * + * @param model the model + */ + public void setModel(TreeModel model) + { + treeModel = model; + } + + /** + * Returns the model that provides the tree data. + * + * @return the model + */ + public TreeModel getModel() + { + return treeModel; + } + + /** + * setRootVisible + * + * @param visible <code>true</code> if root should be visible, + * <code>false</code> otherwise + */ + public void setRootVisible(boolean visible) + { + rootVisible = visible; + } + + /** + * isRootVisible + * + * @return <code>true</code> if root is visible, + * <code>false</code> otherwise + */ + public boolean isRootVisible() + { + return rootVisible; + } + + /** + * setRowHeight + * + * @param height the row height + */ + public void setRowHeight(int height) + { + rowHeight = height; + invalidateSizes(); + } + + /** + * getRowHeight + * + * @return the row height + */ + public int getRowHeight() + { + return rowHeight; + } + + /** + * setSelectionModel + * + * @param model the model + */ + public void setSelectionModel(TreeSelectionModel model) + { + treeSelectionModel = model; + } + + /** + * getSelectionModel + * + * @return the model + */ + public TreeSelectionModel getSelectionModel() + { + return treeSelectionModel; + } + + /** + * Get the sum of heights for all rows. This class provides a general not + * optimized implementation that is overridded in derived classes + * ({@link VariableHeightLayoutCache}, {@link FixedHeightLayoutCache}) for + * the better performance. + */ + public int getPreferredHeight() + { + int height = 0; + int n = getRowCount(); + Rectangle r = new Rectangle(); + for (int i = 0; i < n; i++) + { + TreePath path = getPathForRow(i); + height += getBounds(path, r).height; + } + return height; + } + + /** + * Get the maximal width. This class provides a general not + * optimized implementation that is overridded in derived classes + * ({@link VariableHeightLayoutCache}, {@link FixedHeightLayoutCache}) for + * the better performance. + * + * @param rect the rectangle that is used during the method work + */ + public int getPreferredWidth(Rectangle rect) + { + int maximalWidth = 0; + Rectangle r = new Rectangle(); + int n = getRowCount(); + for (int i = 0; i < n; i++) + { + TreePath path = getPathForRow(i); + r.setBounds(0,0,0,0); + r = getBounds(path, r); + if (r.x + r.width > maximalWidth) + maximalWidth = r.x + r.width; + // Invalidate the cached value as this may be the very early call + // before the heigth is properly set (the vertical coordinate may + // not be correct). + invalidatePathBounds(path); + } + return maximalWidth; + } + /** + * isExpanded + * + * @param value0 TODO + * + * @return boolean + */ + public abstract boolean isExpanded(TreePath value0); + + /** + * getBounds + * + * @param value0 TODO + * @param value1 TODO + * + * @return Rectangle + */ + public abstract Rectangle getBounds(TreePath value0, Rectangle value1); + + /** + * getPathForRow + * + * @param row the row + * + * @return the tree path + */ + public abstract TreePath getPathForRow(int row); + + /** + * getRowForPath + * + * @param path the tree path + * + * @return the row + */ + public abstract int getRowForPath(TreePath path); + + /** + * getPathClosestTo + * + * @param value0 TODO + * @param value1 TODO + * + * @return the tree path + */ + public abstract TreePath getPathClosestTo(int value0, int value1); + + /** + * getVisiblePathsFrom + * + * @param path the tree path + * + * @return Enumeration + */ + public abstract Enumeration getVisiblePathsFrom(TreePath path); + + /** + * getVisibleChildCount + * + * @param path the tree path + * + * @return int + */ + public abstract int getVisibleChildCount(TreePath path); + + /** + * setExpandedState + * + * @param value0 TODO + * + * @param value1 TODO + */ + public abstract void setExpandedState(TreePath value0, boolean value1); + + /** + * getExpandedState + * + * @param path the tree path + * + * @return boolean + */ + public abstract boolean getExpandedState(TreePath path); + + /** + * getRowCount + * + * @return the number of rows + */ + public abstract int getRowCount(); + + /** + * invalidateSizes + */ + public abstract void invalidateSizes(); + + /** + * invalidatePathBounds + * + * @param path the tree path + */ + public abstract void invalidatePathBounds(TreePath path); + + /** + * treeNodesChanged + * + * @param event the event to send + */ + public abstract void treeNodesChanged(TreeModelEvent event); + + /** + * treeNodesInserted + * + * @param event the event to send + */ + public abstract void treeNodesInserted(TreeModelEvent event); + + /** + * treeNodesRemoved + * + * @param event the event to send + */ + public abstract void treeNodesRemoved(TreeModelEvent event); + + /** + * treeStructureChanged + * + * @param event the event to send + */ + public abstract void treeStructureChanged(TreeModelEvent event); + + /** + * Get the tree row numbers for the given pathes. This method performs + * the "bulk" conversion that may be faster than mapping pathes one by + * one. To have the benefit from the bulk conversion, the method must be + * overridden in the derived classes. The default method delegates work + * to the {@link #getRowForPath(TreePath)}. + * + * @param paths the tree paths the array of the tree pathes. + * @return the array of the matching tree rows. + */ + public int[] getRowsForPaths(TreePath[] paths) + { + int[] rows = new int[paths.length]; + for (int i = 0; i < rows.length; i++) + rows[i] = getRowForPath(paths[i]); + return rows; + } + + /** + * Returns true if this layout supposes that all rows have the fixed + * height. + * + * @return boolean true if all rows in the tree must have the fixed + * height (false by default). + */ + protected boolean isFixedRowHeight() + { + return false; + } } diff --git a/libjava/classpath/javax/swing/tree/DefaultMutableTreeNode.java b/libjava/classpath/javax/swing/tree/DefaultMutableTreeNode.java index d9747729317..be8317f975c 100644 --- a/libjava/classpath/javax/swing/tree/DefaultMutableTreeNode.java +++ b/libjava/classpath/javax/swing/tree/DefaultMutableTreeNode.java @@ -1,5 +1,5 @@ /* DefaultMutableTreeNode.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. @@ -53,7 +53,7 @@ import java.util.Vector; /** - * DefaultMutableTreeNode + * A default implementation of the {@link MutableTreeNode} interface. * * @author Andrew Selkirk * @author Robert Schuster (robertschuster@fsfe.org) @@ -64,18 +64,19 @@ public class DefaultMutableTreeNode private static final long serialVersionUID = -4298474751201349152L; /** - * EMPTY_ENUMERATION + * An empty enumeration, returned by {@link #children()} if a node has no + * children. */ public static final Enumeration EMPTY_ENUMERATION = EmptyEnumeration.getInstance(); /** - * parent + * The parent of this node (possibly <code>null</code>). */ protected MutableTreeNode parent; /** - * children + * The child nodes for this node (may be empty). */ protected Vector children = new Vector(); @@ -91,7 +92,7 @@ public class DefaultMutableTreeNode /** * Creates a <code>DefaultMutableTreeNode</code> object. - * This node allows to add child nodes. + * This is equivalent to <code>DefaultMutableTreeNode(null, true)</code>. */ public DefaultMutableTreeNode() { @@ -100,9 +101,10 @@ public class DefaultMutableTreeNode /** * Creates a <code>DefaultMutableTreeNode</code> object with the given - * user object attached to it. This node allows to add child nodes. + * user object attached to it. This is equivalent to + * <code>DefaultMutableTreeNode(userObject, true)</code>. * - * @param userObject the user object + * @param userObject the user object (<code>null</code> permitted). */ public DefaultMutableTreeNode(Object userObject) { @@ -113,7 +115,7 @@ public class DefaultMutableTreeNode * Creates a <code>DefaultMutableTreeNode</code> object with the given * user object attached to it. * - * @param userObject the user object + * @param userObject the user object (<code>null</code> permitted). * @param allowsChildren <code>true</code> if the code allows to add child * nodes, <code>false</code> otherwise */ @@ -124,28 +126,22 @@ public class DefaultMutableTreeNode } /** - * clone + * Returns a clone of the node. The clone contains a shallow copy of the + * user object, and does not copy the parent node or the child nodes. * - * @return Object + * @return A clone of the node. */ public Object clone() { - try - { - return super.clone(); - // TODO: Do we need to do more here ? - } - catch (CloneNotSupportedException e) - { - // This never happens. - return null; - } + return new DefaultMutableTreeNode(this.userObject, this.allowsChildren); } /** - * Returns a string representation of this node + * Returns a string representation of the node. This implementation returns + * <code>getUserObject().toString()</code>, or <code>null</code> if there + * is no user object. * - * @return a human-readable String representing this node + * @return A string representation of the node (possibly <code>null</code>). */ public String toString() { @@ -156,20 +152,30 @@ public class DefaultMutableTreeNode } /** - * Adds a new child node to this node. + * Adds a new child node to this node and sets this node as the parent of + * the child node. The child node must not be an ancestor of this node. + * If the tree uses the {@link DefaultTreeModel}, you must subsequently + * call {@link DefaultTreeModel#reload(TreeNode)}. * - * @param child the child node + * @param child the child node (<code>null</code> not permitted). * - * @throws IllegalArgumentException if <code>child</code> is null - * @throws IllegalStateException if the node does not allow children + * @throws IllegalStateException if {@link #getAllowsChildren()} returns + * <code>false</code>. + * @throws IllegalArgumentException if {@link #isNodeAncestor} returns + * <code>true</code>. + * @throws IllegalArgumentException if <code>child</code> is + * <code>null</code>. */ public void add(MutableTreeNode child) { + if (! allowsChildren) + throw new IllegalStateException(); + if (child == null) throw new IllegalArgumentException(); - if (! allowsChildren) - throw new IllegalStateException(); + if (isNodeAncestor(child)) + throw new IllegalArgumentException("Cannot add ancestor node."); children.add(child); child.setParent(this); @@ -178,7 +184,7 @@ public class DefaultMutableTreeNode /** * Returns the parent node of this node. * - * @return the parent node + * @return The parent node (possibly <code>null</code>). */ public TreeNode getParent() { @@ -186,23 +192,39 @@ public class DefaultMutableTreeNode } /** - * Removes the child with the given index from this node + * Removes the child with the given index from this node. * - * @param index the index + * @param index the index (in the range <code>0</code> to + * <code>getChildCount() - 1</code>). + * + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is outside + * the valid range. */ public void remove(int index) { - children.remove(index); + MutableTreeNode child = (MutableTreeNode) children.remove(index); + child.setParent(null); } /** - * Removes the given child from this node. + * Removes the given child from this node and sets its parent to + * <code>null</code>. * - * @param node the child node + * @param node the child node (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>node</code> is not a child of + * this node. + * @throws IllegalArgumentException if <code>node</code> is null. */ public void remove(MutableTreeNode node) { + if (node == null) + throw new IllegalArgumentException("Null 'node' argument."); + if (node.getParent() != this) + throw new IllegalArgumentException( + "The given 'node' is not a child of this node."); children.remove(node); + node.setParent(null); } /** @@ -235,11 +257,23 @@ public class DefaultMutableTreeNode /** * Inserts given child node at the given index. * - * @param node the child node + * @param node the child node (<code>null</code> not permitted). * @param index the index. + * + * @throws IllegalArgumentException if <code>node</code> is + * </code>null</code>. */ public void insert(MutableTreeNode node, int index) { + if (! allowsChildren) + throw new IllegalStateException(); + + if (node == null) + throw new IllegalArgumentException("Null 'node' argument."); + + if (isNodeAncestor(node)) + throw new IllegalArgumentException("Cannot insert ancestor node."); + children.insertElementAt(node, index); } @@ -300,24 +334,33 @@ public class DefaultMutableTreeNode } /** - * Returns the child index for a given node. - * - * @param node this node - * - * @return the index + * Returns the index of the specified child node, or -1 if the node is not + * in fact a child of this node. + * + * @param node the node (<code>null</code> not permitted). + * + * @return The index of the specified child node, or -1. + * + * @throws IllegalArgumentException if <code>node</code> is <code>null</code>. */ public int getIndex(TreeNode node) { + if (node == null) + throw new IllegalArgumentException("Null 'node' argument."); return children.indexOf(node); } /** - * setAllowsChildren + * Sets the flag that controls whether or not this node allows the addition / + * insertion of child nodes. If the flag is set to <code>false</code>, any + * existing children are removed. * - * @param allowsChildren TODO + * @param allowsChildren the flag. */ public void setAllowsChildren(boolean allowsChildren) { + if (!allowsChildren) + removeAllChildren(); this.allowsChildren = allowsChildren; } @@ -366,15 +409,24 @@ public class DefaultMutableTreeNode */ public void removeAllChildren() { - children.removeAllElements(); + for (int i = getChildCount() - 1; i >= 0; i--) + remove(i); } /** - * isNodeAncestor - * - * @param node TODO - * - * @return boolean + * Returns <code>true</code> if <code>node</code> is an ancestor of this + * tree node, and <code>false</code> otherwise. An ancestor node is any of: + * <ul> + * <li>this tree node;</li> + * <li>the parent node (if there is one);</li> + * <li>any ancestor of the parent node;</li> + * </ul> + * If <code>node</code> is <code>null</code>, this method returns + * <code>false</code>. + * + * @param node the node (<code>null</code> permitted). + * + * @return A boolean. */ public boolean isNodeAncestor(TreeNode node) { @@ -383,19 +435,26 @@ public class DefaultMutableTreeNode TreeNode current = this; - while (current != null - && current != node) + while (current != null && current != node) current = current.getParent(); return current == node; } /** - * isNodeDescendant - * - * @param node TODO - * - * @return boolean + * Returns <code>true</code> if <code>node</code> is a descendant of this + * tree node, and <code>false</code> otherwise. A descendant node is any of: + * <ul> + * <li>this tree node;</li> + * <li>the child nodes belonging to this tree node, if there are any;</li> + * <li>any descendants of the child nodes;</li> + * </ul> + * If <code>node</code> is <code>null</code>, this method returns + * <code>false</code>. + * + * @param node the node (<code>null</code> permitted). + * + * @return A boolean. */ public boolean isNodeDescendant(DefaultMutableTreeNode node) { @@ -722,11 +781,13 @@ public class DefaultMutableTreeNode } /** - * isNodeChild + * Returns <code>true</code> if <code>node</code> is a child of this tree + * node, and <code>false</code> otherwise. If <code>node</code> is + * <code>null</code>, this method returns <code>false</code>. * - * @param node TODO + * @param node the node (<code>null</code> permitted). * - * @return boolean + * @return A boolean. */ public boolean isNodeChild(TreeNode node) { @@ -737,9 +798,11 @@ public class DefaultMutableTreeNode } /** - * getFirstChild + * Returns the first child node belonging to this tree node. * - * @return TreeNode + * @return The first child node. + * + * @throws NoSuchElementException if this tree node has no children. */ public TreeNode getFirstChild() { @@ -747,9 +810,11 @@ public class DefaultMutableTreeNode } /** - * getLastChild + * Returns the last child node belonging to this tree node. * - * @return TreeNode + * @return The last child node. + * + * @throws NoSuchElementException if this tree node has no children. */ public TreeNode getLastChild() { @@ -757,16 +822,20 @@ public class DefaultMutableTreeNode } /** - * getChildAfter + * Returns the next child after the specified <code>node</code>, or + * <code>null</code> if there is no child after the specified + * <code>node</code>. * - * @param node TODO + * @param node a child of this node (<code>null</code> not permitted). * - * @return TreeNode + * @return The next child, or <code>null</code>. + * + * @throws IllegalArgumentException if <code>node</code> is not a child of + * this node, or is <code>null</code>. */ public TreeNode getChildAfter(TreeNode node) { - if (node == null - || node.getParent() != this) + if (node == null || node.getParent() != this) throw new IllegalArgumentException(); int index = getIndex(node) + 1; @@ -778,16 +847,20 @@ public class DefaultMutableTreeNode } /** - * getChildBefore + * Returns the previous child before the specified <code>node</code>, or + * <code>null</code> if there is no child before the specified + * <code>node</code>. * - * @param node TODO + * @param node a child of this node (<code>null</code> not permitted). * - * @return TreeNode + * @return The previous child, or <code>null</code>. + * + * @throws IllegalArgumentException if <code>node</code> is not a child of + * this node, or is <code>null</code>. */ public TreeNode getChildBefore(TreeNode node) { - if (node == null - || node.getParent() != this) + if (node == null || node.getParent() != this) throw new IllegalArgumentException(); int index = getIndex(node) - 1; @@ -799,25 +872,31 @@ public class DefaultMutableTreeNode } /** - * isNodeSibling + * Returns <code>true</code> if this tree node and <code>node</code> share + * the same parent. If <code>node</code> is this tree node, the method + * returns <code>true</code> and if <code>node</code> is <code>null</code> + * this method returns <code>false</code>. * - * @param node TODO + * @param node the node (<code>null</code> permitted). * - * @return boolean + * @return A boolean. */ public boolean isNodeSibling(TreeNode node) { if (node == null) return false; - + if (node == this) + return true; return (node.getParent() == getParent() && getParent() != null); } /** - * getSiblingCount + * Returns the number of siblings for this tree node. If the tree node has + * a parent, this method returns the child count for the parent, otherwise + * it returns <code>1</code>. * - * @return int + * @return The sibling count. */ public int getSiblingCount() { @@ -828,9 +907,11 @@ public class DefaultMutableTreeNode } /** - * getNextSibling + * Returns the next sibling for this tree node. If this node has no parent, + * or this node is the last child of its parent, this method returns + * <code>null</code>. * - * @return DefaultMutableTreeNode + * @return The next sibling, or <code>null</code>. */ public DefaultMutableTreeNode getNextSibling() { @@ -846,9 +927,11 @@ public class DefaultMutableTreeNode } /** - * getPreviousSibling + * Returns the previous sibling for this tree node. If this node has no + * parent, or this node is the first child of its parent, this method returns + * <code>null</code>. * - * @return DefaultMutableTreeNode + * @return The previous sibling, or <code>null</code>. */ public DefaultMutableTreeNode getPreviousSibling() { @@ -864,9 +947,10 @@ public class DefaultMutableTreeNode } /** - * isLeaf + * Returns <code>true</code> if this tree node is a lead node (that is, it + * has no children), and <code>false</otherwise>. * - * @return boolean + * @return A boolean. */ public boolean isLeaf() { @@ -874,9 +958,11 @@ public class DefaultMutableTreeNode } /** - * getFirstLeaf + * Returns the first leaf node that is a descendant of this node. Recall + * that a node is its own descendant, so if this node has no children then + * it is returned as the first leaf. * - * @return DefaultMutableTreeNode + * @return The first leaf node. */ public DefaultMutableTreeNode getFirstLeaf() { @@ -889,9 +975,11 @@ public class DefaultMutableTreeNode } /** - * getLastLeaf + * Returns the last leaf node that is a descendant of this node. Recall + * that a node is its own descendant, so if this node has no children then + * it is returned as the last leaf. * - * @return DefaultMutableTreeNode + * @return The first leaf node. */ public DefaultMutableTreeNode getLastLeaf() { @@ -908,33 +996,37 @@ public class DefaultMutableTreeNode } /** - * getNextLeaf + * Returns the next leaf node after this tree node. * - * @return DefaultMutableTreeNode + * @return The next leaf node, or <code>null</code>. */ public DefaultMutableTreeNode getNextLeaf() { - if (parent == null) - return null; - - // TODO: Fix implementation. + // if there is a next sibling, return its first leaf + DefaultMutableTreeNode sibling = getNextSibling(); + if (sibling != null) + return sibling.getFirstLeaf(); + // otherwise move up one level and try again... + if (parent != null) + return ((DefaultMutableTreeNode) parent).getNextLeaf(); return null; - //return parent.getChildAfter(this); } /** - * getPreviousLeaf + * Returns the previous leaf node before this tree node. * - * @return DefaultMutableTreeNode + * @return The previous leaf node, or <code>null</code>. */ public DefaultMutableTreeNode getPreviousLeaf() { - if (parent == null) - return null; - - // TODO: Fix implementation. + // if there is a previous sibling, return its last leaf + DefaultMutableTreeNode sibling = getPreviousSibling(); + if (sibling != null) + return sibling.getLastLeaf(); + // otherwise move up one level and try again... + if (parent != null) + return ((DefaultMutableTreeNode) parent).getPreviousLeaf(); return null; - //return parent.getChildBefore(this); } /** diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java b/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java index e28c9261bab..cc19501d2b6 100644 --- a/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java +++ b/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java @@ -77,17 +77,6 @@ public class DefaultTreeCellEditor implements ActionListener, TreeCellEditor, TreeSelectionListener { /** - * The gap between the icon and editing component during editing. - */ - static int ICON_TEXT_GAP = 3; - - /** - * The left margin of the editing container (the gap between the tree and - * the editing component of the editing icon. - */ - static int TREE_ICON_GAP = ICON_TEXT_GAP; - - /** * The number of the fast mouse clicks, required to start the editing * session. */ @@ -141,7 +130,7 @@ public class DefaultTreeCellEditor { // From the previous version, the left margin is taken as half // of the icon width. - editingIcon.paintIcon(this, g, TREE_ICON_GAP, 0); + editingIcon.paintIcon(this, g, 0, 0); } super.paint(g); } @@ -157,7 +146,7 @@ public class DefaultTreeCellEditor // Move the component to the left, leaving room for the editing icon: if (editingIcon != null) - eOffset = TREE_ICON_GAP + editingIcon.getIconWidth() + ICON_TEXT_GAP; + eOffset = editingIcon.getIconWidth(); else eOffset = 0; @@ -166,7 +155,7 @@ public class DefaultTreeCellEditor c.setLocation(eOffset, 0); // Span the editing component near over all window width. - c.setSize(bounds.width - eOffset - TREE_ICON_GAP, bounds.height); + c.setSize(bounds.width - eOffset, bounds.height); /* * @specnote the Sun sets some more narrow editing component width (it is * not documented how does it is calculated). However as our text field is @@ -542,7 +531,8 @@ public class DefaultTreeCellEditor * If the realEditor returns true to this message, prepareForEditing * is messaged and true is returned. * - * @param event - the event the editor should use to consider whether to begin editing or not + * @param event - the event the editor should use to consider whether to + * begin editing or not * @return true if editing can be started */ public boolean isCellEditable(EventObject event) diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeCellRenderer.java b/libjava/classpath/javax/swing/tree/DefaultTreeCellRenderer.java index df70ba7fb9f..5e93145ae5c 100644 --- a/libjava/classpath/javax/swing/tree/DefaultTreeCellRenderer.java +++ b/libjava/classpath/javax/swing/tree/DefaultTreeCellRenderer.java @@ -407,7 +407,7 @@ public class DefaultTreeCellRenderer this.hasFocus = hasFocus; setHorizontalAlignment(LEFT); setOpaque(false); - setVerticalAlignment(TOP); + setVerticalAlignment(CENTER); setEnabled(true); super.setFont(UIManager.getFont("Tree.font")); @@ -445,8 +445,7 @@ public class DefaultTreeCellRenderer /** * Paints the value. The background is filled based on selected. * - * @param g - * the graphics device. + * @param g the graphics device. */ public void paint(Graphics g) { @@ -468,17 +467,27 @@ public class DefaultTreeCellRenderer getHorizontalTextPosition(), vr, ir, tr, getIconTextGap()); + // Reusing one rectangle. + Rectangle bounds = getBounds(ir); + + bounds.x = tr.x - insets.left; + bounds.width = tr.width + insets.left+insets.right; + g.setColor(super.getBackground()); - g.fillRect(tr.x, tr.y, tr.width, tr.height - insets.top - insets.bottom); + g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); - // paint border - Color b = getBorderSelectionColor(); - if (b != null) + super.paint(g); + + // Paint the border of the focused element only (lead selection) + if (hasFocus) { - g.setColor(b); - g.drawRect(tr.x, tr.y, tr.width, tr.height - insets.top - insets.bottom); + Color b = getBorderSelectionColor(); + if (b != null) + { + g.setColor(b); + g.drawRect(bounds.x, bounds.y, bounds.width, bounds.height - 1); + } } - super.paint(g); } /** diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeModel.java b/libjava/classpath/javax/swing/tree/DefaultTreeModel.java index 818f548a78d..c1ca679d006 100644 --- a/libjava/classpath/javax/swing/tree/DefaultTreeModel.java +++ b/libjava/classpath/javax/swing/tree/DefaultTreeModel.java @@ -37,6 +37,8 @@ exception statement from your version. */ package javax.swing.tree; +import gnu.classpath.NotImplementedException; + import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -46,7 +48,6 @@ import java.util.EventListener; import javax.swing.event.EventListenerList; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; -import javax.swing.tree.DefaultMutableTreeNode; /** * DefaultTreeModel @@ -74,26 +75,29 @@ public class DefaultTreeModel protected boolean asksAllowsChildren; /** - * Constructor DefaultTreeModel + * Constructor DefaultTreeModel where any node can have children. * * @param root the tree root. */ public DefaultTreeModel(TreeNode root) { - if (root == null) - root = new DefaultMutableTreeNode(); - setRoot(root); + this (root, false); } /** - * Constructor DefaultTreeModel + * Create the DefaultTreeModel that may check if the nodes can have + * children or not. * - * @param root the tree root. - * @param asksAllowsChildren TODO + * @param aRoot the tree root. + * @param asksAllowsChildren if true, each node is asked if it can have + * children. If false, the model does not care about this, supposing, that + * any node can have children. */ - public DefaultTreeModel(TreeNode root, boolean asksAllowsChildren) + public DefaultTreeModel(TreeNode aRoot, boolean asksAllowsChildren) { - setRoot(root); + if (aRoot == null) + aRoot = new DefaultMutableTreeNode(); + this.root = aRoot; this.asksAllowsChildren = asksAllowsChildren; } @@ -222,25 +226,60 @@ public class DefaultTreeModel } /** - * Invoke this method if you've modified the TreeNodes upon - * which this model depends. The model will notify all of its - * listeners that the model has changed. + * <p> + * Invoke this method if you've modified the TreeNodes upon which this model + * depends. The model will notify all of its listeners that the model has + * changed. It will fire the events, necessary to update the layout caches and + * repaint the tree. The tree will <i>not</i> be properly refreshed if you + * call the JTree.repaint instead. + * </p> + * <p> + * This method will refresh the information about whole tree from the root. If + * only part of the tree should be refreshed, it is more effective to call + * {@link #reload(TreeNode)}. + * </p> */ public void reload() { - // TODO + // Need to duplicate the code because the root can formally be + // no an instance of the TreeNode. + int n = getChildCount(root); + int[] childIdx = new int[n]; + Object[] children = new Object[n]; + + for (int i = 0; i < n; i++) + { + childIdx[i] = i; + children[i] = getChild(root, i); + } + + fireTreeStructureChanged(this, new Object[] { root }, childIdx, children); } /** - * Invoke this method if you've modified the TreeNodes upon - * which this model depends. The model will notify all of its - * listeners that the model has changed. + * Invoke this method if you've modified the TreeNodes upon which this model + * depends. The model will notify all of its listeners that the model has + * changed. It will fire the events, necessary to update the layout caches and + * repaint the tree. The tree will <i>not</i> be properly refreshed if you + * call the JTree.repaint instead. * - * @param node - TODO + * @param node - the tree node, from which the tree nodes have changed + * (inclusive). If you do not know this node, call {@link #reload()} + * instead. */ public void reload(TreeNode node) { - // TODO + int n = getChildCount(node); + int[] childIdx = new int[n]; + Object[] children = new Object[n]; + + for (int i = 0; i < n; i++) + { + childIdx[i] = i; + children[i] = getChild(node, i); + } + + fireTreeStructureChanged(this, getPathToRoot(node), childIdx, children); } /** @@ -390,7 +429,17 @@ public class DefaultTreeModel */ public void nodeStructureChanged(TreeNode node) { - // TODO + int n = getChildCount(root); + int[] childIdx = new int[n]; + Object[] children = new Object[n]; + + for (int i = 0; i < n; i++) + { + childIdx[i] = i; + children[i] = getChild(root, i); + } + + fireTreeStructureChanged(this, new Object[] { root }, childIdx, children); } /** diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java b/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java index de27dad04f9..0676f7ec8f4 100644 --- a/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java +++ b/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java @@ -1,5 +1,5 @@ /* DefaultTreeSelectionModel.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. @@ -35,6 +35,7 @@ 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.tree; import java.beans.PropertyChangeListener; @@ -42,7 +43,10 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.Arrays; import java.util.EventListener; +import java.util.HashSet; +import java.util.Iterator; import java.util.Vector; import javax.swing.DefaultListSelectionModel; @@ -52,703 +56,968 @@ import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; /** - * DefaultTreeSelectionModel + * The implementation of the default tree selection model. The installed + * listeners are notified about the path and not the row changes. If you + * specifically need to track the row changes, register the listener for the + * expansion events. * * @author Andrew Selkirk + * @author Audrius Meskauskas */ public class DefaultTreeSelectionModel - implements Cloneable, Serializable, TreeSelectionModel + implements Cloneable, Serializable, TreeSelectionModel { - static final long serialVersionUID = 3288129636638950196L; - - /** - * SELECTION_MODE_PROPERTY - */ - public static final String SELECTION_MODE_PROPERTY = "selectionMode"; - - /** - * Our Swing property change support. - */ - protected SwingPropertyChangeSupport changeSupport; - - /** - * The current selection. - */ - protected TreePath[] selection; - - /** - * Our TreeSelectionListeners. - */ - protected EventListenerList listenerList; - - /** - * The current RowMapper. - */ - protected transient RowMapper rowMapper; - - /** - * The current listSelectionModel. - */ - protected DefaultListSelectionModel listSelectionModel; - - /** - * The current selection mode. - */ - protected int selectionMode; - - /** - * The path that has been added last. - */ - protected TreePath leadPath; - - /** - * The index of the last added path. - */ - protected int leadIndex; - - /** - * The row of the last added path according to the RowMapper. - */ - protected int leadRow; - - /** - * Constructs a new DefaultTreeSelectionModel. - */ - public DefaultTreeSelectionModel() - { - setSelectionMode(DISCONTIGUOUS_TREE_SELECTION); - listenerList = new EventListenerList(); - } - - /** - * Creates a clone of this DefaultTreeSelectionModel with the same - * selection. - * - * @exception CloneNotSupportedException should not be thrown here - * - * @return a clone of this DefaultTreeSelectionModel - */ - public Object clone() throws CloneNotSupportedException - { - return null; // TODO - } - - /** - * Returns a string that shows this object's properties. - * - * @return a string that shows this object's properties - */ - public String toString() - { - return null; // TODO - } - - /** - * writeObject - * - * @param value0 TODO - * @exception IOException TODO - */ - private void writeObject(ObjectOutputStream value0) throws IOException - { - // TODO - } - - /** - * readObject - * - * @param value0 TODO - * @exception IOException TODO - * @exception ClassNotFoundException TODO - */ - private void readObject(ObjectInputStream value0) throws IOException, - ClassNotFoundException - { - // TODO - } - - /** - * Sets the RowMapper that should be used to map between paths and their - * rows. - * - * @param rowMapper the RowMapper to set - * - * @see RowMapper - */ - public void setRowMapper(RowMapper rowMapper) - { - // TODO - } - - /** - * Returns the RowMapper that is currently used to map between paths and - * their rows. - * - * @return the current RowMapper - * - * @see RowMapper - */ - public RowMapper getRowMapper() - { - return rowMapper; - } - - /** - * Sets the current selection mode. Possible values are - * {@link #SINGLE_TREE_SELECTION}, {@link #CONTIGUOUS_TREE_SELECTION} and - * {@link #DISCONTIGUOUS_TREE_SELECTION}. - * - * @param mode the selection mode to be set - * - * @see #getSelectionMode - * @see #SINGLE_TREE_SELECTION - * @see #CONTIGUOUS_TREE_SELECTION - * @see #DISCONTIGUOUS_TREE_SELECTION - */ - public void setSelectionMode(int mode) - { - selectionMode = mode; - } - - /** - * Returns the current selection mode. - * - * @return the current selection mode - * - * @see #setSelectionMode - * @see #SINGLE_TREE_SELECTION - * @see #CONTIGUOUS_TREE_SELECTION - * @see #DISCONTIGUOUS_TREE_SELECTION - */ - public int getSelectionMode() - { - return selectionMode; - } - - /** - * Sets this path as the only selection. - * - * If this changes the selection the registered TreeSelectionListeners are - * notified. - * - * @param path the path to set as selection - */ - public void setSelectionPath(TreePath path) - { - selection = new TreePath[] { - path }; - } - - /** - * Sets the paths as selection. This method checks for duplicates and - * removes them. - * - * If this changes the selection the registered TreeSelectionListeners are - * notified. - * - * @param paths the paths to set as selection - */ - public void setSelectionPaths(TreePath[] paths) - { - // TODO - } - - /** - * Adds a path to the list of selected paths. This method checks if the path - * is already selected and doesn't add the same path twice. - * - * If this changes the selection the registered TreeSelectionListeners are - * notified. - * - * @param path the path to add to the selection - */ - public void addSelectionPath(TreePath path) - { - if (!isPathSelected(path)) - { - if (isSelectionEmpty()) - setSelectionPath(path); - else - { - TreePath[] temp = new TreePath[selection.length + 1]; - System.arraycopy(selection, 0, temp, 0, selection.length); - temp[temp.length - 1] = path; - selection = new TreePath[temp.length]; - System.arraycopy(temp, 0, selection, 0, temp.length); - } - leadPath = path; - fireValueChanged(new TreeSelectionEvent(this, path, true, - leadPath, path)); - } - } - - /** - * Adds the paths to the list of selected paths. This method checks if the - * paths are already selected and doesn't add the same path twice. - * - * If this changes the selection the registered TreeSelectionListeners are - * notified. - * - * @param paths the paths to add to the selection - */ - public void addSelectionPaths(TreePath[] paths) - { - if (paths != null) - { - TreePath v0 = null; - for (int i = 0; i < paths.length; i++) - { - v0 = paths[i]; - if (!isPathSelected(v0)) - { - if (isSelectionEmpty()) - setSelectionPath(v0); - else - { - TreePath[] temp = new TreePath[selection.length + 1]; - System.arraycopy(selection, 0, temp, 0, - selection.length); - temp[temp.length - 1] = v0; - selection = new TreePath[temp.length]; - System.arraycopy(temp, 0, selection, 0, temp.length); - } - leadPath = paths[paths.length - 1]; - fireValueChanged(new TreeSelectionEvent(this, v0, true, - leadPath, paths[0])); - } - } - } - } - - /** - * Removes the path from the selection. - * - * If this changes the selection the registered TreeSelectionListeners are - * notified. - * - * @param path the path to remove - */ - public void removeSelectionPath(TreePath path) - { - int index = -1; - if (isPathSelected(path)) - { - for (int i = 0; i < selection.length; i++) - { - if (selection[i].equals(path)) - { - index = i; - break; - } - } - TreePath[] temp = new TreePath[selection.length - 1]; - System.arraycopy(selection, 0, temp, 0, index); - System.arraycopy(selection, index + 1, temp, index, - selection.length - index - 1); - selection = new TreePath[temp.length]; - System.arraycopy(temp, 0, selection, 0, temp.length); - - fireValueChanged(new TreeSelectionEvent(this, path, false, - leadPath, path)); - } - } - - /** - * Removes the paths from the selection. - * - * If this changes the selection the registered TreeSelectionListeners are - * notified. - * - * @param paths the paths to remove - */ - public void removeSelectionPaths(TreePath[] paths) - { - if (paths != null) - { - int index = -1; - TreePath v0 = null; - for (int i = 0; i < paths.length; i++) - { - v0 = paths[i]; - if (isPathSelected(v0)) - { - for (int x = 0; x < selection.length; x++) - { - if (selection[i].equals(v0)) - { - index = x; - break; - } - } - TreePath[] temp = new TreePath[selection.length - 1]; - System.arraycopy(selection, 0, temp, 0, index); - System.arraycopy(selection, index + 1, temp, index, - selection.length - index - 1); - selection = new TreePath[temp.length]; - System.arraycopy(temp, 0, selection, 0, temp.length); - - fireValueChanged(new TreeSelectionEvent(this, v0, false, - leadPath, paths[0])); - } - } - } - } - - /** - * Returns the first path in the selection. This is especially useful when - * the selectionMode is {@link #SINGLE_TREE_SELECTION}. - * - * @return the first path in the selection - */ - public TreePath getSelectionPath() - { - if ((selection == null) || (selection.length == 0)) - return null; - else - return selection[0]; - } - - /** - * Returns the complete selection. - * - * @return the complete selection - */ - public TreePath[] getSelectionPaths() - { - return selection; - } - - /** - * Returns the number of paths in the selection. - * - * @return the number of paths in the selection - */ - public int getSelectionCount() - { - if (selection == null) - return 0; - else - return selection.length; - } - - /** - * Checks if a given path is in the selection. - * - * @param path the path to check - * - * @return <code>true</code> if the path is in the selection, - * <code>false</code> otherwise - */ - public boolean isPathSelected(TreePath path) - { - if (selection == null) - return false; - - for (int i = 0; i < selection.length; i++) - { - if (selection[i].equals(path)) - return true; - } - return false; - } - - /** - * Checks if the selection is empty. - * - * @return <code>true</code> if the selection is empty, <code>false</code> - * otherwise - */ - public boolean isSelectionEmpty() - { - return ((selection == null) || (selection.length == 0)); - } - - /** - * Removes all paths from the selection. - */ - public void clearSelection() - { - leadPath = null; - selection = null; - } - - /** - * Adds a <code>TreeSelectionListener</code> object to this model. - * - * @param listener the listener to add - */ - public void addTreeSelectionListener(TreeSelectionListener listener) - { - listenerList.add(TreeSelectionListener.class, listener); - } - - /** - * Removes a <code>TreeSelectionListener</code> object from this model. - * - * @param listener the listener to remove - */ - public void removeTreeSelectionListener(TreeSelectionListener listener) - { - listenerList.remove(TreeSelectionListener.class, listener); - } - - /** - * Returns all <code>TreeSelectionListener</code> added to this model. - * - * @return an array of listeners - * - * @since 1.4 - */ - public TreeSelectionListener[] getTreeSelectionListeners() - { - return (TreeSelectionListener[]) - getListeners(TreeSelectionListener.class); - } - - /** - * fireValueChanged - * - * @param event the event to fire. - */ - protected void fireValueChanged(TreeSelectionEvent event) - { - TreeSelectionListener[] listeners = getTreeSelectionListeners(); - - for (int i = 0; i < listeners.length; ++i) - listeners[i].valueChanged(event); - } - - /** - * Returns all added listeners of a special type. - * - * @param listenerType the listener type - * - * @return an array of listeners - * - * @since 1.3 - */ - public EventListener[] getListeners(Class listenerType) - { - return listenerList.getListeners(listenerType); - } - - /** - * Returns the currently selected rows. - * - * @return the currently selected rows - */ - public int[] getSelectionRows() - { - if (rowMapper == null) - return null; - else - return rowMapper.getRowsForPaths(selection); - } - - /** - * Returns the smallest row index from the selection. - * - * @return the smallest row index from the selection - */ - public int getMinSelectionRow() - { - if ((rowMapper == null) || (selection == null) - || (selection.length == 0)) - return -1; - else - { - int[] rows = rowMapper.getRowsForPaths(selection); - int minRow = Integer.MAX_VALUE; - for (int index = 0; index < rows.length; index++) - minRow = Math.min(minRow, rows[index]); - return minRow; - } - } - - /** - * Returns the largest row index from the selection. - * - * @return the largest row index from the selection - */ - public int getMaxSelectionRow() - { - if ((rowMapper == null) || (selection == null) - || (selection.length == 0)) - return -1; - else - { - int[] rows = rowMapper.getRowsForPaths(selection); - int maxRow = -1; - for (int index = 0; index < rows.length; index++) - maxRow = Math.max(maxRow, rows[index]); - return maxRow; - } - } - - /** - * Checks if a particular row is selected. - * - * @param row the index of the row to check - * - * @return <code>true</code> if the row is in this selection, - * <code>false</code> otherwise - */ - public boolean isRowSelected(int row) - { - return false; // TODO - } - - /** - * Updates the mappings from TreePaths to row indices. - */ - public void resetRowSelection() - { - // TODO - } - - /** - * getLeadSelectionRow - * - * @return int - */ - public int getLeadSelectionRow() - { - if ((rowMapper == null) || (leadPath == null)) - return -1; - else - return rowMapper.getRowsForPaths(new TreePath[] { - leadPath })[0]; - } - - /** - * getLeadSelectionPath - * - * @return TreePath - */ - public TreePath getLeadSelectionPath() - { - return leadPath; - } - - /** - * Adds a <code>PropertyChangeListener</code> object to this model. - * - * @param listener the listener to add. - */ - public void addPropertyChangeListener(PropertyChangeListener listener) - { - changeSupport.addPropertyChangeListener(listener); - } - - /** - * Removes a <code>PropertyChangeListener</code> object from this model. - * - * @param listener the listener to remove. - */ - public void removePropertyChangeListener(PropertyChangeListener listener) - { - changeSupport.removePropertyChangeListener(listener); - } - - /** - * Returns all added <code>PropertyChangeListener</code> objects. - * - * @return an array of listeners. - * - * @since 1.4 - */ - public PropertyChangeListener[] getPropertyChangeListeners() - { - return changeSupport.getPropertyChangeListeners(); - } - - /** - * Makes sure the currently selected paths are valid according to the - * current selectionMode. - * - * If the selectionMode is set to {@link #CONTIGUOUS_TREE_SELECTION} and the - * selection isn't contiguous then the selection is reset to the first set - * of contguous paths. - * - * If the selectionMode is set to {@link #SINGLE_TREE_SELECTION} and the - * selection has more than one path, the selection is reset to the contain - * only the first path. - */ - protected void insureRowContinuity() - { - // TODO - } - - /** - * Returns <code>true</code> if the paths are contiguous or we have no - * RowMapper assigned. - * - * @param paths the paths to check for continuity - * @return <code>true</code> if the paths are contiguous or we have no - * RowMapper assigned - */ - protected boolean arePathsContiguous(TreePath[] paths) - { - return false; // TODO - } - - /** - * Checks if the paths can be added. This returns <code>true</code> if: - * <ul> - * <li><code>paths</code> is <code>null</code> or empty</li> - * <li>we have no RowMapper assigned</li> - * <li>nothing is currently selected</li> - * <li>selectionMode is {@link #DISCONTIGUOUS_TREE_SELECTION}</li> - * <li>adding the paths to the selection still results in a contiguous set - * of paths</li> - * - * @param paths the paths to check - * - * @return <code>true</code> if the paths can be added with respect to the - * selectionMode - */ - protected boolean canPathsBeAdded(TreePath[] paths) - { - return false; // TODO - } - - /** - * Checks if the paths can be removed without breaking the continuity of the - * selection according to selectionMode. - * - * @param paths the paths to check - * @return <code>true</code> if the paths can be removed with respect to - * the selectionMode - */ - protected boolean canPathsBeRemoved(TreePath[] paths) - { - return false; // TODO - } - - /** - * notifyPathChange - * - * @param value0 TODO - * @param value1 TODO - */ - protected void notifyPathChange(Vector value0, TreePath value1) - { - // TODO - } - - /** - * Updates the lead index instance field. - */ - protected void updateLeadIndex() - { - // TODO - } - - /** - * Deprecated and not used. - */ - protected void insureUniqueness() - { - // TODO - } + + /** + * Use serialVersionUID for interoperability. + */ + static final long serialVersionUID = 3288129636638950196L; + + /** + * The name of the selection mode property. + */ + public static final String SELECTION_MODE_PROPERTY = "selectionMode"; + + /** + * Our Swing property change support. + */ + protected SwingPropertyChangeSupport changeSupport; + + /** + * The current selection. + */ + protected TreePath[] selection; + + /** + * Our TreeSelectionListeners. + */ + protected EventListenerList listenerList; + + /** + * The current RowMapper. + */ + protected transient RowMapper rowMapper; + + /** + * The current listSelectionModel. + */ + protected DefaultListSelectionModel listSelectionModel; + + /** + * The current selection mode. + */ + protected int selectionMode; + + /** + * The path that has been added last. + */ + protected TreePath leadPath; + + /** + * The index of the last added path. + */ + protected int leadIndex; + + /** + * The row of the last added path according to the RowMapper. + */ + protected int leadRow = -1; + + /** + * Constructs a new DefaultTreeSelectionModel. + */ + public DefaultTreeSelectionModel() + { + setSelectionMode(DISCONTIGUOUS_TREE_SELECTION); + listenerList = new EventListenerList(); + } + + /** + * Creates a clone of this DefaultTreeSelectionModel with the same selection. + * The cloned instance will have the same registered listeners, the listeners + * themselves will not be cloned. The selection will be cloned. + * + * @exception CloneNotSupportedException should not be thrown here + * @return a copy of this DefaultTreeSelectionModel + */ + public Object clone() throws CloneNotSupportedException + { + DefaultTreeSelectionModel cloned = + (DefaultTreeSelectionModel) super.clone(); + + // Clone the selection and the list selection model. + cloned.selection = (TreePath[]) selection.clone(); + if (listSelectionModel!=null) + cloned.listSelectionModel = + (DefaultListSelectionModel) listSelectionModel.clone(); + return cloned; + } + + /** + * Returns a string that shows this object's properties. + * The returned string lists the selected tree rows, if any. + * + * @return a string that shows this object's properties + */ + public String toString() + { + if (isSelectionEmpty()) + return "[selection empty]"; + else + { + StringBuffer b = new StringBuffer("selected rows: ["); + for (int i = 0; i < selection.length; i++) + { + b.append(getRow(selection[i])); + b.append(' '); + } + b.append(", lead "+getLeadSelectionRow()); + return b.toString(); + } + } + + /** + * writeObject + * + * @param value0 TODO + * @exception IOException TODO + */ + private void writeObject(ObjectOutputStream value0) throws IOException + { + // TODO + } + + /** + * readObject + * + * @param value0 TODO + * @exception IOException TODO + * @exception ClassNotFoundException TODO + */ + private void readObject(ObjectInputStream value0) throws IOException, + ClassNotFoundException + { + // TODO + } + + /** + * Sets the RowMapper that should be used to map between paths and their rows. + * + * @param mapper the RowMapper to set + * @see RowMapper + */ + public void setRowMapper(RowMapper mapper) + { + rowMapper = mapper; + } + + /** + * Returns the RowMapper that is currently used to map between paths and their + * rows. + * + * @return the current RowMapper + * @see RowMapper + */ + public RowMapper getRowMapper() + { + return rowMapper; + } + + /** + * Sets the current selection mode. Possible values are + * {@link #SINGLE_TREE_SELECTION}, {@link #CONTIGUOUS_TREE_SELECTION} and + * {@link #DISCONTIGUOUS_TREE_SELECTION}. + * + * @param mode the selection mode to be set + * @see #getSelectionMode + * @see #SINGLE_TREE_SELECTION + * @see #CONTIGUOUS_TREE_SELECTION + * @see #DISCONTIGUOUS_TREE_SELECTION + */ + public void setSelectionMode(int mode) + { + selectionMode = mode; + insureRowContinuity(); + } + + /** + * Returns the current selection mode. + * + * @return the current selection mode + * @see #setSelectionMode + * @see #SINGLE_TREE_SELECTION + * @see #CONTIGUOUS_TREE_SELECTION + * @see #DISCONTIGUOUS_TREE_SELECTION + */ + public int getSelectionMode() + { + return selectionMode; + } + + /** + * Sets this path as the only selection. If this changes the selection the + * registered TreeSelectionListeners are notified. + * + * @param path the path to set as selection + */ + public void setSelectionPath(TreePath path) + { + // The most frequently only one cell in the tree is selected. + TreePath[] ose = selection; + selection = new TreePath[] { path }; + TreePath oldLead = leadPath; + leadIndex = 0; + leadRow = getRow(path); + leadPath = path; + + TreeSelectionEvent event; + + if (ose != null && ose.length > 0) + { + // The first item in the path list is the selected path. + // The remaining items are unselected pathes. + TreePath[] changed = new TreePath[ose.length + 1]; + boolean[] news = new boolean[changed.length]; + news[0] = true; + changed[0] = path; + System.arraycopy(ose, 0, changed, 1, ose.length); + event = new TreeSelectionEvent(this, changed, news, oldLead, path); + } + else + { + event = new TreeSelectionEvent(this, path, true, oldLead, path); + } + fireValueChanged(event); + } + + /** + * Get the number of the tree row for the given path. + * + * @param path the tree path + * @return the tree row for this path or -1 if the path is not visible. + */ + int getRow(TreePath path) + { + RowMapper mapper = getRowMapper(); + + if (mapper instanceof AbstractLayoutCache) + { + // The absolute majority of cases, unless the TreeUI is very + // seriously rewritten + AbstractLayoutCache ama = (AbstractLayoutCache) mapper; + return ama.getRowForPath(path); + } + else + { + // Generic non optimized implementation. + int[] rows = mapper.getRowsForPaths(new TreePath[] { path }); + if (rows.length == 0) + return - 1; + else + return rows[0]; + } + } + + /** + * Sets the paths as selection. This method checks for duplicates and removes + * them. If this changes the selection the registered TreeSelectionListeners + * are notified. + * + * @param paths the paths to set as selection + */ + public void setSelectionPaths(TreePath[] paths) + { + // Must be called, as defined in JDK API 1.4. + insureUniqueness(); + clearSelection(); + addSelectionPaths(paths); + } + + /** + * Adds a path to the list of selected paths. This method checks if the path + * is already selected and doesn't add the same path twice. If this changes + * the selection the registered TreeSelectionListeners are notified. + * + * The lead path is changed to the added path. This also happen if the + * passed path was already selected before. + * + * @param path the path to add to the selection + */ + public void addSelectionPath(TreePath path) + { + if (! isPathSelected(path)) + { + if (selectionMode == SINGLE_TREE_SELECTION || isSelectionEmpty() + || ! canPathBeAdded(path)) + setSelectionPath(path); + else + { + TreePath[] temp = new TreePath[selection.length + 1]; + System.arraycopy(selection, 0, temp, 0, selection.length); + temp[temp.length - 1] = path; + selection = new TreePath[temp.length]; + System.arraycopy(temp, 0, selection, 0, temp.length); + } + } + + if (path!=leadPath) + { + TreePath oldLead = leadPath; + leadPath = path; + leadRow = getRow(path); + leadIndex = selection.length - 1; + fireValueChanged(new TreeSelectionEvent(this, path, true, oldLead, + leadPath)); + } + } + + /** + * Adds the paths to the list of selected paths. This method checks if the + * paths are already selected and doesn't add the same path twice. If this + * changes the selection the registered TreeSelectionListeners are notified. + * + * @param paths the paths to add to the selection + */ + public void addSelectionPaths(TreePath[] paths) + { + // Must be called, as defined in JDK API 1.4. + insureUniqueness(); + + if (paths != null) + { + TreePath v0 = null; + for (int i = 0; i < paths.length; i++) + { + v0 = paths[i]; + if (! isPathSelected(v0)) + { + if (isSelectionEmpty()) + setSelectionPath(v0); + else + { + TreePath[] temp = new TreePath[selection.length + 1]; + System.arraycopy(selection, 0, temp, 0, selection.length); + temp[temp.length - 1] = v0; + selection = new TreePath[temp.length]; + System.arraycopy(temp, 0, selection, 0, temp.length); + } + TreePath oldLead = leadPath; + leadPath = paths[paths.length - 1]; + leadRow = getRow(leadPath); + leadIndex = selection.length - 1; + + fireValueChanged(new TreeSelectionEvent(this, v0, true, + oldLead, leadPath)); + } + } + insureRowContinuity(); + } + } + + /** + * Removes the path from the selection. If this changes the selection the + * registered TreeSelectionListeners are notified. + * + * @param path the path to remove + */ + public void removeSelectionPath(TreePath path) + { + if (isSelectionEmpty()) + return; + + int index = - 1; + if (isPathSelected(path)) + { + for (int i = 0; i < selection.length; i++) + { + if (selection[i].equals(path)) + { + index = i; + break; + } + } + TreePath[] temp = new TreePath[selection.length - 1]; + System.arraycopy(selection, 0, temp, 0, index); + System.arraycopy(selection, index + 1, temp, index, selection.length + - index - 1); + selection = new TreePath[temp.length]; + System.arraycopy(temp, 0, selection, 0, temp.length); + + // If the removed path was the lead path, set the lead path to null. + TreePath oldLead = leadPath; + if (path!=null && leadPath!=null && path.equals(leadPath)) + leadPath = null; + + fireValueChanged(new TreeSelectionEvent(this, path, false, oldLead, + leadPath)); + insureRowContinuity(); + } + } + + /** + * Removes the paths from the selection. If this changes the selection the + * registered TreeSelectionListeners are notified. + * + * @param paths the paths to remove + */ + public void removeSelectionPaths(TreePath[] paths) + { + if (isSelectionEmpty()) + return; + if (paths != null) + { + int index = - 1; + TreePath v0 = null; + TreePath oldLead = leadPath; + for (int i = 0; i < paths.length; i++) + { + v0 = paths[i]; + if (isPathSelected(v0)) + { + for (int x = 0; x < selection.length; x++) + { + if (selection[i].equals(v0)) + { + index = x; + break; + } + if (leadPath != null && leadPath.equals(v0)) + leadPath = null; + } + TreePath[] temp = new TreePath[selection.length - 1]; + System.arraycopy(selection, 0, temp, 0, index); + System.arraycopy(selection, index + 1, temp, index, + selection.length - index - 1); + selection = new TreePath[temp.length]; + System.arraycopy(temp, 0, selection, 0, temp.length); + + fireValueChanged(new TreeSelectionEvent(this, v0, false, + oldLead, leadPath)); + } + } + insureRowContinuity(); + } + } + + /** + * Returns the first path in the selection. This is especially useful when the + * selectionMode is {@link #SINGLE_TREE_SELECTION}. + * + * @return the first path in the selection + */ + public TreePath getSelectionPath() + { + if ((selection == null) || (selection.length == 0)) + return null; + else + return selection[0]; + } + + /** + * Returns the complete selection. + * + * @return the complete selection + */ + public TreePath[] getSelectionPaths() + { + return selection; + } + + /** + * Returns the number of paths in the selection. + * + * @return the number of paths in the selection + */ + public int getSelectionCount() + { + if (selection == null) + return 0; + else + return selection.length; + } + + /** + * Checks if a given path is in the selection. + * + * @param path the path to check + * @return <code>true</code> if the path is in the selection, + * <code>false</code> otherwise + */ + public boolean isPathSelected(TreePath path) + { + if (selection == null) + return false; + + for (int i = 0; i < selection.length; i++) + { + if (selection[i].equals(path)) + return true; + } + return false; + } + + /** + * Checks if the selection is empty. + * + * @return <code>true</code> if the selection is empty, <code>false</code> + * otherwise + */ + public boolean isSelectionEmpty() + { + return ((selection == null) || (selection.length == 0)); + } + + /** + * Removes all paths from the selection. Fire the unselection event. + */ + public void clearSelection() + { + if (! isSelectionEmpty()) + { + TreeSelectionEvent event = new TreeSelectionEvent( + this, selection, new boolean[selection.length], leadPath, null); + leadPath = null; + selection = null; + fireValueChanged(event); + } + else + { + leadPath = null; + selection = null; + } + } + + /** + * Adds a <code>TreeSelectionListener</code> object to this model. + * + * @param listener the listener to add + */ + public void addTreeSelectionListener(TreeSelectionListener listener) + { + listenerList.add(TreeSelectionListener.class, listener); + } + + /** + * Removes a <code>TreeSelectionListener</code> object from this model. + * + * @param listener the listener to remove + */ + public void removeTreeSelectionListener(TreeSelectionListener listener) + { + listenerList.remove(TreeSelectionListener.class, listener); + } + + /** + * Returns all <code>TreeSelectionListener</code> added to this model. + * + * @return an array of listeners + * @since 1.4 + */ + public TreeSelectionListener[] getTreeSelectionListeners() + { + return (TreeSelectionListener[]) getListeners(TreeSelectionListener.class); + } + + /** + * fireValueChanged + * + * @param event the event to fire. + */ + protected void fireValueChanged(TreeSelectionEvent event) + { + TreeSelectionListener[] listeners = getTreeSelectionListeners(); + + for (int i = 0; i < listeners.length; ++i) + listeners[i].valueChanged(event); + } + + /** + * Returns all added listeners of a special type. + * + * @param listenerType the listener type + * @return an array of listeners + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + /** + * Returns the currently selected rows. + * + * @return the currently selected rows + */ + public int[] getSelectionRows() + { + if (rowMapper == null) + return null; + else + return rowMapper.getRowsForPaths(selection); + } + + /** + * Returns the smallest row index from the selection. + * + * @return the smallest row index from the selection + */ + public int getMinSelectionRow() + { + if ((rowMapper == null) || (selection == null) || (selection.length == 0)) + return - 1; + else + { + int[] rows = rowMapper.getRowsForPaths(selection); + int minRow = Integer.MAX_VALUE; + for (int index = 0; index < rows.length; index++) + minRow = Math.min(minRow, rows[index]); + return minRow; + } + } + + /** + * Returns the largest row index from the selection. + * + * @return the largest row index from the selection + */ + public int getMaxSelectionRow() + { + if ((rowMapper == null) || (selection == null) || (selection.length == 0)) + return - 1; + else + { + int[] rows = rowMapper.getRowsForPaths(selection); + int maxRow = - 1; + for (int index = 0; index < rows.length; index++) + maxRow = Math.max(maxRow, rows[index]); + return maxRow; + } + } + + /** + * Checks if a particular row is selected. + * + * @param row the index of the row to check + * @return <code>true</code> if the row is in this selection, + * <code>false</code> otherwise + * @throws NullPointerException if the row mapper is not set (can only happen + * if the user has plugged in the custom incorrect TreeUI + * implementation. + */ + public boolean isRowSelected(int row) + { + // Return false if nothing is selected. + if (isSelectionEmpty()) + return false; + + RowMapper mapper = getRowMapper(); + + if (mapper instanceof AbstractLayoutCache) + { + // The absolute majority of cases, unless the TreeUI is very + // seriously rewritten + AbstractLayoutCache ama = (AbstractLayoutCache) mapper; + TreePath path = ama.getPathForRow(row); + return isPathSelected(path); + } + else + { + // Generic non optimized implementation. + int[] rows = mapper.getRowsForPaths(selection); + for (int i = 0; i < rows.length; i++) + if (rows[i] == row) + return true; + return false; + } + } + + /** + * Updates the mappings from TreePaths to row indices. + */ + public void resetRowSelection() + { + // Nothing to do here. + } + + /** + * getLeadSelectionRow + * + * @return int + */ + public int getLeadSelectionRow() + { + return leadRow; + } + + /** + * getLeadSelectionPath + * + * @return TreePath + */ + public TreePath getLeadSelectionPath() + { + return leadPath; + } + + /** + * Adds a <code>PropertyChangeListener</code> object to this model. + * + * @param listener the listener to add. + */ + public void addPropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.addPropertyChangeListener(listener); + } + + /** + * Removes a <code>PropertyChangeListener</code> object from this model. + * + * @param listener the listener to remove. + */ + public void removePropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.removePropertyChangeListener(listener); + } + + /** + * Returns all added <code>PropertyChangeListener</code> objects. + * + * @return an array of listeners. + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return changeSupport.getPropertyChangeListeners(); + } + + /** + * Makes sure the currently selected paths are valid according to the current + * selectionMode. If the selectionMode is set to + * {@link #CONTIGUOUS_TREE_SELECTION} and the selection isn't contiguous then + * the selection is reset to the first set of contguous paths. If the + * selectionMode is set to {@link #SINGLE_TREE_SELECTION} and the selection + * has more than one path, the selection is reset to the contain only the + * first path. + */ + protected void insureRowContinuity() + { + if (selection == null || selection.length < 2) + return; + else if (selectionMode == CONTIGUOUS_TREE_SELECTION) + { + if (rowMapper == null) + // This is the best we can do without the row mapper: + selectOne(); + else + { + int[] rows = rowMapper.getRowsForPaths(selection); + Arrays.sort(rows); + int i; + for (i = 1; i < rows.length; i++) + { + if (rows[i - 1] != rows[i] - 1) + // Break if no longer continuous. + break; + } + + if (i < rows.length) + { + TreePath[] ns = new TreePath[i]; + for (int j = 0; j < ns.length; j++) + ns[i] = getPath(j); + setSelectionPaths(ns); + } + } + } + else if (selectionMode == SINGLE_TREE_SELECTION) + selectOne(); + } + + /** + * Keep only one (normally last or leading) path in the selection. + */ + private void selectOne() + { + if (leadIndex > 0 && leadIndex < selection.length) + setSelectionPath(selection[leadIndex]); + else + setSelectionPath(selection[selection.length -1]); + } + + /** + * Get path for the given row that must be in the current selection. + */ + private TreePath getPath(int row) + { + if (rowMapper instanceof AbstractLayoutCache) + return ((AbstractLayoutCache) rowMapper).getPathForRow(row); + else + { + int[] rows = rowMapper.getRowsForPaths(selection); + for (int i = 0; i < rows.length; i++) + if (rows[i] == row) + return selection[i]; + } + throw new InternalError(row + " not in selection"); + } + + /** + * Returns <code>true</code> if the paths are contiguous (take subsequent + * rows in the diplayed tree view. The method returns <code>true</code> if + * we have no RowMapper assigned. + * + * @param paths the paths to check for continuity + * @return <code>true</code> if the paths are contiguous or we have no + * RowMapper assigned + */ + protected boolean arePathsContiguous(TreePath[] paths) + { + if (rowMapper == null || paths.length < 2) + return true; + + int[] rows = rowMapper.getRowsForPaths(paths); + + // The patches may not be sorted. + Arrays.sort(rows); + + for (int i = 1; i < rows.length; i++) + { + if (rows[i-1] != rows[i] - 1) + return false; + } + return true; + } + + /** + * Checks if the paths can be added. This returns <code>true</code> if: + * <ul> + * <li><code>paths</code> is <code>null</code> or empty</li> + * <li>we have no RowMapper assigned</li> + * <li>nothing is currently selected</li> + * <li>selectionMode is {@link #DISCONTIGUOUS_TREE_SELECTION}</li> + * <li>adding the paths to the selection still results in a contiguous set of + * paths</li> + * + * @param paths the paths to check + * @return <code>true</code> if the paths can be added with respect to the + * selectionMode + */ + protected boolean canPathsBeAdded(TreePath[] paths) + { + if (rowMapper == null || isSelectionEmpty() + || selectionMode == DISCONTIGUOUS_TREE_SELECTION) + return true; + + TreePath [] all = new TreePath[paths.length + selection.length]; + System.arraycopy(paths, 0, all, 0, paths.length); + System.arraycopy(selection, 0, all, paths.length, selection.length); + + return arePathsContiguous(all); + } + + /** + * Checks if the single path can be added to selection. + */ + private boolean canPathBeAdded(TreePath path) + { + if (rowMapper == null || isSelectionEmpty() + || selectionMode == DISCONTIGUOUS_TREE_SELECTION) + return true; + + TreePath[] all = new TreePath[selection.length + 1]; + System.arraycopy(selection, 0, all, 0, selection.length); + all[all.length - 1] = path; + + return arePathsContiguous(all); + } + + /** + * Checks if the paths can be removed without breaking the continuity of the + * selection according to selectionMode. + * + * @param paths the paths to check + * @return <code>true</code> if the paths can be removed with respect to the + * selectionMode + */ + protected boolean canPathsBeRemoved(TreePath[] paths) + { + if (rowMapper == null || isSelectionEmpty() + || selectionMode == DISCONTIGUOUS_TREE_SELECTION) + return true; + + HashSet set = new HashSet(); + for (int i = 0; i < selection.length; i++) + set.add(selection[i]); + + for (int i = 0; i < paths.length; i++) + set.remove(paths[i]); + + TreePath[] remaining = new TreePath[set.size()]; + Iterator iter = set.iterator(); + + for (int i = 0; i < remaining.length; i++) + remaining[i] = (TreePath) iter.next(); + + return arePathsContiguous(remaining); + } + + /** + * Notify the installed listeners that the given patches have changed. This + * method will call listeners if invoked, but it is not called from the + * implementation of this class. + * + * @param vPathes the vector of the changed patches + * @param oldLeadSelection the old selection index + */ + protected void notifyPathChange(Vector vPathes, TreePath oldLeadSelection) + { + TreePath[] pathes = new TreePath[vPathes.size()]; + for (int i = 0; i < pathes.length; i++) + pathes[i] = (TreePath) vPathes.get(i); + + boolean[] news = new boolean[pathes.length]; + for (int i = 0; i < news.length; i++) + news[i] = isPathSelected(pathes[i]); + + TreeSelectionEvent event = new TreeSelectionEvent(this, pathes, news, + oldLeadSelection, + leadPath); + fireValueChanged(event); + } + + /** + * Updates the lead selection row number after changing the lead selection + * path. + */ + protected void updateLeadIndex() + { + if (isSelectionEmpty()) + { + leadRow = leadIndex = - 1; + } + else + { + leadRow = getRow(leadPath); + for (int i = 0; i < selection.length; i++) + { + if (selection[i].equals(leadPath)) + { + leadIndex = i; + break; + } + } + leadIndex = leadRow; + } + } + + /** + * This method exists due historical reasons and returns without action + * (unless overridden). For compatibility with the applications that override + * it, it is still called from the {@link #setSelectionPaths(TreePath[])} and + * {@link #addSelectionPaths(TreePath[])}. + */ + protected void insureUniqueness() + { + // Following the API 1.4, the method should return without action. + } } diff --git a/libjava/classpath/javax/swing/tree/FixedHeightLayoutCache.java b/libjava/classpath/javax/swing/tree/FixedHeightLayoutCache.java index 535417ec389..96655ce75fd 100644 --- a/libjava/classpath/javax/swing/tree/FixedHeightLayoutCache.java +++ b/libjava/classpath/javax/swing/tree/FixedHeightLayoutCache.java @@ -1,5 +1,5 @@ -/* FixedHeightLayoutCache.java -- -Copyright (C) 2002, 2004 Free Software Foundation, Inc. +/* FixedHeightLayoutCache.java -- Fixed cell height tree layout cache +Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,208 +37,592 @@ exception statement from your version. */ package javax.swing.tree; +import gnu.javax.swing.tree.GnuPath; + import java.awt.Rectangle; import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.Set; +import java.util.Vector; import javax.swing.event.TreeModelEvent; + /** - * FixedHeightLayoutCache + * The fixed height tree layout. This class assumes that all cells in the tree + * have the same fixed height. This may be not the case, for instance, if leaves + * and branches have different height, of if the tree rows may have arbitrary + * variable height. This class will also work if the NodeDimensions are not + * set. * - * @author Andrew Selkirk + * @author Audrius Meskauskas + * @author Andrew Selkirk */ public class FixedHeightLayoutCache - extends AbstractLayoutCache + extends VariableHeightLayoutCache { + /** + * The cached node record. + */ + class NodeRecord + { + NodeRecord(int aRow, int aDepth, Object aNode, Object aParent) + { + row = aRow; + depth = aDepth; + parent = aParent; + node = aNode; + + isExpanded = expanded.contains(aNode); + } + + /** + * The row, where the tree node is displayed. + */ + final int row; + + /** + * The nesting depth + */ + final int depth; + + /** + * The parent of the given node, null for the root node. + */ + final Object parent; + + /** + * This node. + */ + final Object node; + + /** + * True for the expanded nodes. The value is calculated in constructor. + * Using this field saves one hashtable access operation. + */ + final boolean isExpanded; + + /** + * The cached bounds of the tree row. + */ + Rectangle bounds; + + /** + * The path from the tree top to the given node (computed under first + * demand) + */ + private TreePath path; + + /** + * Get the path for this node. The derived class is returned, + * making check for the last child of some parent easier. + */ + TreePath getPath() + { + if (path == null) + { + boolean lastChild = false; + if (parent != null) + { + int nc = treeModel.getChildCount(parent); + if (nc > 0) + { + int n = treeModel.getIndexOfChild(parent, node); + if (n == nc - 1) + lastChild = true; + } + } + + LinkedList lpath = new LinkedList(); + NodeRecord rp = this; + while (rp != null) + { + lpath.addFirst(rp.node); + if (rp.parent != null) + { + Object parent = rp.parent; + rp = (NodeRecord) nodes.get(parent); + // Add the root node, even if it is not visible. + if (rp == null) + lpath.addFirst(parent); + } + else + rp = null; + } + path = new GnuPath(lpath.toArray(), lastChild); + } + return path; + } + + /** + * Get the rectangle bounds (compute, if required). + */ + Rectangle getBounds() + { + // This method may be called in the context when the tree rectangle is + // not known. To work around this, it is assumed near infinitely large. + if (bounds==null) + bounds = getNodeDimensions(node, row, depth, isExpanded, + new Rectangle()); + return bounds; + } + } + + /** + * The set of all expanded tree nodes. + */ + Set expanded = new HashSet(); + + /** + * Maps nodes to the row numbers. + */ + Hashtable nodes = new Hashtable(); + + /** + * Maps row numbers to nodes. + */ + Hashtable row2node = new Hashtable(); + + /** + * If true, the row map must be recomputed before using. + */ + boolean dirty; + + /** + * The cumulative height of all rows. + */ + int totalHeight; + + /** + * The maximal width. + */ + int maximalWidth; + + /** + * Creates the unitialised instance. Before using the class, the row height + * must be set with the {@link #setRowHeight(int)} and the model must be set + * with {@link #setModel(TreeModel)}. The node dimensions may not be set. + */ + public FixedHeightLayoutCache() + { + // Nothing to do here. + } + + /** + * Get the total number of rows in the tree. Every displayed node occupies the + * single row. The root node row is included if the root node is set as + * visible (false by default). + * + * @return int the number of the displayed rows. + */ + public int getRowCount() + { + if (dirty) update(); + return row2node.size(); + } + + /** + * Refresh the row map. + */ + private final void update() + { + nodes.clear(); + row2node.clear(); + + totalHeight = maximalWidth = 0; + + Object root = treeModel.getRoot(); + + if (rootVisible) + { + countRows(root, null, 0); + } + else + { + int sc = treeModel.getChildCount(root); + for (int i = 0; i < sc; i++) + { + Object child = treeModel.getChild(root, i); + countRows(child, root, 0); + } + } + dirty = false; + } + + /** + * Recursively counts all rows in the tree. + */ + private final void countRows(Object node, Object parent, int depth) + { + Integer n = new Integer(row2node.size()); + row2node.put(n, node); + + NodeRecord nr = new NodeRecord(n.intValue(), depth, node, parent); + nodes.put(node, nr); + + // For expanded nodes and for the root node. + if (expanded.contains(node)) + { + int sc = treeModel.getChildCount(node); + int deeper = depth+1; + for (int i = 0; i < sc; i++) + { + Object child = treeModel.getChild(node, i); + countRows(child, node, deeper); + } + } + } + + /** + * Discard the bound information for the given path. + * + * @param path the path, for that the bound information must be recomputed. + */ + public void invalidatePathBounds(TreePath path) + { + NodeRecord r = (NodeRecord) nodes.get(path.getLastPathComponent()); + if (r!=null) + r.bounds = null; + } + + /** + * Mark all cached information as invalid. + */ + public void invalidateSizes() + { + dirty = true; + } + + /** + * Set the expanded state of the given path. The expansion states must be + * always updated when expanding and colapsing the tree nodes. Otherwise + * other methods will not work correctly after the nodes are collapsed or + * expanded. + * + * @param path the tree path, for that the state is being set. + * @param isExpanded the expanded state of the given path. + */ + public void setExpandedState(TreePath path, boolean isExpanded) + { + if (isExpanded) + expanded.add(path.getLastPathComponent()); + else + expanded.remove(path.getLastPathComponent()); + + dirty = true; + } + + /** + * Get the expanded state for the given tree path. + * + * @return true if the given path is expanded, false otherwise. + */ + public boolean isExpanded(TreePath path) + { + return expanded.contains(path.getLastPathComponent()); + } + + /** + * Get bounds for the given tree path. + * + * @param path the tree path + * @param rect the rectangle that will be reused to return the result. + * @return Rectangle the bounds of the last line, defined by the given path. + */ + public Rectangle getBounds(TreePath path, Rectangle rect) + { + if (path == null) + return null; + if (dirty) + update(); + Object last = path.getLastPathComponent(); + NodeRecord r = (NodeRecord) nodes.get(last); + if (r == null) + // This node is not visible. + { + rect.x = rect.y = rect.width = rect.height = 0; + } + else + { + if (r.bounds == null) + { + Rectangle dim = getNodeDimensions(last, r.row, r.depth, + r.isExpanded, rect); + r.bounds = dim; + } + + rect.setRect(r.bounds); + } + return rect; + } + + /** + * Get the path, the last element of that is displayed in the given row. + * + * @param row the row + * @return TreePath the path + */ + public TreePath getPathForRow(int row) + { + if (dirty) + update(); + Object last = row2node.get(new Integer(row)); + if (last == null) + return null; + else + { + NodeRecord r = (NodeRecord) nodes.get(last); + return r.getPath(); + } + } + + /** + * Get the row, displaying the last node of the given path. + * + * @param path the path + * @return int the row number or -1 if the end of the path is not visible. + */ + public int getRowForPath(TreePath path) + { + if (path == null) + return -1; + + if (dirty) update(); + + NodeRecord r = (NodeRecord) nodes.get(path.getLastPathComponent()); + if (r == null) + return - 1; + else + return r.row; + } + + /** + * Get the path, closest to the given point. + * + * @param x the point x coordinate + * @param y the point y coordinate + * @return the tree path, closest to the the given point + */ + public TreePath getPathClosestTo(int x, int y) + { + if (dirty) + update(); + + // As the rows have arbitrary height, we need to iterate. + NodeRecord best = null; + NodeRecord r; + Enumeration en = nodes.elements(); + + int dist = Integer.MAX_VALUE; + + while (en.hasMoreElements() && dist > 0) + { + r = (NodeRecord) en.nextElement(); + if (best == null) + { + best = r; + dist = distance(r.getBounds(), x, y); + } + else + { + int rr = distance(r.getBounds(), x, y); + if (rr < dist) + { + best = r; + dist = rr; + } + } + } + + if (best == null) + return null; + else + return best.getPath(); + } + + /** + * Get the closest distance from this point till the given rectangle. Only + * vertical distance is taken into consideration. + */ + int distance(Rectangle r, int x, int y) + { + if (y < r.y) + return r.y - y; + else if (y > r.y + r.height) + return y - (r.y + r.height); + else + return 0; + } + + /** + * Get the number of the visible childs for the given tree path. If the node + * is not expanded, 0 is returned. Otherwise, the number of children is + * obtained from the model as the number of children for the last path + * component. + * + * @param path the tree path + * @return int the number of the visible childs (for row). + */ + public int getVisibleChildCount(TreePath path) + { + if (isExpanded(path)) + return 0; + else + return treeModel.getChildCount(path.getLastPathComponent()); + } + + /** + * Get the enumeration over all visible pathes that start from the given + * parent path. + * + * @param parentPath the parent path + * @return the enumeration over pathes + */ + public Enumeration getVisiblePathsFrom(TreePath parentPath) + { + if (dirty) + update(); + Vector p = new Vector(parentPath.getPathCount()); + Object node; + NodeRecord nr; + + for (int i = 0; i < parentPath.getPathCount(); i++) + { + node = parentPath.getPathComponent(i); + nr = (NodeRecord) nodes.get(node); + if (nr.row >= 0) + p.add(node); + } + return p.elements(); + } + + /** + * Return the expansion state of the given tree path. The expansion state + * must be previously set with the + * {@link #setExpandedState(TreePath, boolean)} + * + * @param path the path being checked + * @return true if the last node of the path is expanded, false otherwise. + */ + public boolean getExpandedState(TreePath path) + { + return expanded.contains(path.getLastPathComponent()); + } + + /** + * The listener method, called when the tree nodes are changed. + * + * @param event the change event + */ + public void treeNodesChanged(TreeModelEvent event) + { + dirty = true; + } + + /** + * The listener method, called when the tree nodes are inserted. + * + * @param event the change event + */ + public void treeNodesInserted(TreeModelEvent event) + { + dirty = true; + } + + /** + * The listener method, called when the tree nodes are removed. + * + * @param event the change event + */ + public void treeNodesRemoved(TreeModelEvent event) + { + dirty = true; + } + + /** + * Called when the tree structure has been changed. + * + * @param event the change event + */ + public void treeStructureChanged(TreeModelEvent event) + { + dirty = true; + } + + /** + * Set the tree model that will provide the data. + */ + public void setModel(TreeModel newModel) + { + treeModel = newModel; + // The root node is expanded by default. + expanded.add(treeModel.getRoot()); + dirty = true; + } + + /** + * Inform the instance if the tree root node is visible. If this method + * is not called, it is assumed that the tree root node is not visible. + * + * @param visible true if the tree root node is visible, false + * otherwise. + */ + public void setRootVisible(boolean visible) + { + rootVisible = visible; + dirty = true; + } + + /** + * Get the sum of heights for all rows. + */ + public int getPreferredHeight() + { + if (dirty) + update(); + totalHeight = 0; + Enumeration en = nodes.elements(); + while (en.hasMoreElements()) + { + NodeRecord nr = (NodeRecord) en.nextElement(); + Rectangle r = nr.getBounds(); + totalHeight += r.height; + } + return totalHeight; + } - // ------------------------------------------------------------- - // Variables -------------------------------------------------- - // ------------------------------------------------------------- - - // ------------------------------------------------------------- - // Initialization --------------------------------------------- - // ------------------------------------------------------------- - - /** - * Constructor FixedHeightLayoutCache - */ - public FixedHeightLayoutCache() - { - // TODO - } // FixedHeightLayoutCache() - - // ------------------------------------------------------------- - // Methods ---------------------------------------------------- - // ------------------------------------------------------------- - - /** - * getRowCount - * - * @returns int - */ - public int getRowCount() - { - return 0; // TODO - } // getRowCount() - - /** - * invalidatePathBounds - * - * @param value0 TODO - */ - public void invalidatePathBounds(TreePath value0) - { - // TODO - } // invalidatePathBounds() - - /** - * invalidateSizes - */ - public void invalidateSizes() - { - // TODO - } // invalidateSizes() - - /** - * isExpanded - * - * @param value0 TODO - * @returns boolean - */ - public boolean isExpanded(TreePath value0) - { - return false; // TODO - } // isExpanded() - - /** - * getBounds - * - * @param value0 TODO - * @param value1 TODO - * @returns Rectangle - */ - public Rectangle getBounds(TreePath value0, Rectangle value1) - { - return null; // TODO - } // getBounds() - - /** - * getPathForRow - * - * @param row TODO - * @returns TreePath - */ - public TreePath getPathForRow(int row) - { - //TODO - return null; - } // getPathForRow() - - /** - * getRowForPath - * - * @param value0 TODO - * @returns int - */ - public int getRowForPath(TreePath value0) - { - return 0; - } // getRowForPath() - - /** - * getPathClosestTo - * - * @param value0 TODO - * @param value1 TODO - * @returns TreePath - */ - public TreePath getPathClosestTo(int value0, int value1) - { - return null; // TODO - } // getPathClosestTo() - - /** - * getVisibleChildCount - * - * @param value0 TODO - * @returns int - */ - public int getVisibleChildCount(TreePath value0) - { - return 0; // TODO - } // getVisibleChildCount() - - /** - * getVisiblePathsFrom - * - * @param value0 TODO - * @returns Enumeration - */ - public Enumeration getVisiblePathsFrom(TreePath value0) - { - return null; // TODO - } // getVisiblePathsFrom() - - /** - * setExpandedState - * - * @param value0 TODO - * @param value1 TODO - */ - public void setExpandedState(TreePath value0, boolean value1) - { - // TODO - } // setExpandedState() - - /** - * getExpandedState - * - * @param value0 TODO - * @returns boolean - */ - public boolean getExpandedState(TreePath value0) - { - return false; // TODO - } // getExpandedState() - - /** - * treeNodesChanged - * - * @param value0 TODO - */ - public void treeNodesChanged(TreeModelEvent value0) - { - // TODO - } // treeNodesChanged() - - /** - * treeNodesInserted - * - * @param value0 TODO - */ - public void treeNodesInserted(TreeModelEvent value0) - { - // TODO - } // treeNodesInserted() - - /** - * treeNodesRemoved - * - * @param value0 TODO - */ - public void treeNodesRemoved(TreeModelEvent value0) - { - // TODO - } // treeNodesRemoved() - - /** - * treeStructureChanged - * - * @param value0 TODO - */ - public void treeStructureChanged(TreeModelEvent value0) - { - // TODO - } // treeStructureChanged() - -} // FixedHeightLayoutCache + /** + * Get the maximal width. + */ + public int getPreferredWidth(Rectangle value) + { + if (dirty) + update(); + + maximalWidth = 0; + Enumeration en = nodes.elements(); + while (en.hasMoreElements()) + { + NodeRecord nr = (NodeRecord) en.nextElement(); + Rectangle r = nr.getBounds(); + if (r.x + r.width > maximalWidth) + maximalWidth = r.x + r.width; + } + return maximalWidth; + } + + /** + * Returns true if this layout supposes that all rows have the fixed + * height. + * + * @return boolean true if all rows in the tree must have the fixed + * height (true by default). + */ + protected boolean isFixedRowHeight() + { + return true; + } + +} diff --git a/libjava/classpath/javax/swing/tree/TreeCellEditor.java b/libjava/classpath/javax/swing/tree/TreeCellEditor.java index 691cbc16386..8951f313798 100644 --- a/libjava/classpath/javax/swing/tree/TreeCellEditor.java +++ b/libjava/classpath/javax/swing/tree/TreeCellEditor.java @@ -1,5 +1,5 @@ /* TreeCellEditor.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,20 +44,26 @@ import javax.swing.CellEditor; import javax.swing.JTree; /** - * TreeCellEditor public interface + * A <code>TreeCellEditor</code> is used by the {@link JTree} component to + * edit individual tree elements (nodes). + * * @author Andrew Selkirk */ public interface TreeCellEditor extends CellEditor { /** - * getTreeCellEditorComponent - * @param tree TODO - * @param value TODO - * @param isSelected TODO - * @param expanded TODO - * @param leaf TODO - * @param row TODO - * @return TODO + * Returns a component that has been configured to edit one element (or + * node) in a {@link JTree} component. The arguments to this method are used + * to pass in the value and state of the element to be edited. + * + * @param tree the tree. + * @param value the value to render. + * @param isSelected is the tree element selected? + * @param expanded is the tree element expanded? + * @param leaf is the tree element a leaf node? + * @param row the row index. + * + * @return A component that is configured for editing the tree element. */ Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, diff --git a/libjava/classpath/javax/swing/tree/TreeCellRenderer.java b/libjava/classpath/javax/swing/tree/TreeCellRenderer.java index a1808c9ee91..b7eeb9c6ca4 100644 --- a/libjava/classpath/javax/swing/tree/TreeCellRenderer.java +++ b/libjava/classpath/javax/swing/tree/TreeCellRenderer.java @@ -1,5 +1,5 @@ /* TreeCellRenderer.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. @@ -43,27 +43,31 @@ import java.awt.Component; import javax.swing.JTree; /** - * TreeCellRenderer public interface + * A <code>TreeCellRenderer</code> is used by the {@link JTree} component to + * paint individual tree elements (nodes). + * * @author Andrew Selkirk */ public interface TreeCellRenderer { - /** - * getTreeCellRendererComponent - * @param tree TODO - * @param value TODO - * @param selected TODO - * @param expanded TODO - * @param leaf TODO - * @param row TODO - * @param hasFocus TODO - * @returns TODO + * Returns a component that has been configured to display one element (or + * node) in a {@link JTree} component. The arguments to this method are used + * to pass in the value and state of the element to be rendered. + * + * @param tree the tree. + * @param value the value to render. + * @param selected is the tree element selected? + * @param expanded is the tree element expanded? + * @param leaf is the tree element a leaf node? + * @param row the row index. + * @param hasFocus does the tree element have the focus? + * + * @return A component that is configured for rendering the tree element. */ Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus); - } diff --git a/libjava/classpath/javax/swing/tree/TreeNode.java b/libjava/classpath/javax/swing/tree/TreeNode.java index fb8f880f286..94f2c69f895 100644 --- a/libjava/classpath/javax/swing/tree/TreeNode.java +++ b/libjava/classpath/javax/swing/tree/TreeNode.java @@ -1,5 +1,5 @@ /* TreeNode.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,59 +41,72 @@ package javax.swing.tree; import java.util.Enumeration; /** - * TreeNode public interface + * A tree node. + * * @author Andrew Selkirk */ public interface TreeNode { - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getParent - * @returns TreeNode - */ - TreeNode getParent(); - - /** - * getIndex - * @param node TODO - * @returns int - */ - int getIndex(TreeNode node); - - /** - * getChildAt - * @param index TODO - * @returns TreeNode - */ - TreeNode getChildAt(int index); - - /** - * getChildCount - * @returns int - */ - int getChildCount(); - - /** - * getAllowsChildren - * @returns boolean - */ - boolean getAllowsChildren(); - - /** - * isLeaf - * @returns boolean - */ - boolean isLeaf(); - - /** - * children - * @returns Enumeration - */ - Enumeration children(); - - -} // TreeNode + /** + * Returns the parent node for this tree node, or <code>null</code> if this + * node has no parent. + * + * @return The parent node (possibly <code>null</code>). + */ + TreeNode getParent(); + + /** + * Returns the index of the specified child node, or -1 if the node is not + * in fact a child of this node. + * + * @param node the node (<code>null</code> not permitted). + * + * @return The index of the specified child node, or -1. + * + * @throws IllegalArgumentException if <code>node</code> is <code>null</code>. + */ + int getIndex(TreeNode node); + + /** + * Returns the child node at the given index. + * + * @param index the index (in the range <code>0</code> to + * <code>getChildCount() - 1</code>). + * + * @return The child node at the given index. + */ + TreeNode getChildAt(int index); + + /** + * Returns the number of children for this node. + * + * @return The number of children for this node. + */ + int getChildCount(); + + /** + * Returns <code>true</code> if this node allows children, and + * <code>false</code> otherwise. + * + * @return A boolean. + */ + boolean getAllowsChildren(); + + /** + * Returns <code>true</code> if this node is a leaf node, and + * <code>false</code> otherwise. + * + * @return A boolean. + */ + boolean isLeaf(); + + /** + * Returns an enumeration of the children of this node, or an empty + * enumeration if this node has no children. + * + * @return An enumeration of the children of this node. + */ + Enumeration children(); + +} diff --git a/libjava/classpath/javax/swing/tree/TreePath.java b/libjava/classpath/javax/swing/tree/TreePath.java index 37ec632c95f..4671c4be54b 100644 --- a/libjava/classpath/javax/swing/tree/TreePath.java +++ b/libjava/classpath/javax/swing/tree/TreePath.java @@ -1,5 +1,5 @@ /* TreePath.java -- - Copyright (C) 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -53,9 +53,15 @@ public class TreePath implements Serializable static final long serialVersionUID = 4380036194768077479L; /** - * path + * The actual patch. The {@link DefaultTreeSelectionModel#clone()} + * assumes that the TreePath is immutable, so it is marked final here. */ - private Object[] path = null; + private final Object[] path; + + /** + * The parent path (to be reused). + */ + private transient TreePath parentPath; /** @@ -153,8 +159,8 @@ public class TreePath implements Serializable * * @param object the object (<code>null</code> permitted). * - * @returns <code>true</code> if <code>obj</code> is equal to this tree path, - * and <code>false</code> otherwise. + * @return <code>true</code> if <code>obj</code> is equal to this tree path, + * and <code>false</code> otherwise. */ public boolean equals(Object object) { @@ -196,7 +202,7 @@ public class TreePath implements Serializable /** * Returns an array containing the path elements. * - * @returns An array containing the path elements. + * @return An array containing the path elements. */ public Object[] getPath() { @@ -216,7 +222,7 @@ public class TreePath implements Serializable /** * Returns the number of elements in the path. * - * @returns The number of elements in the path. + * @return The number of elements in the path. */ public int getPathCount() { @@ -248,8 +254,8 @@ public class TreePath implements Serializable * * @param path the path to check (<code>null</code> permitted). * - * @returns <code>true</code> if <code>path</code> is a descendant of this - * path, and <code>false</code> otherwise + * @return <code>true</code> if <code>path</code> is a descendant of this + * path, and <code>false</code> otherwise */ public boolean isDescendant(TreePath path) { @@ -272,7 +278,7 @@ public class TreePath implements Serializable * * @param element the element. * - * @returns A tree path. + * @return A tree path. */ public TreePath pathByAddingChild(Object element) { @@ -284,8 +290,8 @@ public class TreePath implements Serializable * as this path, except for the last one. If this path contains only one * element, the method returns <code>null</code>. * - * @returns The parent path, or <code>null</code> if this path has only one - * element. + * @return The parent path, or <code>null</code> if this path has only one + * element. */ public TreePath getParentPath() { @@ -293,7 +299,12 @@ public class TreePath implements Serializable // is what the JDK does. if (path.length <= 1) return null; - - return new TreePath(this.getPath(), path.length - 1); + + // Reuse the parent path, if possible. The parent path is requested + // during the tree repainting, so reusing generates a lot less garbage. + if (parentPath == null) + parentPath = new TreePath(this.getPath(), path.length - 1); + + return parentPath; } } diff --git a/libjava/classpath/javax/swing/tree/VariableHeightLayoutCache.java b/libjava/classpath/javax/swing/tree/VariableHeightLayoutCache.java index 2c9136c5103..a9ed552e635 100644 --- a/libjava/classpath/javax/swing/tree/VariableHeightLayoutCache.java +++ b/libjava/classpath/javax/swing/tree/VariableHeightLayoutCache.java @@ -1,5 +1,5 @@ /* VariableHeightLayoutCache.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. @@ -35,219 +35,579 @@ 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.tree; +import gnu.javax.swing.tree.GnuPath; + import java.awt.Rectangle; import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.Set; +import java.util.Vector; import javax.swing.event.TreeModelEvent; /** - * VariableHeightLayoutCache - * @author Andrew Selkirk + * The fixed height tree layout. This class requires the NodeDimensions to be + * set and ignores the row height property. + * + * @specnote the methods, of this class, returning TreePath, actually returns + * the derived class GnuPath that provides additional information for optimized + * painting. See the GnuPath code for details. + * + * @author Audrius Meskauskas */ -public class VariableHeightLayoutCache extends AbstractLayoutCache { - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor VariableHeightLayoutCache - */ - public VariableHeightLayoutCache() { - // TODO - } // VariableHeightLayoutCache() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * setModel - * @param value0 TODO - */ - public void setModel(TreeModel value0) { - // TODO - } // setModel() - - /** - * setRootVisible - * @param value0 TODO - */ - public void setRootVisible(boolean value0) { - // TODO - } // setRootVisible() - - /** - * setNodeDimensions - * @param value0 TODO - */ - public void setNodeDimensions(NodeDimensions value0) { - // TODO - } // setNodeDimensions() - - /** - * setExpandedState - * @param value0 TODO - * @param value1 TODO - */ - public void setExpandedState(TreePath value0, boolean value1) { - // TODO - } // setExpandedState() - - /** - * getExpandedState - * @param value0 TODO - * @returns boolean - */ - public boolean getExpandedState(TreePath value0) { - return false; // TODO - } // getExpandedState() - - /** - * getBounds - * @param value0 TODO - * @param value1 TODO - * @returns Rectangle - */ - public Rectangle getBounds(TreePath value0, Rectangle value1) { - return null; // TODO - } // getBounds() - - /** - * getPathForRow - * @param value0 TODO - * @returns TreePath - */ - public TreePath getPathForRow(int value0) { - return null; // TODO - } // getPathForRow() - - /** - * getRowForPath - * @param value0 TODO - * @returns int - */ - public int getRowForPath(TreePath value0) { - return 0; // TODO - } // getRowForPath() - - /** - * getRowCount - * @returns int - */ - public int getRowCount() { - return 0; // TODO - } // getRowCount() - - /** - * invalidatePathBounds - * @param value0 TODO - */ - public void invalidatePathBounds(TreePath value0) { - // TODO - } // invalidatePathBounds() - - /** - * getPreferredHeight - * @returns int - */ - public int getPreferredHeight() { - return 0; // TODO - } // getPreferredHeight() - - /** - * getPreferredWidth - * @param value0 TODO - * @returns int - */ - public int getPreferredWidth(Rectangle value0) { - return 0; // TODO - } // getPreferredWidth() - - /** - * getPathClosestTo - * @param value0 TODO - * @param value1 TODO - * @returns TreePath - */ - public TreePath getPathClosestTo(int value0, int value1) { - return null; // TODO - } // getPathClosestTo() - - /** - * getVisiblePathsFrom - * @param value0 TODO - * @returns Enumeration - */ - public Enumeration getVisiblePathsFrom(TreePath value0) { - return null; // TODO - } // getVisiblePathsFrom() - - /** - * getVisibleChildCount - * @param value0 TODO - * @returns int - */ - public int getVisibleChildCount(TreePath value0) { - return 0; // TODO - } // getVisibleChildCount() - - /** - * invalidateSizes - */ - public void invalidateSizes() { - // TODO - } // invalidateSizes() - - /** - * isExpanded - * @param value0 TODO - * @returns boolean - */ - public boolean isExpanded(TreePath value0) { - return false; // TODO - } // isExpanded() - - /** - * treeNodesChanged - * @param value0 TODO - */ - public void treeNodesChanged(TreeModelEvent value0) { - // TODO - } // treeNodesChanged() - - /** - * treeNodesInserted - * @param value0 TODO - */ - public void treeNodesInserted(TreeModelEvent value0) { - // TODO - } // treeNodesInserted() - - /** - * treeNodesRemoved - * @param value0 TODO - */ - public void treeNodesRemoved(TreeModelEvent value0) { - // TODO - } // treeNodesRemoved() - - /** - * treeStructureChanged - * @param value0 TODO - */ - public void treeStructureChanged(TreeModelEvent value0) { - // TODO - } // treeStructureChanged() - - -} // VariableHeightLayoutCache +public class VariableHeightLayoutCache + extends AbstractLayoutCache +{ + /** + * The cached node record. + */ + class NodeRecord + { + NodeRecord(int aRow, int aDepth, Object aNode, Object aParent) + { + row = aRow; + depth = aDepth; + parent = aParent; + node = aNode; + + isExpanded = expanded.contains(aNode); + } + + /** + * The row, where the tree node is displayed. + */ + final int row; + + /** + * The nesting depth + */ + final int depth; + + /** + * The parent of the given node, null for the root node. + */ + final Object parent; + + /** + * This node. + */ + final Object node; + + /** + * True for the expanded nodes. The value is calculated in constructor. + * Using this field saves one hashtable access operation. + */ + final boolean isExpanded; + + /** + * The cached bounds of the tree row. + */ + Rectangle bounds; + + /** + * The path from the tree top to the given node (computed under first + * demand) + */ + private TreePath path; + + /** + * Get the path for this node. The derived class is returned, making check + * for the last child of some parent easier. + */ + TreePath getPath() + { + if (path == null) + { + boolean lastChild = false; + if (parent != null) + { + int nc = treeModel.getChildCount(parent); + if (nc > 0) + { + int n = treeModel.getIndexOfChild(parent, node); + if (n == nc - 1) + lastChild = true; + } + } + + LinkedList lpath = new LinkedList(); + NodeRecord rp = this; + while (rp != null) + { + lpath.addFirst(rp.node); + if (rp.parent != null) + { + Object parent = rp.parent; + rp = (NodeRecord) nodes.get(parent); + // Add the root node, even if it is not visible. + if (rp == null) + lpath.addFirst(parent); + } + else + rp = null; + } + path = new GnuPath(lpath.toArray(), lastChild); + } + return path; + } + + /** + * Get the rectangle bounds (compute, if required). + */ + Rectangle getBounds() + { + // This method may be called in the context when the tree rectangle is + // not known. To work around this, it is assumed near infinitely large. + if (bounds==null) + bounds = getNodeDimensions(node, row, depth, isExpanded, + new Rectangle()); + return bounds; + } + } + + /** + * The set of all expanded tree nodes. + */ + Set expanded = new HashSet(); + + /** + * Maps nodes to the row numbers. + */ + Hashtable nodes = new Hashtable(); + + /** + * Maps row numbers to nodes. + */ + Hashtable row2node = new Hashtable(); + + /** + * If true, the row map must be recomputed before using. + */ + boolean dirty; + + /** + * The cumulative height of all rows. + */ + int totalHeight; + + /** + * The maximal width. + */ + int maximalWidth; + + /** + * Creates the unitialised instance. Before using the class, the row height + * must be set with the {@link #setRowHeight(int)} and the model must be set + * with {@link #setModel(TreeModel)}. The node dimensions may not be set. + */ + public VariableHeightLayoutCache() + { + // Nothing to do here. + } + + /** + * Get the total number of rows in the tree. Every displayed node occupies the + * single row. The root node row is included if the root node is set as + * visible (false by default). + * + * @return int the number of the displayed rows. + */ + public int getRowCount() + { + if (dirty) update(); + return row2node.size(); + } + + /** + * Refresh the row map. + */ + private final void update() + { + nodes.clear(); + row2node.clear(); + + totalHeight = maximalWidth = 0; + + Object root = treeModel.getRoot(); + + if (rootVisible) + { + countRows(root, null, 0); + } + else + { + int sc = treeModel.getChildCount(root); + for (int i = 0; i < sc; i++) + { + Object child = treeModel.getChild(root, i); + countRows(child, root, 0); + } + } + dirty = false; + } + + /** + * Recursively counts all rows in the tree. + */ + private final void countRows(Object node, Object parent, int depth) + { + Integer n = new Integer(row2node.size()); + row2node.put(n, node); + + NodeRecord nr = new NodeRecord(n.intValue(), depth, node, parent); + nodes.put(node, nr); + + // For expanded nodes + if (expanded.contains(node)) + { + int sc = treeModel.getChildCount(node); + int deeper = depth+1; + for (int i = 0; i < sc; i++) + { + Object child = treeModel.getChild(node, i); + countRows(child, node, deeper); + } + } + } + + /** + * Discard the bound information for the given path. + * + * @param path the path, for that the bound information must be recomputed. + */ + public void invalidatePathBounds(TreePath path) + { + NodeRecord r = (NodeRecord) nodes.get(path.getLastPathComponent()); + if (r!=null) + r.bounds = null; + } + + /** + * Mark all cached information as invalid. + */ + public void invalidateSizes() + { + dirty = true; + } + + /** + * Set the expanded state of the given path. The expansion states must be + * always updated when expanding and colapsing the tree nodes. Otherwise + * other methods will not work correctly after the nodes are collapsed or + * expanded. + * + * @param path the tree path, for that the state is being set. + * @param isExpanded the expanded state of the given path. + */ + public void setExpandedState(TreePath path, boolean isExpanded) + { + if (isExpanded) + expanded.add(path.getLastPathComponent()); + else + expanded.remove(path.getLastPathComponent()); + + dirty = true; + } + + /** + * Get the expanded state for the given tree path. + * + * @return true if the given path is expanded, false otherwise. + */ + public boolean isExpanded(TreePath path) + { + return expanded.contains(path.getLastPathComponent()); + } + + /** + * Get bounds for the given tree path. + * + * @param path the tree path + * @param rect the rectangle that will be reused to return the result. + * @return Rectangle the bounds of the last line, defined by the given path. + */ + public Rectangle getBounds(TreePath path, Rectangle rect) + { + if (path == null) + return null; + if (dirty) + update(); + Object last = path.getLastPathComponent(); + NodeRecord r = (NodeRecord) nodes.get(last); + if (r == null) + // This node is not visible. + { + rect.x = rect.y = rect.width = rect.height = 0; + } + else + { + if (r.bounds == null) + { + Rectangle dim = getNodeDimensions(last, r.row, r.depth, + r.isExpanded, rect); + r.bounds = dim; + } + + rect.setRect(r.bounds); + } + return rect; + } + + /** + * Get the path, the last element of that is displayed in the given row. + * + * @param row the row + * @return TreePath the path + */ + public TreePath getPathForRow(int row) + { + if (dirty) + update(); + Object last = row2node.get(new Integer(row)); + if (last == null) + return null; + else + { + NodeRecord r = (NodeRecord) nodes.get(last); + return r.getPath(); + } + } + + /** + * Get the row, displaying the last node of the given path. + * + * @param path the path + * @return int the row number or -1 if the end of the path is not visible. + */ + public int getRowForPath(TreePath path) + { + if (path == null) + return -1; + if (dirty) update(); + + NodeRecord r = (NodeRecord) nodes.get(path.getLastPathComponent()); + if (r == null) + return - 1; + else + return r.row; + } + + /** + * Get the path, closest to the given point. + * + * @param x the point x coordinate + * @param y the point y coordinate + * @return the tree path, closest to the the given point + */ + public TreePath getPathClosestTo(int x, int y) + { + if (dirty) + update(); + + // As the rows have arbitrary height, we need to iterate. + NodeRecord best = null; + NodeRecord r; + Enumeration en = nodes.elements(); + + int dist = Integer.MAX_VALUE; + + while (en.hasMoreElements() && dist > 0) + { + r = (NodeRecord) en.nextElement(); + if (best == null) + { + best = r; + dist = distance(r.getBounds(), x, y); + } + else + { + int rr = distance(r.getBounds(), x, y); + if (rr < dist) + { + best = r; + dist = rr; + } + } + } + + if (best == null) + return null; + else + return best.getPath(); + } + + /** + * Get the closest distance from this point till the given rectangle. Only + * vertical distance is taken into consideration. + */ + int distance(Rectangle r, int x, int y) + { + if (y < r.y) + return r.y - y; + else if (y > r.y + r.height) + return y - (r.y + r.height); + else + return 0; + } + + /** + * Get the number of the visible childs for the given tree path. If the node + * is not expanded, 0 is returned. Otherwise, the number of children is + * obtained from the model as the number of children for the last path + * component. + * + * @param path the tree path + * @return int the number of the visible childs (for row). + */ + public int getVisibleChildCount(TreePath path) + { + if (isExpanded(path)) + return 0; + else + return treeModel.getChildCount(path.getLastPathComponent()); + } + + /** + * Get the enumeration over all visible pathes that start from the given + * parent path. + * + * @param parentPath the parent path + * @return the enumeration over pathes + */ + public Enumeration getVisiblePathsFrom(TreePath parentPath) + { + if (dirty) + update(); + Vector p = new Vector(parentPath.getPathCount()); + Object node; + NodeRecord nr; + + for (int i = 0; i < parentPath.getPathCount(); i++) + { + node = parentPath.getPathComponent(i); + nr = (NodeRecord) nodes.get(node); + if (nr.row >= 0) + p.add(node); + } + return p.elements(); + } + + /** + * Return the expansion state of the given tree path. The expansion state + * must be previously set with the + * {@link #setExpandedState(TreePath, boolean)} + * + * @param path the path being checked + * @return true if the last node of the path is expanded, false otherwise. + */ + public boolean getExpandedState(TreePath path) + { + return expanded.contains(path.getLastPathComponent()); + } + + /** + * The listener method, called when the tree nodes are changed. + * + * @param event the change event + */ + public void treeNodesChanged(TreeModelEvent event) + { + dirty = true; + } + + /** + * The listener method, called when the tree nodes are inserted. + * + * @param event the change event + */ + public void treeNodesInserted(TreeModelEvent event) + { + dirty = true; + } + + /** + * The listener method, called when the tree nodes are removed. + * + * @param event the change event + */ + public void treeNodesRemoved(TreeModelEvent event) + { + dirty = true; + } + + /** + * Called when the tree structure has been changed. + * + * @param event the change event + */ + public void treeStructureChanged(TreeModelEvent event) + { + dirty = true; + } + + /** + * Set the tree model that will provide the data. + */ + public void setModel(TreeModel newModel) + { + treeModel = newModel; + // The root node is expanded by default. + expanded.add(treeModel.getRoot()); + dirty = true; + } + + /** + * Inform the instance if the tree root node is visible. If this method + * is not called, it is assumed that the tree root node is not visible. + * + * @param visible true if the tree root node is visible, false + * otherwise. + */ + public void setRootVisible(boolean visible) + { + rootVisible = visible; + dirty = true; + } + + /** + * Get the sum of heights for all rows. + */ + public int getPreferredHeight() + { + if (dirty) + update(); + totalHeight = 0; + Enumeration en = nodes.elements(); + while (en.hasMoreElements()) + { + NodeRecord nr = (NodeRecord) en.nextElement(); + Rectangle r = nr.getBounds(); + totalHeight += r.height; + } + return totalHeight; + } + + /** + * Get the maximal width. + */ + public int getPreferredWidth(Rectangle value) + { + if (dirty) + update(); + + maximalWidth = 0; + Enumeration en = nodes.elements(); + while (en.hasMoreElements()) + { + NodeRecord nr = (NodeRecord) en.nextElement(); + Rectangle r = nr.getBounds(); + if (r.x + r.width > maximalWidth) + maximalWidth = r.x + r.width; + } + return maximalWidth; + } +} diff --git a/libjava/classpath/javax/swing/undo/StateEditable.java b/libjava/classpath/javax/swing/undo/StateEditable.java index bec396e1e20..459025be7da 100644 --- a/libjava/classpath/javax/swing/undo/StateEditable.java +++ b/libjava/classpath/javax/swing/undo/StateEditable.java @@ -1,5 +1,5 @@ /* StateEditable.java -- Interface for collaborating with StateEdit. - Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -90,9 +90,9 @@ public interface StateEditable * from the specified hash table. * * <p><b>Note to implementors of this interface:</b> To increase - * efficiency, the <code>StateEdit</code> class {@linkplan - * StateEdit#removeRedundantState() removes redundant state - * information}. Therefore, implementations of this interface must be + * efficiency, the <code>StateEdit</code> class {@link + * StateEdit#removeRedundantState()} removes redundant state + * information. Therefore, implementations of this interface must be * prepared for the case where certain keys were stored into the * table by {@link #storeState}, but are not present anymore * when the <code>restoreState</code> method gets called. diff --git a/libjava/classpath/javax/swing/undo/UndoManager.java b/libjava/classpath/javax/swing/undo/UndoManager.java index 565b5ca8884..b9e6de67576 100644 --- a/libjava/classpath/javax/swing/undo/UndoManager.java +++ b/libjava/classpath/javax/swing/undo/UndoManager.java @@ -1,5 +1,5 @@ -/* AbstractTableModel.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. +/* UndoManager.java -- + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -265,7 +265,7 @@ public class UndoManager * Determines which significant edit would be undone if {@link * #undo()} was called. * - * @returns the significant edit that would be undone, or + * @return the significant edit that would be undone, or * <code>null</code> if no significant edit would be affected by * calling {@link #undo()}. */ @@ -288,7 +288,7 @@ public class UndoManager * Determines which significant edit would be redone if {@link * #redo()} was called. * - * @returns the significant edit that would be redone, or + * @return the significant edit that would be redone, or * <code>null</code> if no significant edit would be affected by * calling {@link #redo()}. */ diff --git a/libjava/classpath/javax/swing/undo/UndoableEdit.java b/libjava/classpath/javax/swing/undo/UndoableEdit.java index 982d7f2a729..9938af751c7 100644 --- a/libjava/classpath/javax/swing/undo/UndoableEdit.java +++ b/libjava/classpath/javax/swing/undo/UndoableEdit.java @@ -1,5 +1,5 @@ -/* AbstractTableModel.java -- - Copyright (C) 2002 Free Software Foundation, Inc. +/* UndoableEdit.java -- + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,77 +38,120 @@ exception statement from your version. */ package javax.swing.undo; /** - * UndoableEdit public interface + * An editing operation that supports undo/redoability. + * * @author Andrew Selkirk */ -public interface UndoableEdit { - - /** - * anEdit - * @param anEdit TODO - * @returns TODO - */ - boolean addEdit(UndoableEdit anEdit); - - /** - * canRedo - * @returns TODO - */ - boolean canRedo(); - - /** - * canRedo - * @returns TODO - */ - boolean canUndo(); - - /** - * die - */ - void die(); - - /** - * getPresentationName - * @returns TODO - */ - String getPresentationName(); - - /** - * getRedoPresentationName - * @returns TODO - */ - String getRedoPresentationName(); - - /** - * getUndoPresentationName - * @returns TODO - */ - String getUndoPresentationName(); - - /** - * isSignificant - * @returns TODO - */ - boolean isSignificant(); - - /** - * redo - * @throws CannotRedoException TODO - */ - void redo() throws CannotRedoException; - - /** - * replaceEdit - * @param anEdit TODO - * @returns TODO - */ - boolean replaceEdit(UndoableEdit anEdit); - - /** - * undo - * @throws CannotUndoException TODO - */ - void undo() throws CannotUndoException; - - -} // UndoableEdit +public interface UndoableEdit +{ + + /** + * Incorporates another editing action into this one, thus forming a + * combined action. + * + * @param edit the editing action to be incorporated. + * + * @return <code>true</code> if the edit was combined successfully, and + * <code>false</code> if it could not be combined. + */ + boolean addEdit(UndoableEdit edit); + + /** + * Determines whether it would be possible to redo this editing + * action. + * + * @return <code>true</code> to indicate that this action can be + * redone, <code>false</code> otherwise. + * + * @see #redo() + * @see #canUndo() + */ + boolean canRedo(); + + /** + * Determines whether it would be possible to undo this editing + * action. + * + * @return <code>true</code> to indicate that this action can be + * undone, <code>false</code> otherwise. + * + * @see #undo() + * @see #canRedo() + */ + boolean canUndo(); + + /** + * Informs this edit action that it will no longer be used. Some + * actions might use this information to release resources, for + * example open files. Called by {@link UndoManager} before this + * action is removed from the edit queue. + */ + void die(); + + /** + * Returns a human-readable, localized name that describes this + * editing action and can be displayed to the user. + * + * @return The presentation name. + */ + String getPresentationName(); + + /** + * Returns the redo presentation name. + * + * @return The redo presentation name. + */ + String getRedoPresentationName(); + + /** + * Returns the undo presentation name. + * + * @return The undo presentation name. + */ + String getUndoPresentationName(); + + /** + * Determines whether this editing action is significant enough for + * being seperately undoable by the user. A typical significant + * action would be the resizing of an object. However, changing the + * selection in a text document would usually not be considered + * significant. + * + * @return <code>true</code> to indicate that the action is + * significant enough for being separately undoable, or + * <code>false</code> otherwise. + */ + boolean isSignificant(); + + /** + * Redoes this editing action. + * + * @throws CannotRedoException if the edit cannot be undone. + * + * @see #canRedo() + * @see #undo() + */ + void redo() throws CannotRedoException; + + /** + * Incorporates another editing action into this one, thus forming a + * combined action that replaces the argument action. + * + * @param edit the editing action to be replaced. + * + * @return <code>true</code> if the edit is successfully replaced, and + * <code>false</code> otherwise. + */ + boolean replaceEdit(UndoableEdit edit); + + /** + * Undoes this editing action. + * + * @throws CannotUndoException if the edit cannot be undone. + * + * @see #canUndo() + * @see #redo() + */ + void undo() throws CannotUndoException; + +} diff --git a/libjava/classpath/javax/swing/undo/UndoableEditSupport.java b/libjava/classpath/javax/swing/undo/UndoableEditSupport.java index 918e7352313..6d7bbea0728 100644 --- a/libjava/classpath/javax/swing/undo/UndoableEditSupport.java +++ b/libjava/classpath/javax/swing/undo/UndoableEditSupport.java @@ -1,5 +1,5 @@ /* UndoableEditSupport.java -- - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -238,7 +238,7 @@ public class UndoableEditSupport * on a specific {@link #compoundEdit}, it should override this * method. * - * @returns a newly created instance of {@link CompoundEdit}. + * @return a newly created instance of {@link CompoundEdit}. */ protected CompoundEdit createCompoundEdit() { diff --git a/libjava/classpath/javax/xml/XMLConstants.java b/libjava/classpath/javax/xml/XMLConstants.java index 735620755df..0d4a65ff981 100644 --- a/libjava/classpath/javax/xml/XMLConstants.java +++ b/libjava/classpath/javax/xml/XMLConstants.java @@ -1,5 +1,5 @@ /* XMLConstants.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. @@ -41,10 +41,15 @@ package javax.xml; * Repository for well-known XML constants. * * @author (a href='mailto:dog@gnu.org'>Chris Burdess</a) - * @since 1.3 + * @since 1.5 */ public final class XMLConstants { + + private XMLConstants() + { + // to prevent instantiation + } /** * Dummy namespace URI indicating that there is no namespace. diff --git a/libjava/classpath/javax/xml/datatype/DatatypeConstants.java b/libjava/classpath/javax/xml/datatype/DatatypeConstants.java index 3919d03daff..6098e084b7b 100644 --- a/libjava/classpath/javax/xml/datatype/DatatypeConstants.java +++ b/libjava/classpath/javax/xml/datatype/DatatypeConstants.java @@ -1,5 +1,5 @@ /* DatatypeConstants.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. @@ -43,11 +43,16 @@ import javax.xml.namespace.QName; * Basic data type constants. * * @author (a href='mailto:dog@gnu.org'>Chris Burdess</a) - * @since 1.3 + * @since 1.5 */ public final class DatatypeConstants { + private DatatypeConstants() + { + // to prevent instantiation + } + /** * Typesafe enumerated class representing the six fields of the * <a href='Duration.html'>Duration</a> class. diff --git a/libjava/classpath/javax/xml/datatype/DatatypeFactory.java b/libjava/classpath/javax/xml/datatype/DatatypeFactory.java index 98a5690e873..14f507416ab 100644 --- a/libjava/classpath/javax/xml/datatype/DatatypeFactory.java +++ b/libjava/classpath/javax/xml/datatype/DatatypeFactory.java @@ -1,5 +1,5 @@ /* DatatypeFactory.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. @@ -37,16 +37,24 @@ exception statement from your version. */ package javax.xml.datatype; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; import java.math.BigDecimal; import java.math.BigInteger; import java.util.GregorianCalendar; +import java.util.Iterator; +import java.util.Properties; +import gnu.classpath.ServiceFactory; /** * Factory class to create new datatype objects mapping XML to and from Java * objects. * - * @author (a href='mailto:dog@gnu.org'>Chris Burdess</a) - * @since 1.3 + * @author Chris Burdess + * @since 1.5 */ public abstract class DatatypeFactory { @@ -59,7 +67,7 @@ public abstract class DatatypeFactory /** * JAXP 1.3 default implementation class name. */ - public static final java.lang.String DATATYPEFACTORY_IMPLEMENTATION_CLASS = "gnu.xml.datatype.JAXPDatatypeFactory"; + public static final String DATATYPEFACTORY_IMPLEMENTATION_CLASS = "gnu.xml.datatype.JAXPDatatypeFactory"; protected DatatypeFactory() { @@ -73,12 +81,35 @@ public abstract class DatatypeFactory { try { + // 1. system property + String className = System.getProperty(DATATYPEFACTORY_PROPERTY); + if (className != null) + return (DatatypeFactory) Class.forName(className).newInstance(); + // 2. jaxp.properties property + File javaHome = new File(System.getProperty("java.home")); + File javaHomeLib = new File(javaHome, "lib"); + File jaxpProperties = new File(javaHomeLib, "jaxp.properties"); + if (jaxpProperties.exists()) + { + FileInputStream in = new FileInputStream(jaxpProperties); + Properties p = new Properties(); + p.load(in); + in.close(); + className = p.getProperty(DATATYPEFACTORY_PROPERTY); + if (className != null) + return (DatatypeFactory) Class.forName(className).newInstance(); + } + // 3. services + Iterator i = ServiceFactory.lookupProviders(DatatypeFactory.class); + if (i.hasNext()) + return (DatatypeFactory) i.next(); + // 4. fallback Class t = Class.forName(DATATYPEFACTORY_IMPLEMENTATION_CLASS); return (DatatypeFactory) t.newInstance(); } catch (Exception e) { - throw new DatatypeConfigurationException (e); + throw new DatatypeConfigurationException(e); } } @@ -172,7 +203,7 @@ public abstract class DatatypeFactory BigInteger days, BigInteger hours, BigInteger minutes, - BigDecimal seconds) + BigInteger seconds) { return newDuration(isPositive, null, @@ -180,7 +211,7 @@ public abstract class DatatypeFactory days, hours, minutes, - seconds); + new BigDecimal(seconds)); } /** diff --git a/libjava/classpath/javax/xml/datatype/Duration.java b/libjava/classpath/javax/xml/datatype/Duration.java index fb1d65537cc..96390fde467 100644 --- a/libjava/classpath/javax/xml/datatype/Duration.java +++ b/libjava/classpath/javax/xml/datatype/Duration.java @@ -1,5 +1,5 @@ /* Duration.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. @@ -48,7 +48,7 @@ import javax.xml.namespace.QName; * An immutable time space as specified in XML Schema 1.0. * * @author (a href='mailto:dog@gnu.org'>Chris Burdess</a) - * @since 1.3 + * @since 1.5 */ public abstract class Duration { @@ -240,11 +240,7 @@ public abstract class Duration /** * Returns the result of multiplying this duration by the given factor. */ - public Duration multiply(BigDecimal factor) - { - // TODO - throw new UnsupportedOperationException(); - } + public abstract Duration multiply(BigDecimal factor); /** * Returns the unary negative of this duration. diff --git a/libjava/classpath/javax/xml/validation/SchemaFactory.java b/libjava/classpath/javax/xml/validation/SchemaFactory.java index f33c1c6297e..0042ea32348 100644 --- a/libjava/classpath/javax/xml/validation/SchemaFactory.java +++ b/libjava/classpath/javax/xml/validation/SchemaFactory.java @@ -1,5 +1,5 @@ /* SchemaFactory.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. @@ -52,13 +52,10 @@ import org.xml.sax.SAXNotSupportedException; * Factory for obtaining schemata. * * @author Chris Burdess (dog@gnu.org) - * @since 1.3 + * @since 1.5 */ public abstract class SchemaFactory { - - ErrorHandler errorHandler; - protected SchemaFactory() { } @@ -109,15 +106,9 @@ public abstract class SchemaFactory throw new SAXNotRecognizedException(name); } - public ErrorHandler getErrorHandler() - { - return errorHandler; - } + public abstract ErrorHandler getErrorHandler(); - public void setErrorHandler(ErrorHandler errorHandler) - { - this.errorHandler = errorHandler; - } + public abstract void setErrorHandler(ErrorHandler errorHandler); public abstract LSResourceResolver getResourceResolver(); diff --git a/libjava/classpath/javax/xml/validation/SchemaFactoryLoader.java b/libjava/classpath/javax/xml/validation/SchemaFactoryLoader.java new file mode 100644 index 00000000000..dc80a33ccab --- /dev/null +++ b/libjava/classpath/javax/xml/validation/SchemaFactoryLoader.java @@ -0,0 +1,52 @@ +/* SchemaFactory.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.xml.validation; + +/** + * API compatibility class. Do not use. + */ +public abstract class SchemaFactoryLoader +{ + + protected SchemaFactoryLoader() + { + } + + public abstract SchemaFactory newFactory(String schemaLanguage); + +} diff --git a/libjava/classpath/javax/xml/xpath/XPathConstants.java b/libjava/classpath/javax/xml/xpath/XPathConstants.java index 3b2d5d2d992..fbfb9998118 100644 --- a/libjava/classpath/javax/xml/xpath/XPathConstants.java +++ b/libjava/classpath/javax/xml/xpath/XPathConstants.java @@ -1,5 +1,5 @@ /* XPathConstants.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. @@ -43,10 +43,14 @@ import javax.xml.namespace.QName; * XPath constants. * * @author (a href='mailto:dog@gnu.org'>Chris Burdess</a) - * @since 1.3 + * @since 1.5 */ public class XPathConstants { + private XPathConstants() + { + // to prevent instantiation + } /** * The XPath 1.0 number data type. |