diff options
author | mark <mark@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-03-10 21:46:48 +0000 |
---|---|---|
committer | mark <mark@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-03-10 21:46:48 +0000 |
commit | ce57ab760f69de6db452def7ffbf5b114a2d8694 (patch) | |
tree | ea38c56431c5d4528fb54254c3f8e50f517bede3 /libjava/classpath/javax | |
parent | 50996fe55769882de3f410896032c887f0ff0d04 (diff) | |
download | gcc-ce57ab760f69de6db452def7ffbf5b114a2d8694.tar.gz |
Imported GNU Classpath 0.90
* scripts/makemake.tcl: Set gnu/java/awt/peer/swing to ignore.
* gnu/classpath/jdwp/VMFrame.java (SIZE): New constant.
* java/lang/VMCompiler.java: Use gnu.java.security.hash.MD5.
* java/lang/Math.java: New override file.
* java/lang/Character.java: Merged from Classpath.
(start, end): Now 'int's.
(canonicalName): New field.
(CANONICAL_NAME, NO_SPACES_NAME, CONSTANT_NAME): New constants.
(UnicodeBlock): Added argument.
(of): New overload.
(forName): New method.
Updated unicode blocks.
(sets): Updated.
* sources.am: Regenerated.
* Makefile.in: Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111942 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/classpath/javax')
249 files changed, 17096 insertions, 6100 deletions
diff --git a/libjava/classpath/javax/crypto/EncryptedPrivateKeyInfo.java b/libjava/classpath/javax/crypto/EncryptedPrivateKeyInfo.java index a52d7b15d23..0fddd54bb44 100644 --- a/libjava/classpath/javax/crypto/EncryptedPrivateKeyInfo.java +++ b/libjava/classpath/javax/crypto/EncryptedPrivateKeyInfo.java @@ -92,6 +92,9 @@ public class EncryptedPrivateKeyInfo /** The OID of the encryption algorithm. */ private OID algOid; + /** The encryption algorithm name. */ + private String algName; + /** The encryption algorithm's parameters. */ private AlgorithmParameters params; @@ -125,7 +128,8 @@ public class EncryptedPrivateKeyInfo throw new IllegalArgumentException("0-length encryptedData"); } this.params = params; - algOid = new OID(params.getAlgorithm()); + algName = params.getAlgorithm (); + algOid = getOid (algName); this.encryptedData = (byte[]) encryptedData.clone(); } @@ -168,10 +172,36 @@ public class EncryptedPrivateKeyInfo { throw new IllegalArgumentException("0-length encryptedData"); } - this.algOid = new OID(algName); + this.algName = algName.toString (); // do NP check + this.algOid = getOid (algName); this.encryptedData = (byte[]) encryptedData.clone(); } + /** + * Return the OID for the given cipher name. + * + * @param str The string. + * @throws NoSuchAlgorithmException If the OID is not known. + */ + private static OID getOid (final String str) + throws NoSuchAlgorithmException + { + if (str.equalsIgnoreCase ("DSA")) + { + return new OID ("1.2.840.10040.4.3"); + } + // FIXME add more + + try + { + return new OID (str); + } + catch (Throwable t) + { + } + throw new NoSuchAlgorithmException ("cannot determine OID for '" + str + "'"); + } + // Instance methods. // ------------------------------------------------------------------------ @@ -196,6 +226,7 @@ public class EncryptedPrivateKeyInfo } catch (NoSuchAlgorithmException ignore) { + // FIXME throw exception? } catch (IOException ignore) { @@ -272,7 +303,11 @@ public class EncryptedPrivateKeyInfo getAlgParameters(); if (params != null) { - algId.add(DERReader.read(params.getEncoded())); + algId.add (DERReader.read (params.getEncoded())); + } + else + { + algId.add (new DERValue (DER.NULL, null)); } List epki = new ArrayList(2); epki.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, algId)); diff --git a/libjava/classpath/javax/imageio/ImageWriteParam.java b/libjava/classpath/javax/imageio/ImageWriteParam.java index 84b257e04eb..1979957fef1 100644 --- a/libjava/classpath/javax/imageio/ImageWriteParam.java +++ b/libjava/classpath/javax/imageio/ImageWriteParam.java @@ -46,27 +46,121 @@ import java.util.Locale; */ public class ImageWriteParam extends IIOParam { + + /** + * Can be passed to setTilingMode, setProgressiveMode and + * setCompressionMode to disable feature. + */ public static final int MODE_DISABLED = 0; + + /** + * Can be passed to setTilingMode, setProgressiveMode and + * setCompressionMode to enable feature. + */ public static final int MODE_DEFAULT = 1; + + /** + * Can be passed to setTilingMode, setCompressionMode to disable feature. + */ public static final int MODE_EXPLICIT = 2; + + /** + * Can be passed to setTilingMode, setProgressiveMode and + * setCompressionMode to enable feature. + */ public static final int MODE_COPY_FROM_METADATA = 3; + /** + * True if tiling grid offset parameters can be set. + */ protected boolean canOffsetTiles; + + /** + * True if this writer can write images using compression. + */ protected boolean canWriteCompressed; + + /** + * True if images can be written as a progressive sequence + * of increasing quality. + */ protected boolean canWriteProgressive; + + /** + * True if tile width and height parameters can be set. + */ protected boolean canWriteTiles; + + /** + * Controls compression settings, which must be set to one of the four + * MODE_* values. + */ protected int compressionMode = MODE_COPY_FROM_METADATA; + + /** + * Contains the current compression quality setting. + */ protected float compressionQuality; + + /** + * Contains the name of the available compression types. + */ protected String compressionType; + + /** + * Array of the names of the available compression types. + */ protected String[] compressionTypes; + + /** + * Localizes compression type names and quality descriptions, + * or null to use default Locale. + */ protected Locale locale; + + /** + * Preferred tile size range pairs. + */ protected Dimension[] preferredTileSizes; + + /** + * The mode controlling progressive encoding, which must + * be set to one of the four MODE_* values, except + * MODE_EXPLICIT. + */ protected int progressiveMode = MODE_COPY_FROM_METADATA; + + /** + * The amount by which the tile grid origin should be offset + * horizontally from the image origin if tiling has been set. + */ protected int tileGridXOffset; + + /** + * The amount by which the tile grid origin should be offset + * vertically from the image origin if tiling has been set. + */ protected int tileGridYOffset; + + /** + * The height of each tile if tiling has been set. + */ protected int tileHeight; + + /** + * The width of each tile if tiling has been set. + */ protected int tileWidth; + + /** + * The mode controlling tiling settings, which must be + * set to one of the four MODE_* values. + */ protected int tilingMode; + + /** + * True if the tiling parameters have been specified. + */ protected boolean tilingSet; /** diff --git a/libjava/classpath/javax/imageio/plugins/bmp/BMPImageWriteParam.java b/libjava/classpath/javax/imageio/plugins/bmp/BMPImageWriteParam.java new file mode 100644 index 00000000000..de59efba4ea --- /dev/null +++ b/libjava/classpath/javax/imageio/plugins/bmp/BMPImageWriteParam.java @@ -0,0 +1,144 @@ +/* BMPImageWriteParam.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.bmp; + +import java.util.Locale; + +import javax.imageio.ImageWriteParam; + +/** + * A class to encode images in the BMP format. + * By default, the data layout is bottom-up, such that the pixels are stored in + * bottom-up order. + * + * The compression scheme can be specified by using setCompressionType() + * appropriate type string. The compression scheme specified will be honored + * if it is compatible with the type of image being written. If the + * compression scheme is not compatible with the type of image being written, + * then an IOException will be thrown by the BMP image writer. If the + * compression type is not set, then getCompressionType() will return null. + * In this case the BMP image writer will select a compression type that + * supports encoding of the given image without loss of the color resolution. + * + * The compression type strings and the image type each supports are: + * Uncompressed RLE: BI_RGB, image type: <= 8-bits/sample. + * 8-bit Run Length Encoding: BI_RLE8, image type: <= 8-bits/sample + * 4-bit Run Length Encoding: BI_RLE4, image type: <= 4-bits/sample + * Packed data: BI_BITFIELDS, image type: 16 or 32 bits/sample + * + * @author Lillian Angel (langel at redhat dot com) + */ +public class BMPImageWriteParam + extends ImageWriteParam +{ + + /** + * This boolean is true if the data will be written in a topdown manner. + */ + private boolean topDown; + + /** + * Compression type strings. + */ + String rgb = "BI_RGB"; + String rle8 = "BI_RLE8"; + String rle4 = "BI_RLE4"; + String bitfields = "BI_BITFIELDS"; + + /** + * Constants to represent image types. + */ + static final int BI_RGB = 0; + static final int BI_RLE8 = 1; + static final int BI_RLE4 = 2; + static final int BI_BITFIELDS = 3; + + /** + * Constructs an <code>BMPImageWriteParam</code> object with default values + * and a <code>null Locale</code>. + */ + public BMPImageWriteParam() + { + this(null); + } + + /** + * Constructs a <code>BMPImageWriteParam</code> set to use a given + * <code>Locale</code> and with default values for all parameters. + * + * @param locale - a <code>Locale</code> to be used to localize compression + * type names and quality descriptions, or <code>null</code>. + */ + public BMPImageWriteParam(Locale locale) + { + super(locale); + topDown = false; + canWriteCompressed = true; + + compressionTypes = new String[4]; + compressionTypes[BI_RGB] = rgb; + compressionTypes[BI_RLE8] = rle8; + compressionTypes[BI_RLE4] = rle4; + compressionTypes[BI_BITFIELDS] = bitfields; + + compressionType = compressionTypes[BI_RGB]; + } + + /** + * If set, the data will be written out in a top-down manner, the first + * scanline being written first. + * + * @param topDown - whether the data are written in top-down order. + */ + public void setTopDown(boolean topDown) + { + this.topDown = topDown; + } + + /** + * Returns the value of the <code>topDown</code> parameter. The default is + * false. + * + * @return whether the data are written in top-down order. + */ + public boolean isTopDown() + { + return topDown; + } +} diff --git a/libjava/classpath/javax/naming/AuthenticationException.java b/libjava/classpath/javax/naming/AuthenticationException.java index f332561e49b..1a6ade93055 100644 --- a/libjava/classpath/javax/naming/AuthenticationException.java +++ b/libjava/classpath/javax/naming/AuthenticationException.java @@ -1,5 +1,5 @@ /* AuthenticationException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class AuthenticationException extends NamingSecurityException { + private static final long serialVersionUID = 3678497619904568096L; + public AuthenticationException () { super (); diff --git a/libjava/classpath/javax/naming/AuthenticationNotSupportedException.java b/libjava/classpath/javax/naming/AuthenticationNotSupportedException.java index 52b133a5cf5..a1e811b44dc 100644 --- a/libjava/classpath/javax/naming/AuthenticationNotSupportedException.java +++ b/libjava/classpath/javax/naming/AuthenticationNotSupportedException.java @@ -1,5 +1,5 @@ /* AuthenticationNotSupportedException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,8 @@ package javax.naming; public class AuthenticationNotSupportedException extends NamingSecurityException { + private static final long serialVersionUID = - 7149033933259492300L; + public AuthenticationNotSupportedException () { super (); diff --git a/libjava/classpath/javax/naming/Binding.java b/libjava/classpath/javax/naming/Binding.java index 91c0d95f7d5..9d6608ababe 100644 --- a/libjava/classpath/javax/naming/Binding.java +++ b/libjava/classpath/javax/naming/Binding.java @@ -1,5 +1,5 @@ /* Binding.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. @@ -44,6 +44,8 @@ package javax.naming; */ public class Binding extends NameClassPair { + private static final long serialVersionUID = 8839217842691845890L; + public Binding (String name, Object obj) { super (name, null); diff --git a/libjava/classpath/javax/naming/CannotProceedException.java b/libjava/classpath/javax/naming/CannotProceedException.java index 3a69cd3819c..27868e21ea2 100644 --- a/libjava/classpath/javax/naming/CannotProceedException.java +++ b/libjava/classpath/javax/naming/CannotProceedException.java @@ -1,5 +1,5 @@ /* CannotProceedException.java -- - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -47,6 +47,8 @@ import java.util.Hashtable; public class CannotProceedException extends NamingException { + private static final long serialVersionUID = 1219724816191576813L; + // Serialized fields. protected Name remainingNewName; protected Hashtable environment; diff --git a/libjava/classpath/javax/naming/CommunicationException.java b/libjava/classpath/javax/naming/CommunicationException.java index c780387cf05..7b11b5fac81 100644 --- a/libjava/classpath/javax/naming/CommunicationException.java +++ b/libjava/classpath/javax/naming/CommunicationException.java @@ -1,5 +1,5 @@ /* CommunicationException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class CommunicationException extends NamingException { + private static final long serialVersionUID = 3618507780299986611L; + public CommunicationException () { super (); diff --git a/libjava/classpath/javax/naming/ConfigurationException.java b/libjava/classpath/javax/naming/ConfigurationException.java index 196654865b8..1f4002aa465 100644 --- a/libjava/classpath/javax/naming/ConfigurationException.java +++ b/libjava/classpath/javax/naming/ConfigurationException.java @@ -1,5 +1,5 @@ /* ConfigurationException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class ConfigurationException extends NamingException { + private static final long serialVersionUID = - 2535156726228855704L; + public ConfigurationException () { super (); diff --git a/libjava/classpath/javax/naming/ContextNotEmptyException.java b/libjava/classpath/javax/naming/ContextNotEmptyException.java index c6fe5e81c39..acbd46bffc4 100644 --- a/libjava/classpath/javax/naming/ContextNotEmptyException.java +++ b/libjava/classpath/javax/naming/ContextNotEmptyException.java @@ -1,5 +1,5 @@ /* ContextNotEmptyException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class ContextNotEmptyException extends NamingException { + private static final long serialVersionUID = 1090963683348219877L; + public ContextNotEmptyException () { super (); diff --git a/libjava/classpath/javax/naming/InsufficientResourcesException.java b/libjava/classpath/javax/naming/InsufficientResourcesException.java index bcb9fe577f8..7a9ebe0370c 100644 --- a/libjava/classpath/javax/naming/InsufficientResourcesException.java +++ b/libjava/classpath/javax/naming/InsufficientResourcesException.java @@ -1,5 +1,5 @@ /* InsufficientResourcesException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class InsufficientResourcesException extends NamingException { + private static final long serialVersionUID = 6227672693037844532L; + public InsufficientResourcesException () { super (); diff --git a/libjava/classpath/javax/naming/InterruptedNamingException.java b/libjava/classpath/javax/naming/InterruptedNamingException.java index 8cdf30d4e4c..90d6e5ec052 100644 --- a/libjava/classpath/javax/naming/InterruptedNamingException.java +++ b/libjava/classpath/javax/naming/InterruptedNamingException.java @@ -1,5 +1,5 @@ /* InterruptedNamingException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class InterruptedNamingException extends NamingException { + private static final long serialVersionUID = 6404516648893194728L; + public InterruptedNamingException () { super (); diff --git a/libjava/classpath/javax/naming/InvalidNameException.java b/libjava/classpath/javax/naming/InvalidNameException.java index a3b99e1f69f..286f0455dba 100644 --- a/libjava/classpath/javax/naming/InvalidNameException.java +++ b/libjava/classpath/javax/naming/InvalidNameException.java @@ -1,5 +1,5 @@ /* InvalidNameException.java -- Exception indicating an invalid component/name - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -47,6 +47,8 @@ package javax.naming; */ public class InvalidNameException extends NamingException { + private static final long serialVersionUID = - 8370672380823801105L; + /** * Creates a new exception without setting any of its fields. */ diff --git a/libjava/classpath/javax/naming/LimitExceededException.java b/libjava/classpath/javax/naming/LimitExceededException.java index 7e7af81c76b..8c005ac2c5d 100644 --- a/libjava/classpath/javax/naming/LimitExceededException.java +++ b/libjava/classpath/javax/naming/LimitExceededException.java @@ -1,5 +1,5 @@ /* LimitExceededException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class LimitExceededException extends NamingException { + private static final long serialVersionUID = - 776898738660207856L; + public LimitExceededException () { super (); diff --git a/libjava/classpath/javax/naming/LinkException.java b/libjava/classpath/javax/naming/LinkException.java index 2c3c507113c..8f5df8b03bf 100644 --- a/libjava/classpath/javax/naming/LinkException.java +++ b/libjava/classpath/javax/naming/LinkException.java @@ -1,5 +1,5 @@ /* LinkException.java -- - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -46,6 +46,8 @@ package javax.naming; public class LinkException extends NamingException { + private static final long serialVersionUID = - 7967662604076777712L; + // Serialized fields. protected Name linkResolvedName; protected Object linkResolvedObj; diff --git a/libjava/classpath/javax/naming/LinkLoopException.java b/libjava/classpath/javax/naming/LinkLoopException.java index 9c00dbeb622..0c68e01bff3 100644 --- a/libjava/classpath/javax/naming/LinkLoopException.java +++ b/libjava/classpath/javax/naming/LinkLoopException.java @@ -1,5 +1,5 @@ /* LinkLoopException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class LinkLoopException extends LinkException { + private static final long serialVersionUID = - 3119189944325198009L; + public LinkLoopException () { super (); diff --git a/libjava/classpath/javax/naming/MalformedLinkException.java b/libjava/classpath/javax/naming/MalformedLinkException.java index 5422b90946f..db0753ded6c 100644 --- a/libjava/classpath/javax/naming/MalformedLinkException.java +++ b/libjava/classpath/javax/naming/MalformedLinkException.java @@ -1,5 +1,5 @@ /* MalformedLinkException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class MalformedLinkException extends LinkException { + private static final long serialVersionUID = - 3066740437737830242L; + public MalformedLinkException () { super (); diff --git a/libjava/classpath/javax/naming/NameAlreadyBoundException.java b/libjava/classpath/javax/naming/NameAlreadyBoundException.java index 4b2fb0e74f9..5ddd7d8ba88 100644 --- a/libjava/classpath/javax/naming/NameAlreadyBoundException.java +++ b/libjava/classpath/javax/naming/NameAlreadyBoundException.java @@ -1,5 +1,5 @@ /* NameAlreadyBoundException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class NameAlreadyBoundException extends NamingException { + private static final long serialVersionUID = - 8491441000356780586L; + public NameAlreadyBoundException () { super (); diff --git a/libjava/classpath/javax/naming/NameClassPair.java b/libjava/classpath/javax/naming/NameClassPair.java index 4e260513171..127730af4ef 100644 --- a/libjava/classpath/javax/naming/NameClassPair.java +++ b/libjava/classpath/javax/naming/NameClassPair.java @@ -1,5 +1,5 @@ /* NameClassPair.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. @@ -46,6 +46,8 @@ import java.io.Serializable; */ public class NameClassPair implements Serializable { + private static final long serialVersionUID = 5620776610160863339L; + public NameClassPair (String name, String className) { this (name, className, true); diff --git a/libjava/classpath/javax/naming/NameNotFoundException.java b/libjava/classpath/javax/naming/NameNotFoundException.java index b533b041261..b7c24a62927 100644 --- a/libjava/classpath/javax/naming/NameNotFoundException.java +++ b/libjava/classpath/javax/naming/NameNotFoundException.java @@ -1,5 +1,5 @@ /* NameNotFoundException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class NameNotFoundException extends NamingException { + private static final long serialVersionUID = - 8007156725367842053L; + public NameNotFoundException () { super (); diff --git a/libjava/classpath/javax/naming/NamingException.java b/libjava/classpath/javax/naming/NamingException.java index ad3923326db..dbe1e3792a7 100644 --- a/libjava/classpath/javax/naming/NamingException.java +++ b/libjava/classpath/javax/naming/NamingException.java @@ -223,7 +223,7 @@ public class NamingException extends Exception /** * Gets the message given to the constructor or null if no message was given. * - * @see Throwable#getMessage(); + * @see Throwable#getMessage() */ public String getExplanation() { diff --git a/libjava/classpath/javax/naming/NoInitialContextException.java b/libjava/classpath/javax/naming/NoInitialContextException.java index d12dfcb7b27..5e4f6df0e16 100644 --- a/libjava/classpath/javax/naming/NoInitialContextException.java +++ b/libjava/classpath/javax/naming/NoInitialContextException.java @@ -1,5 +1,5 @@ /* NoInitialContextException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class NoInitialContextException extends NamingException { + private static final long serialVersionUID = - 3413733186901258623L; + public NoInitialContextException() { super(); diff --git a/libjava/classpath/javax/naming/NoPermissionException.java b/libjava/classpath/javax/naming/NoPermissionException.java index ddc43937ce8..02764a991f2 100644 --- a/libjava/classpath/javax/naming/NoPermissionException.java +++ b/libjava/classpath/javax/naming/NoPermissionException.java @@ -1,5 +1,5 @@ /* NoPermissionException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class NoPermissionException extends NamingSecurityException { + private static final long serialVersionUID = 8395332708699751775L; + public NoPermissionException () { super (); diff --git a/libjava/classpath/javax/naming/NotContextException.java b/libjava/classpath/javax/naming/NotContextException.java index b3d02cfbb4e..a27f10f182d 100644 --- a/libjava/classpath/javax/naming/NotContextException.java +++ b/libjava/classpath/javax/naming/NotContextException.java @@ -1,5 +1,5 @@ /* NotContextException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class NotContextException extends NamingException { + private static final long serialVersionUID = 849752551644540417L; + public NotContextException () { super (); diff --git a/libjava/classpath/javax/naming/OperationNotSupportedException.java b/libjava/classpath/javax/naming/OperationNotSupportedException.java index a4a4945af55..d813403ded5 100644 --- a/libjava/classpath/javax/naming/OperationNotSupportedException.java +++ b/libjava/classpath/javax/naming/OperationNotSupportedException.java @@ -1,5 +1,5 @@ /* OperationNotSupportedException.java -- - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,6 +40,8 @@ package javax.naming; public class OperationNotSupportedException extends NamingException { + private static final long serialVersionUID = 5493232822427682064L; + public OperationNotSupportedException() { super(); diff --git a/libjava/classpath/javax/naming/PartialResultException.java b/libjava/classpath/javax/naming/PartialResultException.java index 32f389d1335..61660781f68 100644 --- a/libjava/classpath/javax/naming/PartialResultException.java +++ b/libjava/classpath/javax/naming/PartialResultException.java @@ -1,5 +1,5 @@ /* PartialResultException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class PartialResultException extends NamingException { + private static final long serialVersionUID = 2572144970049426786L; + public PartialResultException () { super (); diff --git a/libjava/classpath/javax/naming/Reference.java b/libjava/classpath/javax/naming/Reference.java index 6cc4d15708b..5b9883aecd4 100644 --- a/libjava/classpath/javax/naming/Reference.java +++ b/libjava/classpath/javax/naming/Reference.java @@ -1,5 +1,5 @@ /* Reference.java -- - Copyright (C) 2000, 2001, 2005 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -48,6 +48,8 @@ import java.util.Vector; */ public class Reference implements Cloneable, Serializable { + private static final long serialVersionUID = - 1673475790065791735L; + public Reference (String className) { this.className = className; diff --git a/libjava/classpath/javax/naming/ServiceUnavailableException.java b/libjava/classpath/javax/naming/ServiceUnavailableException.java index 678eb132866..ddb154f9e77 100644 --- a/libjava/classpath/javax/naming/ServiceUnavailableException.java +++ b/libjava/classpath/javax/naming/ServiceUnavailableException.java @@ -1,5 +1,5 @@ /* ServiceUnavailableException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class ServiceUnavailableException extends NamingException { + private static final long serialVersionUID = - 4996964726566773444L; + public ServiceUnavailableException () { super (); diff --git a/libjava/classpath/javax/naming/SizeLimitExceededException.java b/libjava/classpath/javax/naming/SizeLimitExceededException.java index e23f4d2da09..3ca9a23b7b1 100644 --- a/libjava/classpath/javax/naming/SizeLimitExceededException.java +++ b/libjava/classpath/javax/naming/SizeLimitExceededException.java @@ -1,5 +1,5 @@ /* SizeLimitExceededException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class SizeLimitExceededException extends LimitExceededException { + private static final long serialVersionUID = 7129289564879168579L; + public SizeLimitExceededException () { super (); diff --git a/libjava/classpath/javax/naming/TimeLimitExceededException.java b/libjava/classpath/javax/naming/TimeLimitExceededException.java index f4be6759b49..e3456f5bbe8 100644 --- a/libjava/classpath/javax/naming/TimeLimitExceededException.java +++ b/libjava/classpath/javax/naming/TimeLimitExceededException.java @@ -1,5 +1,5 @@ /* TimeLimitExceededException.java -- - Copyright (C) 2000, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,8 @@ package javax.naming; public class TimeLimitExceededException extends LimitExceededException { + private static final long serialVersionUID = - 3597009011385034696L; + public TimeLimitExceededException () { super (); diff --git a/libjava/classpath/javax/naming/directory/AttributeInUseException.java b/libjava/classpath/javax/naming/directory/AttributeInUseException.java index 46614245282..9be25c9a967 100644 --- a/libjava/classpath/javax/naming/directory/AttributeInUseException.java +++ b/libjava/classpath/javax/naming/directory/AttributeInUseException.java @@ -1,5 +1,5 @@ /* AttributeInUseException.java -- - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,8 @@ import javax.naming.NamingException; public class AttributeInUseException extends NamingException { + private static final long serialVersionUID = 4437710305529322564L; + public AttributeInUseException () { super (); diff --git a/libjava/classpath/javax/naming/directory/AttributeModificationException.java b/libjava/classpath/javax/naming/directory/AttributeModificationException.java index 4ef6fc20b66..9614bac1333 100644 --- a/libjava/classpath/javax/naming/directory/AttributeModificationException.java +++ b/libjava/classpath/javax/naming/directory/AttributeModificationException.java @@ -1,5 +1,5 @@ /* AttributeModificationException.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. @@ -47,6 +47,7 @@ import javax.naming.NamingException; public class AttributeModificationException extends NamingException { + private static final long serialVersionUID = 8060676069678710186L; // Serialized fields. private ModificationItem[] unexecs; diff --git a/libjava/classpath/javax/naming/directory/InvalidAttributeIdentifierException.java b/libjava/classpath/javax/naming/directory/InvalidAttributeIdentifierException.java index af1a8c7a27f..afd9a902b5a 100644 --- a/libjava/classpath/javax/naming/directory/InvalidAttributeIdentifierException.java +++ b/libjava/classpath/javax/naming/directory/InvalidAttributeIdentifierException.java @@ -1,5 +1,5 @@ /* InvalidAttributeIdentifierException.java -- - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,8 @@ import javax.naming.NamingException; public class InvalidAttributeIdentifierException extends NamingException { + private static final long serialVersionUID = - 9036920266322999923L; + public InvalidAttributeIdentifierException () { super (); diff --git a/libjava/classpath/javax/naming/directory/InvalidAttributeValueException.java b/libjava/classpath/javax/naming/directory/InvalidAttributeValueException.java index b667fa9a732..a18adbfa2fe 100644 --- a/libjava/classpath/javax/naming/directory/InvalidAttributeValueException.java +++ b/libjava/classpath/javax/naming/directory/InvalidAttributeValueException.java @@ -1,5 +1,5 @@ /* InvalidAttributeValueException.java -- - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,8 @@ import javax.naming.NamingException; public class InvalidAttributeValueException extends NamingException { + private static final long serialVersionUID = 8720050295499275011L; + public InvalidAttributeValueException () { super (); diff --git a/libjava/classpath/javax/naming/directory/InvalidAttributesException.java b/libjava/classpath/javax/naming/directory/InvalidAttributesException.java index ad7f7c1c111..ac540e2d0b0 100644 --- a/libjava/classpath/javax/naming/directory/InvalidAttributesException.java +++ b/libjava/classpath/javax/naming/directory/InvalidAttributesException.java @@ -1,5 +1,5 @@ /* InvalidAttributesException.java -- - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,8 @@ import javax.naming.NamingException; public class InvalidAttributesException extends NamingException { + private static final long serialVersionUID = 2607612850539889765L; + public InvalidAttributesException () { super (); diff --git a/libjava/classpath/javax/naming/directory/InvalidSearchControlsException.java b/libjava/classpath/javax/naming/directory/InvalidSearchControlsException.java index 594e5d1bfe5..9c716fa0f05 100644 --- a/libjava/classpath/javax/naming/directory/InvalidSearchControlsException.java +++ b/libjava/classpath/javax/naming/directory/InvalidSearchControlsException.java @@ -1,5 +1,5 @@ /* InvalidSearchControlsException.java -- - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,8 @@ import javax.naming.NamingException; public class InvalidSearchControlsException extends NamingException { + private static final long serialVersionUID = - 5124108943352665777L; + public InvalidSearchControlsException () { super (); diff --git a/libjava/classpath/javax/naming/directory/InvalidSearchFilterException.java b/libjava/classpath/javax/naming/directory/InvalidSearchFilterException.java index 127b381ea6d..21843cc01e1 100644 --- a/libjava/classpath/javax/naming/directory/InvalidSearchFilterException.java +++ b/libjava/classpath/javax/naming/directory/InvalidSearchFilterException.java @@ -1,5 +1,5 @@ /* InvalidSearchFilterException.java -- - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,8 @@ import javax.naming.NamingException; public class InvalidSearchFilterException extends NamingException { + private static final long serialVersionUID = 2902700940682875441L; + public InvalidSearchFilterException () { super (); diff --git a/libjava/classpath/javax/naming/directory/ModificationItem.java b/libjava/classpath/javax/naming/directory/ModificationItem.java index f0a69f56a8c..56a5ae60958 100644 --- a/libjava/classpath/javax/naming/directory/ModificationItem.java +++ b/libjava/classpath/javax/naming/directory/ModificationItem.java @@ -1,5 +1,5 @@ /* ModificationItem.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. @@ -47,6 +47,7 @@ import java.io.Serializable; public class ModificationItem implements Serializable { + private static final long serialVersionUID = 7573258562534746850L; // Serialized fields. private int mod_op; private Attribute attr; diff --git a/libjava/classpath/javax/naming/directory/NoSuchAttributeException.java b/libjava/classpath/javax/naming/directory/NoSuchAttributeException.java index cff9f95b7e5..8eb5e95704f 100644 --- a/libjava/classpath/javax/naming/directory/NoSuchAttributeException.java +++ b/libjava/classpath/javax/naming/directory/NoSuchAttributeException.java @@ -1,5 +1,5 @@ /* NoSuchAttributeException.java -- - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,8 @@ import javax.naming.NamingException; public class NoSuchAttributeException extends NamingException { + private static final long serialVersionUID = 4836415647935888137L; + public NoSuchAttributeException () { super (); diff --git a/libjava/classpath/javax/naming/directory/SchemaViolationException.java b/libjava/classpath/javax/naming/directory/SchemaViolationException.java index a11e50f2002..f60f32aad54 100644 --- a/libjava/classpath/javax/naming/directory/SchemaViolationException.java +++ b/libjava/classpath/javax/naming/directory/SchemaViolationException.java @@ -1,5 +1,5 @@ /* SchemaViolationException.java -- - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,8 @@ import javax.naming.NamingException; public class SchemaViolationException extends NamingException { + private static final long serialVersionUID = - 3041762429525049663L; + public SchemaViolationException () { super (); diff --git a/libjava/classpath/javax/naming/directory/SearchControls.java b/libjava/classpath/javax/naming/directory/SearchControls.java index 4cc789d52e1..5ba488bf78f 100644 --- a/libjava/classpath/javax/naming/directory/SearchControls.java +++ b/libjava/classpath/javax/naming/directory/SearchControls.java @@ -1,5 +1,5 @@ /* SearchControls.java -- - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -47,6 +47,7 @@ import java.io.Serializable; public class SearchControls implements Serializable { + private static final long serialVersionUID = - 2480540967773454797L; public static final int OBJECT_SCOPE = 0; public static final int ONELEVEL_SCOPE = 1; public static final int SUBTREE_SCOPE = 2; diff --git a/libjava/classpath/javax/naming/directory/SearchResult.java b/libjava/classpath/javax/naming/directory/SearchResult.java index a6d5490df99..ce6bfed6ed2 100644 --- a/libjava/classpath/javax/naming/directory/SearchResult.java +++ b/libjava/classpath/javax/naming/directory/SearchResult.java @@ -1,5 +1,5 @@ /* SearchResult.java -- - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -47,6 +47,7 @@ import javax.naming.Binding; public class SearchResult extends Binding { + private static final long serialVersionUID = - 9158063327699723172L; // Serialized fields. private Attributes attrs; diff --git a/libjava/classpath/javax/naming/event/NamingEvent.java b/libjava/classpath/javax/naming/event/NamingEvent.java index a121b8e13d3..1bf381a4467 100644 --- a/libjava/classpath/javax/naming/event/NamingEvent.java +++ b/libjava/classpath/javax/naming/event/NamingEvent.java @@ -1,5 +1,5 @@ /* NamingEvent.java -- - Copyright (C) 2001, 2004 Free Software Foundation, Inc. + Copyright (C) 2001, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -48,6 +48,8 @@ import javax.naming.Binding; */ public class NamingEvent extends EventObject { + private static final long serialVersionUID = - 7126752885365133499L; + public static final int OBJECT_ADDED = 0; public static final int OBJECT_REMOVED = 1; public static final int OBJECT_RENAMED = 2; diff --git a/libjava/classpath/javax/naming/event/NamingExceptionEvent.java b/libjava/classpath/javax/naming/event/NamingExceptionEvent.java index 07896d48d45..3a9de21f5d0 100644 --- a/libjava/classpath/javax/naming/event/NamingExceptionEvent.java +++ b/libjava/classpath/javax/naming/event/NamingExceptionEvent.java @@ -1,5 +1,5 @@ /* NamingExceptionEvent.java -- - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -49,6 +49,8 @@ import javax.naming.NamingException; public class NamingExceptionEvent extends EventObject { + private static final long serialVersionUID = - 4877678086134736336L; + // Serialized fields. private NamingException exception; diff --git a/libjava/classpath/javax/naming/spi/ResolveResult.java b/libjava/classpath/javax/naming/spi/ResolveResult.java index 72a101ec567..07e2df3c01c 100644 --- a/libjava/classpath/javax/naming/spi/ResolveResult.java +++ b/libjava/classpath/javax/naming/spi/ResolveResult.java @@ -1,5 +1,5 @@ /* ResolveResult.java -- - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -51,6 +51,8 @@ import javax.naming.Name; public class ResolveResult implements Serializable { + private static final long serialVersionUID = - 4552108072002407559L; + // Serialized fields. protected Object resolvedObj; protected Name remainingName; diff --git a/libjava/classpath/javax/net/ssl/SSLException.java b/libjava/classpath/javax/net/ssl/SSLException.java index 91d4cb78cbf..3213b0b458f 100644 --- a/libjava/classpath/javax/net/ssl/SSLException.java +++ b/libjava/classpath/javax/net/ssl/SSLException.java @@ -1,5 +1,5 @@ /* SSLException.java -- generic SSL exception. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,15 +45,47 @@ import java.io.IOException; * exception is thrown instead of this exception. * * @author Casey Marshall (rsdio@metastatic.org) + * + * @since 1.4 */ public class SSLException extends IOException { + private static final long serialVersionUID = 4511006460650708967L; // Constructor. // ------------------------------------------------------------------ + /** + * Create a new instance with a descriptive error message. + * + * @param message the descriptive error message + */ public SSLException(String message) { super(message); } + + /** + * Create a new instance with a descriptive error message and + * a cause. + * @param message the descriptive error message + * @param cause the cause + * @since 1.5 + */ + public SSLException(String message, Throwable cause) + { + super(message); + initCause(cause); + } + + /** + * Create a new instance with a cause. + * @param cause the cause + * @since 1.5 + */ + public SSLException(Throwable cause) + { + super(cause == null ? null : cause.toString()); + initCause(cause); + } } diff --git a/libjava/classpath/javax/print/CancelablePrintJob.java b/libjava/classpath/javax/print/CancelablePrintJob.java index 94e9475e587..39a25440e5e 100644 --- a/libjava/classpath/javax/print/CancelablePrintJob.java +++ b/libjava/classpath/javax/print/CancelablePrintJob.java @@ -1,5 +1,5 @@ /* CancelablePrintJob.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,14 +39,29 @@ exception statement from your version. */ package javax.print; /** + * <code>CancelablePrintJob</code> represents a print job which can be + * canceled. + * <p> + * It is implemented by <code>DocPrintJob</code>s which support to cancel + * a print job during processing. Clients need to explicitly test if a given + * <code>DocPrintJob</code> object from a print service implementes this + * interface and therefore supports cancelling. + * </p><p> + * Implementor of java print services should implement this interface if + * cancelling is supported by the underlying print system. If implemented the + * corresponding print job event + * {@link javax.print.event.PrintJobEvent#JOB_CANCELED} should be delivered to + * registered clients. Implementations have to be thread-safe. + * </p> + * * @author Michael Koch (konqueror@gmx.de) */ public interface CancelablePrintJob extends DocPrintJob { /** - * Cancel print job. + * Cancel the print job. * - * @exception PrintException if an error occured + * @exception PrintException if an error during cancellation occurs. */ void cancel() throws PrintException; } diff --git a/libjava/classpath/javax/print/Doc.java b/libjava/classpath/javax/print/Doc.java index 00e9dc9867f..c489de1b64e 100644 --- a/libjava/classpath/javax/print/Doc.java +++ b/libjava/classpath/javax/print/Doc.java @@ -1,5 +1,5 @@ /* Doc.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,51 +45,102 @@ import java.io.Reader; import javax.print.attribute.DocAttributeSet; /** + * <code>Doc</code> specifies the interface for print services how to obtain + * the print data and document specific attributes for printing. + * <p> + * The print data is always passed to a {@link javax.print.DocPrintJob} object + * as a <code>Doc</code> object which allows the print services to: + * <ul> + * <li>Determine the actual document format of the supplied print data. This + * is supplied as a {@link javax.print.DocFlavor} object with the MIME type + * and the representation class of the print data.</li> + * <li>Obtain the print data either in its representation class or depending + * on the document format through convenience methods as a + * {@link java.io.Reader} or an {@link java.io.InputStream}.</li> + * <li>Obtain the document's attribute set specifying the attributes which + * apply to this document instance.</li> + * </ul> + * </p><p> + * Every method of a <code>Doc</code> implementation has to return always the + * same object on every method call. Therefore if the print job consumes the + * print data via a stream or a reader object it can read only once the + * supplied print data. Implementations of this interface have to be thread + * safe. + * </p> + * * @author Michael Koch (konqueror@gmx.de) */ public interface Doc { /** - * Returns a set of attributes applying to this document. + * Returns the unmodifiable view of the attributes of this doc object. + * <p> + * The attributes of this doc's attributes set overrides attributes of + * the same category in the print job's attribute set. If an attribute + * is not available in this doc's attributes set or <code>null</code> + * is returned the attributes of the same category of the print job are + * used. + * </p> * - * @return the attributes + * @return The unmodifiable attributes set, or <code>null</code>. */ DocAttributeSet getAttributes(); /** - * Returns the flavor in which this document will provide its print data. - * - * @return the document flavor for printing + * Returns the flavor of this doc objects print data. + * + * @return The document flavor. */ DocFlavor getDocFlavor(); /** - * Returns the print data of this document represented in a format that supports - * the document flavor. - * - * @return the print data + * Returns the print data of this doc object. + * <p> + * The returned object is an instance as described by the associated + * document flavor ({@link DocFlavor#getRepresentationClassName()}) + * and can be cast to this representation class. + * </p> * - * @throws IOException if an error occurs + * @return The print data in the representation class. + * @throws IOException if representation class is a stream and I/O + * exception occures. */ Object getPrintData() throws IOException; /** * Returns a <code>Reader</code> object for extracting character print data * from this document. + * <p> + * This method is supported if the document flavor is of type: + * <ul> + * <li><code>char[]</code></li> + * <li><code>java.lang.String</code></li> + * <li><code>java.io.Reader</code></li> + * </ul> + * otherwise this method returns <code>null</code>. + * </p> * - * @return the <code>Reader</code> object + * @return The <code>Reader</code> object, or <code>null</code>. * - * @throws IOException if an error occurs + * @throws IOException if an error occurs. */ Reader getReaderForText() throws IOException; /** * Returns an <code>InputStream</code> object for extracting byte print data * from this document. + * <p> + * This method is supported if the document flavor is of type: + * <ul> + * <li><code>byte[]</code></li> + * <li><code>java.io.InputStream</code></li> + * </ul> + * otherwise this method returns <code>null</code>. + * </p> * - * @return the <code>InputStream</code> object + * @return The <code>InputStream</code> object, or <code>null</code>. * - * @throws IOException if an error occurs + * @throws IOException if an error occurs. */ InputStream getStreamForBytes() throws IOException; }
\ No newline at end of file diff --git a/libjava/classpath/javax/print/DocFlavor.java b/libjava/classpath/javax/print/DocFlavor.java index 1e96a70c024..6030595254d 100644 --- a/libjava/classpath/javax/print/DocFlavor.java +++ b/libjava/classpath/javax/print/DocFlavor.java @@ -1,5 +1,5 @@ /* DocFlavor.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,17 +38,108 @@ exception statement from your version. */ package javax.print; +import java.io.IOException; +import java.io.ObjectInputStream; import java.io.Serializable; -import java.util.HashMap; +import java.io.StreamTokenizer; +import java.io.StringReader; +import java.nio.charset.Charset; import java.util.Iterator; import java.util.Map; +import java.util.TreeMap; /** + * <code>DocFlavor</code> provides a description of the format in which the + * print data will be supplied in a print job to the print service. + * <p> + * A doc flavor 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><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 + * <code>"[B"</code> or for an input stream <code>"java.io.InputStream"</code>. + * </li> + * </ul> + * The <code>DocFlavor</code> class is therefore used in several places in the + * Java Print Service API. A print service provides its supported document + * flavors as an array of DocFlavor objects and a print job gets the flavor of + * its data to print from the <code>Doc</code> object provided as a DocFlavor + * instance. + * </p> + * <p> + * It has to be differentiated between <b>client formatted</b> and <b>service + * formatted</b> print data. Client formatted print data is already provided + * formatted by the client e.g. in an image format or as postscript. For + * service formatted print data, the Java Print Service instance 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. + * </p> + * <p> + * <h3>Client formatted print data document flavors</h3> + * The print service uses the representation class of the doc flavor to know + * how to retrieve the print data. If the representation class is a + * <code>URL</code> it will open the URL to read the print data from it. If it is + * a <code>byte[]</code> it will directly use the array and send it to the + * printer. There are predefined doc flavor as inner class for the most common + * representation class types: + * <ul> + * <li>Character arrays (<code>char[]</code>): The characters of the array + * represent the print data.</li> + * <li>Character streams (<code>java.io.Reader</code>): The whole characters + * read from the stream represent the print data.</li> + * <li>String (<code>java.lang.String</code>): The characters of the String + * represent the print data.</li> + * <li>Byte arrays (<code>byte[]</code>): The bytes of the array represent the + * print data. Encoding if text content is given in the mime type.</li> + * <li>Byte streams (<code>java.io.InputStream</code>): The whole bytes read + * from the stream represent the print data. If text content the encoding is + * specified in the mime type.</li> + * <li>Uniform Resource Locator (<code>java.net.URL</code>): The bytes read + * from the stream through opening of the URL represent the print data. + * If text content the encoding is specified in the mime type.</li></li> + * </ul> + * </p> + * <p> + * <h3>Service formatted print data document flavors</h3> + * The print service uses the provided object implementing the interface + * specified by the representation class to produce the formatted print data. + * The mime type of service formatted data is always + * <code>"application/x-java-jvm-local-objectref"</code> to signal the local + * reference to the print data object implementing the interface. Predefined + * doc flavor classes exist as an inner class for the three available interface + * to produce print data: + * <ul> + * <li>Pageable object (<code>java.awt.print.Pageable</code>): A pageable object + * is supplied to the print service. The print service will call the methods of + * the interface with a Grahics object to produce the formatted print data.</li> + * <li>Printable object (<code>java.awt.print.Printable</code>): A printable object + * is supplied to the print service. The print service will call the methods of + * the interface with a Grahics object to produce the formatted print data.</li> + * <li>Renderable Image object + * (<code>java.awt.image.renderable.RenderableImage</code>): A renderable image + * object is supplied to the print service. The print service calls methods of + * this interface to obtain the image to be printed.</li> + * </ul> + * </p> + * * @author Michael Koch (konqueror@gmx.de) + * @author Wolfgang Baer (WBaer@gmx.de) */ public class DocFlavor implements Cloneable, Serializable { /** + * Predefined static <code>DocFlavor</code> objects for document + * types which use a byte array for the print data representation. + * <p>All the defined doc flavors have a print data representation + * classname of "[B" (byte array).</p> + * * @author Michael Koch (konqueror@gmx.de) */ public static class BYTE_ARRAY @@ -56,26 +147,92 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = -9065578006593857475L; + /** + * Byte array doc flavor with a MIME Type of "application/octet-stream". + */ public static final BYTE_ARRAY AUTOSENSE = new BYTE_ARRAY("application/octet-stream"); + /** + * Byte array doc flavor with a MIME Type of "image/gif". + */ public static final BYTE_ARRAY GIF = new BYTE_ARRAY("image/gif"); + /** + * Byte array doc flavor with a MIME Type of "image/jpeg". + */ public static final BYTE_ARRAY JPEG = new BYTE_ARRAY("image/jpeg"); + /** + * Byte array doc flavor with a MIME Type of "application/vnd.hp-PCL". + */ public static final BYTE_ARRAY PCL = new BYTE_ARRAY("application/vnd.hp-PCL"); + /** + * Byte array doc flavor with a MIME Type of "application/pdf". + */ public static final BYTE_ARRAY PDF = new BYTE_ARRAY("application/pdf"); + /** + * Byte array doc flavor with a MIME Type of "image/png". + */ public static final BYTE_ARRAY PNG = new BYTE_ARRAY("image/png"); + /** + * Byte array doc flavor with a MIME Type of "application/postscript". + */ public static final BYTE_ARRAY POSTSCRIPT = new BYTE_ARRAY("application/postscript"); - public static final BYTE_ARRAY TEXT_HTML_HOST = new BYTE_ARRAY("text/html"); + /** + * Byte array doc flavor with a MIME Type of "text/html" in the host encoding. + */ + public static final BYTE_ARRAY TEXT_HTML_HOST = new BYTE_ARRAY("text/html; charset=" + hostEncoding); + /** + * Byte array doc flavor with a MIME Type of "text/html; charset=us-ascii". + */ public static final BYTE_ARRAY TEXT_HTML_US_ASCII = new BYTE_ARRAY("text/html; charset=us-ascii"); + /** + * Byte array doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final BYTE_ARRAY TEXT_HTML_UTF_16 = new BYTE_ARRAY("text/html; charset=utf-16"); + /** + * Byte array doc flavor with a MIME Type of "text/html; charset=utf-16be". + */ public static final BYTE_ARRAY TEXT_HTML_UTF_16BE = new BYTE_ARRAY("text/html; charset=utf-16be"); + /** + * Byte array doc flavor with a MIME Type of "text/html; charset=utf-16le". + */ public static final BYTE_ARRAY TEXT_HTML_UTF_16LE = new BYTE_ARRAY("text/html; charset=utf-16le"); + /** + * Byte array doc flavor with a MIME Type of "text/html; charset=utf-8". + */ public static final BYTE_ARRAY TEXT_HTML_UTF_8 = new BYTE_ARRAY("text/html; charset=utf-8"); - public static final BYTE_ARRAY TEXT_PLAIN_HOST = new BYTE_ARRAY("text/plain"); - public static final BYTE_ARRAY TEXT_PLAIN_US_ASCII = new BYTE_ARRAY("text/plain; charset=us-ascii"); + /** + * Byte array doc flavor with a MIME Type of "text/plain" in the host encoding. + */ + public static final BYTE_ARRAY TEXT_PLAIN_HOST = new BYTE_ARRAY("text/plain; charset=" + hostEncoding); + /** + * Byte array doc flavor with a MIME Type of "text/plain; charset=us-ascii". + */ + public static final BYTE_ARRAY TEXT_PLAIN_US_ASCII = new BYTE_ARRAY("text/plain; charset=us-ascii"); + /** + * Byte array doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final BYTE_ARRAY TEXT_PLAIN_UTF_16 = new BYTE_ARRAY("text/plain; charset=utf-16"); + /** + * Byte array doc flavor with a MIME Type of "text/plain; charset=utf-16be". + */ public static final BYTE_ARRAY TEXT_PLAIN_UTF_16BE = new BYTE_ARRAY("text/plain; charset=utf-16be"); + /** + * Byte array doc flavor with a MIME Type of "text/plain; charset=utf-16le". + */ public static final BYTE_ARRAY TEXT_PLAIN_UTF_16LE = new BYTE_ARRAY("text/plain; charset=utf-16le"); + /** + * Byte array doc flavor with a MIME Type of "text/plain; charset=utf-8". + */ public static final BYTE_ARRAY TEXT_PLAIN_UTF_8 = new BYTE_ARRAY("text/plain; charset=utf-8"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "[B". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is <code>null</code>. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public BYTE_ARRAY(String mimeType) { super(mimeType, "[B"); @@ -83,6 +240,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static <code>DocFlavor</code> objects for document + * types which use a char array for the print data representation. + * <p>All the defined doc flavors have a print data representation + * classname of "[C" (char array).</p> + * * @author Michael Koch (konqueror@gmx.de) */ public static class CHAR_ARRAY @@ -90,9 +252,24 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = -8720590903724405128L; + /** + * Char array doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final DocFlavor.CHAR_ARRAY TEXT_HTML = new CHAR_ARRAY("text/html; charset=utf-16"); + /** + * Char array doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final DocFlavor.CHAR_ARRAY TEXT_PLAIN = new CHAR_ARRAY("text/plain; charset=utf-16"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "[C". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is <code>null</code>. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public CHAR_ARRAY(String mimeType) { super(mimeType, "[C"); @@ -100,6 +277,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static <code>DocFlavor</code> objects for document + * types which use an InputStream to retrieve the print data. + * <p>All the defined doc flavors have a print data representation + * classname of "java.io.InputStream".</p> + * * @author Michael Koch (konqueror@gmx.de) */ public static class INPUT_STREAM @@ -107,26 +289,92 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = -7045842700749194127L; + /** + * InputStream doc flavor with a MIME Type of "application/octet-stream". + */ public static final INPUT_STREAM AUTOSENSE = new INPUT_STREAM("application/octet-stream"); + /** + * InputStream doc flavor with a MIME Type of "image/gif". + */ public static final INPUT_STREAM GIF = new INPUT_STREAM("image/gif"); + /** + * InputStream doc flavor with a MIME Type of "image/jpeg". + */ public static final INPUT_STREAM JPEG = new INPUT_STREAM("image/jpeg"); + /** + * InputStream doc flavor with a MIME Type of "application/vnd.hp-PCL". + */ public static final INPUT_STREAM PCL = new INPUT_STREAM("application/vnd.hp-PCL"); + /** + * InputStream doc flavor with a MIME Type of "application/pdf". + */ public static final INPUT_STREAM PDF = new INPUT_STREAM("application/pdf"); + /** + * InputStream doc flavor with a MIME Type of "image/png". + */ public static final INPUT_STREAM PNG = new INPUT_STREAM("image/png"); + /** + * InputStream doc flavor with a MIME Type of "application/postscript". + */ public static final INPUT_STREAM POSTSCRIPT = new INPUT_STREAM("application/postscript"); - public static final INPUT_STREAM TEXT_HTML_HOST = new INPUT_STREAM("text/html"); + /** + * InputStream doc flavor with a MIME Type of "text/html" in the host encoding. + */ + public static final INPUT_STREAM TEXT_HTML_HOST = new INPUT_STREAM("text/html; charset=" + hostEncoding); + /** + * InputStream doc flavor with a MIME Type of "text/html; charset=us-ascii". + */ public static final INPUT_STREAM TEXT_HTML_US_ASCII = new INPUT_STREAM("text/html; charset=us-ascii"); + /** + * InputStream doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final INPUT_STREAM TEXT_HTML_UTF_16 = new INPUT_STREAM("text/html; charset=utf-16"); + /** + * InputStream doc flavor with a MIME Type of "text/html; charset=utf-16be". + */ public static final INPUT_STREAM TEXT_HTML_UTF_16BE = new INPUT_STREAM("text/html; charset=utf-16be"); + /** + * InputStream doc flavor with a MIME Type of "text/html; charset=utf-16le". + */ public static final INPUT_STREAM TEXT_HTML_UTF_16LE = new INPUT_STREAM("text/html; charset=utf-16le"); + /** + * InputStream doc flavor with a MIME Type of "text/html; charset=utf-8". + */ public static final INPUT_STREAM TEXT_HTML_UTF_8 = new INPUT_STREAM("text/html; charset=utf-8"); - public static final INPUT_STREAM TEXT_PLAIN_HOST = new INPUT_STREAM("text/plain"); + /** + * InputStream doc flavor with a MIME Type of "text/plain" in the host encoding. + */ + public static final INPUT_STREAM TEXT_PLAIN_HOST = new INPUT_STREAM("text/plain; charset=" + hostEncoding); + /** + * InputStream doc flavor with a MIME Type of "text/plain; charset=us-ascii". + */ public static final INPUT_STREAM TEXT_PLAIN_US_ASCII = new INPUT_STREAM("text/plain; charset=us-ascii"); + /** + * InputStream doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final INPUT_STREAM TEXT_PLAIN_UTF_16 = new INPUT_STREAM("text/plain; charset=utf-16"); + /** + * InputStream doc flavor with a MIME Type of "text/plain; charset=utf-16be". + */ public static final INPUT_STREAM TEXT_PLAIN_UTF_16BE = new INPUT_STREAM("text/plain; charset=utf-16be"); + /** + * InputStream doc flavor with a MIME Type of "text/plain; charset=utf-16le". + */ public static final INPUT_STREAM TEXT_PLAIN_UTF_16LE = new INPUT_STREAM("text/plain; charset=utf-16le"); + /** + * InputStream doc flavor with a MIME Type of "text/plain; charset=utf-8". + */ public static final INPUT_STREAM TEXT_PLAIN_UTF_8 = new INPUT_STREAM("text/plain; charset=utf-8"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "java.io.InputStream". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is <code>null</code>. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public INPUT_STREAM(String mimeType) { super(mimeType, "java.io.InputStream"); @@ -134,6 +382,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static <code>DocFlavor</code> objects for document + * types which use an Reader to retrieve the print data. + * <p>All the defined doc flavors have a print data representation + * classname of "java.io.Reader".</p> + * * @author Michael Koch (konqueror@gmx.de) */ public static class READER @@ -141,9 +394,24 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = 7100295812579351567L; + /** + * Reader doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final DocFlavor.READER TEXT_HTML = new READER("text/html; charset=utf-16"); + /** + * Reader doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final DocFlavor.READER TEXT_PLAIN = new READER("text/plain; charset=utf-16"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "java.io.Reader". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is <code>null</code>. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public READER(String mimeType) { super(mimeType, "java.io.Reader"); @@ -151,6 +419,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static <code>DocFlavor</code> objects for document + * types which use service formatted print data. + * <p>All the defined doc flavors have a MIME type of + * "application/x-java-jvm-local-objectref".</p> + * * @author Michael Koch (konqueror@gmx.de) */ public static class SERVICE_FORMATTED @@ -158,10 +431,31 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = 6181337766266637256L; + /** + * Service formatted doc flavor with a representation class of + * "java.awt.print.Pageable". + */ public static final DocFlavor.SERVICE_FORMATTED PAGEABLE = new SERVICE_FORMATTED("java.awt.print.Pageable"); + /** + * Service formatted doc flavor with a representation class of + * "java.awt.print.Printable". + */ public static final DocFlavor.SERVICE_FORMATTED PRINTABLE = new SERVICE_FORMATTED("java.awt.print.Printable"); + /** + * Service formatted doc flavor with a representation class of + * "java.awt.image.renderable.RenderableImage". + */ public static final DocFlavor.SERVICE_FORMATTED RENDERABLE_IMAGE = new SERVICE_FORMATTED("java.awt.image.renderable.RenderableImage"); + /** + * Constructor for doc flavor objects with a MIME type of + * "application/x-java-jvm-local-objectref" and the given + * print data representation classname. + * + * @param className the representation classname + * + * @throws NullPointerException if className is <code>null</code>. + */ public SERVICE_FORMATTED(String className) { super("application/x-java-jvm-local-objectref", className); @@ -169,6 +463,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static <code>DocFlavor</code> objects for document + * types which use a String for the print data representation. + * <p>All the defined doc flavors have a print data representation + * classname of "java.lang.String".</p> + * * @author Michael Koch (konqueror@gmx.de) */ public static class STRING @@ -176,9 +475,24 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = 4414407504887034035L; + /** + * String doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final DocFlavor.STRING TEXT_HTML = new STRING("text/html; charset=utf-16"); + /** + * String doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final DocFlavor.STRING TEXT_PLAIN = new STRING("text/plain; charset=utf-16"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "java.lang.String". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is <code>null</code>. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public STRING(String mimeType) { super(mimeType, "java.lang.String"); @@ -186,6 +500,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static <code>DocFlavor</code> objects for document + * types which have an URL where to retrieve the print data. + * <p>All the defined doc flavors have a print data representation + * classname of "java.net.URL".</p> + * * @author Michael Koch (konqueror@gmx.de) */ public static class URL @@ -193,26 +512,92 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = 2936725788144902062L; + /** + * URL doc flavor with a MIME Type of "application/octet-stream". + */ public static final DocFlavor.URL AUTOSENSE = new URL("application/octet-stream"); + /** + * URL doc flavor with a MIME Type of "image/gif". + */ public static final DocFlavor.URL GIF = new URL("image/gif"); + /** + * URL doc flavor with a MIME Type of "image/jpeg". + */ public static final DocFlavor.URL JPEG = new URL("image/jpeg"); + /** + * URL doc flavor with a MIME Type of "application/vnd.hp-PCL". + */ public static final DocFlavor.URL PCL = new URL("application/vnd.hp-PCL"); + /** + * URL doc flavor with a MIME Type of "application/pdf". + */ public static final DocFlavor.URL PDF = new URL("application/pdf"); + /** + * URL doc flavor with a MIME Type of "image/png". + */ public static final DocFlavor.URL PNG = new URL("image/png"); + /** + * URL doc flavor with a MIME Type of "application/postscript". + */ public static final DocFlavor.URL POSTSCRIPT = new URL("application/postscript"); - public static final DocFlavor.URL TEXT_HTML_HOST = new URL("text/html"); + /** + * URL doc flavor with a MIME Type of "text/html" in the host encoding. + */ + public static final DocFlavor.URL TEXT_HTML_HOST = new URL("text/html; charset=" + hostEncoding); + /** + * URL doc flavor with a MIME Type of "text/html; charset=us-ascii". + */ public static final DocFlavor.URL TEXT_HTML_US_ASCII = new URL("text/html; charset=us-ascii"); + /** + * URL doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final DocFlavor.URL TEXT_HTML_UTF_16 = new URL("text/html; charset=utf-16"); + /** + * URL doc flavor with a MIME Type of "text/html; charset=utf-16be". + */ public static final DocFlavor.URL TEXT_HTML_UTF_16BE = new URL("text/html; charset=utf-16be"); + /** + * URL doc flavor with a MIME Type of "text/html; charset=utf-16le". + */ public static final DocFlavor.URL TEXT_HTML_UTF_16LE = new URL("text/html; charset=utf-16le"); + /** + * URL doc flavor with a MIME Type of "text/html; charset=utf-8". + */ public static final DocFlavor.URL TEXT_HTML_UTF_8 = new URL("text/html; charset=utf-8"); - public static final DocFlavor.URL TEXT_PLAIN_HOST = new URL("text/plain"); + /** + * URL doc flavor with a MIME Type of "text/plain" in the host encoding. + */ + public static final DocFlavor.URL TEXT_PLAIN_HOST = new URL("text/plain; charset=" + hostEncoding); + /** + * URL doc flavor with a MIME Type of "text/plain; charset=us-ascii". + */ public static final DocFlavor.URL TEXT_PLAIN_US_ASCII = new URL("text/plain; charset=us-ascii"); + /** + * URL doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final DocFlavor.URL TEXT_PLAIN_UTF_16 = new URL("text/plain; charset=utf-16"); + /** + * URL doc flavor with a MIME Type of "text/plain; charset=utf-16be". + */ public static final DocFlavor.URL TEXT_PLAIN_UTF_16BE = new URL("text/plain; charset=utf-16be"); + /** + * URL doc flavor with a MIME Type of "text/plain; charset=utf-16le". + */ public static final DocFlavor.URL TEXT_PLAIN_UTF_16LE = new URL("text/plain; charset=utf-16le"); + /** + * URL doc flavor with a MIME Type of "text/plain; charset=utf-8". + */ public static final DocFlavor.URL TEXT_PLAIN_UTF_8 = new URL("text/plain; charset=utf-8"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "java.net.URL". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is <code>null</code>. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public URL(String mimeType) { super(mimeType, "java.net.URL"); @@ -221,47 +606,191 @@ public class DocFlavor implements Cloneable, Serializable private static final long serialVersionUID = -4512080796965449721L; - // FIXME: Get the host encoding from somewhere. Note that the new String is to make - // sure the field won't be a compile time constant. - public static final String hostEncoding = new String("US-ASCII"); - - private String mediaSubtype; - private String mediaType; - private String className; - private HashMap params = new HashMap(); + /** + * The string representing the host encoding. This is the encoding + * used in the predefined HOST doc flavors + * (e.g. {@link BYTE_ARRAY#TEXT_HTML_HOST}). + */ + public static final String hostEncoding = Charset.defaultCharset().name(); + + private transient String mediaSubtype; + private transient String mediaType; + private transient TreeMap params; + // name as defined in Serialized Form JDK 1.4 + private String myClassName; + + /** + * Constructs a <code>DocFlavor</code> object with the given MIME type and + * representation class name. + * + * @param mimeType the MIME type string. + * @param className the fully-qualified name of the representation class. + * + * @throws NullPointerException if mimeType or className are <code>null</code>. + * @throws IllegalArgumentException if given mimeType has syntax errors. + */ public DocFlavor(String mimeType, String className) { if (mimeType == null || className == null) throw new NullPointerException(); + params = new TreeMap(); parseMimeType(mimeType); - this.className = className; + + myClassName = className; } - + + /** + * Parses the given string as MIME type. + * The mediatype, mediasubtype and all parameter/value + * combinations are extracted, comments are dropped. + * + * @param mimeType the string to parse + * @throws IllegalArgumentException if not conformant. + */ private void parseMimeType(String mimeType) { - // FIXME: This method is know to be not completely correct, but it works for now. + int MEDIA = 1; + int MEDIASUB = 2; + int PARAM_NAME = 3; + int PARAM_VALUE = 4; + int COMMENT_START = 5; - int pos = mimeType.indexOf(';'); - - if (pos != -1) + int state = 0; + int lastState = 0; // keeps track of state before comment + int tok; + + try { - String tmp = mimeType.substring(pos + 2); - mimeType = mimeType.substring(0, pos); - pos = tmp.indexOf('='); - params.put(tmp.substring(0, pos), tmp.substring(pos + 1)); + String paramName = null; + StreamTokenizer in = new StreamTokenizer(new StringReader(mimeType)); + in.resetSyntax(); + // Allowed characters are anything except: + // SPACE, CTLs (= Unicode characters U+0000 - U+001F and U+007F) + // and tspecials ( ) < > @ , ; : \ " / [ ] ? = + in.whitespaceChars(0x00, 0x20); + in.whitespaceChars(0x7F, 0x7F); + in.wordChars('A', 'Z'); + in.wordChars('a', 'z'); + in.wordChars('0', '9'); + in.wordChars(0xA0, 0xFF); + in.wordChars(0x21, 0x21); + in.wordChars(0x23, 0x27); + in.wordChars(0x2A, 0x2B); + in.wordChars(0x2D, 0x2E); + in.wordChars(0x5E, 0x60); + in.wordChars(0x7B, 0x7E); + in.quoteChar('"'); + + while ((tok = in.nextToken()) != StreamTokenizer.TT_EOF) + { + switch (tok) + { + case StreamTokenizer.TT_WORD: + if (state == 0) + { + mediaType = in.sval.toLowerCase(); + state = MEDIA; + break; + } + if (state == MEDIA) + { + mediaSubtype = in.sval.toLowerCase(); + state = MEDIASUB; + break; + } + // begin of parameters is either after mediasub or a parameter value + if (state == MEDIASUB || state == PARAM_VALUE) + { + paramName = in.sval.toLowerCase(); + state = PARAM_NAME; + break; + } + // a parameter always needs to follow a value + if (state == PARAM_NAME) + { + String paramValue = in.sval; + // if a charset param the value needs to be stored lowercase + if (paramName.equals("charset")) + paramValue = paramValue.toLowerCase(); + + state = PARAM_VALUE; + params.put(paramName, paramValue); + break; + } + if (state == COMMENT_START) + { + // ignore; + break; + } + break; + case '/': + // may only occur after the mediatype + if (state != MEDIA) + throw new IllegalArgumentException(); + + break; + case '=': + // may only occur after a parameter + if (state != PARAM_NAME) + throw new IllegalArgumentException(); + + break; + case ';': + // differentiates mime type and parameters/value combinations + if (state != MEDIASUB && state != PARAM_VALUE) + throw new IllegalArgumentException(); + + break; + case '(': // begin comment + lastState = state; + state = COMMENT_START; + break; + case ')': // end comment + state = lastState; + break; + // a parameter always needs to follow a value / or quoted value + case '"': + if (state == PARAM_NAME) + { + String paramValue = in.sval; + // if a charset param the value needs to be stored lowercase + if (paramName.equals("charset")) + paramValue = paramValue.toLowerCase(); + + state = PARAM_VALUE; + params.put(paramName, paramValue); + break; + } + + // only values may be quoted + throw new IllegalArgumentException(); + default: + // if any other char is observed its not allowed + throw new IllegalArgumentException(); + } + } + } + catch (IOException e) + { + // should not happen as mimetype str cannot be null + throw new InternalError("IOException during parsing String " + mimeType); } - - pos = mimeType.indexOf('/'); - - if (pos == -1) - throw new IllegalArgumentException(); - - mediaType = mimeType.substring(0, pos); - mediaSubtype = mimeType.substring(pos + 1); } + /** + * Checks if this doc flavor object is equal to the given object. + * <p> + * Two doc flavor objects are considered equal if the provided object is not + * <code>null</code> and an instance of <code>DocFlavor</code>. The MIME + * types has to be equal in their media type, media subtype, their + * paramter/value combinations and the representation classname. + * </p> + * + * @param obj the object to test. + * @return <code>true</code> if equal, <code>false</code> otherwise. + */ public boolean equals(Object obj) { if (! (obj instanceof DocFlavor)) @@ -273,20 +802,39 @@ public class DocFlavor implements Cloneable, Serializable && getRepresentationClassName().equals(tmp.getRepresentationClassName())); } + /** + * Returns the media subtype of this flavor object. + * A mimetype of "text/html; charset=us-ascii" will + * return "html" as the media subtype. + * + * @return The media subtype. + */ public String getMediaSubtype() { return mediaSubtype; } + /** + * Returns the media type of this flavor object. + * A mimetype of "text/html; charset=us-ascii" will + * return "text" as the media type. + * + * @return The media type. + */ public String getMediaType() { return mediaType; } + /** + * Returns the mime type of this flavor object. + * The mimetype will have every parameter value + * enclosed in quotes. + * + * @return The mime type. + */ public String getMimeType() { - // FIXME: Check if this algorithm is correct. - String mimeType = getMediaType() + "/" + getMediaSubtype(); Iterator it = params.entrySet().iterator(); @@ -299,28 +847,69 @@ public class DocFlavor implements Cloneable, Serializable return mimeType; } + /** + * Returns the value for an optional parameter of the mime type of this + * flavor object. + * + * @param paramName the name of the parameter + * @return The value for the parameter, or <code>null</code> if none bound. + * @throws NullPointerException if paramName is <code>null</code>. + */ public String getParameter(String paramName) { if (paramName == null) throw new NullPointerException(); - return (String) params.get(paramName); + return (String) params.get(paramName.toLowerCase()); } + /** + * Returns the name of the representation class of this flavor object. + * + * @return The representation classname. + */ public String getRepresentationClassName() { - return className; + return myClassName; } + /** + * Returns a hash code for this doc flavor object. + * + * @return The hashcode. + */ public int hashCode() { return ((mediaType.hashCode() * mediaSubtype.hashCode() - * className.hashCode()) ^ params.hashCode()); + * myClassName.hashCode()) ^ params.hashCode()); } + /** + * Returns a string representation of this doc flavor object. + * The returned string is of the form + * getMimeType() + "; class=\"" + getRepresentationClassName() + "\""; + * + * @return The constructed string representation. + */ public String toString() { - return getMimeType(); + return getMimeType() + "; class=\"" + getRepresentationClassName() + "\""; + } + + // needs special treatment for serialization + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + params = new TreeMap(); + myClassName = (String) stream.readObject(); + parseMimeType((String) stream.readObject()); + } + + private void writeObject(java.io.ObjectOutputStream stream) + throws IOException + { + stream.writeObject(myClassName); + stream.writeObject(getMimeType()); } } diff --git a/libjava/classpath/javax/print/DocPrintJob.java b/libjava/classpath/javax/print/DocPrintJob.java index f7d36159405..eec4e2afca4 100644 --- a/libjava/classpath/javax/print/DocPrintJob.java +++ b/libjava/classpath/javax/print/DocPrintJob.java @@ -1,5 +1,5 @@ /* DocPrintJob.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,61 +44,105 @@ import javax.print.event.PrintJobAttributeListener; import javax.print.event.PrintJobListener; /** + * <code>DocPrintJob</code> represents a print job which supports printing + * of a single document. + * <p> + * An instance can be obtained from every <code>PrintService</code> available + * by calling the {@link javax.print.PrintService#createPrintJob()} method. + * A print job is bound to the print service it is created from. + * </p> + * * @author Michael Koch (konqueror@gmx.de) */ public interface DocPrintJob { /** - * Registers a listener for changes in the specified attributes. + * Registers a listener for changes in the specified attribute set + * during processing of this print job. + * <p> + * If the given attribute set is empty no changes will be reported. + * If the set is <code>null</code> all attributes are monitored. + * </p> * - * @param listener the listener to add - * @param attributes the attributes to observe + * @param listener the listener to register. + * @param attributes the attributes to observe. + * + * @see #removePrintJobAttributeListener(PrintJobAttributeListener) */ void addPrintJobAttributeListener(PrintJobAttributeListener listener, PrintJobAttributeSet attributes); /** - * Registers a listener for events occuring during this print job. + * Registers a listener for events occuring during processing + * of this print job. + * + * @param listener the listener to add, if <code>null</code> nothing is done. * - * @param listener the listener to add + * @see #removePrintJobListener(PrintJobListener) */ void addPrintJobListener(PrintJobListener listener); /** - * Returns the print job's attributes. + * Returns the print job's attributes. + * <p> + * The returned set of attributes is a snapshot at the time of calling this + * method and will not be updated if changes to the print job's attributes + * happens. To monitor changes register a print job listener. + * </p> * - * @return the attributes of this print job + * @return The attributes of this print job, + * may be empty but never <code>null</code>. */ PrintJobAttributeSet getAttributes(); /** * Returns the <code>PrintService</code> object this print job is bound to. * - * @return the print service + * @return The print service. */ PrintService getPrintService(); /** * Prints a document with the specified print job attributes. * + * <p> + * If the doc flavor provided by the <code>Doc</code> implementation is + * not supported by this print service a <code>PrintException</code> + * implementing the <code>FlavorException</code> interface will be thrown. + * </p> + * * @param doc the document to print - * @param attributes the attributes to use + * @param attributes the job attributes to use. If <code>null</code> the + * default attribute values of the print service will be used. + * + * @throws PrintException if an error occurs. The thrown exception may + * implement refining print exception interface to provide more detail of + * the error. * - * @throws PrintException if an error occurs + * @see AttributeException + * @see FlavorException */ void print(Doc doc, PrintRequestAttributeSet attributes) throws PrintException; /** - * De-registers an attribute listener. + * Removes the given listener from the listeners registered for changes + * in their provided attribute set during processing of this print job. * - * @param listener the listener to remove - */ + * @param listener the listener to remove, if <code>null</code> or not + * registered nothing will be done. + * + * @see #addPrintJobAttributeListener(PrintJobAttributeListener, PrintJobAttributeSet) + */ void removePrintJobAttributeListener(PrintJobAttributeListener listener); /** - * De-registers a print job listener. + * Removes the given listener from the listeners registered for events + * occuring during processing of this print job. + * + * @param listener the listener to remove, if <code>null</code> or not + * registered nothing will be done. * - * @param listener the listener to remove + * @see #addPrintJobListener(PrintJobListener) */ void removePrintJobListener(PrintJobListener listener); }
\ No newline at end of file diff --git a/libjava/classpath/javax/print/PrintService.java b/libjava/classpath/javax/print/PrintService.java index d34fde843f0..b5fe004a730 100644 --- a/libjava/classpath/javax/print/PrintService.java +++ b/libjava/classpath/javax/print/PrintService.java @@ -1,5 +1,5 @@ /* PrintService.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,14 +45,25 @@ import javax.print.attribute.PrintServiceAttributeSet; import javax.print.event.PrintServiceAttributeListener; /** + * A <code>PrintService</code> represents a printer available for printing. + * <p> + * The print service hereby may be a real physical printer device, a printer + * group with same capabilities or a logical print service (like for example + * a PDF writer). The print service is used to query the capabilities of the + * represented printer instance. If a suitable print service is found it is + * used to create a print job for the actual printing process. + * </p> + * @see javax.print.DocPrintJob + * * @author Michael Koch (konqueror@gmx.de) */ public interface PrintService { /** - * Returns a new print job capable to handle all supported document flavors. + * Creates and returns a new print job which is capable to handle all + * the document flavors supported by this print service. * - * @return the new print job + * @return The created print job object. */ DocPrintJob createPrintJob(); @@ -61,39 +72,54 @@ public interface PrintService * * @param obj the service to check against * - * @return <code>true</code> if both services refer to the sam underlying - * service, <code>false</code> otherwise + * @return <code>true</code> if both services refer to the same underlying + * service, <code>false</code> otherwise. */ boolean equals(Object obj); /** - * Returns the value of a single specified attribute. + * Returns the value of the single specified attribute. * * @param category the category of a <code>PrintServiceAttribute</code> * - * @return the value of the attribute + * @return The value of the attribute, or <code>null</code> if the attribute + * category is not supported by this print service implementation. * - * @throws NullPointerException if category is null + * @throws NullPointerException if category is <code>null</code>. * @throws IllegalArgumentException if category is not a class that - * implements <code>PrintServiceAttribute</code> + * implements <code>PrintServiceAttribute</code>. */ PrintServiceAttribute getAttribute(Class category); /** - * Returns all attributes of this printer service - * - * @return all attributes of this print service + * Returns the attributes describing this print service. The returned + * attributes set is unmodifiable and represents the current state of + * the print service. As some print service attributes may change + * (depends on the print service implementation) a subsequent call to + * this method may return a different set. To monitor changes a + * <code>PrintServiceAttributeListener</code> may be registered. + * + * @return All the description attributes of this print service. + * @see #addPrintServiceAttributeListener(PrintServiceAttributeListener) */ PrintServiceAttributeSet getAttributes(); /** - * Returns the service's default value for a given attribute. + * Determines and returns the default value for a given attribute category + * of this print service. + * <p> + * A return value of <code>null</code> means either that the print service + * does not support the attribute category or there is no default value + * available for this category. To distinguish these two case one can test + * with {@link #isAttributeCategorySupported(Class)} if the category is + * supported. + * </p> * * @param category the category of the attribute * - * @return the default value + * @return The default value, or <code>null</code>. * - * @throws NullPointerException if <code>category</code> is null + * @throws NullPointerException if <code>category</code> is <code>null</code> * @throws IllegalArgumentException if <code>category</code> is a class * not implementing <code>Attribute</code> */ @@ -101,36 +127,50 @@ public interface PrintService /** * Returns the name of this print service. + * This may be the value of the <code>PrinterName</code> attribute. * - * @return the name + * @return The print service name. */ String getName(); /** - * Returns a factory for UI components. + * Returns a factory for UI components if supported by the print service. * - * @return the factory + * @return A factory for UI components or <code>null</code>. */ ServiceUIFactory getServiceUIFactory(); /** * Returns all supported attribute categories. * - * @return an array of all supported attribute categories + * @return The class array of all supported attribute categories. */ Class[] getSupportedAttributeCategories(); /** - * Returns all supported attribute values a client can use when setting up - * a print job with this service. + * Determines and returns all supported attribute values of a given + * attribute category a client can use when setting up a print job + * for this print service. + * <p> + * The returned object may be one of the following types: + * <ul> + * <li>A single instance of the attribute category to indicate that any + * value will be supported.</li> + * <li>An array of the same type as the attribute category to test, + * containing all the supported values for this category.</li> + * <li>A single object (of any other type than the attribute category) + * which indicates bounds on the supported values.</li> + * </ul> + * </p> * * @param category the attribute category to test - * @param flavor the document flavor to use, or null - * @param attributes set of printing attributes for a supposed job, or null + * @param flavor the document flavor to use, or <code>null</code> + * @param attributes set of attributes for a supposed job, + * or <code>null</code> * - * @return object indicating supported values for <code>category</code>, - * or null if this print service doesnt support specifying doc-level or - * job-level attribute in a print request. + * @return A object (as defined above) indicating the supported values + * for the given attribute category, or <code>null</code> if this print + * service doesn't support the given attribute category at all. * * @throws NullPointerException if <code>category</code> is null * @throws IllegalArgumentException if <code>category</code> is a class not @@ -140,73 +180,101 @@ public interface PrintService Object getSupportedAttributeValues(Class category, DocFlavor flavor, AttributeSet attributes); /** - * Returns an array of all supproted document flavors. - * - * @return the supported document flavors + * Determines and returns an array of all supported document flavors which + * can be used to supply print data to this print service. + * <p> + * The supported attribute categories may differ between the supported + * document flavors. To test for supported attributes one can use the + * {@link #getUnsupportedAttributes(DocFlavor, AttributeSet)} method with + * the specific doc flavor and attributes set. + * </p> + * + * @return The supported document flavors. */ DocFlavor[] getSupportedDocFlavors(); /** - * Returns all attributes that are unsupported for a print request in the - * context of a particular document flavor. - * - * @param flavor document flavor to test, or null + * Identifies all the unsupported attributes of the given set of attributes + * in the context of the specified document flavor. + * <p> + * The given flavor has to be supported by the print service (use + * {@link #isDocFlavorSupported(DocFlavor)} to verify). The method will + * return <code>null</code> if all given attributes are supported. Otherwise + * a set of unsupported attributes are returned. The attributes in the + * returned set may be completely unsupported or only the specific requested + * value. If flavor is <code>null</code> the default document flavor of the + * print service is used in the identification process. + * </p> + * + * @param flavor document flavor to test, or <code>null</code>. * @param attributes set of printing attributes for a supposed job * - * @return null if this <code>PrintService</code> supports the print request - * specification, else the unsupported attributes + * @return <code>null</code> if this print service supports all the given + * attributes for the specified doc flavor. Otherwise the set of unsupported + * attributes are returned. * * @throws IllegalArgumentException if <code>flavor</code> is unsupported */ AttributeSet getUnsupportedAttributes(DocFlavor flavor, AttributeSet attributes); + /** - * Returns a hashcode for this printer service. + * Returns a hashcode for this print service. * - * @return the hashcode + * @return The hashcode. */ int hashCode(); /** - * Determines a given attribute category is supported or not. + * Determines a given attribute category is supported by this + * print service implementation. This only tests for the category + * not for any specific values of this category nor in the context + * of a specific document flavor. * * @param category the category to check * * @return <code>true</code> if <code>category</code> is supported, - * <code>false</code> otherwise + * <code>false</code> otherwise. * - * @throws NullPointerException if <code>category</code> is null + * @throws NullPointerException if <code>category</code> is <code>null</code> * @throws IllegalArgumentException if <code>category</code> is a class not * implementing <code>Attribute</code>. */ boolean isAttributeCategorySupported(Class category); /** - * Determines a given attribute value is supported when creating a print job - * for this print service. + * Determines if a given attribute value is supported when creating a print + * job for this print service. + * <p> + * If either the document flavor or the provided attributes are + * <code>null</code> it is determined if the given attribute value is + * supported in some combination of the available document flavors and + * attributes of the print service. Otherwise it is checked for the + * specific context of the given document flavor/attributes set. + * </p> * * @param attrval the attribute value to check - * @param flavor the document flavor to use, or null - * @param attributes set of printing attributes to use, or null + * @param flavor the document flavor to use, or <code>null</code>. + * @param attributes set of attributes to use, or <code>null</code>. * - * @return <code>true</code> if the attribute value is supported, - * <code>false</code> otherwise + * @return <code>true</code> if the attribute value is supported in the + * requested context, <code>false</code> otherwise. * - * @throws NullPointerException if <code>attrval</code> is null + * @throws NullPointerException if <code>attrval</code> is <code>null</code>. * @throws IllegalArgumentException if <code>flavor</code> is not supported * by this print service */ boolean isAttributeValueSupported(Attribute attrval, DocFlavor flavor, AttributeSet attributes); /** - * Determines a given document flavor is supported or not. + * Determines if a given document flavor is supported or not. * * @param flavor the document flavor to check * * @return <code>true</code> if <code>flavor</code> is supported, - * <code>false</code> otherwise + * <code>false</code> otherwise. * - * @throws NullPointerException if <code>flavor</code> is null + * @throws NullPointerException if <code>flavor</code> is null. */ boolean isDocFlavorSupported(DocFlavor flavor); diff --git a/libjava/classpath/javax/print/ServiceUIFactory.java b/libjava/classpath/javax/print/ServiceUIFactory.java index 66e6114413b..1a5c1cfe2fb 100644 --- a/libjava/classpath/javax/print/ServiceUIFactory.java +++ b/libjava/classpath/javax/print/ServiceUIFactory.java @@ -1,5 +1,5 @@ /* ServiceUIFactory.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,18 +39,47 @@ exception statement from your version. */ package javax.print; /** + * <code>ServiceUIFactory</code> enables print services to provide additional + * user interface dialogs. + * <p> + * A print service may provide a <code>ServiceUIFactory</code> implementation + * if its <code>getServiceUIFactory()</code> method is called. If a factory + * object is returned it can be queried for provided user interface dialogs. + * Different roles are defined to denote dialogs providing informations about + * the print service, dialogs for administration of a print service and for + * end-user browsing dialogs. + * </p><p> + * The factory can support providing these UI roles in different dialog types + * (AWT, Swing, JComponent, Panel). The support and use of Swing interfaces is + * however preferred. + * </p> + * * @author Michael Koch */ public abstract class ServiceUIFactory { + /** A user interface providing informations about the print service. */ public static final int ABOUT_UIROLE = 1; + + /** A user interface to administer the print service. */ public static final int ADMIN_UIROLE = 2; + + /** A user interface for end-user browsing of the print service. */ public static final int MAIN_UIROLE = 3; + + /** Role IDs greater than this may be used for other private roles. */ public static final int RESERVED_UIROLE = 99; + /** Identifies a UI provided as an AWT dialog. */ public static final String DIALOG_UI = "java.awt.Dialog"; + + /** Identifies a UI provided as a Swing JComponent. */ public static final String JCOMPONENT_UI = "javax.swing.JComponent"; + + /** Identifies a UI provided as a Swing JDialog. */ public static final String JDIALOG_UI = "javax.swing.JDialog"; + + /** Identifies a UI provided as an AWT Panel. */ public static final String PANEL_UI = "java.awt.Panel"; /** diff --git a/libjava/classpath/javax/print/SimpleDoc.java b/libjava/classpath/javax/print/SimpleDoc.java new file mode 100644 index 00000000000..a49406bcb76 --- /dev/null +++ b/libjava/classpath/javax/print/SimpleDoc.java @@ -0,0 +1,223 @@ +/* SimpleDoc.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 java.io.ByteArrayInputStream; +import java.io.CharArrayReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; + +import javax.print.attribute.AttributeSetUtilities; +import javax.print.attribute.DocAttributeSet; + +/** + * Simple implementation of the <code>Doc</code> interface capable of handling + * the predefined document flavors of <code>DocFlavor</code>. + * <p> + * This implementation can construct a reader or stream for the service from + * the print data and ensures that always the same object is returned on each + * method call. It does simple checks that the supplied data matches the + * specified flavor of the doc object and supports thread safe access. + * </p> + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class SimpleDoc implements Doc +{ + private final Object printData; + private final DocFlavor flavor; + private final DocAttributeSet attributes; + + private InputStream stream; + private Reader reader; + + /** + * Constructs a SimpleDoc with the specified print data, doc flavor and doc attribute set. + * @param printData the object with the data to print. + * @param flavor the document flavor of the print data. + * @param attributes the attributes of the doc (may be <code>null</code>). + * + * @throws IllegalArgumentException if either <code>printData</code> or + * <code>flavor</code> are <code>null</code>, or the print data is not + * supplied in the document format specified by the given flavor object. + */ + public SimpleDoc(Object printData, DocFlavor flavor, + DocAttributeSet attributes) + { + if (printData == null || flavor == null) + throw new IllegalArgumentException("printData/flavor may not be null"); + + if (! (printData.getClass().getName().equals( + flavor.getRepresentationClassName()) + || flavor.getRepresentationClassName().equals("java.io.Reader") + && printData instanceof Reader + || flavor.getRepresentationClassName().equals("java.io.InputStream") + && printData instanceof InputStream)) + { + throw new IllegalArgumentException("data is not of declared flavor type"); + } + + this.printData = printData; + this.flavor = flavor; + + if (attributes != null) + this.attributes = AttributeSetUtilities.unmodifiableView(attributes); + else + this.attributes = null; + + stream = null; + reader = null; + } + + /** + * Returns the unmodifiable view of the attributes of this doc object. + * <p> + * The attributes of this doc's attributes set overrides attributes of + * the same category in the print job's attribute set. If an attribute + * is not available in this doc's attributes set or <code>null</code> + * is returned the attributes of the same category of the print job are + * used. + * </p> + * + * @return The unmodifiable attributes set, or <code>null</code>. + */ + public DocAttributeSet getAttributes() + { + return attributes; + } + + /** + * Returns the flavor of this doc objects print data. + * + * @return The document flavor. + */ + public DocFlavor getDocFlavor() + { + return flavor; + } + + /** + * Returns the print data of this doc object. + * <p> + * The returned object is an instance as described by the associated + * document flavor ({@link DocFlavor#getRepresentationClassName()}) + * and can be cast to this representation class. + * </p> + * + * @return The print data in the representation class. + * @throws IOException if representation class is a stream and I/O + * exception occures. + */ + public Object getPrintData() throws IOException + { + return printData; + } + + /** + * Returns a <code>Reader</code> object for extracting character print data + * from this document. + * <p> + * This method is supported if the document flavor is of type: + * <ul> + * <li><code>char[]</code></li> + * <li><code>java.lang.String</code></li> + * <li><code>java.io.Reader</code></li> + * </ul> + * otherwise this method returns <code>null</code>. + * </p> + * + * @return The <code>Reader</code> object, or <code>null</code>. + * + * @throws IOException if an error occurs. + */ + public Reader getReaderForText() throws IOException + { + synchronized (this) + { + // construct the reader if applicable on request + if (reader == null) + { + if (flavor instanceof DocFlavor.CHAR_ARRAY) + reader = new CharArrayReader((char[]) printData); + else if (flavor instanceof DocFlavor.STRING) + reader = new StringReader((String) printData); + else if (flavor instanceof DocFlavor.READER) + reader = (Reader) printData; + } + + return reader; + } + } + + /** + * Returns an <code>InputStream</code> object for extracting byte print data + * from this document. + * <p> + * This method is supported if the document flavor is of type: + * <ul> + * <li><code>byte[]</code></li> + * <li><code>java.io.InputStream</code></li> + * </ul> + * otherwise this method returns <code>null</code>. + * </p> + * + * @return The <code>InputStream</code> object, or <code>null</code>. + * + * @throws IOException if an error occurs. + */ + public InputStream getStreamForBytes() throws IOException + { + synchronized (this) + { + // construct the stream if applicable on request + if (stream == null) + { + if (flavor instanceof DocFlavor.BYTE_ARRAY) + stream = new ByteArrayInputStream((byte[]) printData); + else if (flavor instanceof DocFlavor.INPUT_STREAM) + stream = (InputStream) printData; + } + + return stream; + } + } + +} diff --git a/libjava/classpath/javax/print/StreamPrintService.java b/libjava/classpath/javax/print/StreamPrintService.java index 9246ea47e39..8398a734ce4 100644 --- a/libjava/classpath/javax/print/StreamPrintService.java +++ b/libjava/classpath/javax/print/StreamPrintService.java @@ -1,5 +1,5 @@ /* StreamPrintService.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,15 @@ import java.io.OutputStream; /** + * <code>StreamPrintService</code> is a special print service capable of + * printing into a supplied output stream. + * <p> + * Beside providing the same functionality as a print service it additionally + * allows to specify the output stream for the print data. A stream print + * service is obtained via the {@link javax.print.StreamPrintServiceFactory} + * by looking for services supporting a given output format type. + * </p> + * * @author Michael Koch (konqueror@gmx.de) */ public abstract class StreamPrintService implements PrintService @@ -68,16 +77,18 @@ public abstract class StreamPrintService implements PrintService } /** - * Returns the document format emited by this print service. + * Returns the document format emitted by this print service. + * The returned string is a MIME type compatible with the + * {@link DocFlavor} class. * - * @return the document format + * @return The document format of the output. */ public abstract String getOutputFormat(); /** * Returns the <code>OutputStream</code> of this object. * - * @return the <code>OutputStream</code> + * @return The <code>OutputStream</code> */ public OutputStream getOutputStream() { diff --git a/libjava/classpath/javax/print/StreamPrintServiceFactory.java b/libjava/classpath/javax/print/StreamPrintServiceFactory.java new file mode 100644 index 00000000000..90496b36af4 --- /dev/null +++ b/libjava/classpath/javax/print/StreamPrintServiceFactory.java @@ -0,0 +1,130 @@ +/* StreamPrintServiceFactory.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.classpath.ServiceFactory; + +import java.io.OutputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; + +/** + * <code>StreamPrintServiceFactory</code> provides a static method to lookup + * registered factories to construct <code>StreamPrintService</code> instances. + * <p> + * <code>StreamPrintService</code> are used to print into a provided output + * stream in the document format provided by the stream print service + * implementation. + * </p><p> + * Implementations are located and loaded automatically through the SPI JAR + * file specification. Therefore implementation classes must provide a default + * constructor for instantiation. + * </p> + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public abstract class StreamPrintServiceFactory +{ + /** + * Default public constructor. + * Used for automatic loading and instantiation through + * the SPI jar file specification. + */ + public StreamPrintServiceFactory() + { + // nothing to do + } + + /** + * Searches for matching factories providing stream print services that + * support the printing of documents with the given document flavor into + * the given output mime type. + * + * @param flavor the document flavor needed, <code>null</code> doesn't + * constrain the lookup result. + * @param outputMimeType the mime type needed, <code>null</code> doesn't + * constrain the lookup result. + * + * @return The matching <code>StreamPrintServiceFactory</code> instances. + */ + public static StreamPrintServiceFactory[] lookupStreamPrintServiceFactories( + DocFlavor flavor, String outputMimeType) + { + HashSet set = new HashSet(); + + Iterator it = + ServiceFactory.lookupProviders(StreamPrintServiceFactory.class); + + while (it.hasNext()) + { + StreamPrintServiceFactory tmp = (StreamPrintServiceFactory) it.next(); + if (tmp.getOutputFormat().equals(outputMimeType) + && Arrays.asList(tmp.getSupportedDocFlavors()).contains(flavor)) + set.add(tmp); + } + + StreamPrintServiceFactory[] tmp = new StreamPrintServiceFactory[set.size()]; + return (StreamPrintServiceFactory[]) set.toArray(tmp); + } + + /** + * Returns the output format supported by this factory. + * + * @return The mime type of the output format as string representation. + */ + public abstract String getOutputFormat(); + + /** + * Returns the document flavors this factory supports as flavors + * for the input documents. + * + * @return The array of supported document flavors. + */ + public abstract DocFlavor[] getSupportedDocFlavors(); + + /** + * Constructs a <code>StreamPrintService</code> which directs its output + * the given output stream. + * + * @param out the output stream for the produced document. + * @return The constructed stream print service. + */ + public abstract StreamPrintService getPrintService(OutputStream out); +} diff --git a/libjava/classpath/javax/print/attribute/AttributeSetUtilities.java b/libjava/classpath/javax/print/attribute/AttributeSetUtilities.java index 5d97c66f21a..f6a64ebc531 100644 --- a/libjava/classpath/javax/print/attribute/AttributeSetUtilities.java +++ b/libjava/classpath/javax/print/attribute/AttributeSetUtilities.java @@ -1,5 +1,5 @@ /* AttributeSetUtilities.java -- - Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -78,14 +78,14 @@ public final class AttributeSetUtilities private static class UnmodifiableAttributeSet implements AttributeSet, Serializable { - private AttributeSet set; + private AttributeSet attrset; public UnmodifiableAttributeSet(AttributeSet attributeSet) { if (attributeSet == null) throw new NullPointerException("attributeSet may not be null"); - this.set = attributeSet; + this.attrset = attributeSet; } public boolean add(Attribute attribute) @@ -105,32 +105,32 @@ public final class AttributeSetUtilities public boolean containsKey(Class category) { - return set.containsKey(category); + return attrset.containsKey(category); } public boolean containsValue(Attribute attribute) { - return set.containsValue(attribute); + return attrset.containsValue(attribute); } public boolean equals(Object obj) { - return set.equals(obj); + return attrset.equals(obj); } public Attribute get(Class interfaceName) { - return set.get(interfaceName); + return attrset.get(interfaceName); } public int hashCode() { - return set.hashCode(); + return attrset.hashCode(); } public boolean isEmpty() { - return set.isEmpty(); + return attrset.isEmpty(); } public boolean remove(Class category) @@ -145,12 +145,12 @@ public final class AttributeSetUtilities public int size() { - return set.size(); + return attrset.size(); } public Attribute[] toArray() { - return set.toArray(); + return attrset.toArray(); } } @@ -197,79 +197,79 @@ public final class AttributeSetUtilities private static class SynchronizedAttributeSet implements AttributeSet, Serializable { - private AttributeSet set; + private AttributeSet attrset; public SynchronizedAttributeSet(AttributeSet attributeSet) { if (attributeSet == null) throw new NullPointerException("attributeSet may not be null"); - this.set = attributeSet; + attrset = attributeSet; } public synchronized boolean add(Attribute attribute) { - return set.add(attribute); + return attrset.add(attribute); } public synchronized boolean addAll(AttributeSet attributes) { - return set.addAll(attributes); + return attrset.addAll(attributes); } public synchronized void clear() { - set.clear(); + attrset.clear(); } public synchronized boolean containsKey(Class category) { - return set.containsKey(category); + return attrset.containsKey(category); } public synchronized boolean containsValue(Attribute attribute) { - return set.containsValue(attribute); + return attrset.containsValue(attribute); } public synchronized boolean equals(Object obj) { - return set.equals(obj); + return attrset.equals(obj); } public synchronized Attribute get(Class interfaceName) { - return set.get(interfaceName); + return attrset.get(interfaceName); } public synchronized int hashCode() { - return set.hashCode(); + return attrset.hashCode(); } public synchronized boolean isEmpty() { - return set.isEmpty(); + return attrset.isEmpty(); } public synchronized boolean remove(Class category) { - return set.remove(category); + return attrset.remove(category); } public synchronized boolean remove(Attribute attribute) { - return set.remove(attribute); + return attrset.remove(attribute); } public synchronized int size() { - return set.size(); + return attrset.size(); } public synchronized Attribute[] toArray() { - return set.toArray(); + return attrset.toArray(); } } diff --git a/libjava/classpath/javax/print/attribute/DateTimeSyntax.java b/libjava/classpath/javax/print/attribute/DateTimeSyntax.java index d59193265e2..8cff702199d 100644 --- a/libjava/classpath/javax/print/attribute/DateTimeSyntax.java +++ b/libjava/classpath/javax/print/attribute/DateTimeSyntax.java @@ -102,4 +102,14 @@ public abstract class DateTimeSyntax implements Cloneable, Serializable { return value.hashCode(); } + + /** + * Returns the string representation for this object. + * + * @return The string representation. + */ + public String toString() + { + return value.toString(); + } } diff --git a/libjava/classpath/javax/print/attribute/HashAttributeSet.java b/libjava/classpath/javax/print/attribute/HashAttributeSet.java index 0db81bae540..65371ea9fa2 100644 --- a/libjava/classpath/javax/print/attribute/HashAttributeSet.java +++ b/libjava/classpath/javax/print/attribute/HashAttributeSet.java @@ -1,5 +1,5 @@ /* HashAttributeSet.java -- - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,6 +37,9 @@ exception statement from your version. */ package javax.print.attribute; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; @@ -49,8 +52,8 @@ public class HashAttributeSet implements AttributeSet, Serializable { private static final long serialVersionUID = 5311560590283707917L; - private Class interfaceName; - private HashMap attributeMap = new HashMap(); + private Class myInterface; + private transient HashMap attributeMap = new HashMap(); /** * Creates an empty <code>HashAttributeSet</code> object. @@ -112,7 +115,7 @@ public class HashAttributeSet implements AttributeSet, Serializable if (interfaceName == null) throw new NullPointerException("interfaceName may not be null"); - this.interfaceName = interfaceName; + myInterface = interfaceName; } /** @@ -192,7 +195,7 @@ public class HashAttributeSet implements AttributeSet, Serializable */ public boolean add(Attribute attribute) { - return addInternal(attribute, interfaceName); + return addInternal(attribute, myInterface); } private boolean addInternal(Attribute attribute, Class interfaceName) @@ -201,7 +204,7 @@ public class HashAttributeSet implements AttributeSet, Serializable throw new NullPointerException("attribute may not be null"); AttributeSetUtilities.verifyAttributeCategory(interfaceName, - this.interfaceName); + myInterface); Object old = attributeMap.put (attribute.getCategory(), AttributeSetUtilities.verifyAttributeValue @@ -220,7 +223,7 @@ public class HashAttributeSet implements AttributeSet, Serializable */ public boolean addAll(AttributeSet attributes) { - return addAllInternal(attributes, interfaceName); + return addAllInternal(attributes, myInterface); } private boolean addAllInternal(AttributeSet attributes, Class interfaceName) @@ -393,4 +396,24 @@ public class HashAttributeSet implements AttributeSet, Serializable return array; } + + // Implemented as specified in serialized form + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException + { + myInterface = (Class) s.readObject(); + int size = s.readInt(); + attributeMap = new HashMap(size); + for (int i=0; i < size; i++) + add((Attribute) s.readObject()); + } + + private void writeObject(ObjectOutputStream s) throws IOException + { + s.writeObject(myInterface); + s.writeInt(size()); + Iterator it = attributeMap.values().iterator(); + while (it.hasNext()) + s.writeObject(it.next()); + } } diff --git a/libjava/classpath/javax/print/attribute/standard/Compression.java b/libjava/classpath/javax/print/attribute/standard/Compression.java index d29ffa0fcaf..01891fe2369 100644 --- a/libjava/classpath/javax/print/attribute/standard/Compression.java +++ b/libjava/classpath/javax/print/attribute/standard/Compression.java @@ -1,5 +1,5 @@ /* Compression.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. @@ -91,7 +91,7 @@ public class Compression extends EnumSyntax * * @return The class <code>Compression</code> itself. */ - public Class getCategory() + public final Class getCategory() { return Compression.class; } @@ -101,7 +101,7 @@ public class Compression extends EnumSyntax * * @return The name "compression". */ - public String getName() + public final String getName() { return "compression"; } diff --git a/libjava/classpath/javax/print/attribute/standard/Finishings.java b/libjava/classpath/javax/print/attribute/standard/Finishings.java index 6d474a6ead1..963485e7b87 100644 --- a/libjava/classpath/javax/print/attribute/standard/Finishings.java +++ b/libjava/classpath/javax/print/attribute/standard/Finishings.java @@ -1,5 +1,5 @@ /* Finishings.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. @@ -238,7 +238,7 @@ public class Finishings extends EnumSyntax * * @return the class <code>Finishings</code> itself */ - public Class getCategory() + public final Class getCategory() { return Finishings.class; } @@ -248,7 +248,7 @@ public class Finishings extends EnumSyntax * * @return The name "finishings". */ - public String getName() + public final String getName() { return "finishings"; } diff --git a/libjava/classpath/javax/print/attribute/standard/JobMediaSheets.java b/libjava/classpath/javax/print/attribute/standard/JobMediaSheets.java index 75e072c54a6..04b83069c2a 100644 --- a/libjava/classpath/javax/print/attribute/standard/JobMediaSheets.java +++ b/libjava/classpath/javax/print/attribute/standard/JobMediaSheets.java @@ -1,5 +1,5 @@ /* JobMediaSheets.java -- - Copyright (C) 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -107,7 +107,7 @@ public class JobMediaSheets extends IntegerSyntax * * @return The class <code>JobMediaSheets</code> itself. */ - public Class getCategory() + public final Class getCategory() { return JobMediaSheets.class; } @@ -117,7 +117,7 @@ public class JobMediaSheets extends IntegerSyntax * * @return The name "job-media-sheets". */ - public String getName() + public final String getName() { return "job-media-sheets"; } diff --git a/libjava/classpath/javax/print/attribute/standard/JobSheets.java b/libjava/classpath/javax/print/attribute/standard/JobSheets.java index d61acfee99c..f2cfacc9ecd 100644 --- a/libjava/classpath/javax/print/attribute/standard/JobSheets.java +++ b/libjava/classpath/javax/print/attribute/standard/JobSheets.java @@ -1,5 +1,5 @@ /* JobSheets.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. @@ -88,7 +88,7 @@ public class JobSheets extends EnumSyntax * * @return The class <code>JobSheets</code> itself. */ - public Class getCategory() + public final Class getCategory() { return JobSheets.class; } @@ -98,7 +98,7 @@ public class JobSheets extends EnumSyntax * * @return The name "job-sheets". */ - public String getName() + public final String getName() { return "job-sheets"; } diff --git a/libjava/classpath/javax/print/attribute/standard/JobState.java b/libjava/classpath/javax/print/attribute/standard/JobState.java index bd09e1fb1d2..8289569c35c 100644 --- a/libjava/classpath/javax/print/attribute/standard/JobState.java +++ b/libjava/classpath/javax/print/attribute/standard/JobState.java @@ -1,5 +1,5 @@ /* JobState.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. @@ -137,7 +137,7 @@ public class JobState extends EnumSyntax * * @return The class <code>JobState</code> itself. */ - public Class getCategory() + public final Class getCategory() { return JobState.class; } @@ -147,7 +147,7 @@ public class JobState extends EnumSyntax * * @return The name "job-state". */ - public String getName() + public final String getName() { return "job-state"; } diff --git a/libjava/classpath/javax/print/attribute/standard/JobStateReason.java b/libjava/classpath/javax/print/attribute/standard/JobStateReason.java index bd831cda51f..967a6bf2e53 100644 --- a/libjava/classpath/javax/print/attribute/standard/JobStateReason.java +++ b/libjava/classpath/javax/print/attribute/standard/JobStateReason.java @@ -1,5 +1,5 @@ /* JobStateReason.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. @@ -262,7 +262,7 @@ public class JobStateReason extends EnumSyntax * * @return The class <code>JobStateReason</code> itself. */ - public Class getCategory() + public final Class getCategory() { return JobStateReason.class; } @@ -272,7 +272,7 @@ public class JobStateReason extends EnumSyntax * * @return The name "job-state-reason". */ - public String getName() + public final String getName() { return "job-state-reason"; } diff --git a/libjava/classpath/javax/print/attribute/standard/JobStateReasons.java b/libjava/classpath/javax/print/attribute/standard/JobStateReasons.java index 9dbca0cd57b..32f942b6bd7 100644 --- a/libjava/classpath/javax/print/attribute/standard/JobStateReasons.java +++ b/libjava/classpath/javax/print/attribute/standard/JobStateReasons.java @@ -131,7 +131,7 @@ public final class JobStateReasons extends HashSet if (o == null) throw new NullPointerException("reason is null"); - return add((JobStateReason) o); + return super.add((JobStateReason) o); } /** diff --git a/libjava/classpath/javax/print/attribute/standard/Media.java b/libjava/classpath/javax/print/attribute/standard/Media.java index 202a3f3f091..37132e72706 100644 --- a/libjava/classpath/javax/print/attribute/standard/Media.java +++ b/libjava/classpath/javax/print/attribute/standard/Media.java @@ -1,5 +1,5 @@ /* Media.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. @@ -105,7 +105,7 @@ public abstract class Media extends EnumSyntax * * @return The class <code>Media</code> itself. */ - public Class getCategory() + public final Class getCategory() { return Media.class; } @@ -115,7 +115,7 @@ public abstract class Media extends EnumSyntax * * @return The name "media". */ - public String getName() + public final String getName() { return "media"; } diff --git a/libjava/classpath/javax/print/attribute/standard/MediaPrintableArea.java b/libjava/classpath/javax/print/attribute/standard/MediaPrintableArea.java index 9a1342cb43f..e0366f589ad 100644 --- a/libjava/classpath/javax/print/attribute/standard/MediaPrintableArea.java +++ b/libjava/classpath/javax/print/attribute/standard/MediaPrintableArea.java @@ -1,5 +1,5 @@ /* MediaPrintableArea.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -95,9 +95,9 @@ public final class MediaPrintableArea /** y in micrometers. */ private int y; /** width in micrometers. */ - private int width; + private int w; /** height in micrometers. */ - private int height; + private int h; /** * Creates a new <code>MediaPrintableArea</code> object with the given @@ -119,8 +119,8 @@ public final class MediaPrintableArea this.x = (int) (x * units + 0.5f); this.y = (int) (y * units + 0.5f); - this.width = (int) (w * units + 0.5f); - this.height = (int) (h * units + 0.5f); + this.w = (int) (w * units + 0.5f); + this.h = (int) (h * units + 0.5f); } /** @@ -143,8 +143,8 @@ public final class MediaPrintableArea this.x = x * units; this.y = y * units; - this.width = w * units; - this.height = h * units; + this.w = w * units; + this.h = h * units; } /** @@ -180,7 +180,7 @@ public final class MediaPrintableArea if (units < 1) throw new IllegalArgumentException("units may not be less than 1"); - return height / ((float)units); + return h / ((float)units); } /** @@ -196,7 +196,7 @@ public final class MediaPrintableArea if (units < 1) throw new IllegalArgumentException("units may not be less than 1"); - return width / ((float)units); + return w / ((float)units); } /** @@ -248,7 +248,7 @@ public final class MediaPrintableArea MediaPrintableArea tmp = (MediaPrintableArea) obj; return (x == tmp.getX(1) && y == tmp.getY(1) - && width == tmp.getWidth(1) && height == tmp.getHeight(1)); + && w == tmp.getWidth(1) && h == tmp.getHeight(1)); } /** @@ -270,7 +270,7 @@ public final class MediaPrintableArea */ public int hashCode() { - return x ^ y + width ^ height; + return x ^ y + w ^ h; } /** diff --git a/libjava/classpath/javax/print/attribute/standard/MediaSize.java b/libjava/classpath/javax/print/attribute/standard/MediaSize.java index 00bcb34954f..982b5c5ef7b 100644 --- a/libjava/classpath/javax/print/attribute/standard/MediaSize.java +++ b/libjava/classpath/javax/print/attribute/standard/MediaSize.java @@ -1,5 +1,5 @@ /* MediaSize.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -72,7 +72,14 @@ public class MediaSize extends Size2DSyntax static { mediaCache = new ArrayList(); - + + // We call one instance of every container class to make sure it gets + // loaded during class initialization and therefore all other static + // fields of this container class also. + + // This is needed to put all MediaSize instance into the mediaCache + // for use by the static methods in this class. + MediaSize tmp = MediaSize.ISO.A0; tmp = MediaSize.JIS.B0; tmp = MediaSize.Engineering.A; @@ -80,16 +87,21 @@ public class MediaSize extends Size2DSyntax tmp = MediaSize.Other.EXECUTIVE; } - private MediaSizeName media; + private MediaSizeName mediaName; /** - * Creates a <code>MediaSize</code> object. + * Creates a <code>MediaSize</code> object. The created object will be added + * to an internal cache used in the static methods of this class for lookup + * of available <code>MediaSize</code> instances. * * @param x the size in x direction * @param y the size in y direction * @param units the units to use for the sizes * * @exception IllegalArgumentException if x or y < 0 or units < 1 + * + * @see #findMedia(float, float, int) + * @see #getMediaSizeForName(MediaSizeName) */ public MediaSize(float x, float y, int units) { @@ -99,7 +111,9 @@ public class MediaSize extends Size2DSyntax /** * Creates a <code>MediaSize</code> object associated with the given - * media name. + * media name. The created object will be added to an internal cache used + * in the static methods of this class for lookup of available + * <code>MediaSize</code> instances. * * @param x the size in x direction * @param y the size in y direction @@ -107,22 +121,30 @@ public class MediaSize extends Size2DSyntax * @param media the media name to associate * * @exception IllegalArgumentException if x or y < 0 or units < 1 + * + * @see #findMedia(float, float, int) + * @see #getMediaSizeForName(MediaSizeName) */ public MediaSize(float x, float y, int units, MediaSizeName media) { super(x, y, units); - this.media = media; + mediaName = media; mediaCache.add(this); } /** - * Creates a <code>MediaSize</code> object. + * Creates a <code>MediaSize</code> object. The created object will be added + * to an internal cache used in the static methods of this class for lookup + * of available <code>MediaSize</code> instances. * * @param x the size in x direction * @param y the size in y direction * @param units the units to use for the sizes * * @exception IllegalArgumentException if x or y < 0 or units < 1 + * + * @see #findMedia(float, float, int) + * @see #getMediaSizeForName(MediaSizeName) */ public MediaSize(int x, int y, int units) { @@ -132,7 +154,9 @@ public class MediaSize extends Size2DSyntax /** * Creates a <code>MediaSize</code> object associated with the given - * media name. + * media name. The created object will be added to an internal cache used + * in the static methods of this class for lookup of available + * <code>MediaSize</code> instances. * * @param x the size in x direction * @param y the size in y direction @@ -140,11 +164,14 @@ public class MediaSize extends Size2DSyntax * @param media the media name to associate * * @exception IllegalArgumentException if x or y < 0 or units < 1 + * + * @see #findMedia(float, float, int) + * @see #getMediaSizeForName(MediaSizeName) */ public MediaSize(int x, int y, int units, MediaSizeName media) { super(x, y, units); - this.media = media; + mediaName = media; mediaCache.add(this); } @@ -153,7 +180,7 @@ public class MediaSize extends Size2DSyntax * * @return The class <code>MediaSize</code> itself. */ - public Class getCategory() + public final Class getCategory() { return MediaSize.class; } @@ -246,7 +273,7 @@ public class MediaSize extends Size2DSyntax */ public MediaSizeName getMediaSizeName() { - return media; + return mediaName; } /** @@ -254,7 +281,7 @@ public class MediaSize extends Size2DSyntax * * @return The name "media-size". */ - public String getName() + public final String getName() { return "media-size"; } @@ -266,7 +293,11 @@ public class MediaSize extends Size2DSyntax */ public static final class ISO { - + private ISO() + { + // prevent instantiation + } + /** * ISO A0 paper, 841 mm x 1189 mm. */ @@ -415,6 +446,11 @@ public class MediaSize extends Size2DSyntax */ public static final class NA { + private NA() + { + // prevent instantiation + } + /** * US Legal paper size, 8.5 inch x 14 inch */ @@ -530,6 +566,11 @@ public class MediaSize extends Size2DSyntax */ public static final class Engineering { + private Engineering() + { + // prevent instantiation + } + /** * ANSI A paper size. 8.5 inch x 11 inch */ @@ -568,6 +609,11 @@ public class MediaSize extends Size2DSyntax */ public static final class JIS { + private JIS() + { + // prevent instantiation + } + /** * JIS B0 paper. 1030 mm x 1456 mm * Note: The JIS B-series is not identical to the ISO B-series. @@ -762,6 +808,11 @@ public class MediaSize extends Size2DSyntax */ public static final class Other { + private Other() + { + // prevent instantiation + } + /** * US Executive paper size, 7.25 inch x 10.5 inch */ @@ -820,6 +871,13 @@ public class MediaSize extends Size2DSyntax * Japanese double postcard, 148 mm x 200 mm */ public static final MediaSize JAPANESE_DOUBLE_POSTCARD = new MediaSize(148, 200, MediaSize.MM, MediaSizeName.JAPANESE_DOUBLE_POSTCARD); + + /** + * Tabloid size, 11 inch x 17 inch. + * @since 1.5 + */ + public static final MediaSize TABLOID = + new MediaSize(11, 17, Size2DSyntax.INCH, MediaSizeName.TABLOID); } } diff --git a/libjava/classpath/javax/print/attribute/standard/MultipleDocumentHandling.java b/libjava/classpath/javax/print/attribute/standard/MultipleDocumentHandling.java index 1ed0c913830..1a89fd01aef 100644 --- a/libjava/classpath/javax/print/attribute/standard/MultipleDocumentHandling.java +++ b/libjava/classpath/javax/print/attribute/standard/MultipleDocumentHandling.java @@ -1,5 +1,5 @@ /* MultipleDocumentHandling.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -108,7 +108,7 @@ public class MultipleDocumentHandling extends EnumSyntax * * @return The class <code>MultipleDocumentHandling</code> itself. */ - public Class getCategory() + public final Class getCategory() { return MultipleDocumentHandling.class; } @@ -118,7 +118,7 @@ public class MultipleDocumentHandling extends EnumSyntax * * @return The name "multiple-document-handling". */ - public String getName() + public final String getName() { return "multiple-document-handling"; } diff --git a/libjava/classpath/javax/print/attribute/standard/PDLOverrideSupported.java b/libjava/classpath/javax/print/attribute/standard/PDLOverrideSupported.java index d3be3e5522a..ee07edb1af5 100644 --- a/libjava/classpath/javax/print/attribute/standard/PDLOverrideSupported.java +++ b/libjava/classpath/javax/print/attribute/standard/PDLOverrideSupported.java @@ -1,5 +1,5 @@ /* PDLOverrideSupported.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. @@ -91,7 +91,7 @@ public class PDLOverrideSupported extends EnumSyntax * * @return The class <code>PDLOverrideSupported</code> itself. */ - public Class getCategory() + public final Class getCategory() { return PDLOverrideSupported.class; } @@ -101,7 +101,7 @@ public class PDLOverrideSupported extends EnumSyntax * * @return The name "pdl-override-supported". */ - public String getName() + public final String getName() { return "pdl-override-supported"; } diff --git a/libjava/classpath/javax/print/attribute/standard/PrintQuality.java b/libjava/classpath/javax/print/attribute/standard/PrintQuality.java index 2f1a105ce54..c581d5f9dbe 100644 --- a/libjava/classpath/javax/print/attribute/standard/PrintQuality.java +++ b/libjava/classpath/javax/print/attribute/standard/PrintQuality.java @@ -1,5 +1,5 @@ /* PrintQuality.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. @@ -92,7 +92,7 @@ public class PrintQuality extends EnumSyntax * * @return The class <code>PrintQuality</code> itself. */ - public Class getCategory() + public final Class getCategory() { return PrintQuality.class; } @@ -102,7 +102,7 @@ public class PrintQuality extends EnumSyntax * * @return The name "print-quality". */ - public String getName() + public final String getName() { return "print-quality"; } diff --git a/libjava/classpath/javax/print/attribute/standard/PrinterIsAcceptingJobs.java b/libjava/classpath/javax/print/attribute/standard/PrinterIsAcceptingJobs.java index 51f96c11d6b..96dbc57ce32 100644 --- a/libjava/classpath/javax/print/attribute/standard/PrinterIsAcceptingJobs.java +++ b/libjava/classpath/javax/print/attribute/standard/PrinterIsAcceptingJobs.java @@ -55,7 +55,7 @@ import javax.print.attribute.PrintServiceAttribute; * @author Michael Koch (konqueror@gmx.de) * @author Wolfgang Baer (WBaer@gmx.de) */ -public class PrinterIsAcceptingJobs extends EnumSyntax +public final class PrinterIsAcceptingJobs extends EnumSyntax implements PrintServiceAttribute { private static final long serialVersionUID = -5052010680537678061L; diff --git a/libjava/classpath/javax/print/attribute/standard/PrinterStateReason.java b/libjava/classpath/javax/print/attribute/standard/PrinterStateReason.java index 3a13585441b..340bfbabf51 100644 --- a/libjava/classpath/javax/print/attribute/standard/PrinterStateReason.java +++ b/libjava/classpath/javax/print/attribute/standard/PrinterStateReason.java @@ -1,5 +1,5 @@ /* PrinterStateReason.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. @@ -293,7 +293,7 @@ public class PrinterStateReason extends EnumSyntax * * @return The class <code>PrintStateReason</code> itself. */ - public Class getCategory() + public final Class getCategory() { return PrinterStateReason.class; } @@ -303,7 +303,7 @@ public class PrinterStateReason extends EnumSyntax * * @return The name "printer-state-reason". */ - public String getName() + public final String getName() { return "printer-state-reason"; } diff --git a/libjava/classpath/javax/print/attribute/standard/PrinterStateReasons.java b/libjava/classpath/javax/print/attribute/standard/PrinterStateReasons.java index 67f160d42fc..40c6f1b7151 100644 --- a/libjava/classpath/javax/print/attribute/standard/PrinterStateReasons.java +++ b/libjava/classpath/javax/print/attribute/standard/PrinterStateReasons.java @@ -178,7 +178,7 @@ public final class PrinterStateReasons extends HashMap if (severity == null) throw new NullPointerException("severity is null"); - return put((PrinterStateReason) reason, (Severity) severity); + return super.put((PrinterStateReason) reason, (Severity) severity); } /** diff --git a/libjava/classpath/javax/print/attribute/standard/ReferenceUriSchemesSupported.java b/libjava/classpath/javax/print/attribute/standard/ReferenceUriSchemesSupported.java index 8a00218b8b7..aeccaac5b5a 100644 --- a/libjava/classpath/javax/print/attribute/standard/ReferenceUriSchemesSupported.java +++ b/libjava/classpath/javax/print/attribute/standard/ReferenceUriSchemesSupported.java @@ -1,5 +1,5 @@ /* ReferenceUriSchemesSupported.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. @@ -128,7 +128,7 @@ public class ReferenceUriSchemesSupported extends EnumSyntax * * @return The class <code>ReferenceUriSchemesSupported</code> itself. */ - public Class getCategory() + public final Class getCategory() { return ReferenceUriSchemesSupported.class; } @@ -138,7 +138,7 @@ public class ReferenceUriSchemesSupported extends EnumSyntax * * @return The name "reference-uri-schemes-supported". */ - public String getName() + public final String getName() { return "reference-uri-schemes-supported"; } diff --git a/libjava/classpath/javax/security/auth/login/AppConfigurationEntry.java b/libjava/classpath/javax/security/auth/login/AppConfigurationEntry.java index 557d3d7f89f..b455dbb6c24 100644 --- a/libjava/classpath/javax/security/auth/login/AppConfigurationEntry.java +++ b/libjava/classpath/javax/security/auth/login/AppConfigurationEntry.java @@ -1,5 +1,5 @@ /* AppConfigurationEntry.java - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,7 +44,6 @@ import java.util.Map; public class AppConfigurationEntry { - // Fields. // ------------------------------------------------------------------------- @@ -61,13 +60,16 @@ public class AppConfigurationEntry { if (loginModuleName == null || loginModuleName.length() == 0) throw new IllegalArgumentException ("module name cannot be null nor empty"); + if (LoginModuleControlFlag.OPTIONAL != controlFlag && LoginModuleControlFlag.REQUIRED != controlFlag && LoginModuleControlFlag.REQUISITE != controlFlag && LoginModuleControlFlag.SUFFICIENT != controlFlag) throw new IllegalArgumentException ("invalid controlFlag"); + if (options == null) throw new IllegalArgumentException ("options cannot be null"); + this.loginModuleName = loginModuleName; this.controlFlag = controlFlag; this.options = Collections.unmodifiableMap (new HashMap (options)); @@ -91,7 +93,17 @@ public class AppConfigurationEntry return options; } -// Inner class. + // Object methods ---------------------------------------------------------- + + public String toString() + { + + return loginModuleName + "\t" + + String.valueOf(controlFlag) + "\t" + + String.valueOf(options); + } + + // Inner class. // ------------------------------------------------------------------------- public static class LoginModuleControlFlag @@ -117,19 +129,15 @@ public class AppConfigurationEntry public String toString() { - StringBuffer buf = new StringBuffer (LoginModuleControlFlag.class.getName()); - buf.append ('.'); - if (this == OPTIONAL) - buf.append ("OPTIONAL"); - else if (this == REQUIRED) - buf.append ("REQUIRED"); - else if (this == REQUISITE) - buf.append ("REQUISITE"); - else if (this == SUFFICIENT) - buf.append ("SUFFICIENT"); - else - buf.append ("HARVEY_THE_RABBIT"); - return buf.toString(); + if (this == LoginModuleControlFlag.REQUIRED) + return "REQUIRED"; + if (this == LoginModuleControlFlag.REQUISITE) + return "REQUISITE"; + if (this == LoginModuleControlFlag.SUFFICIENT) + return "SUFFICIENT"; + if (this == LoginModuleControlFlag.OPTIONAL) + return "OPTIONAL"; + return "???"; } } } diff --git a/libjava/classpath/javax/security/auth/login/Configuration.java b/libjava/classpath/javax/security/auth/login/Configuration.java index eb5e4a81979..fe56f8a5909 100644 --- a/libjava/classpath/javax/security/auth/login/Configuration.java +++ b/libjava/classpath/javax/security/auth/login/Configuration.java @@ -1,5 +1,5 @@ /* Configuration.java - 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.security.auth.login; +import gnu.javax.security.auth.login.GnuConfiguration; + import java.security.AccessController; import java.security.PrivilegedAction; import java.security.Security; @@ -46,7 +48,6 @@ import javax.security.auth.AuthPermission; public abstract class Configuration { - // Fields. // ------------------------------------------------------------------------- @@ -108,11 +109,11 @@ public abstract class Configuration if (conf != null) config = (Configuration) Class.forName (conf).newInstance(); else - config = new NullConfiguration(); + config = new GnuConfiguration(); } catch (Exception x) { - config = new NullConfiguration(); + config = new GnuConfiguration(); } } return config; diff --git a/libjava/classpath/javax/sound/sampled/LineEvent.java b/libjava/classpath/javax/sound/sampled/LineEvent.java index 7bba2cd1d96..db925935b4a 100644 --- a/libjava/classpath/javax/sound/sampled/LineEvent.java +++ b/libjava/classpath/javax/sound/sampled/LineEvent.java @@ -38,16 +38,24 @@ exception statement from your version. */ package javax.sound.sampled; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.EventObject; -// FIXME: attempts to serialize this should fail - /** * This class holds information about a state change of a Line. + * @specnote This class is not really serializable, and attempts to + * serialize it will throw {@link NotSerializableException}. * @since 1.3 */ public class LineEvent extends EventObject { + // We define this even though this class can't be serialized, in + // order to placate the compiler. + private static final long serialVersionUID = -1274246333383880410L; + /** * This class represents the kinds of state changes that can occur * to a Line. The standard states are availabe as static instances. @@ -147,4 +155,16 @@ public class LineEvent extends EventObject return ("type=" + type + "; framePosition=" + framePosition + "line=" + line); } + + private void readObject(ObjectInputStream ois) + throws IOException + { + throw new NotSerializableException("LineEvent is not serializable"); + } + + private void writeObject(ObjectOutputStream oos) + throws IOException + { + throw new NotSerializableException("LineEvent is not serializable"); + } } diff --git a/libjava/classpath/javax/swing/AbstractAction.java b/libjava/classpath/javax/swing/AbstractAction.java index bd3167e1e93..4a2334570aa 100644 --- a/libjava/classpath/javax/swing/AbstractAction.java +++ b/libjava/classpath/javax/swing/AbstractAction.java @@ -1,5 +1,5 @@ /* AbstractAction.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,7 @@ exception statement from your version. */ package javax.swing; +import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.io.ObjectInputStream; @@ -74,28 +75,30 @@ public abstract class AbstractAction private transient HashMap store = new HashMap(); /** - * Creates a new action with an empty string for the name. All other - * properties are initialised to <code>null</code> + * Creates a new action with no properties set. */ public AbstractAction() { - this(null); + // Nothing to do. } /** - * Creates a new action with the specified name. All other properties are - * initialised to <code>null</code>. + * Creates a new action with the specified name. The name is stored as a + * property with the key {@link Action#NAME}, and no other properties are + * initialised. * * @param name the name (<code>null</code> permitted). */ public AbstractAction(String name) { - this(name, null); + putValue(NAME, name); } /** - * Creates a new action with the specified name and icon. All other - * properties are initialised to <code>null</code>. + * Creates a new action with the specified name and icon. The name is stored + * as a property with the key {@link Action#NAME}, the icon is stored as a + * property with the key {@link Action#SMALL_ICON}, and no other properties + * are initialised. * * @param name the name (<code>null</code> permitted). * @param icon the icon (<code>null</code> permitted). @@ -133,11 +136,12 @@ public abstract class AbstractAction } /** - * clone + * Returns a clone of the action. * - * @return Object + * @return A clone of the action. * - * @exception CloneNotSupportedException TODO + * @exception CloneNotSupportedException if there is a problem cloning the + * action. */ protected Object clone() throws CloneNotSupportedException { @@ -153,6 +157,8 @@ public abstract class AbstractAction * * @return The value associated with the specified key, or * <code>null</code> if the key is not found. + * + * @see #putValue(String, Object) */ public Object getValue(String key) { @@ -162,11 +168,17 @@ public abstract class AbstractAction /** * Sets the value associated with the specified key and sends a * {@link java.beans.PropertyChangeEvent} to all registered listeners. - * The standard keys are: {@link #NAME}, {@link #SHORT_DESCRIPTION}, - * {@link #LONG_DESCRIPTION}, {@link #SMALL_ICON}, - * {@link #ACTION_COMMAND_KEY}, {@link #ACCELERATOR_KEY} and - * {@link #MNEMONIC_KEY}. Any existing value associated with the key will be - * overwritten. + * The standard keys are: + * <ul> + * <li>{@link #NAME}</li> + * <li>{@link #SHORT_DESCRIPTION}</li> + * <li>{@link #LONG_DESCRIPTION}</li> + * <li>{@link #SMALL_ICON}</li> + * <li>{@link #ACTION_COMMAND_KEY}</li> + * <li>{@link #ACCELERATOR_KEY}</li> + * <li>{@link #MNEMONIC_KEY}</li> + * </ul> + * Any existing value associated with the key will be overwritten. * * @param key the key (not <code>null</code>). * @param value the value (<code>null</code> permitted). @@ -174,7 +186,7 @@ public abstract class AbstractAction public void putValue(String key, Object value) { Object old = getValue(key); - if (old == null || !old.equals(value)) + if ((old == null && value != null) || (old != null && !old.equals(value))) { store.put(key, value); firePropertyChange(key, old, value); @@ -185,6 +197,8 @@ public abstract class AbstractAction * Returns the flag that indicates whether or not the action is enabled. * * @return The flag. + * + * @see #setEnabled(boolean) */ public boolean isEnabled() { @@ -194,9 +208,12 @@ public abstract class AbstractAction /** * Sets the flag that indicates whether or not the action is enabled and, if * the value of the flag changed from the previous setting, sends a - * {@link java.beans.PropertyChangeEvent} to all registered listeners. + * {@link java.beans.PropertyChangeEvent} to all registered listeners (using + * the property name 'enabled'). * * @param enabled the new flag value. + * + * @see #isEnabled() */ public void setEnabled(boolean enabled) { @@ -208,8 +225,11 @@ public abstract class AbstractAction } /** - * getKeys - * @returns Object[] + * Returns an array of the keys for the property values that have been + * defined via the {@link #putValue(String, Object)} method (or the class + * constructor). + * + * @return An array of keys. */ public Object[] getKeys() { @@ -217,12 +237,12 @@ public abstract class AbstractAction } /** - * This method fires a PropertyChangeEvent given the propertyName - * and the old and new values. + * Sends a {@link PropertyChangeEvent} for the named property to all + * registered listeners. * - * @param propertyName The property that changed. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. + * @param propertyName the property name. + * @param oldValue the old value of the property. + * @param newValue the new value of the property. */ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) @@ -231,22 +251,27 @@ public abstract class AbstractAction } /** - * This convenience method fires a PropertyChangeEvent given - * the propertyName and the old and new values. + * Sends a {@link PropertyChangeEvent} for the named property to all + * registered listeners. This private method is called by the + * {@link #setEnabled(boolean)} method. * - * @param propertyName The property that changed. - * @param oldValue The old value of the property. - * @param newValue The new value of the property. + * @param propertyName the property name. + * @param oldValue the old value of the property. + * @param newValue the new value of the property. */ - private void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) + private void firePropertyChange(String propertyName, boolean oldValue, + boolean newValue) { changeSupport.firePropertyChange(propertyName, oldValue, newValue); } /** - * addPropertyChangeListener + * Registers a listener to receive {@link PropertyChangeEvent} notifications + * from this action. * - * @param listener the listener to add + * @param listener the listener. + * + * @see #removePropertyChangeListener(PropertyChangeListener) */ public void addPropertyChangeListener(PropertyChangeListener listener) { @@ -254,9 +279,12 @@ public abstract class AbstractAction } /** - * removePropertyChangeListener + * Deregisters a listener so that it no longer receives + * {@link PropertyChangeEvent} notifications from this action. * - * @param listener the listener to remove + * @param listener the listener. + * + * @see #addPropertyChangeListener(PropertyChangeListener) */ public void removePropertyChangeListener(PropertyChangeListener listener) { @@ -266,7 +294,7 @@ public abstract class AbstractAction /** * Returns all registered listeners. * - * @return array of listeners. + * @return An array of listeners. * * @since 1.4 */ diff --git a/libjava/classpath/javax/swing/AbstractButton.java b/libjava/classpath/javax/swing/AbstractButton.java index 376b3a056ae..3d289084e20 100644 --- a/libjava/classpath/javax/swing/AbstractButton.java +++ b/libjava/classpath/javax/swing/AbstractButton.java @@ -159,6 +159,14 @@ public abstract class AbstractButton extends JComponent private static final long serialVersionUID = 1471056094226600578L; /** + * The spec has no public/protected constructor for this class, so do we. + */ + ButtonChangeListener() + { + // Nothing to do here. + } + + /** * Notified when the target of the listener changes its state. * * @param ev the ChangeEvent describing the change diff --git a/libjava/classpath/javax/swing/AbstractCellEditor.java b/libjava/classpath/javax/swing/AbstractCellEditor.java index 4ed15809a83..df0d3db12b5 100644 --- a/libjava/classpath/javax/swing/AbstractCellEditor.java +++ b/libjava/classpath/javax/swing/AbstractCellEditor.java @@ -1,5 +1,5 @@ /* AbstractCellEditor.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. @@ -69,10 +69,11 @@ public abstract class AbstractCellEditor /** * Creates a new instance of AbstractCellEditor. */ - public AbstractCellEditor() { + public AbstractCellEditor() + { listenerList = new EventListenerList(); changeEvent = new ChangeEvent(this); - } // AbstractCellEditor() + } /** * Returns <code>true</code> if the cell is editable using @@ -84,9 +85,10 @@ public abstract class AbstractCellEditor * @return <code>true</code> if the cell is editable using * <code>event</code>, <code>false</code> if it's not */ - public boolean isCellEditable(EventObject event) { + public boolean isCellEditable(EventObject event) + { return true; - } // isCellEditable() + } /** * Returns <code>true</code> if the editing cell should be selected, @@ -99,29 +101,32 @@ public abstract class AbstractCellEditor * @return <code>true</code> if the editing cell should be selected, * <code>false</code> otherwise */ - public boolean shouldSelectCell(EventObject event) { + public boolean shouldSelectCell(EventObject event) + { return true; - } // shouldSelectCell() + } /** * Stop editing the cell and accept any partial value that has been entered * into the cell. * - * @returns <code>true</code> if editing has been stopped successfully, + * @return <code>true</code> if editing has been stopped successfully, * <code>false</code>otherwise */ - public boolean stopCellEditing() { + public boolean stopCellEditing() + { fireEditingStopped(); return true; - } // stopCellEditing() + } /** * Stop editing the cell and do not accept any partial value that has * been entered into the cell. */ - public void cancelCellEditing() { + public void cancelCellEditing() + { fireEditingCanceled(); - } // cancelCellEditing() + } /** * Adds a CellEditorListener to the list of CellEditorListeners of this diff --git a/libjava/classpath/javax/swing/AbstractListModel.java b/libjava/classpath/javax/swing/AbstractListModel.java index 8973e529232..4b89689ddda 100644 --- a/libjava/classpath/javax/swing/AbstractListModel.java +++ b/libjava/classpath/javax/swing/AbstractListModel.java @@ -1,5 +1,5 @@ /* AbstractListModel.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. @@ -58,6 +58,9 @@ public abstract class AbstractListModel implements ListModel, Serializable /** List of ListDataListeners called for each change to the list. */ protected EventListenerList listenerList; + /** + * Creates a new model instance - initialises the event listener list. + */ public AbstractListModel() { listenerList = new EventListenerList(); @@ -88,7 +91,7 @@ public abstract class AbstractListModel implements ListModel, Serializable /** * Call {@link ListDataListener#contentsChanged} on each element of the * {@link #listenerList} which is a {@link ListDataListener}. The event - * fired has type {@ListDataEvent.CONTENTS_CHANGED} and represents a + * fired has type {@link ListDataEvent#CONTENTS_CHANGED} and represents a * change to the data elements in the range [startIndex, endIndex] * inclusive. * @@ -110,7 +113,7 @@ public abstract class AbstractListModel implements ListModel, Serializable /** * Call {@link ListDataListener#intervalAdded} on each element of the * {@link #listenerList} which is a {@link ListDataListener}. The event - * fired has type {@ListDataEvent.INTERVAL_ADDED} and represents an + * fired has type {@link ListDataEvent#INTERVAL_ADDED} and represents an * addition of the data elements in the range [startIndex, endIndex] * inclusive. * @@ -132,7 +135,7 @@ public abstract class AbstractListModel implements ListModel, Serializable /** * Call {@link ListDataListener#intervalRemoved} on each element of the * {@link #listenerList} which is a {@link ListDataListener}. The event - * fired has type {@ListDataEvent.INTERVAL_REMOVED} and represents a + * fired has type {@link ListDataEvent#INTERVAL_REMOVED} and represents a * removal of the data elements in the range [startIndex, endIndex] * inclusive. * diff --git a/libjava/classpath/javax/swing/CellEditor.java b/libjava/classpath/javax/swing/CellEditor.java index 3d229b26675..9eb083ab25d 100644 --- a/libjava/classpath/javax/swing/CellEditor.java +++ b/libjava/classpath/javax/swing/CellEditor.java @@ -1,5 +1,5 @@ /* CellEditor.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. @@ -41,6 +41,7 @@ package javax.swing; import java.util.EventObject; import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; /** * Provides edit capabilities for components that display cells like @@ -51,46 +52,57 @@ import javax.swing.event.CellEditorListener; public interface CellEditor { /** - * getCellEditorValue - * @returns Object + * Returns the current value for the <code>CellEditor</code>. + * + * @return The value. */ Object getCellEditorValue(); /** - * isCellEditable - * @param event TODO - * @returns boolean + * Returns <code>true</code> if the specified event makes the editor + * editable, and <code>false</code> otherwise. + * + * @param event the event. + * + * @return A boolean. */ boolean isCellEditable(EventObject event); /** * shouldSelectCell * @param event TODO - * @returns boolean + * @return boolean */ boolean shouldSelectCell(EventObject event); /** - * stopCellEditing - * @returns boolean + * Signals to the <code>CellEditor</code> that it should stop editing, + * accepting the current cell value, and returns <code>true</code> if the + * editor actually stops editing, and <code>false</code> otherwise. + * + * @return A boolean. */ boolean stopCellEditing(); /** - * cancelCellEditing + * Signals to the <code>CellEditor</code> that it should cancel editing. */ void cancelCellEditing(); /** - * addCellEditorListener - * @param listener TODO + * Registers a listener to receive {@link ChangeEvent} notifications from the + * <code>CellEditor</code>. + * + * @param listener the listener. */ void addCellEditorListener(CellEditorListener listener); /** - * removeCellEditorListener - * @param listener TODO + * Deregisters a listener so that it no longer receives {@link ChangeEvent} + * notifications from the <code>CellEditor</code>. + * + * @param listener the listener. */ void removeCellEditorListener(CellEditorListener listener); -} // CellEditor +} diff --git a/libjava/classpath/javax/swing/CellRendererPane.java b/libjava/classpath/javax/swing/CellRendererPane.java index c59afd3188a..b3d6f6a7364 100644 --- a/libjava/classpath/javax/swing/CellRendererPane.java +++ b/libjava/classpath/javax/swing/CellRendererPane.java @@ -1,5 +1,5 @@ /* CellRendererPane.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. @@ -75,7 +75,7 @@ public class CellRendererPane extends Container implements Accessible /** * getAccessibleRole - * @returns AccessibleRole + * @return AccessibleRole */ public AccessibleRole getAccessibleRole() { @@ -169,24 +169,32 @@ public class CellRendererPane extends Container implements Accessible addImpl(c, null, 0); Rectangle oldClip = graphics.getClipBounds(); - // translate to (x,y) - graphics.translate(x, y); - graphics.clipRect(0, 0, w, h); - // set bounds of c - c.setBounds(0, 0, w, h); - - // validate if necessary - if (shouldValidate) + boolean translated = false; + try { - c.validate(); + // translate to (x,y) + graphics.translate(x, y); + translated = true; + graphics.clipRect(0, 0, w, h); + // set bounds of c + c.setBounds(0, 0, w, h); + + // validate if necessary + if (shouldValidate) + { + c.validate(); + } + + // paint component + c.paint(graphics); + } + finally + { + // untranslate g + if (translated) + graphics.translate(-x, -y); + graphics.setClip(oldClip); } - - // paint component - c.paint(graphics); - - // untranslate g - graphics.translate(-x, -y); - graphics.setClip(oldClip); } /** diff --git a/libjava/classpath/javax/swing/ComboBoxModel.java b/libjava/classpath/javax/swing/ComboBoxModel.java index 6968db49091..61052758758 100644 --- a/libjava/classpath/javax/swing/ComboBoxModel.java +++ b/libjava/classpath/javax/swing/ComboBoxModel.java @@ -1,5 +1,5 @@ /* ComboBoxModel.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,31 +37,33 @@ exception statement from your version. */ package javax.swing; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; /** - * The data model for {@link JComboBox}. This model keeps - * track of elements contained in the JComboBox as well as the current - * combo box selection. Whenever selection in the JComboBox changes, the - * ComboBoxModel should fire ListDataEvents to ComboBox's ListDataListeners. + * The data model for a {@link JComboBox}. This model keeps track of elements + * contained in the <code>JComboBox</code> as well as the current + * combo box selection. Whenever the selection in the <code>JComboBox</code> + * changes, the <code>ComboBoxModel</code> should fire a {@link ListDataEvent} + * to the model's {@link ListDataListener}s. * * @author Andrew Selkirk */ public interface ComboBoxModel extends ListModel { /** - * This method sets the selected item in the combo box. Class - * implementing this interface should fire ListDataEvents to - * all registered ListDataListeners to indicated that the - * selection has changed. + * Sets the selected item in the combo box. Classes implementing this + * interface should fire a {@link ListDataEvent} to all registered + * {@link ListDataListener}s to indicate that the selection has changed. * - * @param item item in the combo box that should be selected + * @param item the selected item (<code>null</code> permitted). */ void setSelectedItem(Object item); /** - * The method returns currently selected item in the combo box + * Returns the currently selected item in the combo box. * - * @returns item that is currently selected in the combo box. + * @return The selected item (possibly <code>null</code>). */ Object getSelectedItem(); -} // ComboBoxModel +} diff --git a/libjava/classpath/javax/swing/DefaultCellEditor.java b/libjava/classpath/javax/swing/DefaultCellEditor.java index 39e48551efb..7f1c395ad03 100644 --- a/libjava/classpath/javax/swing/DefaultCellEditor.java +++ b/libjava/classpath/javax/swing/DefaultCellEditor.java @@ -1,5 +1,5 @@ /* DefaultCellEditor.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,8 +59,7 @@ import javax.swing.tree.TreeCellEditor; * some standard object types. * * @author Andrew Selkirk - * - * @status mostly unimplemented + * @author Audrius Meskauskas */ public class DefaultCellEditor extends AbstractCellEditor @@ -69,17 +68,26 @@ public class DefaultCellEditor private static final long serialVersionUID = 3564035141373880027L; /** - * Delegates a couple of method calls (such as {@link #isCellEditable} - * to the component it contains and listens for events that indicate - * that editing has stopped. + * This changeable module access the editor component in the component + * specific way. For instance, to set the value for JTextField, we need to + * call setText(String), and for JCheckBox we need to call + * setSelected(boolean). Each default editor has the component specific + * derivative of this class. These derivatives are private inner classes of + * the DefaultCellEditor. + * + * The editor delegate is also set for the editor component as the action + * listener. It listens for the events that indicate that editing has stopped. */ protected class EditorDelegate implements ActionListener, ItemListener, Serializable { + /** + * Use the serial version UID for interoperability. + */ private static final long serialVersionUID = -1420007406015481933L; /** - * value + * The object value (updated when getting and setting the value). */ protected Object value; @@ -90,35 +98,38 @@ public class DefaultCellEditor { // Nothing to do here. } - + /** - * setValue + * Set the value for the editor component. This method is normally + * overridden to set the value in the way, specific for the text + * component, check box or combo box. * - * @param value TODO + * @param aValue the value to set (String, Boolean or Number). */ - public void setValue(Object value) + public void setValue(Object aValue) { - // TODO: should be setting the value in the editorComp - this.value = value; + value = aValue; } - /** - * getCellEditorValue - * - * @returns Object + /** + * Get the value for the editor component. This method is normally + * overridden to obtain the value in the way, specific for the text + * component, check box or combo box. + * + * @return value the value of the component (String, Boolean or Number). */ public Object getCellEditorValue() { - // TODO: should be getting the updated value from the editorComp return value; - } // getCellEditorValue() + } /** - * isCellEditable + * The default method returns true for the {@link MouseEvent} and false + * for any other events. * - * @param event TODO + * @param event the event to check * - * @returns boolean + * @return true if the passed event is the mouse event and false otherwise. */ public boolean isCellEditable(EventObject event) { @@ -129,22 +140,27 @@ public class DefaultCellEditor } // isCellEditable() /** - * shouldSelectCell + * Returns true to indicate that the editing cell can be selected. + * + * The default method returns true without action but may be overridden + * in derived classes for more specific behavior. * - * @param event TODO + * @param event unused in default method * - * @returns boolean + * @return true always */ public boolean shouldSelectCell(EventObject event) { // return true to indicate that the editing cell may be selected return true; - } // shouldSelectCell() + } /** - * stopCellEditing + * Finish the cell editing session. This method notifies the registered + * cell editor listeners (including the table) that the editing has been + * stopped. * - * @returns boolean + * @return boolean */ public boolean stopCellEditing() { @@ -153,7 +169,11 @@ public class DefaultCellEditor } // stopCellEditing() /** - * cancelCellEditing + * Cancel the cell editing session. This method notifies the registered + * cell editor listeners (including the table) that the editing has been + * canceled. + * + * @returns boolean */ public void cancelCellEditing() { @@ -161,11 +181,13 @@ public class DefaultCellEditor } // cancelCellEditing() /** - * startCellEditing + * Start editing session and returns true to indicate the editing has begun. + * The default method returns true without action but may be overridden + * in derived classes for more specific behavior. * - * @param event TODO - * - * @returns boolean + * @param event the event. + * + * @return true, always */ public boolean startCellEditing(EventObject event) { @@ -174,9 +196,11 @@ public class DefaultCellEditor } // startCellEditing() /** - * actionPerformed + * This event is fired by the editor component (for instance, by pressing + * ENTER in the {@link JTextField}. The default method delegates call to + * the {@link #stopCellEditing}, finishing the editing session. * - * @param event TODO + * @param event unused in default method */ public void actionPerformed(ActionEvent event) { @@ -184,15 +208,20 @@ public class DefaultCellEditor } // actionPerformed() /** - * itemStateChanged + * This event is fired by the editor component.The default method delegates + * call to the {@link #stopCellEditing}, finishing the editing session. * - * @param event TODO + * @param event unused in default method */ public void itemStateChanged(ItemEvent event) { stopCellEditing(); } // itemStateChanged() + /** + * Notify the registered listeners (including the table) that the editing + * has been completed. + */ void fireEditingStopped() { CellEditorListener[] listeners = getCellEditorListeners(); @@ -201,6 +230,10 @@ public class DefaultCellEditor } + /** + * Notify the registered listeners (including the table) that the editing + * has been canceled. + */ void fireEditingCanceled() { CellEditorListener[] listeners = getCellEditorListeners(); @@ -208,59 +241,185 @@ public class DefaultCellEditor listeners[index].editingCanceled(changeEvent); } } // EditorDelegate + + /** + * Provides getter and setter methods to work with the text component. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ + private class JTextFieldDelegate extends EditorDelegate + { + /** + * Use the serial version UID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Set the value for the editor component. + * + * @param aValue the value to set (toString() will be called). + */ + public void setValue(Object aValue) + { + value = aValue; + JTextField f = (JTextField) editorComponent; + if (value == null) + f.setText(""); + else + f.setText(value.toString()); + } + + /** + * Get the value for the editor component. + * + * @return value the value of the component (String) + */ + public Object getCellEditorValue() + { + JTextField f = (JTextField) editorComponent; + return value = f.getText(); + } + } + + /** + * Provides getter and setter methods to work with the combo box. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ + private class JComboBoxDelegate extends EditorDelegate + { + /** + * Use the serial version UID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Set the value for the editor component. + * + * @param aValue the value to set. + */ + public void setValue(Object aValue) + { + value = aValue; + JComboBox c = (JComboBox) editorComponent; + if (value != null) + c.setSelectedItem(value); + } - /** - * editorComponent + /** + * Get the value for the editor component. + * + * @return value the value of the component (as String) + */ + public Object getCellEditorValue() + { + JComboBox c = (JComboBox) editorComponent; + return value = c.getSelectedItem(); + } + } + + /** + * Provides getter and setter methods to work with the check box. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ + private class JCheckBoxDelegate extends EditorDelegate + { + /** + * Use the serial version UID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Set the value for the editor component. + * + * @param value the value to set (must be Boolean). + */ + public void setValue(Object value) + { + JCheckBox c = (JCheckBox) editorComponent; + + if (value == null) + c.setSelected(false); + else + c.setSelected( ((Boolean) value).booleanValue()); + } + + /** + * Get the value for the editor component. + * + * @return value the value of the component (must be CharSequence) + */ + public Object getCellEditorValue() + { + JCheckBox c = (JCheckBox) editorComponent; + value = c.isSelected() ? Boolean.TRUE : Boolean.FALSE; + return value; + } + } + + /** + * The Swing JComponent, performing the editing session. */ protected JComponent editorComponent; /** - * delegate + * The editor delegate, responsible for listening the {@link #editorComponent} + * events and getting/setting its value. */ protected EditorDelegate delegate; /** - * clickCountToStart + * The number of the mouse clicks, required to start the editing session. */ protected int clickCountToStart; /** - * Constructor DefaultCellEditor + * Create the DefaultCellEditor that uses the text field as its editor + * component (appropriate for the text content) * - * @param textfield TODO + * @param textfield the text field as will be used as the editor component */ public DefaultCellEditor(JTextField textfield) { editorComponent = textfield; - clickCountToStart = 3; + clickCountToStart = 2; + delegate = new JTextFieldDelegate(); + textfield.addActionListener(delegate); } // DefaultCellEditor() /** - * Constructor DefaultCellEditor + * Constructor DefaultCellEditor that uses the checkbox (appropriate + * for boolean values) * - * @param checkbox TODO + * @param checkbox the checkbox that will be used with this editor. */ public DefaultCellEditor(JCheckBox checkbox) { editorComponent = checkbox; clickCountToStart = 1; + delegate = new JCheckBoxDelegate(); + checkbox.addActionListener(delegate); } // DefaultCellEditor() /** - * Constructor DefaultCellEditor + * Constructor DefaultCellEditor that uses the combo box. * - * @param combobox TODO + * @param combobox the combo box that will be used with this editor. */ public DefaultCellEditor(JComboBox combobox) { editorComponent = combobox; clickCountToStart = 1; + delegate = new JComboBoxDelegate(); + combobox.addActionListener(delegate); } // DefaultCellEditor() /** - * getComponent + * Get the component that performs the editing sessions. It is the same + * component that was passed in constructor. * - * @returns Component + * @return the component, performing the editing sessions. */ public Component getComponent() { @@ -268,9 +427,9 @@ public class DefaultCellEditor } // getComponent() /** - * getClickCountToStart + * Get the number of mouse clicks, required to start the editing session. * - * @returns int + * @return int the number of mouse clicks, required to start the session */ public int getClickCountToStart() { @@ -278,9 +437,9 @@ public class DefaultCellEditor } // getClickCountToStart() /** - * setClickCountToStart + * Set the number of mouse clicks, required to start the editing session. * - * @param count TODO + * @param count the number of clicks, required to start the session */ public void setClickCountToStart(int count) { @@ -288,9 +447,10 @@ public class DefaultCellEditor } // setClickCountToStart() /** - * getCellEditorValue + * Get the value, currently being displayed by the editor component. The + * call is forwarded to the {@link #delegate}. * - * @returns Object + * @return Object the value (class depends on the editor component) */ public Object getCellEditorValue() { @@ -298,11 +458,11 @@ public class DefaultCellEditor } // getCellEditorValue() /** - * isCellEditable + * Forwards call to the {@link #delegate}. * - * @param event TODO + * @param event forwarded to the delegate. * - * @returns boolean + * @return boolean returned by delegate */ public boolean isCellEditable(EventObject event) { @@ -310,11 +470,11 @@ public class DefaultCellEditor } // isCellEditable() /** - * shouldSelectCell + * Forwards call to the {@link #delegate}. * - * @param event TODO + * @param event forwarded to the delegate. * - * @returns boolean + * @return boolean returned by delegate */ public boolean shouldSelectCell(EventObject event) { @@ -322,9 +482,9 @@ public class DefaultCellEditor } // shouldSelectCell() /** - * stopCellEditing + * Forwards call to the {@link #delegate}. * - * @returns boolean + * @return boolean returned by delegate */ public boolean stopCellEditing() { @@ -332,7 +492,7 @@ public class DefaultCellEditor } // stopCellEditing() /** - * cancelCellEditing + * Forwards call to the {@link #delegate}. */ public void cancelCellEditing() { @@ -356,45 +516,30 @@ public class DefaultCellEditor * @param leaf - true if the node is a leaf node * @param row - the row index of the node being edited * - * @returns Component the component for editing + * @return Component the component for editing */ public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) { - if (editorComponent instanceof JTextField) - { - ((JTextField)editorComponent).setText(value.toString()); - delegate = new EditorDelegate(); - ((JTextField)editorComponent).addActionListener(delegate); - } - else if (editorComponent instanceof JCheckBox) - { - ((JCheckBox)editorComponent).setText(value.toString()); - delegate = new EditorDelegate(); - ((JCheckBox)editorComponent).addActionListener(delegate); - } - else if (editorComponent instanceof JComboBox) - { - ((JComboBox)editorComponent).setSelectedItem(value.toString()); - delegate = new EditorDelegate(); - ((JComboBox)editorComponent).addActionListener(delegate); - } - + delegate.setValue(value); return editorComponent; } // getTreeCellEditorComponent() /** - * getTableCellEditorComponent + * Get the cell editor component that will perform the editing session. If + * returned once, the same component is also returned on the repetetive calls + * again (reused). * - * @param table TODO - * @param value TODO - * @param isSelected TODO - * @param row TODO - * @param column TODO - * - * @returns Component + * @param table the table where the editing is performed + * @param value the current value of the table. It is set as the initial + * component value. + * @param isSelected if true, the cell is currently selected + * @param row the row of the cell being edited + * @param column the column of the cell being edited + * + * @return Component the component that will perform the editing session */ public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, @@ -402,24 +547,9 @@ public class DefaultCellEditor { // NOTE: as specified by Sun, we don't call new() everytime, we return // editorComponent on each call to getTableCellEditorComponent or - // getTreeCellEditorComponent. However, currently JTextFields have a - // problem with getting rid of old text, so without calling new() there - // are some strange results. If you edit more than one cell in the table - // text from previously edited cells may unexpectedly show up in the - // cell you are currently editing. This will be fixed automatically - // when JTextField is fixed. - if (editorComponent instanceof JTextField) - { - ((JTextField)editorComponent).setText(value.toString()); - delegate = new EditorDelegate(); - ((JTextField)editorComponent).addActionListener(delegate); - } - else - { - // TODO - } + // getTreeCellEditorComponent. + delegate.setValue(value); return editorComponent; } // getTableCellEditorComponent() - } diff --git a/libjava/classpath/javax/swing/DefaultListCellRenderer.java b/libjava/classpath/javax/swing/DefaultListCellRenderer.java index 9a8e07071b5..598627fac35 100644 --- a/libjava/classpath/javax/swing/DefaultListCellRenderer.java +++ b/libjava/classpath/javax/swing/DefaultListCellRenderer.java @@ -93,7 +93,7 @@ public class DefaultListCellRenderer extends JLabel int index, boolean isSelected, boolean cellHasFocus) { - String s = value.toString(); + String s = value != null ? value.toString() : ""; setText(s); setOpaque(true); setHorizontalAlignment(LEFT); diff --git a/libjava/classpath/javax/swing/DefaultListSelectionModel.java b/libjava/classpath/javax/swing/DefaultListSelectionModel.java index ce1dfdd79c5..7ec4e614c8f 100644 --- a/libjava/classpath/javax/swing/DefaultListSelectionModel.java +++ b/libjava/classpath/javax/swing/DefaultListSelectionModel.java @@ -447,6 +447,9 @@ public class DefaultListSelectionModel implements Cloneable, */ public void addSelectionInterval(int index0, int index1) { + if (index0 == -1 || index1 == -1) + return; + int lo = Math.min(index0, index1); int hi = Math.max(index0, index1); oldSel = sel.clone(); @@ -508,6 +511,9 @@ public class DefaultListSelectionModel implements Cloneable, public void removeSelectionInterval(int index0, int index1) { + if (index0 == -1 || index1 == -1) + return; + oldSel = sel.clone(); int lo = Math.min(index0, index1); int hi = Math.max(index0, index1); @@ -551,6 +557,9 @@ public class DefaultListSelectionModel implements Cloneable, */ public void setSelectionInterval(int index0, int index1) { + if (index0 == -1 || index1 == -1) + return; + oldSel = sel.clone(); sel.clear(); if (selectionMode == SINGLE_SELECTION) diff --git a/libjava/classpath/javax/swing/ImageIcon.java b/libjava/classpath/javax/swing/ImageIcon.java index b6ed949d8dc..9e6265830a3 100644 --- a/libjava/classpath/javax/swing/ImageIcon.java +++ b/libjava/classpath/javax/swing/ImageIcon.java @@ -205,13 +205,13 @@ public class ImageIcon private static final long serialVersionUID = 532615968316031794L; /** A dummy Component that is used in the MediaTracker. */ - protected static Component component = new Component() + protected static final Component component = new Component() { // No need to implement this. }; /** The MediaTracker used to monitor the loading of images. */ - protected static MediaTracker tracker = new MediaTracker(component); + protected static final MediaTracker tracker = new MediaTracker(component); /** The ID that is used in the tracker. */ private static int id; diff --git a/libjava/classpath/javax/swing/JApplet.java b/libjava/classpath/javax/swing/JApplet.java index e90c451891e..68eb983dd01 100644 --- a/libjava/classpath/javax/swing/JApplet.java +++ b/libjava/classpath/javax/swing/JApplet.java @@ -66,7 +66,7 @@ public class JApplet extends Applet /** * Creates a new instance of <code>AccessibleJApplet</code>. */ - public AccessibleJApplet() + protected AccessibleJApplet() { super(); // Nothing to do here. diff --git a/libjava/classpath/javax/swing/JCheckBox.java b/libjava/classpath/javax/swing/JCheckBox.java index 74fda8f6dbe..26f9f6ca595 100644 --- a/libjava/classpath/javax/swing/JCheckBox.java +++ b/libjava/classpath/javax/swing/JCheckBox.java @@ -67,7 +67,7 @@ public class JCheckBox extends JToggleButton implements Accessible /** * Creates a new instance of <code>AccessibleJCheckBox</code>. */ - public AccessibleJCheckBox() + protected AccessibleJCheckBox() { // Nothing to do here. } diff --git a/libjava/classpath/javax/swing/JComponent.java b/libjava/classpath/javax/swing/JComponent.java index 747eba54db4..ddd70860869 100644 --- a/libjava/classpath/javax/swing/JComponent.java +++ b/libjava/classpath/javax/swing/JComponent.java @@ -1,5 +1,5 @@ /* JComponent.java -- Every component in swing inherits from this class. - 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. @@ -64,10 +64,10 @@ import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; -import java.awt.geom.Rectangle2D; 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; @@ -88,7 +88,6 @@ import javax.swing.border.TitledBorder; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import javax.swing.event.EventListenerList; -import javax.swing.event.SwingPropertyChangeSupport; import javax.swing.plaf.ComponentUI; /** @@ -165,11 +164,11 @@ public abstract class JComponent extends Container implements Serializable /** * Manages the property change listeners; */ - private SwingPropertyChangeSupport changeSupport; + private PropertyChangeSupport changeSupport; protected AccessibleJComponent() { - changeSupport = new SwingPropertyChangeSupport(this); + changeSupport = new PropertyChangeSupport(this); } /** @@ -528,14 +527,6 @@ public abstract class JComponent extends Container implements Serializable protected EventListenerList listenerList = new EventListenerList(); /** - * Support for {@link PropertyChangeEvent} events. This is constructed - * lazily when the component gets its first {@link - * PropertyChangeListener} subscription; until then it's an empty slot. - */ - private SwingPropertyChangeSupport changeSupport; - - - /** * Storage for "client properties", which are key/value pairs associated * with this component by a "client", such as a user application or a * layout manager. This is lazily constructed when the component gets its @@ -697,36 +688,6 @@ public abstract class JComponent extends Container implements Serializable } /** - * Unregister a <code>PropertyChangeListener</code>. - * - * @param listener The listener to register - * - * @see #addPropertyChangeListener(PropertyChangeListener) - * @see #changeSupport - */ - public void removePropertyChangeListener(PropertyChangeListener listener) - { - if (changeSupport != null) - changeSupport.removePropertyChangeListener(listener); - } - - /** - * Unregister a <code>PropertyChangeListener</code>. - * - * @param propertyName The property name to unregister the listener from - * @param listener The listener to unregister - * - * @see #addPropertyChangeListener(String, PropertyChangeListener) - * @see #changeSupport - */ - public void removePropertyChangeListener(String propertyName, - PropertyChangeListener listener) - { - if (changeSupport != null) - changeSupport.removePropertyChangeListener(propertyName, listener); - } - - /** * Unregister a <code>VetoableChangeChangeListener</code>. * * @param listener The listener to unregister @@ -751,24 +712,6 @@ public abstract class JComponent extends Container implements Serializable } /** - * Register a <code>PropertyChangeListener</code>. This listener will - * receive any PropertyChangeEvent, regardless of property name. To - * listen to a specific property name, use {@link - * #addPropertyChangeListener(String,PropertyChangeListener)} instead. - * - * @param listener The listener to register - * - * @see #removePropertyChangeListener(PropertyChangeListener) - * @see #changeSupport - */ - public void addPropertyChangeListener(PropertyChangeListener listener) - { - if (changeSupport == null) - changeSupport = new SwingPropertyChangeSupport(this); - changeSupport.addPropertyChangeListener(listener); - } - - /** * Register a <code>PropertyChangeListener</code> for a specific, named * property. To listen to all property changes, regardless of name, use * {@link #addPropertyChangeListener(PropertyChangeListener)} instead. @@ -819,7 +762,10 @@ public abstract class JComponent extends Container implements Serializable */ public EventListener[] getListeners(Class listenerType) { - return listenerList.getListeners(listenerType); + if (listenerType == PropertyChangeListener.class) + return getPropertyChangeListeners(); + else + return listenerList.getListeners(listenerType); } /** @@ -845,134 +791,48 @@ public abstract class JComponent extends Container implements Serializable } /** - * Return all <code>PropertyChangeListener</code> objects registered to listen - * for a particular property. - * - * @param property The property to return the listeners of - * - * @return The set of <code>PropertyChangeListener</code> objects in - * {@link #changeSupport} registered to listen on the specified property - */ - public PropertyChangeListener[] getPropertyChangeListeners(String property) - { - return changeSupport == null ? new PropertyChangeListener[0] - : changeSupport.getPropertyChangeListeners(property); - } - - /** * A variant of {@link #firePropertyChange(String,Object,Object)} * for properties with <code>boolean</code> values. + * + * @specnote It seems that in JDK1.5 all property related methods have been + * moved to java.awt.Component, except this and 2 others. We call + * super here. I guess this will also be removed in one of the next + * releases. */ public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, Boolean.valueOf(oldValue), - Boolean.valueOf(newValue)); - } - - /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with <code>byte</code> values. - */ - public void firePropertyChange(String propertyName, byte oldValue, - byte newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Byte(oldValue), - new Byte(newValue)); + super.firePropertyChange(propertyName, oldValue, newValue); } /** * A variant of {@link #firePropertyChange(String,Object,Object)} * for properties with <code>char</code> values. + * + * @specnote It seems that in JDK1.5 all property related methods have been + * moved to java.awt.Component, except this and 2 others. We call + * super here. I guess this will also be removed in one of the next + * releases. */ public void firePropertyChange(String propertyName, char oldValue, char newValue) { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Character(oldValue), - new Character(newValue)); - } - - /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with <code>double</code> values. - */ - public void firePropertyChange(String propertyName, double oldValue, - double newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Double(oldValue), - new Double(newValue)); - } - - /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with <code>float</code> values. - */ - public void firePropertyChange(String propertyName, float oldValue, - float newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Float(oldValue), - new Float(newValue)); + super.firePropertyChange(propertyName, oldValue, newValue); } /** * A variant of {@link #firePropertyChange(String,Object,Object)} * for properties with <code>int</code> values. + * + * @specnote It seems that in JDK1.5 all property related methods have been + * moved to java.awt.Component, except this and 2 others. We call + * super here. I guess this will also be removed in one of the next + * releases. */ public void firePropertyChange(String propertyName, int oldValue, int newValue) { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Integer(oldValue), - new Integer(newValue)); - } - - /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with <code>long</code> values. - */ - public void firePropertyChange(String propertyName, long oldValue, - long newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Long(oldValue), - new Long(newValue)); - } - - /** - * Call {@link PropertyChangeListener#propertyChange} on all listeners - * registered to listen to a given property. Any method which changes - * the specified property of this component should call this method. - * - * @param propertyName The property which changed - * @param oldValue The old value of the property - * @param newValue The new value of the property - * - * @see #changeSupport - * @see #addPropertyChangeListener(PropertyChangeListener) - * @see #removePropertyChangeListener(PropertyChangeListener) - */ - protected void firePropertyChange(String propertyName, Object oldValue, - Object newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, oldValue, newValue); - } - - /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with <code>short</code> values. - */ - public void firePropertyChange(String propertyName, short oldValue, - short newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Short(oldValue), - new Short(newValue)); + super.firePropertyChange(propertyName, oldValue, newValue); } /** @@ -1518,9 +1378,8 @@ public abstract class JComponent extends Container implements Serializable { ((JComponent) c).computeVisibleRect(rect); rect.translate(-getX(), -getY()); - Rectangle2D.intersect(rect, - new Rectangle(0, 0, getWidth(), getHeight()), - rect); + rect = SwingUtilities.computeIntersection(0, 0, getWidth(), + getHeight(), rect); } else rect.setRect(0, 0, getWidth(), getHeight()); @@ -1530,7 +1389,7 @@ public abstract class JComponent extends Container implements Serializable * Return the component's visible rectangle in a new {@link Rectangle}, * rather than via a return slot. * - * @return The component's visible rectangle + * @return the component's visible rectangle * * @see #computeVisibleRect(Rectangle) */ @@ -1691,7 +1550,10 @@ public abstract class JComponent extends Container implements Serializable // screen. if (!isPaintingDoubleBuffered && isDoubleBuffered() && rm.isDoubleBufferingEnabled()) - paintDoubleBuffered(g); + { + Rectangle clip = g.getClipBounds(); + paintDoubleBuffered(clip); + } else { if (g.getClip() == null) @@ -1755,11 +1617,10 @@ public abstract class JComponent extends Container implements Serializable // optimizedDrawingEnabled (== it tiles its children). if (! isOptimizedDrawingEnabled()) { - Rectangle clip = g.getClipBounds(); for (int i = 0; i < children.length; i++) { Rectangle childBounds = children[i].getBounds(); - if (children[i].isOpaque() + if (children[i].isOpaque() && children[i].isVisible() && SwingUtilities.isRectangleContainingRectangle(childBounds, g.getClipBounds())) { @@ -1892,33 +1753,29 @@ public abstract class JComponent extends Container implements Serializable void paintImmediately2(Rectangle r) { RepaintManager rm = RepaintManager.currentManager(this); - Graphics g = getGraphics(); - g.setClip(r.x, r.y, r.width, r.height); if (rm.isDoubleBufferingEnabled() && isDoubleBuffered()) - paintDoubleBuffered(g); + paintDoubleBuffered(r); else - paintSimple(g); - g.dispose(); + paintSimple(r); } /** * Performs double buffered repainting. - * - * @param g the graphics context to paint to */ - void paintDoubleBuffered(Graphics g) + private void paintDoubleBuffered(Rectangle r) { - - Rectangle r = g.getClipBounds(); - if (r == null) - r = new Rectangle(0, 0, getWidth(), getHeight()); RepaintManager rm = RepaintManager.currentManager(this); // Paint on the offscreen buffer. - Image buffer = rm.getOffscreenBuffer(this, getWidth(), getHeight()); + Component root = SwingUtilities.getRoot(this); + Image buffer = rm.getOffscreenBuffer(this, root.getWidth(), + root.getHeight()); + //Rectangle targetClip = SwingUtilities.convertRectangle(this, r, root); + Point translation = SwingUtilities.convertPoint(this, 0, 0, root); Graphics g2 = buffer.getGraphics(); - g2 = getComponentGraphics(g2); + g2.translate(translation.x, translation.y); g2.setClip(r.x, r.y, r.width, r.height); + g2 = getComponentGraphics(g2); isPaintingDoubleBuffered = true; try { @@ -1929,20 +1786,27 @@ public abstract class JComponent extends Container implements Serializable isPaintingDoubleBuffered = false; g2.dispose(); } - + // Paint the buffer contents on screen. - g.drawImage(buffer, 0, 0, this); + rm.commitBuffer(root, new Rectangle(translation.x + r.x, + translation.y + r.y, r.width, + r.height)); } /** * Performs normal painting without double buffering. * - * @param g the graphics context to use + * @param r the area that should be repainted */ - void paintSimple(Graphics g) + void paintSimple(Rectangle r) { + Graphics g = getGraphics(); Graphics g2 = getComponentGraphics(g); + g2.setClip(r); paint(g2); + g2.dispose(); + if (g != g2) + g.dispose(); } /** @@ -2339,12 +2203,8 @@ public abstract class JComponent extends Container implements Serializable */ public void repaint(long tm, int x, int y, int width, int height) { - Rectangle dirty = new Rectangle(x, y, width, height); - Rectangle vis = getVisibleRect(); - dirty = dirty.intersection(vis); - RepaintManager.currentManager(this).addDirtyRegion(this, dirty.x, dirty.y, - dirty.width, - dirty.height); + RepaintManager.currentManager(this).addDirtyRegion(this, x, y, width, + height); } /** @@ -2356,8 +2216,8 @@ public abstract class JComponent extends Container implements Serializable */ public void repaint(Rectangle r) { - repaint((long) 0, (int) r.getX(), (int) r.getY(), (int) r.getWidth(), - (int) r.getHeight()); + RepaintManager.currentManager(this).addDirtyRegion(this, r.x, r.y, r.width, + r.height); } /** @@ -2879,7 +2739,7 @@ public abstract class JComponent extends Container implements Serializable * * @since 1.4 */ - public boolean requestFocusInWindow(boolean temporary) + protected boolean requestFocusInWindow(boolean temporary) { return super.requestFocusInWindow(temporary); } @@ -3046,19 +2906,6 @@ public abstract class JComponent extends Container implements Serializable } /** - * Return all <code>PropertyChangeListener</code> objects registered. - * - * @return The set of <code>PropertyChangeListener</code> objects - */ - public PropertyChangeListener[] getPropertyChangeListeners() - { - if (changeSupport == null) - return new PropertyChangeListener[0]; - else - return changeSupport.getPropertyChangeListeners(); - } - - /** * Prints this component to the given Graphics context. A call to this * method results in calls to the methods {@link #printComponent}, * {@link #printBorder} and {@link #printChildren} in this order. @@ -3098,7 +2945,7 @@ public abstract class JComponent extends Container implements Serializable * * @since 1.3 */ - public void printComponent(Graphics g) + protected void printComponent(Graphics g) { paintComponent(g); } @@ -3112,7 +2959,7 @@ public abstract class JComponent extends Container implements Serializable * * @since 1.3 */ - public void printChildren(Graphics g) + protected void printChildren(Graphics g) { paintChildren(g); } @@ -3126,7 +2973,7 @@ public abstract class JComponent extends Container implements Serializable * * @since 1.3 */ - public void printBorder(Graphics g) + protected void printBorder(Graphics g) { paintBorder(g); } @@ -3245,62 +3092,25 @@ public abstract class JComponent extends Container implements Serializable while (parent != null && !(parent instanceof Window)) { Container newParent = parent.getParent(); - if (newParent == null) + if (newParent == null || newParent instanceof Window) break; // If the parent is optimizedDrawingEnabled, then its children are // tiled and cannot have an overlapping child. Go directly to next // parent. - if (newParent instanceof JComponent - && ((JComponent) newParent).isOptimizedDrawingEnabled()) + if ((newParent instanceof JComponent + && ((JComponent) newParent).isOptimizedDrawingEnabled())) + { parent = newParent; continue; } - - // First we must check if the new parent itself somehow clips the - // target rectangle. This can happen in JViewports. - Rectangle parRect = new Rectangle(0, 0, newParent.getWidth(), - newParent.getHeight()); + // If the parent is not optimizedDrawingEnabled, we must paint the + // parent. Rectangle target = SwingUtilities.convertRectangle(found, currentClip, newParent); - if (! target.intersection(parRect).equals(target)) - { - found = newParent; - currentClip = target; - parent = newParent; - continue; - } - - // Otherwise we must check if one of the children of this parent - // overlaps with the current component. - Component[] children = newParent.getComponents(); - // This flag is used to skip components that are 'below' the component - // in question. - boolean skip = true; - for (int i = children.length - 1; i >= 0; i--) - { - boolean nextSkip = skip; - if (children[i] == parent) - nextSkip = false; - if (skip) - continue; - skip = nextSkip; - Component c = children[i]; - Rectangle compBounds = c.getBounds(); - // If the component completely overlaps the clip in question, we - // don't need to repaint. Return null. - if (compBounds.contains(target)) - return null; - if (compBounds.intersects(target)) - { - // We found a parent whose children overlap with our current - // component. Make this the current component. - found = newParent; - currentClip = target; - break; - } - } + found = newParent; + currentClip = target; parent = newParent; } return found; diff --git a/libjava/classpath/javax/swing/JDialog.java b/libjava/classpath/javax/swing/JDialog.java index b3f7c011f68..08dada2fd81 100644 --- a/libjava/classpath/javax/swing/JDialog.java +++ b/libjava/classpath/javax/swing/JDialog.java @@ -74,7 +74,7 @@ public class JDialog extends Dialog implements Accessible, WindowConstants, /** * Creates a new instance of <code>AccessibleJDialog</code>. */ - public AccessibleJDialog() + protected AccessibleJDialog() { super(); // Nothing to do here. @@ -107,7 +107,7 @@ public class JDialog extends Dialog implements Accessible, WindowConstants, */ public JDialog() { - this(SwingUtilities.getOwnerFrame(), "", false, null); + this((Frame) SwingUtilities.getOwnerFrame(null), "", false, null); } /** @@ -234,8 +234,7 @@ public class JDialog extends Dialog implements Accessible, WindowConstants, public JDialog(Frame owner, String title, boolean modal, GraphicsConfiguration gc) { - super((owner == null) ? SwingUtilities.getOwnerFrame() : owner, - title, modal, gc); + super((Frame) SwingUtilities.getOwnerFrame(owner), title, modal, gc); dialogInit(); } diff --git a/libjava/classpath/javax/swing/JEditorPane.java b/libjava/classpath/javax/swing/JEditorPane.java index 3560ffd57d4..73b775738de 100644 --- a/libjava/classpath/javax/swing/JEditorPane.java +++ b/libjava/classpath/javax/swing/JEditorPane.java @@ -38,6 +38,7 @@ exception statement from your version. */ package javax.swing; +import java.awt.Container; import java.awt.Dimension; import java.io.IOException; import java.io.InputStream; @@ -682,27 +683,59 @@ public class JEditorPane extends JTextComponent } /** - * Returns the preferred size for the JEditorPane. + * Returns the preferred size for the JEditorPane. This is implemented to + * return the super's preferred size, unless one of + * {@link #getScrollableTracksViewportHeight()} or + * {@link #getScrollableTracksViewportWidth()} returns <code>true</code>, + * in which case the preferred width and/or height is replaced by the UI's + * minimum size. + * + * @return the preferred size for the JEditorPane */ public Dimension getPreferredSize() { - return super.getPreferredSize(); + Dimension pref = super.getPreferredSize(); + if (getScrollableTracksViewportWidth()) + pref.width = getUI().getMinimumSize(this).width; + if (getScrollableTracksViewportHeight()) + pref.height = getUI().getMinimumSize(this).height; + return pref; } + /** + * Returns <code>true</code> when a Viewport should force the height of + * this component to match the viewport height. This is implemented to return + * <code>true</code> when the parent is an instance of JViewport and + * the viewport height > the UI's minimum height. + * + * @return <code>true</code> when a Viewport should force the height of + * this component to match the viewport height + */ public boolean getScrollableTracksViewportHeight() { - /* Container parent = getParent(); - return (parent instanceof JViewport && - parent.isValid());*/ - return isValid(); + // Tests show that this returns true when the parent is a JViewport + // and has a height > minimum UI height. + Container parent = getParent(); + return parent instanceof JViewport + && parent.getHeight() > getUI().getMinimumSize(this).height; } + /** + * Returns <code>true</code> when a Viewport should force the width of + * this component to match the viewport width. This is implemented to return + * <code>true</code> when the parent is an instance of JViewport and + * the viewport width > the UI's minimum width. + * + * @return <code>true</code> when a Viewport should force the width of + * this component to match the viewport width + */ public boolean getScrollableTracksViewportWidth() { - /*Container parent = getParent(); - return (parent instanceof JViewport && - parent.isValid());*/ - return isValid(); + // Tests show that this returns true when the parent is a JViewport + // and has a width > minimum UI width. + Container parent = getParent(); + return parent != null && parent instanceof JViewport + && parent.getWidth() > getUI().getMinimumSize(this).width; } public URL getPage() @@ -893,7 +926,7 @@ public class JEditorPane extends JTextComponent // Remove the current content. Document doc = getDocument(); doc.remove(0, doc.getLength()); - if (t == null || t == "") + if (t == null || t.equals("")) return; // Let the EditorKit read the text into the Document. diff --git a/libjava/classpath/javax/swing/JFileChooser.java b/libjava/classpath/javax/swing/JFileChooser.java index 3a9d6a01f38..72bd2bb28f5 100644 --- a/libjava/classpath/javax/swing/JFileChooser.java +++ b/libjava/classpath/javax/swing/JFileChooser.java @@ -40,7 +40,6 @@ package javax.swing; import java.awt.Component; import java.awt.Frame; import java.awt.HeadlessException; -import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; @@ -658,8 +657,7 @@ public class JFileChooser extends JComponent implements Accessible retval = ERROR_OPTION; - Insets i = d.getInsets(); - d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height); + d.pack(); d.show(); return retval; } @@ -683,8 +681,7 @@ public class JFileChooser extends JComponent implements Accessible retval = ERROR_OPTION; - Insets i = d.getInsets(); - d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height); + d.pack(); d.show(); return retval; } @@ -710,8 +707,7 @@ public class JFileChooser extends JComponent implements Accessible retval = ERROR_OPTION; - Insets i = d.getInsets(); - d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height); + d.pack(); d.show(); return retval; } @@ -729,7 +725,7 @@ public class JFileChooser extends JComponent implements Accessible { Frame toUse = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, parent); if (toUse == null) - toUse = SwingUtilities.getOwnerFrame(); + toUse = (Frame) SwingUtilities.getOwnerFrame(null); JDialog dialog = new JDialog(toUse); setSelectedFile(null); diff --git a/libjava/classpath/javax/swing/JFrame.java b/libjava/classpath/javax/swing/JFrame.java index 8d4dcb53b3c..d2512056085 100644 --- a/libjava/classpath/javax/swing/JFrame.java +++ b/libjava/classpath/javax/swing/JFrame.java @@ -76,7 +76,7 @@ public class JFrame extends Frame /** * Creates a new instance of <code>AccessibleJFrame</code>. */ - public AccessibleJFrame() + protected AccessibleJFrame() { super(); // Nothing to do here. @@ -150,6 +150,15 @@ public class JFrame extends Frame super.setLayout(new BorderLayout(1, 1)); enableEvents(AWTEvent.WINDOW_EVENT_MASK); getRootPane(); // will do set/create + + // Setup the defaultLookAndFeelDecoration if requested. + if (isDefaultLookAndFeelDecorated() + && UIManager.getLookAndFeel().getSupportsWindowDecorations()) + { + setUndecorated(true); + getRootPane().setWindowDecorationStyle(JRootPane.FRAME); + } + // We're now done the init stage. setRootPaneCheckingEnabled(true); } diff --git a/libjava/classpath/javax/swing/JInternalFrame.java b/libjava/classpath/javax/swing/JInternalFrame.java index 948988c24a7..5bd6f781cd0 100644 --- a/libjava/classpath/javax/swing/JInternalFrame.java +++ b/libjava/classpath/javax/swing/JInternalFrame.java @@ -559,6 +559,8 @@ public class JInternalFrame extends JComponent implements Accessible, this.iconable = iconifiable; storedBounds = new Rectangle(); setRootPane(createRootPane()); + // JInternalFrames are invisible by default. + setVisible(false); updateUI(); setRootPaneCheckingEnabled(true); // Done the init stage, now adds go to content pane. } @@ -616,7 +618,7 @@ public class JInternalFrame extends JComponent implements Accessible, */ public void dispose() { - hide(); + setVisible(false); JDesktopPane pane = getDesktopPane(); if (pane != null) pane.setSelectedFrame(null); @@ -647,11 +649,11 @@ public class JInternalFrame extends JComponent implements Accessible, switch (getDefaultCloseOperation()) { case HIDE_ON_CLOSE: - hide(); - break; + setVisible(false); + break; case DISPOSE_ON_CLOSE: - dispose(); - break; + dispose(); + break; } } @@ -1257,13 +1259,14 @@ public class JInternalFrame extends JComponent implements Accessible, { if (b && ! isClosed()) { - fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING); - fireVetoableChange(IS_CLOSED_PROPERTY, false, true); + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING); + fireVetoableChange(IS_CLOSED_PROPERTY, false, true); - isClosed = b; + isClosed = b; + dispose(); - firePropertyChange(IS_CLOSED_PROPERTY, false, true); - fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED); + firePropertyChange(IS_CLOSED_PROPERTY, false, true); + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED); } } @@ -1628,27 +1631,27 @@ public class JInternalFrame extends JComponent implements Accessible, { if (! isVisible()) { - super.show(); - - JDesktopPane pane = getDesktopPane(); - if (pane != null) - pane.setSelectedFrame(this); - else - { - try - { - setSelected(true); - } - catch (PropertyVetoException e) - { - // Do nothing. if they don't want to be selected. - } - } - if (isFirstTimeVisible) - { - isFirstTimeVisible = false; - fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED); - } + super.show(); + + JDesktopPane pane = getDesktopPane(); + if (pane != null) + pane.setSelectedFrame(this); + else + { + try + { + setSelected(true); + } + catch (PropertyVetoException e) + { + // Do nothing. if they don't want to be selected. + } + } + if (isFirstTimeVisible) + { + isFirstTimeVisible = false; + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED); + } } } diff --git a/libjava/classpath/javax/swing/JLayeredPane.java b/libjava/classpath/javax/swing/JLayeredPane.java index dc8b10d2178..ffd803c8706 100644 --- a/libjava/classpath/javax/swing/JLayeredPane.java +++ b/libjava/classpath/javax/swing/JLayeredPane.java @@ -43,11 +43,7 @@ import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.awt.Rectangle; -import java.awt.Shape; import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; -import java.util.TreeMap; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; @@ -119,6 +115,7 @@ import javax.accessibility.AccessibleRole; * component indexing and position order</p> * * @author Graydon Hoare (graydon@redhat.com) + * @author Roman Kennke (kennke@aicas.com) */ public class JLayeredPane extends JComponent implements Accessible { @@ -131,7 +128,7 @@ public class JLayeredPane extends JComponent implements Accessible /** * Creates a new instance of <code>AccessibleJLayeredPane</code>. */ - public AccessibleJLayeredPane() + protected AccessibleJLayeredPane() { // Nothing to do here. } @@ -150,22 +147,18 @@ public class JLayeredPane extends JComponent implements Accessible public static final String LAYER_PROPERTY = "layeredContainerLayer"; - public static Integer FRAME_CONTENT_LAYER = new Integer (-30000); + public static final Integer FRAME_CONTENT_LAYER = new Integer (-30000); - public static Integer DEFAULT_LAYER = new Integer (0); - public static Integer PALETTE_LAYER = new Integer (100); - public static Integer MODAL_LAYER = new Integer (200); - public static Integer POPUP_LAYER = new Integer (300); - public static Integer DRAG_LAYER = new Integer (400); + public static final Integer DEFAULT_LAYER = new Integer (0); + public static final Integer PALETTE_LAYER = new Integer (100); + public static final Integer MODAL_LAYER = new Integer (200); + public static final Integer POPUP_LAYER = new Integer (300); + public static final Integer DRAG_LAYER = new Integer (400); - TreeMap layers; // Layer Number (Integer) -> Layer Size (Integer) - Hashtable componentToLayer; // Component -> Layer Number (Integer) + private Hashtable componentToLayer; // Component -> Layer Number (Integer) - private transient Rectangle rectCache; - public JLayeredPane() { - layers = new TreeMap (); componentToLayer = new Hashtable (); setLayout(null); } @@ -173,47 +166,50 @@ public class JLayeredPane extends JComponent implements Accessible /** * Looks up the layer a child component is currently assigned to. * + * If <code>c</code> is an instance of {@link JComponent}, then the layer + * is fetched from the client property with the key {@link #LAYER_PROPERTY}. + * Otherwise it is looked up in an internal hashtable that maps + * non-JComponent components to layers. If the components cannot be found + * in either way, the {@link #DEFAULT_LAYER} is returned. + * * @param c the component to look up. - * @return the layer the component is currently assigned to, in this container. - * @throws IllegalArgumentException if the component is not a child of this container. + * + * @return the layer the component is currently assigned to; if the component + * is not in this layered pane, then 0 (DEFAULT_LAYER) is returned */ public int getLayer(Component c) { - Component myComp = c; - while(! componentToLayer.containsKey(myComp)) + Integer layerObj; + if (c instanceof JComponent) { - myComp = myComp.getParent(); - if (myComp == null) - break; + JComponent jc = (JComponent) c; + layerObj = (Integer) jc.getClientProperty(LAYER_PROPERTY); } - if (myComp == null) - throw new IllegalArgumentException - ("component is not in this JLayeredPane"); - Integer layerObj = (Integer) componentToLayer.get(myComp); + else + layerObj = (Integer) componentToLayer.get(c); + + if (layerObj == null) + layerObj = DEFAULT_LAYER; + return layerObj.intValue(); } /** - * Looks up the layer of <code>comp</code> in the component's nearest - * JLayeredPane ancestor. If <code>comp</code> is not contained - * in a JLayeredPane, the value 0 (default layer) is returned. - * + * Looks up the layer in the client property with the key + * {@link #LAYER_PROPERTY} of <code>comp</code>. If no such property can be + * found, we return <code>0</code> ({@link #DEFAULT_LAYER}). + * * @param comp the component for which the layer is looked up * - * @return the layer of <code>comp</code> in its nearest JLayeredPane - * ancestor + * @return the layer of <code>comp</code> as stored in the corresponding + * client property, or <code>0</code> if there is no such property */ public static int getLayer(JComponent comp) { - JLayeredPane lp = (JLayeredPane) SwingUtilities.getAncestorOfClass - (JLayeredPane.class, comp); - if (lp == null) - return 0; - else - // The cast here forces the call to the instance method getLayer() - // instead of the static method (this would lead to infinite - // recursion). - return lp.getLayer((Component) comp); + Integer layerObj = (Integer) comp.getClientProperty(LAYER_PROPERTY); + if (layerObj == null) + layerObj = DEFAULT_LAYER; + return layerObj.intValue(); } /** @@ -236,105 +232,49 @@ public class JLayeredPane extends JComponent implements Accessible } /** - * <p>Returns a pair of ints representing a half-open interval - * <code>[top, bottom)</code>, which is the range of component indices - * the provided layer number corresponds to.</p> - * - * <p>Note that "bottom" is <em>not</em> included in the interval of - * component indices in this layer: a layer with 0 elements in it has - * <code>ret[0] == ret[1]</code>.</p> - * - * @param layer the layer to look up. - * @return the half-open range of indices this layer spans. - * @throws IllegalArgumentException if layer does not refer to an active layer - * in this container. - */ - private int[] layerToRange (Integer layer) - { - int[] ret = new int[2]; - ret[1] = getComponents ().length; - Iterator i = layers.entrySet ().iterator (); - while (i.hasNext()) - { - Map.Entry pair = (Map.Entry) i.next(); - Integer layerNum = (Integer) pair.getKey (); - Integer layerSz = (Integer) pair.getValue (); - int layerInt = layerNum.intValue(); - if (layerInt == layer.intValue()) - { - ret[0] = ret[1] - layerSz.intValue (); - break; - } - // In the following case there exists no layer with the specified - // number, so we return an empty interval here with the index at which - // such a layer would be inserted - else if (layerInt > layer.intValue()) - { - ret[1] = ret[0]; - break; - } - else - { - ret[1] -= layerSz.intValue (); - } - } - return ret; - } - - /** - * Increments the recorded size of a given layer. - * - * @param layer the layer number to increment. - * @see #incrLayer - */ - private void incrLayer(Integer layer) - { - int sz = 1; - if (layers.containsKey (layer)) - sz += ((Integer)(layers.get (layer))).intValue (); - layers.put (layer, new Integer(sz)); - } - - /** - * Decrements the recorded size of a given layer. - * - * @param layer the layer number to decrement. - * @see #incrLayer - */ - private void decrLayer(Integer layer) - { - int sz = 0; - if (layers.containsKey (layer)) - sz = ((Integer)(layers.get (layer))).intValue () - 1; - layers.put (layer, new Integer(sz)); - } - - /** * Return the greatest layer number currently in use, in this container. * This number may legally be positive <em>or</em> negative. * - * @return the least layer number. + * @return the highest layer number + * * @see #lowestLayer() */ public int highestLayer() { - if (layers.size() == 0) - return 0; - return ((Integer)(layers.lastKey ())).intValue (); + Component[] components = getComponents(); + int highest; + if (components.length == 0) + highest = 0; + else + { + highest = Integer.MIN_VALUE; + for (int i = 0; i < components.length; i++) + highest = Math.max(highest, getLayer(components[i])); + } + return highest; } /** * Return the least layer number currently in use, in this container. * This number may legally be positive <em>or</em> negative. * - * @return the least layer number. + * @return the least layer number + * * @see #highestLayer() */ public int lowestLayer() { - if (layers.size() == 0) - return 0; - return ((Integer)(layers.firstKey ())).intValue (); + Component[] components = getComponents(); + int lowest; + if (components.length == 0) + lowest = 0; + else + { + lowest = Integer.MAX_VALUE; + for (int i = 0; i < components.length; i++) + lowest = Math.max(lowest, getLayer(components[i])); + } + return lowest; } /** @@ -343,9 +283,8 @@ public class JLayeredPane extends JComponent implements Accessible * layer, so is usually the component which occludes the most other * components in its layer. * - * @param c the component to move to the front of its layer. - * @throws IllegalArgumentException if the component is not a child of - * this container. + * @param c the component to move to the front of its layer + * * @see #moveToBack */ public void moveToFront(Component c) @@ -363,8 +302,7 @@ public class JLayeredPane extends JComponent implements Accessible * other components in its layer.</p> * * @param c the component to move to the back of its layer. - * @throws IllegalArgumentException if the component is not a child of - * this container. + * * @see #moveToFront */ public void moveToBack(Component c) @@ -377,25 +315,30 @@ public class JLayeredPane extends JComponent implements Accessible * from the "front" (position 0) to the "back" (position N-1), and drawn from * the back towards the front. * - * @param c the component to get the position of. - * @throws IllegalArgumentException if the component is not a child of - * this container. + * @param c the component to get the position of + * + * @return the position of <code>c</code> within its layer or -1 if + * <code>c</code> is not a child of this layered pane + * * @see #setPosition */ public int getPosition(Component c) { - int layer = getLayer (c); - int[] range = layerToRange(new Integer(layer)); - int top = range[0]; - int bot = range[1]; - Component[] comps = getComponents (); - for (int i = top; i < bot; ++i) - { - if (comps[i] == c) - return i - top; - } - // should have found it - throw new IllegalArgumentException (); + int pos = -1; + int index = getIndexOf(c); + Component[] components = getComponents(); + int layer = getLayer(c); + if (index >= 0) + { + for (int i = index; i >= 0; --i) + { + if (layer == getLayer(components[i])) + pos++; + else + break; + } + } + return pos; } /** @@ -403,47 +346,16 @@ public class JLayeredPane extends JComponent implements Accessible * from the "front" (position 0) to the "back" (position N-1), and drawn from * the back towards the front. * - * @param c the component to change the position of. - * @param position the position to assign the component to. - * @throws IllegalArgumentException if the component is not a child of - * this container. + * @param c the component to change the position of + * @param position the position to assign the component to + * * @see #getPosition */ public void setPosition(Component c, int position) { - int layer = getLayer (c); - int[] range = layerToRange(new Integer(layer)); - if (range[0] == range[1]) - throw new IllegalArgumentException (); - - int top = range[0]; - int bot = range[1]; - if (position == -1) - position = (bot - top) - 1; - int targ = Math.min(top + position, bot-1); - int curr = -1; - - Component[] comps = getComponents(); - for (int i = top; i < bot; ++i) - { - if (comps[i] == c) - { - curr = i; - break; - } - } - if (curr == -1) - // should have found it - throw new IllegalArgumentException(); - - if (curr == 0) - super.swapComponents(curr, targ); - else - while (curr > 0) - super.swapComponents (curr, --curr); - - revalidate(); - repaint(); + int layer = getLayer(c); + int index = insertIndexForLayer(layer, position); + setComponentZOrder(c, index); } /** @@ -451,39 +363,44 @@ public class JLayeredPane extends JComponent implements Accessible * container. Components are ordered front-to-back, with the "front" * element (which draws last) at position 0 of the returned array. * - * @param layer the layer to return components from. - * @return the components in the layer. + * @param layer the layer to return components from + * + * @return the components in the layer */ public Component[] getComponentsInLayer(int layer) { - int[] range = layerToRange (getObjectForLayer (layer)); - if (range[0] == range[1]) - return new Component[0]; - else - { - Component[] comps = getComponents (); - int sz = range[1] - range[0]; - Component[] nc = new Component[sz]; - for (int i = 0; i < sz; ++i) - nc[i] = comps[range[0] + i]; - return nc; - } + Component[] inLayer = new Component[getComponentCountInLayer(layer)]; + Component[] components = getComponents(); + int j = 0; + for (int i = 0; i < components.length; ++i) + { + if (layer == getLayer(components[i])) + { + inLayer[j] = components[i]; + j++; + } + } + return inLayer; } /** * Return the number of components within a layer of this * container. * - * @param layer the layer count components in. - * @return the number of components in the layer. + * @param layer the layer count components in + * + * @return the number of components in the layer */ public int getComponentCountInLayer(int layer) { - int[] range = layerToRange (getObjectForLayer (layer)); - if (range[0] == range[1]) - return 0; - else - return (range[1] - range[0]); + Component[] components = getComponents(); + int count = 0; + for (int i = components.length - 1; i >= 0; --i) + { + if (getLayer(components[i]) == layer) + count++; + } + return count; } /** @@ -502,23 +419,14 @@ public class JLayeredPane extends JComponent implements Accessible * drawing order of all children of the container. * * @param c the component to look up. - * @return the external index of the component. - * @throws IllegalArgumentException if the component is not a child of - * this container. + * + * @return the external index of the component or <code>-1</code> if + * <code>c</code> is not a child of this layered pane */ public int getIndexOf(Component c) { - int layer = getLayer (c); - int[] range = layerToRange(new Integer(layer)); - Component[] comps = getComponents(); - for (int i = range[0]; i < range[1]; ++i) - { - if (comps[i] == c) - return i; - } - // should have found the component during iteration - throw new IllegalArgumentException (); - } + return getComponentZOrder(c); + } /** * Return an Integer object which holds the same int value as the @@ -526,6 +434,7 @@ public class JLayeredPane extends JComponent implements Accessible * identical Integer objects which we allocate. * * @param layer the layer number as an int. + * * @return the layer number as an Integer, possibly shared. */ protected Integer getObjectForLayer(int layer) @@ -564,25 +473,39 @@ public class JLayeredPane extends JComponent implements Accessible * * @param layer the layer in which to insert a component. * @param position the position in the layer at which to insert a component. + * * @return the index at which to insert the component. */ protected int insertIndexForLayer(int layer, int position) { + // position < 0 means insert at greatest position within layer. + if (position < 0) + position = Integer.MAX_VALUE; - Integer lobj = getObjectForLayer (layer); - if (! layers.containsKey(lobj)) - layers.put (lobj, new Integer (0)); - int[] range = layerToRange (lobj); - if (range[0] == range[1]) - return range[0]; - - int top = range[0]; - int bot = range[1]; - - if (position == -1 || position > (bot - top)) - return bot; - else - return top + position; + Component[] components = getComponents(); + int index = 0; + + // Try to find the start index of the specified layer. + int p = -1; + for (int i = 0; i < components.length; i++) + { + int l = getLayer(components[i]); + if (l > layer) + index++; + // If we are in the layer we look for, try to find the position. + else if (l == layer) + { + p++; + if (p < position) + index++; + else + break; + } + // No need to look further if the layer at i is smaller than layer. + else + break; + } + return index; } /** @@ -594,12 +517,20 @@ public class JLayeredPane extends JComponent implements Accessible public void remove(int index) { Component c = getComponent(index); - int layer = getLayer(c); - decrLayer(new Integer(layer)); - componentToLayer.remove(c); + if (! (c instanceof JComponent)) + componentToLayer.remove(c); super.remove(index); - // FIXME: Figure out if this call is correct. - revalidate(); + } + + /** + * Removes all components from this container. + * + * @since 1.5 + */ + public void removeAll() + { + componentToLayer.clear(); + super.removeAll(); } /** @@ -615,7 +546,7 @@ public class JLayeredPane extends JComponent implements Accessible */ public void setLayer(Component c, int layer) { - componentToLayer.put (c, getObjectForLayer (layer)); + setLayer(c, layer, -1); } /** @@ -625,15 +556,20 @@ public class JLayeredPane extends JComponent implements Accessible * @param layer the layer number to assign to the component. * @param position the position number to assign to the component. */ - public void setLayer(Component c, - int layer, - int position) + public void setLayer(Component c, int layer, int position) { - remove(c); - add(c, getObjectForLayer (layer)); - setPosition(c, position); - revalidate(); - repaint(); + Integer layerObj = getObjectForLayer(layer); + if (c instanceof JComponent) + { + JComponent jc = (JComponent) c; + jc.putClientProperty(LAYER_PROPERTY, layerObj); + } + else + componentToLayer.put (c, layerObj); + + // Set position only of component is already added to this layered pane. + if (getIndexOf(c) != -1) + setPosition(c, position); } /** @@ -642,26 +578,27 @@ public class JLayeredPane extends JComponent implements Accessible * Integer}, specifying the layer to which the component will be added * (at the bottom position). * - * @param comp the component to add. - * @param layerConstraint an integer specifying the layer to add the component to. - * @param index an ignored parameter, for compatibility. + * The argument <code>index</code> specifies the position within the layer + * at which the component should be added, where <code>0</code> is the top + * position greater values specify positions below that and <code>-1</code> + * specifies the bottom position. + * + * @param comp the component to add + * @param layerConstraint an integer specifying the layer to add the + * component to + * @param index the position within the layer */ protected void addImpl(Component comp, Object layerConstraint, int index) { - Integer layer; + int layer; if (layerConstraint != null && layerConstraint instanceof Integer) - layer = (Integer) layerConstraint; - else if (componentToLayer.containsKey (comp)) - layer = (Integer) componentToLayer.remove (comp); + layer = ((Integer) layerConstraint).intValue(); else - layer = DEFAULT_LAYER; - - int newIdx = insertIndexForLayer(layer.intValue (), index); + layer = getLayer(comp); - componentToLayer.put (comp, layer); - incrLayer (layer); - - super.addImpl(comp, null, newIdx); + int newIdx = insertIndexForLayer(layer, index); + setLayer(comp, layer); + super.addImpl(comp, layerConstraint, newIdx); } /** @@ -672,7 +609,7 @@ public class JLayeredPane extends JComponent implements Accessible */ public static void putLayer(JComponent component, int layer) { - getLayeredPaneAbove(component).setLayer(component, layer); + component.putClientProperty(LAYER_PROPERTY, new Integer(layer)); } /** @@ -711,13 +648,42 @@ public class JLayeredPane extends JComponent implements Accessible } /** - * Overridden to return <code>false</code>, since <code>JLayeredPane</code> - * cannot guarantee that its children don't overlap. + * Returns <code>false</code> if components in this layered pane can overlap, + * otherwise <code>true</code>. * - * @return <code>false</code> + * @return <code>false</code> if components in this layered pane can overlap, + * otherwise <code>true</code> */ public boolean isOptimizedDrawingEnabled() { - return false; + int numChildren = getComponentCount(); + boolean result = true; + for (int i = 0; i < numChildren; ++i) + { + Component c1 = getComponent(i); + if (! c1.isVisible()) + continue; + Rectangle r1 = c1.getBounds(); + if (r1.isEmpty()) + continue; + + for (int j = i + 1; j < numChildren; ++j) + { + Component c2 = getComponent(j); + if (! c2.isVisible()) + continue; + Rectangle r2 = c2.getBounds(); + if (r2.isEmpty()) + continue; + if (r1.intersects(r2)) + { + result = false; + break; + } + if (result == false) + break; + } + } + return result; } } diff --git a/libjava/classpath/javax/swing/JMenu.java b/libjava/classpath/javax/swing/JMenu.java index 369c44d40c6..a160dd44857 100644 --- a/libjava/classpath/javax/swing/JMenu.java +++ b/libjava/classpath/javax/swing/JMenu.java @@ -906,7 +906,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement /** * This class listens to PropertyChangeEvents occuring in menu's action */ - protected class ActionChangedListener implements PropertyChangeListener + private class ActionChangedListener implements PropertyChangeListener { /** menu item associated with the action */ private JMenuItem menuItem; diff --git a/libjava/classpath/javax/swing/JMenuBar.java b/libjava/classpath/javax/swing/JMenuBar.java index f018daabf80..60726fb39bf 100644 --- a/libjava/classpath/javax/swing/JMenuBar.java +++ b/libjava/classpath/javax/swing/JMenuBar.java @@ -1,5 +1,5 @@ /* JMenuBar.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. @@ -51,6 +51,8 @@ import javax.accessibility.AccessibleSelection; import javax.accessibility.AccessibleStateSet; import javax.swing.plaf.MenuBarUI; +import javax.swing.border.Border; + /** * JMenuBar is a container for menu's. For a menu bar to be seen on the * screen, at least one menu should be added to it. Just like adding @@ -437,8 +439,12 @@ public class JMenuBar extends JComponent implements Accessible, MenuElement protected void paintBorder(Graphics g) { if (borderPainted) - getBorder().paintBorder(this, g, 0, 0, getSize(null).width, - getSize(null).height); + { + Border border = getBorder(); + if (border != null) + getBorder().paintBorder(this, g, 0, 0, getSize(null).width, + getSize(null).height); + } } /** diff --git a/libjava/classpath/javax/swing/JOptionPane.java b/libjava/classpath/javax/swing/JOptionPane.java index 057326cd209..705eca832fe 100644 --- a/libjava/classpath/javax/swing/JOptionPane.java +++ b/libjava/classpath/javax/swing/JOptionPane.java @@ -197,7 +197,7 @@ public class JOptionPane extends JComponent implements Accessible public static final String WANTS_INPUT_PROPERTY = "wantsInput"; /** The value returned when the inputValue is uninitialized. */ - public static Object UNINITIALIZED_VALUE = "uninitializedValue"; + public static final Object UNINITIALIZED_VALUE = "uninitializedValue"; /** The icon displayed in the dialog/internal frame. */ protected Icon icon; @@ -236,7 +236,7 @@ public class JOptionPane extends JComponent implements Accessible protected boolean wantsInput; /** The common frame used when no parent is provided. */ - private static Frame privFrame = SwingUtilities.getOwnerFrame(); + private static Frame privFrame = (Frame) SwingUtilities.getOwnerFrame(null); /** * Creates a new JOptionPane object using a message of "JOptionPane diff --git a/libjava/classpath/javax/swing/JPanel.java b/libjava/classpath/javax/swing/JPanel.java index c02a9cfad6f..815e452dc05 100644 --- a/libjava/classpath/javax/swing/JPanel.java +++ b/libjava/classpath/javax/swing/JPanel.java @@ -63,7 +63,7 @@ public class JPanel extends JComponent implements Accessible /** * Creates a new instance of <code>AccessibleJPanel</code>. */ - public AccessibleJPanel() + protected AccessibleJPanel() { // Nothing to do here. } diff --git a/libjava/classpath/javax/swing/JPopupMenu.java b/libjava/classpath/javax/swing/JPopupMenu.java index 1f2282e2326..74f733e921e 100644 --- a/libjava/classpath/javax/swing/JPopupMenu.java +++ b/libjava/classpath/javax/swing/JPopupMenu.java @@ -866,7 +866,7 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement /* This class resizes popup menu and repaints popup menu appropriately if one of item's action has changed */ - protected class ActionChangeListener implements PropertyChangeListener + private class ActionChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { diff --git a/libjava/classpath/javax/swing/JProgressBar.java b/libjava/classpath/javax/swing/JProgressBar.java index abca3e7ae02..e7ee8004c09 100644 --- a/libjava/classpath/javax/swing/JProgressBar.java +++ b/libjava/classpath/javax/swing/JProgressBar.java @@ -1,5 +1,5 @@ /* JProgressBar.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. @@ -174,8 +174,8 @@ public class JProgressBar extends JComponent implements SwingConstants, /** Whether the ProgressBar is determinate. */ private transient boolean indeterminate = false; - /** The orientation of the ProgressBar */ - protected int orientation = HORIZONTAL; + /** The orientation of the ProgressBar. Always set by constructor. */ + protected int orientation; /** Whether borders should be painted. */ protected boolean paintBorder = true; @@ -245,8 +245,9 @@ public class JProgressBar extends JComponent implements SwingConstants, { model = new DefaultBoundedRangeModel(minimum, 0, minimum, maximum); if (orientation != HORIZONTAL && orientation != VERTICAL) - throw new IllegalArgumentException(orientation + " is not a legal orientation"); - setOrientation(orientation); + throw new IllegalArgumentException(orientation + + " is not a legal orientation"); + this.orientation = orientation; changeListener = createChangeListener(); model.addChangeListener(changeListener); updateUI(); @@ -316,11 +317,14 @@ public class JProgressBar extends JComponent implements SwingConstants, * JProgressBar can be either horizontal or vertical. * * @param orientation The orientation of the JProgressBar. + * @throws IllegalArgumentException if <code>orientation</code> is not + * either {@link #HORIZONTAL} or {@link #VERTICAL}. */ public void setOrientation(int orientation) { if (orientation != VERTICAL && orientation != HORIZONTAL) - throw new IllegalArgumentException("orientation must be one of VERTICAL or HORIZONTAL"); + throw new IllegalArgumentException(orientation + + " is not a legal orientation"); if (this.orientation != orientation) { int oldOrientation = this.orientation; diff --git a/libjava/classpath/javax/swing/JRootPane.java b/libjava/classpath/javax/swing/JRootPane.java index dea4ee4b195..dec43956ca3 100644 --- a/libjava/classpath/javax/swing/JRootPane.java +++ b/libjava/classpath/javax/swing/JRootPane.java @@ -120,11 +120,6 @@ public class JRootPane extends JComponent implements Accessible private Rectangle menuBarBounds; /** - * The cached preferred size. - */ - private Dimension prefSize; - - /** * Creates a new <code>RootLayout</code> object. */ protected RootLayout() @@ -191,7 +186,6 @@ public class JRootPane extends JComponent implements Accessible layeredPaneBounds = null; contentPaneBounds = null; menuBarBounds = null; - prefSize = null; } } @@ -251,7 +245,7 @@ public class JRootPane extends JComponent implements Accessible layeredPane.setBounds(layeredPaneBounds); if (menuBar != null) menuBar.setBounds(menuBarBounds); - contentPane.setBounds(contentPaneBounds); + getContentPane().setBounds(contentPaneBounds); } /** @@ -287,29 +281,20 @@ public class JRootPane extends JComponent implements Accessible */ public Dimension preferredLayoutSize(Container c) { - // We must synchronize here, otherwise we cannot guarantee that the - // prefSize is still non-null when returning. - synchronized (this) + Dimension prefSize = new Dimension(); + Insets i = getInsets(); + prefSize = new Dimension(i.left + i.right, i.top + i.bottom); + Dimension contentPrefSize = getContentPane().getPreferredSize(); + prefSize.width += contentPrefSize.width; + prefSize.height += contentPrefSize.height; + if (menuBar != null) { - if (prefSize == null) - { - Insets i = getInsets(); - prefSize = new Dimension(i.left + i.right, i.top + i.bottom); - Dimension contentPrefSize = contentPane.getPreferredSize(); - prefSize.width += contentPrefSize.width; - prefSize.height += contentPrefSize.height; - if (menuBar != null) - { - Dimension menuBarSize = menuBar.getPreferredSize(); - if (menuBarSize.width > contentPrefSize.width) - prefSize.width += menuBarSize.width - contentPrefSize.width; - prefSize.height += menuBarSize.height; - } - } - // Return a copy here so the cached value won't get trashed by some - // other component. - return new Dimension(prefSize); - } + Dimension menuBarSize = menuBar.getPreferredSize(); + if (menuBarSize.width > contentPrefSize.width) + prefSize.width += menuBarSize.width - contentPrefSize.width; + prefSize.height += menuBarSize.height; + } + return prefSize; } /** @@ -541,6 +526,7 @@ public class JRootPane extends JComponent implements Accessible getGlassPane(); getLayeredPane(); getContentPane(); + setOpaque(true); updateUI(); } @@ -674,4 +660,18 @@ public class JRootPane extends JComponent implements Accessible windowDecorationStyle = style; firePropertyChange("windowDecorationStyle", oldStyle, style); } + + /** + * This returns <code>true</code> if the <code>glassPane</code> is not + * visible because then the root pane can guarantee to tile its children + * (the only other direct child is a JLayeredPane which must figure its + * <code>optimizeDrawingEnabled</code> state on its own). + * + * @return <code>true</code> if the <code>glassPane</code> is not + * visible + */ + public boolean isOptimizedDrawingEnable() + { + return ! glassPane.isVisible(); + } } diff --git a/libjava/classpath/javax/swing/JSpinner.java b/libjava/classpath/javax/swing/JSpinner.java index af34d9cf67d..882d216e126 100644 --- a/libjava/classpath/javax/swing/JSpinner.java +++ b/libjava/classpath/javax/swing/JSpinner.java @@ -1,5 +1,5 @@ /* JSpinner.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. @@ -45,7 +45,9 @@ import java.awt.Insets; import java.awt.LayoutManager; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.text.DateFormat; import java.text.DecimalFormat; +import java.text.NumberFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -53,10 +55,15 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.SpinnerUI; import javax.swing.text.DateFormatter; +import javax.swing.text.DefaultFormatterFactory; +import javax.swing.text.NumberFormatter; /** - * A JSpinner is a component which typically contains a numeric value and a - * way to manipulate the value. + * A <code>JSpinner</code> is a component that displays a single value from + * a sequence of values, and provides a convenient means for selecting the + * previous and next values in the sequence. Typically the spinner displays + * a numeric value, but it is possible to display dates or arbitrary items + * from a list. * * @author Ka-Hing Cheung * @@ -65,12 +72,15 @@ import javax.swing.text.DateFormatter; public class JSpinner extends JComponent { /** - * DOCUMENT ME! + * The base class for the editor used by the {@link JSpinner} component. + * The editor is in fact a panel containing a {@link JFormattedTextField} + * component. */ - public static class DefaultEditor extends JPanel implements ChangeListener, - PropertyChangeListener, - LayoutManager + public static class DefaultEditor + extends JPanel + implements ChangeListener, PropertyChangeListener, LayoutManager { + /** The spinner that the editor is allocated to. */ private JSpinner spinner; /** The JFormattedTextField that backs the editor. */ @@ -82,7 +92,8 @@ public class JSpinner extends JComponent private static final long serialVersionUID = -5317788736173368172L; /** - * Creates a new <code>DefaultEditor</code> object. + * Creates a new <code>DefaultEditor</code> object. The editor is + * registered with the spinner as a {@link ChangeListener} here. * * @param spinner the <code>JSpinner</code> associated with this editor */ @@ -94,11 +105,15 @@ public class JSpinner extends JComponent ftf = new JFormattedTextField(); add(ftf); ftf.setValue(spinner.getValue()); + ftf.addPropertyChangeListener(this); spinner.addChangeListener(this); } /** - * Returns the <code>JSpinner</code> object for this editor. + * Returns the <code>JSpinner</code> component that the editor is assigned + * to. + * + * @return The spinner that the editor is assigned to. */ public JSpinner getSpinner() { @@ -114,9 +129,10 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Removes the editor from the {@link ChangeListener} list maintained by + * the specified <code>spinner</code>. * - * @param spinner DOCUMENT ME! + * @param spinner the spinner (<code>null</code> not permitted). */ public void dismiss(JSpinner spinner) { @@ -124,9 +140,10 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Returns the text field used to display and edit the current value in + * the spinner. * - * @return DOCUMENT ME! + * @return The text field. */ public JFormattedTextField getTextField() { @@ -134,9 +151,10 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Sets the bounds for the child components in this container. In this + * case, the text field is the only component to be laid out. * - * @param parent DOCUMENT ME! + * @param parent the parent container. */ public void layoutContainer(Container parent) { @@ -148,11 +166,13 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Calculates the minimum size for this component. In this case, the + * text field is the only subcomponent, so the return value is the minimum + * size of the text field plus the insets of this component. * - * @param parent DOCUMENT ME! + * @param parent the parent container. * - * @return DOCUMENT ME! + * @return The minimum size. */ public Dimension minimumLayoutSize(Container parent) { @@ -163,11 +183,13 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Calculates the preferred size for this component. In this case, the + * text field is the only subcomponent, so the return value is the + * preferred size of the text field plus the insets of this component. * - * @param parent DOCUMENT ME! + * @param parent the parent container. * - * @return DOCUMENT ME! + * @return The preferred size. */ public Dimension preferredLayoutSize(Container parent) { @@ -178,35 +200,51 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Receives notification of property changes. If the text field's 'value' + * property changes, the spinner's model is updated accordingly. * - * @param event DOCUMENT ME! + * @param event the event. */ public void propertyChange(PropertyChangeEvent event) { - // TODO: Implement this properly. + if (event.getSource() == ftf) + { + if (event.getPropertyName().equals("value")) + spinner.getModel().setValue(event.getNewValue()); + } } /** - * DOCUMENT ME! + * Receives notification of changes in the state of the {@link JSpinner} + * that the editor belongs to - the content of the text field is updated + * accordingly. * - * @param event DOCUMENT ME! + * @param event the change event. */ public void stateChanged(ChangeEvent event) { - // TODO: Implement this properly. + ftf.setValue(spinner.getValue()); } + /** + * This method does nothing. It is required by the {@link LayoutManager} + * interface, but since this component has a single child, there is no + * need to use this method. + * + * @param child the child component to remove. + */ public void removeLayoutComponent(Component child) { // Nothing to do here. } /** - * DOCUMENT ME! - * - * @param name DOCUMENT ME! - * @param child DOCUMENT ME! + * This method does nothing. It is required by the {@link LayoutManager} + * interface, but since this component has a single child, there is no + * need to use this method. + * + * @param name the name. + * @param child the child component to add. */ public void addLayoutComponent(String name, Component child) { @@ -215,7 +253,11 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * A panel containing a {@link JFormattedTextField} that is configured for + * displaying and editing numbers. The panel is used as a subcomponent of + * a {@link JSpinner}. + * + * @see JSpinner#createEditor(SpinnerModel) */ public static class NumberEditor extends DefaultEditor { @@ -225,40 +267,72 @@ public class JSpinner extends JComponent private static final long serialVersionUID = 3791956183098282942L; /** - * Creates a new NumberEditor object. + * Creates a new <code>NumberEditor</code> object for the specified + * <code>spinner</code>. The editor is registered with the spinner as a + * {@link ChangeListener}. * - * @param spinner DOCUMENT ME! + * @param spinner the component the editor will be used with. */ public NumberEditor(JSpinner spinner) { super(spinner); + NumberEditorFormatter nef = new NumberEditorFormatter(); + nef.setMinimum(getModel().getMinimum()); + nef.setMaximum(getModel().getMaximum()); + ftf.setFormatterFactory(new DefaultFormatterFactory(nef)); } /** - * Creates a new NumberEditor object. + * Creates a new <code>NumberEditor</code> object. * - * @param spinner DOCUMENT ME! + * @param spinner the spinner. + * @param decimalFormatPattern the number format pattern. */ public NumberEditor(JSpinner spinner, String decimalFormatPattern) { super(spinner); + NumberEditorFormatter nef + = new NumberEditorFormatter(decimalFormatPattern); + nef.setMinimum(getModel().getMinimum()); + nef.setMaximum(getModel().getMaximum()); + ftf.setFormatterFactory(new DefaultFormatterFactory(nef)); } /** - * DOCUMENT ME! + * Returns the format used by the text field. * - * @return DOCUMENT ME! + * @return The format used by the text field. */ public DecimalFormat getFormat() { - return null; + NumberFormatter formatter = (NumberFormatter) ftf.getFormatter(); + return (DecimalFormat) formatter.getFormat(); } + /** + * Returns the model used by the editor's {@link JSpinner} component, + * cast to a {@link SpinnerNumberModel}. + * + * @return The model. + */ public SpinnerNumberModel getModel() { return (SpinnerNumberModel) getSpinner().getModel(); } } + + static class NumberEditorFormatter + extends NumberFormatter + { + public NumberEditorFormatter() + { + super(NumberFormat.getInstance()); + } + public NumberEditorFormatter(String decimalFormatPattern) + { + super(new DecimalFormat(decimalFormatPattern)); + } + } /** * A <code>JSpinner</code> editor used for the {@link SpinnerListModel}. @@ -279,6 +353,11 @@ public class JSpinner extends JComponent super(spinner); } + /** + * Returns the spinner's model cast as a {@link SpinnerListModel}. + * + * @return The spinner's model. + */ public SpinnerListModel getModel() { return (SpinnerListModel) getSpinner().getModel(); @@ -299,9 +378,6 @@ public class JSpinner extends JComponent /** The serialVersionUID. */ private static final long serialVersionUID = -4279356973770397815L; - /** The DateFormat instance used to format the date. */ - SimpleDateFormat dateFormat; - /** * Creates a new instance of DateEditor for the specified * <code>JSpinner</code>. @@ -312,7 +388,10 @@ public class JSpinner extends JComponent public DateEditor(JSpinner spinner) { super(spinner); - init(new SimpleDateFormat()); + DateEditorFormatter nef = new DateEditorFormatter(); + nef.setMinimum(getModel().getStart()); + nef.setMaximum(getModel().getEnd()); + ftf.setFormatterFactory(new DefaultFormatterFactory(nef)); } /** @@ -329,26 +408,10 @@ public class JSpinner extends JComponent public DateEditor(JSpinner spinner, String dateFormatPattern) { super(spinner); - init(new SimpleDateFormat(dateFormatPattern)); - } - - /** - * Initializes the JFormattedTextField for this editor. - * - * @param format the date format to use in the formatted text field - */ - private void init(SimpleDateFormat format) - { - dateFormat = format; - getTextField().setFormatterFactory( - new JFormattedTextField.AbstractFormatterFactory() - { - public JFormattedTextField.AbstractFormatter - getFormatter(JFormattedTextField ftf) - { - return new DateFormatter(dateFormat); - } - }); + DateEditorFormatter nef = new DateEditorFormatter(dateFormatPattern); + nef.setMinimum(getModel().getStart()); + nef.setMaximum(getModel().getEnd()); + ftf.setFormatterFactory(new DefaultFormatterFactory(nef)); } /** @@ -360,7 +423,8 @@ public class JSpinner extends JComponent */ public SimpleDateFormat getFormat() { - return dateFormat; + DateFormatter formatter = (DateFormatter) ftf.getFormatter(); + return (SimpleDateFormat) formatter.getFormat(); } /** @@ -374,25 +438,59 @@ public class JSpinner extends JComponent } } - private static final long serialVersionUID = 3412663575706551720L; + static class DateEditorFormatter + extends DateFormatter + { + public DateEditorFormatter() + { + super(DateFormat.getInstance()); + } + public DateEditorFormatter(String dateFormatPattern) + { + super(new SimpleDateFormat(dateFormatPattern)); + } + } + + /** + * A listener that forwards {@link ChangeEvent} notifications from the model + * to the {@link JSpinner}'s listeners. + */ + class ModelListener implements ChangeListener + { + /** + * Creates a new listener. + */ + public ModelListener() + { + // nothing to do here + } + + /** + * Receives notification from the model that its state has changed. + * + * @param event the event (ignored). + */ + public void stateChanged(ChangeEvent event) + { + fireStateChanged(); + } + } - /** DOCUMENT ME! */ + /** + * The model that defines the current value and permitted values for the + * spinner. + */ private SpinnerModel model; - /** DOCUMENT ME! */ + /** The current editor. */ private JComponent editor; - /** DOCUMENT ME! */ - private ChangeListener listener = new ChangeListener() - { - public void stateChanged(ChangeEvent evt) - { - fireStateChanged(); - } - }; + private static final long serialVersionUID = 3412663575706551720L; /** - * Creates a JSpinner with <code>SpinnerNumberModel</code> + * Creates a new <code>JSpinner</code> with default instance of + * {@link SpinnerNumberModel} (that is, a model with value 0, step size 1, + * and no upper or lower limit). * * @see javax.swing.SpinnerNumberModel */ @@ -402,15 +500,19 @@ public class JSpinner extends JComponent } /** - * Creates a JSpinner with the specific model and sets the default editor + * Creates a new <code>JSpinner with the specified model. The + * {@link #createEditor(SpinnerModel)} method is used to create an editor + * that is suitable for the model. * - * @param model DOCUMENT ME! + * @param model the model (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>model</code> is <code>null</code>. */ public JSpinner(SpinnerModel model) { this.model = model; - model.addChangeListener(listener); - setEditor(createEditor(model)); + this.editor = createEditor(model); + model.addChangeListener(new ModelListener()); updateUI(); } @@ -439,12 +541,13 @@ public class JSpinner extends JComponent } /** - * Changes the current editor to the new editor. This methods should remove - * the old listeners (if any) and adds the new listeners (if any). + * Changes the current editor to the new editor. The old editor is + * removed from the spinner's {@link ChangeEvent} list. * - * @param editor the new editor + * @param editor the new editor (<code>null</code> not permitted. * - * @throws IllegalArgumentException DOCUMENT ME! + * @throws IllegalArgumentException if <code>editor</code> is + * <code>null</code>. * * @see #getEditor */ @@ -453,21 +556,22 @@ public class JSpinner extends JComponent if (editor == null) throw new IllegalArgumentException("editor may not be null"); - if (this.editor instanceof DefaultEditor) - ((DefaultEditor) editor).dismiss(this); - else if (this.editor instanceof ChangeListener) - removeChangeListener((ChangeListener) this.editor); - - if (editor instanceof ChangeListener) - addChangeListener((ChangeListener) editor); - + JComponent oldEditor = this.editor; + if (oldEditor instanceof DefaultEditor) + ((DefaultEditor) oldEditor).dismiss(this); + else if (oldEditor instanceof ChangeListener) + removeChangeListener((ChangeListener) oldEditor); + this.editor = editor; + firePropertyChange("editor", oldEditor, editor); } /** - * Gets the underly model. + * Returns the model used by the {@link JSpinner} component. * - * @return the underly model + * @return The model. + * + * @see #setModel(SpinnerModel) */ public SpinnerModel getModel() { @@ -492,9 +596,7 @@ public class JSpinner extends JComponent SpinnerModel oldModel = model; model = newModel; firePropertyChange("model", oldModel, newModel); - - if (editor == null) - setEditor(createEditor(model)); + setEditor(createEditor(model)); } /** @@ -545,9 +647,9 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Sets the value in the model. * - * @param value DOCUMENT ME! + * @param value the new value. */ public void setValue(Object value) { @@ -555,10 +657,10 @@ public class JSpinner extends JComponent } /** - * This method returns a name to identify which look and feel class will be + * Returns the ID that identifies which look and feel class will be * the UI delegate for this spinner. * - * @return The UIClass identifier. "SpinnerUI" + * @return <code>"SpinnerUI"</code>. */ public String getUIClassID() { @@ -575,7 +677,7 @@ public class JSpinner extends JComponent } /** - * This method sets the spinner's UI delegate. + * Sets the UI delegate for the component. * * @param ui The spinner's UI delegate. */ @@ -628,14 +730,11 @@ public class JSpinner extends JComponent } /** - * Creates an editor for this <code>JSpinner</code>. Really, it should be a - * <code>JSpinner.DefaultEditor</code>, but since that should be - * implemented by a JFormattedTextField, and one is not written, I am just - * using a dummy one backed by a JLabel. + * Creates an editor that is appropriate for the specified <code>model</code>. * - * @param model DOCUMENT ME! + * @param model the model. * - * @return the default editor + * @return The editor. */ protected JComponent createEditor(SpinnerModel model) { @@ -643,6 +742,8 @@ public class JSpinner extends JComponent return new DateEditor(this); else if (model instanceof SpinnerNumberModel) return new NumberEditor(this); + else if (model instanceof SpinnerListModel) + return new ListEditor(this); else return new DefaultEditor(this); } diff --git a/libjava/classpath/javax/swing/JSplitPane.java b/libjava/classpath/javax/swing/JSplitPane.java index 70feefab26e..dc75dfe3184 100644 --- a/libjava/classpath/javax/swing/JSplitPane.java +++ b/libjava/classpath/javax/swing/JSplitPane.java @@ -343,10 +343,13 @@ public class JSplitPane extends JComponent implements Accessible throw new IllegalArgumentException("Constraints is not a known identifier."); + // If no dividerLocation has been set, then we need to trigger an + // initial layout. + if (getDividerLocation() != -1) + resetToPreferredSizes(); + super.addImpl(comp, constraints, index); } - invalidate(); - layout(); } /** diff --git a/libjava/classpath/javax/swing/JTabbedPane.java b/libjava/classpath/javax/swing/JTabbedPane.java index 8a7d4c07fa7..3c91a5ea397 100644 --- a/libjava/classpath/javax/swing/JTabbedPane.java +++ b/libjava/classpath/javax/swing/JTabbedPane.java @@ -44,12 +44,14 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.io.Serializable; +import java.util.Locale; import java.util.Vector; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleStateSet; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.TabbedPaneUI; @@ -136,7 +138,12 @@ public class JTabbedPane extends JComponent implements Serializable, */ public Accessible getAccessibleChild(int i) { - return null; + // Testing shows that the reference implementation returns instances + // of page here. + Accessible child = null; + if (i >= 0 && i < tabs.size()) + child = (Page) tabs.get(i); + return child; } /** @@ -273,6 +280,8 @@ public class JTabbedPane extends JComponent implements Serializable, * A private class that holds all the information for each tab. */ private class Page + extends AccessibleContext + implements Accessible { /** The tooltip string. */ private String tip; @@ -553,6 +562,74 @@ public class JTabbedPane extends JComponent implements Serializable, underlinedChar = index; } + + /** + * Returns the accessible context, which is this object itself. + * + * @return the accessible context, which is this object itself + */ + public AccessibleContext getAccessibleContext() + { + return this; + } + + /** + * Returns the accessible role of this tab, which is always + * {@link AccessibleRole#PAGE_TAB}. + * + * @return the accessible role of this tab + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.PAGE_TAB; + } + + public AccessibleStateSet getAccessibleStateSet() + { + // FIXME: Implement this properly. + return null; + } + + public int getAccessibleIndexInParent() + { + // FIXME: Implement this properly. + return 0; + } + + /** + * Returns the number of accessible children, which is always one (the + * component of this tab). + * + * @return the number of accessible children + */ + public int getAccessibleChildrenCount() + { + return 1; + } + + /** + * Returns the accessible child of this tab, which is the component + * displayed by the tab. + * + * @return the accessible child of this tab + */ + public Accessible getAccessibleChild(int i) + { + // A quick test shows that this method always returns the component + // displayed by the tab, regardless of the index. + return (Accessible) component; + } + + /** + * Returns the locale of this accessible object. + * + * @return the locale of this accessible object + */ + public Locale getLocale() + { + // TODO: Is this ok? + return Locale.getDefault(); + } } private static final long serialVersionUID = 1614381073220130939L; @@ -1088,7 +1165,7 @@ public class JTabbedPane extends JComponent implements Serializable, */ public void remove(int index) { - remove(getComponentAt(index)); + super.remove(index); removeTabAt(index); } diff --git a/libjava/classpath/javax/swing/JTable.java b/libjava/classpath/javax/swing/JTable.java index 0875306a012..fbf74934a0a 100644 --- a/libjava/classpath/javax/swing/JTable.java +++ b/libjava/classpath/javax/swing/JTable.java @@ -1,5 +1,5 @@ /* JTable.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,8 +46,6 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Point; import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.FocusListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -86,8 +84,16 @@ import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; -import javax.swing.text.Caret; +/** + * The table component, displaying information, organized in rows and columns. + * The table can be placed in the scroll bar and have the optional header + * that is always visible. Cell values may be editable after double clicking + * on the cell. Cell columns may have various data types, that are + * displayed and edited by the different renderers and editors. It is possible + * to set different column width. The columns are also resizeable by + * dragging the column boundary in the header. + */ public class JTable extends JComponent implements TableModelListener, Scrollable, TableColumnModelListener, @@ -588,7 +594,7 @@ public class JTable return lastColumn; } } - + /** * Creates a new <code>AccessibleJTable</code>. * @@ -979,9 +985,9 @@ public class JTable class TableColumnPropertyChangeHandler implements PropertyChangeListener { /** - * Receives notification that a property of the observed TableColumns - * has changed. - * + * Receives notification that a property of the observed TableColumns has + * changed. + * * @param ev the property change event */ public void propertyChange(PropertyChangeEvent ev) @@ -989,13 +995,15 @@ public class JTable if (ev.getPropertyName().equals("preferredWidth")) { JTableHeader header = getTableHeader(); - if (header != null) - { - TableColumn col = (TableColumn) ev.getSource(); - header.setResizingColumn(col); - doLayout(); - header.setResizingColumn(null); - } + if (header != null) + // Do nothing if the table is in the resizing mode. + if (header.getResizingColumn() == null) + { + TableColumn col = (TableColumn) ev.getSource(); + header.setResizingColumn(col); + doLayout(); + header.setResizingColumn(null); + } } } } @@ -1006,11 +1014,30 @@ public class JTable private class BooleanCellRenderer extends DefaultTableCellRenderer { - /** * The CheckBox that is used for rendering. */ - private JCheckBox checkBox = new JCheckBox(); + 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. + */ + JCheckBox getCheckBox() + { + return checkBox; + } /** * Returns the component that is used for rendering the value. @@ -1029,8 +1056,14 @@ public class JTable boolean hasFocus, int row, int column) { - Boolean boolValue = (Boolean) value; - checkBox.setSelected(boolValue.booleanValue()); + // Null is rendered as false. + if (value == null) + checkBox.setSelected(false); + else + { + Boolean boolValue = (Boolean) value; + checkBox.setSelected(boolValue.booleanValue()); + } return checkBox; } } @@ -1200,12 +1233,52 @@ public class JTable { Icon iconValue = (Icon) value; setIcon(iconValue); + setText(""); } return this; } } + + /** + * The JTable text component (used in editing) always has the table + * as its parent. The scrollRectToVisible must be adjusted taking the + * relative component position. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ + private class TableTextField extends JTextField + { + /** + * Create the text field without the border. + */ + TableTextField() + { + setBorder(null); + } + + /** + * 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. + */ + 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); + } + } + private static final long serialVersionUID = 3876025080382781659L; + + /** + * This table, for referring identically name methods from inner classes. + */ + final JTable this_table = this; /** @@ -1343,7 +1416,7 @@ public class JTable protected boolean rowSelectionAllowed; /** - * @deprecated Use {@link #rowSelectionAllowed}, {@link + * Obsolete. Use {@link #rowSelectionAllowed}, {@link * #getColumnSelectionAllowed}, or the combined methods {@link * #getCellSelectionEnabled} and {@link #setCellSelectionEnabled(boolean)}. */ @@ -1477,27 +1550,6 @@ public class JTable protected JTableHeader tableHeader; /** - * The row of the cell being edited. - */ - int rowBeingEdited = -1; - - /** - * The column of the cell being edited. - */ - int columnBeingEdited = -1; - - /** - * The action listener for the editor's Timer. - */ - Timer editorTimer = new EditorUpdateTimer(); - - /** - * Stores the old value of a cell before it was edited, in case - * editing is cancelled - */ - Object oldCellValue; - - /** * The property handler for this table's columns. */ TableColumnPropertyChangeHandler tableColumnPropertyChangeHandler = @@ -1510,6 +1562,11 @@ public class JTable private boolean surrendersFocusOnKeystroke = false; /** + * A Rectangle object to be reused in {@link #getCellRect}. + */ + private Rectangle rectCache = new Rectangle(); + + /** * Creates a new <code>JTable</code> instance. */ public JTable () @@ -1518,7 +1575,8 @@ public class JTable } /** - * Creates a new <code>JTable</code> instance. + * Creates a new <code>JTable</code> instance with the given number + * of rows and columns. * * @param numRows an <code>int</code> value * @param numColumns an <code>int</code> value @@ -1529,10 +1587,12 @@ public class JTable } /** - * Creates a new <code>JTable</code> instance. + * Creates a new <code>JTable</code> instance, storing the given data + * array and heaving the given column names. To see the column names, + * you must place the JTable into the {@link JScrollPane}. * - * @param data an <code>Object[][]</code> value - * @param columnNames an <code>Object[]</code> value + * @param data an <code>Object[][]</code> the table data + * @param columnNames an <code>Object[]</code> the column headers */ public JTable(Object[][] data, Object[] columnNames) { @@ -1540,20 +1600,31 @@ public class JTable } /** - * Creates a new <code>JTable</code> instance. - * - * @param dm a <code>TableModel</code> value + * Creates a new <code>JTable</code> instance, using the given data model + * object that provides information about the table content. The table model + * object is asked for the table size, other features and also receives + * notifications in the case when the table has been edited by the user. + * + * @param model + * the table model. */ - public JTable (TableModel dm) + public JTable (TableModel model) { - this(dm, null, null); + this(model, null, null); } /** - * Creates a new <code>JTable</code> instance. - * - * @param dm a <code>TableModel</code> value - * @param cm a <code>TableColumnModel</code> value + * Creates a new <code>JTable</code> instance, using the given model object + * that provides information about the table content. The table data model + * object is asked for the table size, other features and also receives + * notifications in the case when the table has been edited by the user. The + * table column model provides more detailed control on the table column + * related features. + * + * @param dm + * the table data mode + * @param cm + * the table column model */ public JTable (TableModel dm, TableColumnModel cm) { @@ -1561,11 +1632,13 @@ public class JTable } /** - * Creates a new <code>JTable</code> instance. + * Creates a new <code>JTable</code> instance, providing data model, + * column model and list selection model. The list selection model + * manages the selections. * - * @param dm a <code>TableModel</code> value - * @param cm a <code>TableColumnModel</code> value - * @param sm a <code>ListSelectionModel</code> value + * @param dm data model (manages table data) + * @param cm column model (manages table columns) + * @param sm list selection model (manages table selections) */ public JTable (TableModel dm, TableColumnModel cm, ListSelectionModel sm) { @@ -1593,8 +1666,23 @@ public class JTable columnModel.getSelectionModel().setAnchorSelectionIndex(0); columnModel.getSelectionModel().setLeadSelectionIndex(0); updateUI(); - } - + } + + /** + * Creates a new <code>JTable</code> instance that uses data and column + * names, stored in {@link Vector}s. + * + * @param data the table data + * @param columnNames the table column names. + */ + public JTable(Vector data, Vector columnNames) + { + this(new DefaultTableModel(data, columnNames)); + } + + /** + * Initialize local variables to default values. + */ protected void initializeLocalVars() { setTableHeader(createDefaultTableHeader()); @@ -1623,63 +1711,18 @@ public class JTable this.editingRow = -1; setIntercellSpacing(new Dimension(1,1)); } - - /** - * Creates a new <code>JTable</code> instance. - * - * @param data a <code>Vector</code> value - * @param columnNames a <code>Vector</code> value - */ - public JTable(Vector data, Vector columnNames) - { - this(new DefaultTableModel(data, columnNames)); - } - + /** - * The timer that updates the editor component. + * Add the new table column. The table column class allows to specify column + * features more precisely, setting the preferred width, column data type + * (column class) and table headers. + * + * There is no need the add columns to the table if the default column + * handling is sufficient. + * + * @param column + * the new column to add. */ - private class EditorUpdateTimer - extends Timer - implements ActionListener - { - /** - * Creates a new EditorUpdateTimer object with a default delay of 0.5 seconds. - */ - public EditorUpdateTimer() - { - super(500, null); - addActionListener(this); - } - - /** - * Lets the caret blink and repaints the table. - */ - public void actionPerformed(ActionEvent ev) - { - Caret c = ((JTextField)JTable.this.editorComp).getCaret(); - if (c != null) - c.setVisible(!c.isVisible()); - JTable.this.repaint(); - } - - /** - * Updates the blink delay according to the current caret. - */ - public void update() - { - stop(); - Caret c = ((JTextField)JTable.this.editorComp).getCaret(); - if (c != null) - { - setDelay(c.getBlinkRate()); - if (((JTextField)JTable.this.editorComp).isEditable()) - start(); - else - c.setVisible(false); - } - } - } - public void addColumn(TableColumn column) { if (column.getHeaderValue() == null) @@ -1691,12 +1734,24 @@ public class JTable columnModel.addColumn(column); column.addPropertyChangeListener(tableColumnPropertyChangeHandler); } - + + /** + * Create the default editors for this table. The default method creates + * the editor for Booleans. + * + * Other fields are edited as strings at the moment. + */ protected void createDefaultEditors() { - //FIXME: Create the editor object. + JCheckBox box = new BooleanCellRenderer().getCheckBox(); + setDefaultEditor(Boolean.class, new DefaultCellEditor(box)); } - + + /** + * Create the default renderers for this table. The default method creates + * renderers for Boolean, Number, Double, Date, Icon and ImageIcon. + * + */ protected void createDefaultRenderers() { setDefaultRenderer(Boolean.class, new BooleanCellRenderer()); @@ -1705,6 +1760,7 @@ public class JTable setDefaultRenderer(Double.class, new FloatCellRenderer()); setDefaultRenderer(Date.class, new DateCellRenderer()); setDefaultRenderer(Icon.class, new IconCellRenderer()); + setDefaultRenderer(ImageIcon.class, new IconCellRenderer()); } /** @@ -1714,112 +1770,148 @@ public class JTable { return new JScrollPane(table); } - + + /** + * Create the default table column model that is used if the user-defined + * column model is not provided. The default method creates + * {@link DefaultTableColumnModel}. + * + * @return the created table column model. + */ protected TableColumnModel createDefaultColumnModel() { return new DefaultTableColumnModel(); } + /** + * Create the default table data model that is used if the user-defined + * data model is not provided. The default method creates + * {@link DefaultTableModel}. + * + * @return the created table data model. + */ protected TableModel createDefaultDataModel() { return new DefaultTableModel(); } + /** + * Create the default table selection model that is used if the user-defined + * selection model is not provided. The default method creates + * {@link DefaultListSelectionModel}. + * + * @return the created table data model. + */ protected ListSelectionModel createDefaultSelectionModel() { return new DefaultListSelectionModel(); } - + + /** + * Create the default table header, if the user - defined table header is not + * provided. + * + * @return the default table header. + */ protected JTableHeader createDefaultTableHeader() { return new JTableHeader(columnModel); } - - // listener support - + + /** + * Invoked when the column is added. Revalidates and repains the table. + */ public void columnAdded (TableColumnModelEvent event) { revalidate(); repaint(); } + /** + * Invoked when the column margin is changed. + * Revalidates and repains the table. + */ public void columnMarginChanged (ChangeEvent event) { revalidate(); repaint(); } + /** + * Invoked when the column is moved. Revalidates and repains the table. + */ public void columnMoved (TableColumnModelEvent event) { revalidate(); repaint(); } + /** + * Invoked when the column is removed. Revalidates and repains the table. + */ public void columnRemoved (TableColumnModelEvent event) { revalidate(); repaint(); } + /** + * Invoked when the the column selection changes. + */ public void columnSelectionChanged (ListSelectionEvent event) { repaint(); } - + + /** + * Invoked when the editing is cancelled. + */ public void editingCanceled (ChangeEvent event) { - if (rowBeingEdited > -1 && columnBeingEdited > -1) + if (editorComp!=null) { - if (getValueAt(rowBeingEdited, columnBeingEdited) instanceof JTextField) - { - remove ((Component)getValueAt(rowBeingEdited, columnBeingEdited)); - setValueAt(oldCellValue, rowBeingEdited, columnBeingEdited); - } - rowBeingEdited = -1; - columnBeingEdited = -1; + remove(editorComp); + repaint(editorComp.getBounds()); + editorComp = null; } - editorTimer.stop(); - editorComp = null; - cellEditor = null; - requestFocusInWindow(false); - repaint(); } - + + /** + * Finish the current editing session and update the table with the + * new value by calling {@link #setValueAt}. + * + * @param event the change event + */ public void editingStopped (ChangeEvent event) { - if (rowBeingEdited > -1 && columnBeingEdited > -1) + if (editorComp!=null) { - if (getValueAt(rowBeingEdited, columnBeingEdited) instanceof JTextField) - { - remove((Component)getValueAt(rowBeingEdited, columnBeingEdited)); - setValueAt(((JTextField)editorComp).getText(), - rowBeingEdited, columnBeingEdited); - } - rowBeingEdited = -1; - columnBeingEdited = -1; + remove(editorComp); + setValueAt(cellEditor.getCellEditorValue(), editingRow, editingColumn); + repaint(editorComp.getBounds()); + editorComp = null; } - editorTimer.stop(); - editorComp = null; - cellEditor = null; - requestFocusInWindow(false); - repaint(); + requestFocusInWindow(); } + /** + * Invoked when the table changes. + * <code>null</code> means everything changed. + */ public void tableChanged (TableModelEvent event) { // update the column model from the table model if the structure has // changed and the flag autoCreateColumnsFromModel is set - if ((event.getFirstRow() ==TableModelEvent.HEADER_ROW) - && autoCreateColumnsFromModel) - + if ((event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW)) + && autoCreateColumnsFromModel) createDefaultColumnsFromModel(); // If the structure changes, we need to revalidate, since that might // affect the size parameters of the JTable. Otherwise we only need // to perform a repaint to update the view. - if (event.getType() == TableModelEvent.INSERT) + if (event == null || event.getType() == TableModelEvent.INSERT) revalidate(); - else if (event.getType() == TableModelEvent.DELETE) + if (event == null || event.getType() == TableModelEvent.DELETE) { if (dataModel.getRowCount() == 0) clearSelection(); @@ -1828,6 +1920,9 @@ public class JTable repaint(); } + /** + * Invoked when another table row is selected. + */ public void valueChanged (ListSelectionEvent event) { repaint(); @@ -1863,29 +1958,30 @@ 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 - * @return index of the row that contains specified point or - * -1 if this table doesn't contain this point. + * 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 + * @return index of the row that contains specified point or -1 if this table + * doesn't contain this point. */ public int rowAtPoint(Point point) { if (point != null) { int nrows = getRowCount(); - int height = getRowHeight(); + int height = getRowHeight() + getRowMargin(); int y = point.y; - for (int i = 0; i < nrows; ++i) - { - if (0 <= y && y < height) - return i; - y -= height; - } + int r = y / height; + if (r < 0 || r >= nrows) + return -1; + else + return r; } - return -1; + else + return -1; } /** @@ -1908,6 +2004,9 @@ 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(); @@ -1923,9 +2022,10 @@ public class JTable x += columnModel.getColumn(i).getWidth(); if (includeSpacing) - return new Rectangle(x, y, width, height); + rectCache.setBounds(x, y, width, height +y_gap); else - return new Rectangle(x, y, width - x_gap, height - y_gap); + rectCache.setBounds(x, y, width - x_gap, height); + return rectCache; } public void clearSelection() @@ -2008,44 +2108,88 @@ public class JTable } + /** + * 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 + * not provide the editor, the call is forwarded to the + * {@link #getDefaultEditor(Class)} with the parameter, obtained from + * {@link TableModel#getColumnClass(int)}. + * + * @param row the cell row + * @param column the cell column + * @return the editor to edit that cell + */ public TableCellEditor getCellEditor(int row, int column) { TableCellEditor editor = columnModel.getColumn(column).getCellEditor(); if (editor == null) - editor = getDefaultEditor(dataModel.getColumnClass(column)); - + { + int mcolumn = convertColumnIndexToModel(column); + editor = getDefaultEditor(dataModel.getColumnClass(mcolumn)); + } + return editor; } - + + /** + * Get the default editor for editing values of the given type + * (String, Boolean and so on). + * + * @param columnClass the class of the value that will be edited. + * + * @return the editor, suitable for editing this data type + */ public TableCellEditor getDefaultEditor(Class columnClass) { if (defaultEditorsByColumnClass.containsKey(columnClass)) return (TableCellEditor) defaultEditorsByColumnClass.get(columnClass); else { - // FIXME: We have at least an editor for Object.class in our defaults. - TableCellEditor r = new DefaultCellEditor(new JTextField()); + JTextField t = new TableTextField(); + TableCellEditor r = new DefaultCellEditor(t); defaultEditorsByColumnClass.put(columnClass, r); return r; } } - + + /** + * Get the cell renderer for rendering the given cell. + * + * @param row the cell row + * @param column the cell column + * @return the cell renderer to render that cell. + */ public TableCellRenderer getCellRenderer(int row, int column) { - TableCellRenderer renderer = - columnModel.getColumn(column).getCellRenderer(); + TableCellRenderer renderer = columnModel.getColumn(column).getCellRenderer(); if (renderer == null) - renderer = getDefaultRenderer(getColumnClass(column)); - + { + int mcolumn = convertColumnIndexToModel(column); + renderer = getDefaultRenderer(dataModel.getColumnClass(mcolumn)); + } return renderer; } - + + /** + * Set default renderer for rendering the given data type. + * + * @param columnClass the data type (String, Boolean and so on) that must be + * rendered. + * @param rend the renderer that will rend this data type + */ public void setDefaultRenderer(Class columnClass, TableCellRenderer rend) { defaultRenderersByColumnClass.put(columnClass, rend); } - + + /** + * Get the default renderer for rendering the given data type. + * + * @param columnClass the data that must be rendered + * + * @return the appropriate defauld renderer for rendering that data type. + */ public TableCellRenderer getDefaultRenderer(Class columnClass) { if (defaultRenderersByColumnClass.containsKey(columnClass)) @@ -2057,7 +2201,19 @@ public class JTable return r; } } - + + /** + * Convert the table model index into the table column number. + * The model number need not match the real column position. The columns + * may be rearranged by the user with mouse at any time by dragging the + * column headers. + * + * @param vc the column number (0=first). + * + * @return the table column model index of this column. + * + * @see TableColumn#getModelIndex() + */ public int convertColumnIndexToModel(int vc) { if (vc < 0) @@ -2065,7 +2221,19 @@ public class JTable else return columnModel.getColumn(vc).getModelIndex(); } - + + /** + * Convert the table column number to the table column model index. + * The model number need not match the real column position. The columns + * may be rearranged by the user with mouse at any time by dragging the + * column headers. + * + * @param mc the table column index (0=first). + * + * @return the table column number in the model + * + * @see TableColumn#getModelIndex() + */ public int convertColumnIndexToView(int mc) { if (mc < 0) @@ -2078,7 +2246,16 @@ public class JTable } return -1; } - + + /** + * Prepare the renderer for rendering the given cell. + * + * @param renderer the renderer being prepared + * @param row the row of the cell being rendered + * @param column the column of the cell being rendered + * + * @return the component which .paint() method will paint the cell. + */ public Component prepareRenderer(TableCellRenderer renderer, int row, int column) @@ -2640,8 +2817,13 @@ public class JTable if (dataModel != null && columnModel != null) { int ncols = getColumnCount(); + TableColumn column; for (int i = 0; i < ncols; ++i) - columnModel.getColumn(i).setHeaderValue(dataModel.getColumnName(i)); + { + column = columnModel.getColumn(i); + if (column.getHeaderValue()==null) + column.setHeaderValue(dataModel.getColumnName(i)); + } } // according to Sun's spec we also have to set the tableHeader's @@ -2899,10 +3081,36 @@ public class JTable for (int i = 0; i < cols.length; i++) { if (cols[i] != null) - cols[i].setWidth(cols[i].getWidth() + average); + cols[i].setWidth(cols[i].getPreferredWidth() + average); } } - + + /** + * This distributes the superfluous width in a table, setting the width of the + * column being resized strictly to its preferred width. + */ + private void distributeSpillResizing(TableColumn[] cols, int spill, + TableColumn resizeIt) + { + int average = 0; + if (cols.length != 1) + average = spill / (cols.length-1); + for (int i = 0; i < cols.length; i++) + { + if (cols[i] != null && !cols[i].equals(resizeIt)) + cols[i].setWidth(cols[i].getPreferredWidth() + average); + } + resizeIt.setWidth(resizeIt.getPreferredWidth()); + } + + /** + * Set the widths of all columns, taking they preferred widths into + * consideration. The excess space, if any, will be distrubuted between + * all columns. This method also handles special cases when one of the + * collumns is currently being resized. + * + * @see TableColumn#setPreferredWidth(int) + */ public void doLayout() { TableColumn resizingColumn = null; @@ -2911,7 +3119,6 @@ public class JTable if (ncols < 1) return; - int[] pref = new int[ncols]; int prefSum = 0; int rCol = -1; @@ -2921,8 +3128,7 @@ public class JTable for (int i = 0; i < ncols; ++i) { TableColumn col = columnModel.getColumn(i); - int p = col.getWidth(); - pref[i] = p; + int p = col.getPreferredWidth(); prefSum += p; if (resizingColumn == col) rCol = i; @@ -2951,14 +3157,38 @@ public class JTable cols = new TableColumn[ncols]; for (int i = 0; i < ncols; ++i) cols[i] = columnModel.getColumn(i); - distributeSpill(cols, spill); + distributeSpillResizing(cols, spill, resizingColumn); break; case AUTO_RESIZE_SUBSEQUENT_COLUMNS: - cols = new TableColumn[ncols]; - for (int i = rCol; i < ncols; ++i) - cols[i] = columnModel.getColumn(i); - distributeSpill(cols, spill); + + // Subtract the width of the non-resized columns from the spill. + int w = 0; + int wp = 0; + TableColumn column; + for (int i = 0; i < rCol; i++) + { + column = columnModel.getColumn(i); + w += column.getWidth(); + wp+= column.getPreferredWidth(); + } + + // The number of columns right from the column being resized. + int n = ncols-rCol-1; + if (n>0) + { + // If there are any columns on the right sied to resize. + spill = (getWidth()-w) - (prefSum-wp); + int average = spill / n; + + // For all columns right from the column being resized: + for (int i = rCol+1; i < ncols; i++) + { + column = columnModel.getColumn(i); + column.setWidth(column.getPreferredWidth() + average); + } + } + resizingColumn.setWidth(resizingColumn.getPreferredWidth()); break; case AUTO_RESIZE_OFF: @@ -2974,6 +3204,16 @@ public class JTable cols[i] = columnModel.getColumn(i); distributeSpill(cols, spill); } + + if (editorComp!=null) + moveToCellBeingEdited(editorComp); + + // Repaint fixes the invalid view after the first keystroke if the cell + // editing is started immediately after the program start or cell + // resizing. + repaint(); + if (tableHeader!=null) + tableHeader.repaint(); } /** @@ -2983,7 +3223,7 @@ public class JTable { doLayout(); } - + /** * Obsolete since JDK 1.4. Please use <code>doLayout()</code>. */ @@ -3023,48 +3263,109 @@ public class JTable revalidate(); repaint(); } - + + /** + * Get the class (datatype) of the column. The cells are rendered and edited + * differently, depending from they data type. + * + * @param column the column (not the model index). + * + * @return the class, defining data type of that column (String.class for + * String, Boolean.class for boolean and so on). + */ public Class getColumnClass(int column) { - return getModel().getColumnClass(column); + return getModel().getColumnClass(convertColumnIndexToModel(column)); } + /** + * Get the name of the column. If the column has the column identifier set, + * the return value is the result of the .toString() method call on that + * identifier. If the identifier is not explicitly set, the returned value + * is calculated by + * {@link javax.swing.table.AbstractTableModel#getColumnName(int)}. + * + * @param column the column + * + * @return the name of that column. + */ public String getColumnName(int column) { int modelColumn = columnModel.getColumn(column).getModelIndex(); return dataModel.getColumnName(modelColumn); } - + + /** + * Get the column, currently being edited + * + * @return the column, currently being edited. + */ public int getEditingColumn() { return editingColumn; } - + + /** + * Set the column, currently being edited + * + * @param column the column, currently being edited. + */ public void setEditingColumn(int column) { editingColumn = column; } + /** + * Get the row currently being edited. + * + * @return the row, currently being edited. + */ public int getEditingRow() { return editingRow; } - - public void setEditingRow(int column) + + /** + * Set the row currently being edited. + * + * @param row the row, that will be edited + */ + public void setEditingRow(int row) { - editingRow = column; + editingRow = row; } + /** + * Get the editor component that is currently editing one of the cells + * + * @return the editor component or null, if none of the cells is being + * edited. + */ public Component getEditorComponent() { return editorComp; } + /** + * Check if one of the table cells is currently being edited. + * + * @return true if there is a cell being edited. + */ public boolean isEditing() { return editorComp != null; } - + + /** + * Set the default editor for the given column class (column data type). + * By default, String is handled by text field and Boolean is handled by + * the check box. + * + * @param columnClass the column data type + * @param editor the editor that will edit this data type + * + * @see TableModel#getColumnClass(int) + */ public void setDefaultEditor(Class columnClass, TableCellEditor editor) { if (editor != null) @@ -3072,7 +3373,7 @@ public class JTable else defaultEditorsByColumnClass.remove(columnClass); } - + public void addColumnSelectionInterval(int index0, int index1) { if ((index0 < 0 || index0 > (getColumnCount()-1) @@ -3127,21 +3428,49 @@ public class JTable getSelectionModel().removeSelectionInterval(index0, index1); } + /** + * Checks if the given column is selected. + * + * @param column the column + * + * @return true if the column is selected (as reported by the selection + * model, associated with the column model), false otherwise. + */ public boolean isColumnSelected(int column) { return getColumnModel().getSelectionModel().isSelectedIndex(column); } - + + /** + * Checks if the given row is selected. + * + * @param row the row + * + * @return true if the row is selected (as reported by the selection model), + * false otherwise. + */ public boolean isRowSelected(int row) { return getSelectionModel().isSelectedIndex(row); } - + + /** + * Checks if the given cell is selected. The cell is selected if both + * the cell row and the cell column are selected. + * + * @param row the cell row + * @param column the cell column + * + * @return true if the cell is selected, false otherwise + */ public boolean isCellSelected(int row, int column) { return isRowSelected(row) && isColumnSelected(column); } + /** + * Select all table. + */ public void selectAll() { // rowLead and colLead store the current lead selection indices @@ -3156,22 +3485,51 @@ public class JTable addColumnSelectionInterval(colLead,colLead); addRowSelectionInterval(rowLead, rowLead); } - + + /** + * Get the cell value at the given position. + * + * @param row the row to get the value + * @param column the actual column number (not the model index) + * to get the value. + * + * @return the cell value, as returned by model. + */ public Object getValueAt(int row, int column) { return dataModel.getValueAt(row, convertColumnIndexToModel(column)); } - + + /** + * Set value for the cell at the given position. If the cell is not + * editable, this method returns without action. The modified cell is + * repainted. + * + * @param value the value to set + * @param row the row of the cell being modified + * @param column the column of the cell being modified + */ public void setValueAt(Object value, int row, int column) { if (!isCellEditable(row, column)) return; - - if (value instanceof Component) - add((Component)value); dataModel.setValueAt(value, row, convertColumnIndexToModel(column)); + + repaint(getCellRect(row, column, true)); } - + + /** + * Get table column with the given identified. + * + * @param identifier the column identifier + * + * @return the table column with this identifier + * + * @throws IllegalArgumentException if <code>identifier</code> is + * <code>null</code> or there is no column with that identifier. + * + * @see TableColumn#setIdentifier(Object) + */ public TableColumn getColumn(Object identifier) { return columnModel.getColumn(columnModel.getColumnIndex(identifier)); @@ -3184,7 +3542,7 @@ public class JTable * @param row the row index. * @param column the column index. * - * @return A boolean. + * @return true if the cell is editable, false otherwise. */ public boolean isCellEditable(int row, int column) { @@ -3273,19 +3631,50 @@ public class JTable */ public boolean editCellAt (int row, int column) { - oldCellValue = getValueAt(row, column); + // Complete the previous editing session, if still active. + if (isEditing()) + editingStopped(new ChangeEvent("editingStopped")); + + editingRow = row; + editingColumn = column; + setCellEditor(getCellEditor(row, column)); editorComp = prepareEditor(cellEditor, row, column); - cellEditor.addCellEditorListener(this); - rowBeingEdited = row; - columnBeingEdited = column; - setValueAt(editorComp, row, column); - ((JTextField)editorComp).requestFocusInWindow(false); - editorTimer.start(); + + // Remove the previous editor components, if present. Only one + // editor component at time is allowed in the table. + removeAll(); + add(editorComp); + moveToCellBeingEdited(editorComp); + scrollRectToVisible(editorComp.getBounds()); + editorComp.requestFocusInWindow(); return true; } /** + * Move the given component under the cell being edited. + * The table must be in the editing mode. + * + * @param component the component to move. + */ + 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)); + } + + /** * Programmatically starts editing the specified cell. * * @param row the row of the cell to edit. @@ -3343,7 +3732,7 @@ public class JTable // TODO: Implement functionality of this property (in UI impl). surrendersFocusOnKeystroke = value; } - + /** * Returns whether cell editors of this table should receive keyboard focus * when the editor is activated by a keystroke. The default setting is diff --git a/libjava/classpath/javax/swing/JTextField.java b/libjava/classpath/javax/swing/JTextField.java index c4903106131..01c5c06a350 100644 --- a/libjava/classpath/javax/swing/JTextField.java +++ b/libjava/classpath/javax/swing/JTextField.java @@ -41,6 +41,7 @@ package javax.swing; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; +import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; @@ -352,7 +353,10 @@ public class JTextField extends JTextComponent Dimension size = super.getPreferredSize(); if (columns != 0) - size.width = columns * getColumnWidth(); + { + Insets i = getInsets(); + size.width = columns * getColumnWidth() + i.left + i.right; + } return size; } @@ -526,4 +530,18 @@ public class JTextField extends JTextComponent // javax.swing.text.FieldView. return horizontalVisibility; } + + /** + * Returns <code>true</code>, unless this is embedded in a + * <code>JViewport</code> in which case the viewport takes responsibility of + * validating. + * + * @return <code>true</code>, unless this is embedded in a + * <code>JViewport</code> in which case the viewport takes + * responsibility of validating + */ + public boolean isValidateRoot() + { + return ! (getParent() instanceof JViewport); + } } diff --git a/libjava/classpath/javax/swing/JTextPane.java b/libjava/classpath/javax/swing/JTextPane.java index 7c95d7682c5..c0a5f80cfc8 100644 --- a/libjava/classpath/javax/swing/JTextPane.java +++ b/libjava/classpath/javax/swing/JTextPane.java @@ -327,9 +327,11 @@ public class JTextPane if (start == dot && end == dot) // There is no selection, update insertAttributes instead { - MutableAttributeSet inputAttributes = - getStyledEditorKit().getInputAttributes(); - inputAttributes.addAttributes(attribute); + MutableAttributeSet inputAttributes = + getStyledEditorKit().getInputAttributes(); + if (replace) + inputAttributes.removeAttributes(inputAttributes); + inputAttributes.addAttributes(attribute); } else getStyledDocument().setCharacterAttributes(start, end - start, attribute, diff --git a/libjava/classpath/javax/swing/JTree.java b/libjava/classpath/javax/swing/JTree.java index cfcb2291b2c..7876eeb6aaa 100644 --- a/libjava/classpath/javax/swing/JTree.java +++ b/libjava/classpath/javax/swing/JTree.java @@ -1482,6 +1482,9 @@ public class JTree extends JComponent implements Scrollable, Accessible setModel(model); setSelectionModel(new EmptySelectionModel()); selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + + // The root node appears expanded by default. + nodeStates.put(new TreePath(model.getRoot()), EXPANDED); } /** @@ -2497,8 +2500,9 @@ public class JTree extends JComponent implements Scrollable, Accessible { TreeUI ui = getUI(); - if (ui != null) - return ui.stopEditing(this); + if (isEditing()) + if (ui != null) + return ui.stopEditing(this); return false; } @@ -2506,9 +2510,10 @@ public class JTree extends JComponent implements Scrollable, Accessible public void cancelEditing() { TreeUI ui = getUI(); - - if (ui != null) - ui.cancelEditing(this); + + if (isEditing()) + if (ui != null) + ui.cancelEditing(this); } public void startEditingAtPath(TreePath path) @@ -2738,7 +2743,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * * @return a String representation of this JTree */ - public String paramString() + protected String paramString() { // TODO: this is completely legal, but it would possibly be nice // to return some more content, like the tree structure, some properties diff --git a/libjava/classpath/javax/swing/JViewport.java b/libjava/classpath/javax/swing/JViewport.java index debb5742e2c..2b5d1cd5a2f 100644 --- a/libjava/classpath/javax/swing/JViewport.java +++ b/libjava/classpath/javax/swing/JViewport.java @@ -48,6 +48,7 @@ import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Point; import java.awt.Rectangle; +import java.awt.Shape; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.io.Serializable; @@ -113,7 +114,7 @@ public class JViewport extends JComponent implements Accessible /** * Creates a new instance of <code>AccessibleJViewport</code>. */ - public AccessibleJViewport() + protected AccessibleJViewport() { // Nothing to do here. } @@ -252,6 +253,13 @@ public class JViewport extends JComponent implements Accessible boolean sizeChanged = true; /** + * Indicates if this JViewport is the paint root or not. If it is not, then + * we may not assume that the offscreen buffer still has the right content + * because parent components may have cleared the background already. + */ + private boolean isPaintRoot = false; + + /** * Initializes the default setting for the scrollMode property. */ static @@ -635,11 +643,19 @@ public class JViewport extends JComponent implements Accessible */ public void repaint(long tm, int x, int y, int w, int h) { - Component parent = getParent(); - if (parent != null) - { - parent.repaint(tm, x + getX(), y + getY(), w, h); - } +// Component parent = getParent(); +// if (parent != null) +// parent.repaint(tm, x + getX(), y + getY(), w, h); +// else +// super.repaint(tm, x, y, w, h); + + // The specs suggest to implement something like the above. This however + // breaks blit painting, because the parent (most likely a JScrollPane) + // clears the background of the offscreen area of the JViewport, thus + // destroying the pieces that we want to clip. So we simply call super here + // instead. + super.repaint(tm, x, y, w, h); + } protected void addImpl(Component comp, Object constraints, int index) @@ -710,9 +726,11 @@ public class JViewport extends JComponent implements Accessible protected boolean computeBlit(int dx, int dy, Point blitFrom, Point blitTo, Dimension blitSize, Rectangle blitPaint) { - if ((dx != 0 && dy != 0) || damaged) + if ((dx != 0 && dy != 0) || (dy == 0 && dy == 0) || damaged) // We cannot blit if the viewport is scrolled in both directions at - // once. + // once. Also, we do not want to blit if the viewport is not scrolled at + // all, because that probably means the view component repaints itself + // and the buffer needs updating. return false; Rectangle portBounds = SwingUtilities.calculateInnerArea(this, getBounds()); @@ -791,6 +809,8 @@ public class JViewport extends JComponent implements Accessible Point pos = getViewPosition(); Component view = getView(); + Shape oldClip = g.getClip(); + g.clipRect(0, 0, getWidth(), getHeight()); boolean translated = false; try { @@ -802,6 +822,7 @@ public class JViewport extends JComponent implements Accessible { if (translated) g.translate (pos.x, pos.y); + g.setClip(oldClip); } } @@ -854,6 +875,11 @@ public class JViewport extends JComponent implements Accessible // everything. else { + // If the image has not been scrolled at all, only the changed + // clip must be updated in the buffer. + if (dx==0 && dy==0) + g2.setClip(g.getClip()); + paintSimple(g2); } g2.dispose(); @@ -877,23 +903,49 @@ public class JViewport extends JComponent implements Accessible */ void paintBlit(Graphics g) { - // We cannot perform blitted painting as it is described in Sun's API docs. - // There it is suggested that this painting method should blit directly - // on the parent window's surface. This is not possible because when using - // Swing's double buffering (at least our implementation), it would - // immediatly be painted when the buffer is painted on the screen. For this - // to work we would need a kind of hole in the buffer image. And honestly - // I find this method not very elegant. - // The alternative, blitting directly on the buffer image, is also not - // possible because the buffer image gets cleared everytime when an opaque - // parent component is drawn on it. - - // What we do instead is falling back to the backing store approach which - // is in fact a mixed blitting/backing store approach where the blitting - // is performed on the backing store image and this is then drawn to the - // graphics context. This is very robust and works independent of the - // painting mechanism that is used by Swing. And it should have comparable - // performance characteristics as the blitting method. - paintBackingStore(g); + // First we move the part that remains visible after scrolling, then + // we only need to paint the bit that becomes newly visible. + Point viewPosition = getViewPosition(); + int dx = viewPosition.x - lastPaintPosition.x; + int dy = viewPosition.y - lastPaintPosition.y; + boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo, + cachedBlitSize, cachedBlitPaint); + if (canBlit && isPaintRoot) + { + // Copy the part that remains visible during scrolling. + g.copyArea(cachedBlitFrom.x, cachedBlitFrom.y, + cachedBlitSize.width, cachedBlitSize.height, + cachedBlitTo.x - cachedBlitFrom.x, + cachedBlitTo.y - cachedBlitFrom.y); + // Now paint the part that becomes newly visible. + Shape oldClip = g.getClip(); + g.clipRect(cachedBlitPaint.x, cachedBlitPaint.y, + cachedBlitPaint.width, cachedBlitPaint.height); + try + { + paintSimple(g); + } + finally + { + g.setClip(oldClip); + } + } + // If blitting is not possible for some reason, fall back to repainting + // everything. + else + paintSimple(g); + lastPaintPosition.setLocation(getViewPosition()); + } + + /** + * Overridden from JComponent to set the {@link #isPaintRoot} flag. + * + * @param r the rectangle to paint + */ + void paintImmediately2(Rectangle r) + { + isPaintRoot = true; + super.paintImmediately2(r); + isPaintRoot = false; } } diff --git a/libjava/classpath/javax/swing/JWindow.java b/libjava/classpath/javax/swing/JWindow.java index cc0ac7fd95a..19d830ed1f7 100644 --- a/libjava/classpath/javax/swing/JWindow.java +++ b/libjava/classpath/javax/swing/JWindow.java @@ -68,7 +68,7 @@ public class JWindow extends Window implements Accessible, RootPaneContainer /** * Creates a new instance of <code>AccessibleJWindow</code>. */ - public AccessibleJWindow() + protected AccessibleJWindow() { super(); // Nothing to do here. @@ -86,33 +86,73 @@ public class JWindow extends Window implements Accessible, RootPaneContainer protected AccessibleContext accessibleContext; + /** + * Creates a new <code>JWindow</code> that has a shared invisible owner frame + * as its parent. + */ public JWindow() { - super(SwingUtilities.getOwnerFrame()); + super(SwingUtilities.getOwnerFrame(null)); windowInit(); } + /** + * Creates a new <code>JWindow</code> that uses the specified graphics + * environment. This can be used to open a window on a different screen for + * example. + * + * @param gc the graphics environment to use + */ public JWindow(GraphicsConfiguration gc) { - super(SwingUtilities.getOwnerFrame(), gc); + super(SwingUtilities.getOwnerFrame(null), gc); windowInit(); } - + + /** + * Creates a new <code>JWindow</code> that has the specified + * <code>owner</code> frame. If <code>owner</code> is <code>null</code>, then + * an invisible shared owner frame is installed as owner frame. + * + * @param owner the owner frame of this window; if <code>null</code> a shared + * invisible owner frame is used + */ public JWindow(Frame owner) { - super(owner); + super(SwingUtilities.getOwnerFrame(owner)); windowInit(); } + /** + * Creates a new <code>JWindow</code> that has the specified + * <code>owner</code> window. If <code>owner</code> is <code>null</code>, + * then an invisible shared owner frame is installed as owner frame. + * + * @param owner the owner window of this window; if <code>null</code> a + * shared invisible owner frame is used + */ public JWindow(Window owner) { - super(owner); + super(SwingUtilities.getOwnerFrame(owner)); windowInit(); } + /** + * Creates a new <code>JWindow</code> for the given graphics configuration + * and that has the specified <code>owner</code> window. If + * <code>owner</code> is <code>null</code>, then an invisible shared owner + * frame is installed as owner frame. + * + * The <code>gc</code> parameter can be used to open the window on a + * different screen for example. + * + * @param owner the owner window of this window; if <code>null</code> a + * shared invisible owner frame is used + * @param gc the graphics configuration to use + */ public JWindow(Window owner, GraphicsConfiguration gc) { - super(owner, gc); + super(SwingUtilities.getOwnerFrame(owner), gc); windowInit(); } diff --git a/libjava/classpath/javax/swing/Popup.java b/libjava/classpath/javax/swing/Popup.java index 203ee3c9b0c..c3de69e05ab 100644 --- a/libjava/classpath/javax/swing/Popup.java +++ b/libjava/classpath/javax/swing/Popup.java @@ -161,7 +161,7 @@ public class Popup super(owner, contents, x, y); this.contents = contents; - window = new JWindow(); + window = new JWindow(SwingUtilities.getWindowAncestor(owner)); window.getContentPane().add(contents); window.setLocation(x, y); window.setFocusableWindowState(false); diff --git a/libjava/classpath/javax/swing/PopupFactory.java b/libjava/classpath/javax/swing/PopupFactory.java index 7bb2529cd54..b326205999c 100644 --- a/libjava/classpath/javax/swing/PopupFactory.java +++ b/libjava/classpath/javax/swing/PopupFactory.java @@ -152,13 +152,18 @@ public class PopupFactory // If we have a root pane and the contents fits within the root pane and // lightweight popups are enabled, than we can use a lightweight popup. JRootPane root = SwingUtilities.getRootPane(owner); - Point rootLoc = root.getLocationOnScreen(); - Dimension contentsSize = contents.getSize(); - Dimension rootSize = root.getSize(); - if (x >= rootLoc.x && y > rootLoc.y - && (x - rootLoc.x) + contentsSize.width < rootSize.width - && (y - rootLoc.y) + contentsSize.height < rootSize.height) - popup = new Popup.LightweightPopup(owner, contents, x, y); + if (root != null) + { + Point rootLoc = root.getLocationOnScreen(); + Dimension contentsSize = contents.getSize(); + Dimension rootSize = root.getSize(); + if (x >= rootLoc.x && y > rootLoc.y + && (x - rootLoc.x) + contentsSize.width < rootSize.width + && (y - rootLoc.y) + contentsSize.height < rootSize.height) + popup = new Popup.LightweightPopup(owner, contents, x, y); + else + popup = new Popup.JWindowPopup(owner, contents, x, y); + } else popup = new Popup.JWindowPopup(owner, contents, x, y); return popup; diff --git a/libjava/classpath/javax/swing/RepaintManager.java b/libjava/classpath/javax/swing/RepaintManager.java index 0be81053dc5..ed0500992c5 100644 --- a/libjava/classpath/javax/swing/RepaintManager.java +++ b/libjava/classpath/javax/swing/RepaintManager.java @@ -40,14 +40,18 @@ package javax.swing; import java.awt.Component; import java.awt.Dimension; +import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; +import java.awt.Window; import java.awt.image.VolatileImage; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; +import java.util.Map; +import java.util.Set; import java.util.WeakHashMap; /** @@ -62,6 +66,7 @@ import java.util.WeakHashMap; * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html">this * document</a> for more details.</p> * + * @author Roman Kennke (kennke@aicas.com) * @author Graydon Hoare (graydon@redhat.com) */ public class RepaintManager @@ -69,8 +74,13 @@ public class RepaintManager /** * The current repaint managers, indexed by their ThreadGroups. */ - static WeakHashMap currentRepaintManagers; - + private static WeakHashMap currentRepaintManagers; + + /** + * A rectangle object to be reused in damaged regions calculation. + */ + private static Rectangle rectCache = new Rectangle(); + /** * <p>A helper class which is placed into the system event queue at * various times in order to facilitate repainting and layout. There is @@ -84,7 +94,7 @@ public class RepaintManager * swing paint thread, which revalidates all invalid components and * repaints any damage in the swing scene.</p> */ - protected class RepaintWorker + private class RepaintWorker implements Runnable { @@ -107,12 +117,18 @@ public class RepaintManager public void run() { - ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); - RepaintManager rm = - (RepaintManager) currentRepaintManagers.get(threadGroup); - setLive(false); - rm.validateInvalidComponents(); - rm.paintDirtyRegions(); + try + { + ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); + RepaintManager rm = + (RepaintManager) currentRepaintManagers.get(threadGroup); + rm.validateInvalidComponents(); + rm.paintDirtyRegions(); + } + finally + { + setLive(false); + } } } @@ -135,41 +151,23 @@ public class RepaintManager * @param o1 the first component * @param o2 the second component * - * @return a negative integer, if <code>o1</code> is higher in the - * hierarchy than <code>o2</code>, zero, if both are at the same - * level and a positive integer, if <code>o1</code> is deeper in - * the hierarchy than <code>o2</code> + * @return a negative integer, if <code>o1</code> is bigger in than + * <code>o2</code>, zero, if both are at the same size and a + * positive integer, if <code>o1</code> is smaller than + * <code>o2</code> */ public int compare(Object o1, Object o2) { if (o1 instanceof JComponent && o2 instanceof JComponent) { JComponent c1 = (JComponent) o1; + Rectangle d1 = (Rectangle) dirtyComponents.get(c1); JComponent c2 = (JComponent) o2; - return getDepth(c1) - getDepth(c2); - } - else - throw new ClassCastException("This comparator can only be used with " - + "JComponents"); - } - - /** - * Computes the depth for a given JComponent. - * - * @param c the component to compute the depth for - * - * @return the depth of the component - */ - private int getDepth(JComponent c) - { - Component comp = c; - int depth = 0; - while (comp != null) - { - comp = comp.getParent(); - depth++; + Rectangle d2 = (Rectangle) dirtyComponents.get(c2); + return d2.width * d2.height - d1.width * d1.height; } - return depth; + throw new ClassCastException("This comparator can only be used with " + + "JComponents"); } } @@ -179,6 +177,9 @@ public class RepaintManager * to exactly one rectangle. When more regions are marked as dirty on a * component, they are union'ed with the existing rectangle. * + * This is package private to avoid a synthetic accessor method in inner + * class. + * * @see #addDirtyRegion * @see #getDirtyRegion * @see #isCompletelyDirty @@ -187,18 +188,10 @@ public class RepaintManager */ HashMap dirtyComponents; - HashMap workDirtyComponents; - - /** - * Stores the order in which the components get repainted. - */ - ArrayList repaintOrder; - ArrayList workRepaintOrder; - /** * The comparator used for ordered inserting into the repaintOrder list. */ - Comparator comparator; + private transient Comparator comparator; /** * A single, shared instance of the helper class. Any methods which mark @@ -209,7 +202,7 @@ public class RepaintManager * @see #addDirtyRegion * @see #addInvalidComponent */ - RepaintWorker repaintWorker; + private RepaintWorker repaintWorker; /** * The set of components which need revalidation, in the "layout" sense. @@ -221,8 +214,7 @@ public class RepaintManager * @see #removeInvalidComponent * @see #validateInvalidComponents */ - ArrayList invalidComponents; - ArrayList workInvalidComponents; + private ArrayList invalidComponents; /** * Whether or not double buffering is enabled on this repaint @@ -232,17 +224,27 @@ public class RepaintManager * @see #isDoubleBufferingEnabled * @see #setDoubleBufferingEnabled */ - boolean doubleBufferingEnabled; + private boolean doubleBufferingEnabled; - /** - * The current offscreen buffer. This is reused for all requests for - * offscreen drawing buffers. It grows as necessary, up to {@link - * #doubleBufferMaximumSize}, but there is only one shared instance. - * - * @see #getOffscreenBuffer - * @see #doubleBufferMaximumSize + /** + * The offscreen buffers. This map holds one offscreen buffer per + * Window/Applet and releases them as soon as the Window/Applet gets garbage + * collected. */ - Image doubleBuffer; + private WeakHashMap offscreenBuffers; + + /** + * Indicates if the RepaintManager is currently repainting an area. + */ + private boolean repaintUnderway; + + /** + * This holds buffer commit requests when the RepaintManager is working. + * This maps Component objects (the top level components) to Rectangle + * objects (the area of the corresponding buffer that must be blitted on + * the component). + */ + private HashMap commitRequests; /** * The maximum width and height to allocate as a double buffer. Requests @@ -252,7 +254,7 @@ public class RepaintManager * @see #getDoubleBufferMaximumSize * @see #setDoubleBufferMaximumSize */ - Dimension doubleBufferMaximumSize; + private Dimension doubleBufferMaximumSize; /** @@ -261,14 +263,13 @@ public class RepaintManager public RepaintManager() { dirtyComponents = new HashMap(); - workDirtyComponents = new HashMap(); - repaintOrder = new ArrayList(); - workRepaintOrder = new ArrayList(); invalidComponents = new ArrayList(); - workInvalidComponents = new ArrayList(); repaintWorker = new RepaintWorker(); doubleBufferMaximumSize = new Dimension(2000,2000); doubleBufferingEnabled = true; + offscreenBuffers = new WeakHashMap(); + repaintUnderway = false; + commitRequests = new HashMap(); } /** @@ -346,9 +347,9 @@ public class RepaintManager * * @see #removeInvalidComponent */ - public synchronized void addInvalidComponent(JComponent component) + public void addInvalidComponent(JComponent component) { - Component ancestor = component.getParent(); + Component ancestor = component; while (ancestor != null && (! (ancestor instanceof JComponent) @@ -363,8 +364,11 @@ public class RepaintManager if (invalidComponents.contains(component)) return; - invalidComponents.add(component); - + synchronized (invalidComponents) + { + invalidComponents.add(component); + } + if (! repaintWorker.isLive()) { repaintWorker.setLive(true); @@ -379,9 +383,12 @@ public class RepaintManager * * @see #addInvalidComponent */ - public synchronized void removeInvalidComponent(JComponent component) + public void removeInvalidComponent(JComponent component) { - invalidComponents.remove(component); + synchronized (invalidComponents) + { + invalidComponents.remove(component); + } } /** @@ -402,41 +409,40 @@ public class RepaintManager * @see #markCompletelyClean * @see #markCompletelyDirty */ - public synchronized void addDirtyRegion(JComponent component, int x, int y, - int w, int h) + public void addDirtyRegion(JComponent component, int x, int y, + int w, int h) { - if (w == 0 || h == 0 || !component.isShowing()) + if (w <= 0 || h <= 0 || !component.isShowing()) return; - Rectangle r = new Rectangle(x, y, w, h); - if (dirtyComponents.containsKey(component)) - r = r.union((Rectangle)dirtyComponents.get(component)); - else - insertInRepaintOrder(component); - dirtyComponents.put(component, r); - if (! repaintWorker.isLive()) + + component.computeVisibleRect(rectCache); + SwingUtilities.computeIntersection(x, y, w, h, rectCache); + + if (! rectCache.isEmpty()) { - repaintWorker.setLive(true); - SwingUtilities.invokeLater(repaintWorker); + if (dirtyComponents.containsKey(component)) + { + SwingUtilities.computeUnion(rectCache.x, rectCache.y, + rectCache.width, rectCache.height, + (Rectangle) dirtyComponents.get(component)); + } + else + { + synchronized (dirtyComponents) + { + dirtyComponents.put(component, rectCache.getBounds()); + } + } + + if (! repaintWorker.isLive()) + { + repaintWorker.setLive(true); + SwingUtilities.invokeLater(repaintWorker); + } } } /** - * Inserts a component into the repaintOrder list in an ordered fashion, - * using a binary search. - * - * @param c the component to be inserted - */ - private void insertInRepaintOrder(JComponent c) - { - if (comparator == null) - comparator = new ComponentComparator(); - int insertIndex = Collections.binarySearch(repaintOrder, c, comparator); - if (insertIndex < 0) - insertIndex = -(insertIndex + 1); - repaintOrder.add(insertIndex, c); - } - - /** * Get the dirty region associated with a component, or <code>null</code> * if the component has no dirty region. * @@ -489,7 +495,7 @@ public class RepaintManager */ public void markCompletelyClean(JComponent component) { - synchronized (this) + synchronized (dirtyComponents) { dirtyComponents.remove(component); } @@ -523,63 +529,58 @@ public class RepaintManager */ public void validateInvalidComponents() { - // In order to keep the blocking of application threads minimal, we switch - // the invalidComponents field with the workInvalidComponents field and - // work with the workInvalidComponents field. - synchronized(this) - { - ArrayList swap = invalidComponents; - invalidComponents = workInvalidComponents; - workInvalidComponents = swap; - } - for (Iterator i = workInvalidComponents.iterator(); i.hasNext(); ) + // We don't use an iterator here because that would fail when there are + // components invalidated during the validation of others, which happens + // quite frequently. Instead we synchronize the access a little more. + while (invalidComponents.size() > 0) { - Component comp = (Component) i.next(); - // Find validate root. - while ((!(comp instanceof JComponent) - || !((JComponent) comp).isValidateRoot()) - && comp.getParent() != null) - comp = comp.getParent(); - - // Validate the validate root. + Component comp; + synchronized (invalidComponents) + { + comp = (Component) invalidComponents.remove(0); + } + // Validate the validate component. if (! (comp.isVisible() && comp.isShowing())) continue; comp.validate(); } - workInvalidComponents.clear(); } /** * Repaint all regions of all components which have been marked dirty in * the {@link #dirtyComponents} table. */ - public synchronized void paintDirtyRegions() + public void paintDirtyRegions() { - // In order to keep the blocking of application threads minimal, we switch - // the dirtyComponents field with the workdirtyComponents field and the - // repaintOrder field with the workRepaintOrder field and work with the - // work* fields. - synchronized(this) - { - ArrayList swap = workRepaintOrder; - workRepaintOrder = repaintOrder; - repaintOrder = swap; - HashMap swap2 = workDirtyComponents; - workDirtyComponents = dirtyComponents; - dirtyComponents = swap2; - } - for (Iterator i = workRepaintOrder.iterator(); i.hasNext();) + // Short cicuit if there is nothing to paint. + if (dirtyComponents.size() == 0) + return; + + synchronized (dirtyComponents) { - JComponent comp = (JComponent) i.next(); - // If a component is marked completely clean in the meantime, then skip - // it. - Rectangle damaged = (Rectangle) workDirtyComponents.get(comp); - if (damaged == null || damaged.isEmpty()) - continue; - comp.paintImmediately(damaged); + // 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(); } - workRepaintOrder.clear(); - workDirtyComponents.clear(); } /** @@ -592,21 +593,114 @@ public class RepaintManager * @param proposedHeight The proposed height of the offscreen buffer * * @return A shared offscreen buffer for painting - * - * @see #doubleBuffer */ public Image getOffscreenBuffer(Component component, int proposedWidth, int proposedHeight) { - if (doubleBuffer == null - || (((doubleBuffer.getWidth(null) < proposedWidth) - || (doubleBuffer.getHeight(null) < proposedHeight)) - && (proposedWidth < doubleBufferMaximumSize.width) - && (proposedHeight < doubleBufferMaximumSize.height))) + Component root = SwingUtilities.getRoot(component); + Image buffer = (Image) offscreenBuffers.get(root); + if (buffer == null + || buffer.getWidth(null) < proposedWidth + || buffer.getHeight(null) < proposedHeight) + { + int width = Math.max(proposedWidth, root.getWidth()); + width = Math.min(doubleBufferMaximumSize.width, width); + int height = Math.max(proposedHeight, root.getHeight()); + height = Math.min(doubleBufferMaximumSize.height, height); + buffer = component.createImage(width, height); + offscreenBuffers.put(root, buffer); + } + return buffer; + } + + /** + * Blits the back buffer of the specified root component to the screen. If + * the RepaintManager is currently working on a paint request, the commit + * requests are queued up and committed at once when the paint request is + * done (by {@link #commitRemainingBuffers}). This is package private because + * it must get called by JComponent. + * + * @param root the component, either a Window or an Applet instance + * @param area the area to paint on screen + */ + void commitBuffer(Component root, Rectangle area) + { + // We synchronize on dirtyComponents here because that is what + // paintDirtyRegions also synchronizes on while painting. + synchronized (dirtyComponents) + { + // If the RepaintManager is not currently painting, then directly + // blit the requested buffer on the screen. + if (! repaintUnderway) + { + Graphics g = root.getGraphics(); + Image buffer = (Image) offscreenBuffers.get(root); + Rectangle clip = g.getClipBounds(); + if (clip != null) + area = SwingUtilities.computeIntersection(clip.x, clip.y, + clip.width, clip.height, + area); + int dx1 = area.x; + int dy1 = area.y; + int dx2 = area.x + area.width; + int dy2 = area.y + area.height; + // Make sure we have a sane clip at this point. + g.clipRect(area.x, area.y, area.width, area.height); + + // Make sure the coordinates are inside the buffer, everything else + // might lead to problems. + // TODO: This code should not really be necessary, however, in fact + // we have two issues here: + // 1. We shouldn't get repaint requests in areas outside the buffer + // region in the first place. This still happens for example + // when a component is inside a JViewport, and the component has + // a size that would reach beyond the window size. + // 2. Graphics.drawImage() should not behave strange when trying + // to draw regions outside the image. + int bufferWidth = buffer.getWidth(root); + int bufferHeight = buffer.getHeight(root); + dx1 = Math.min(bufferWidth, dx1); + dy1 = Math.min(bufferHeight, dy1); + dx2 = Math.min(bufferWidth, dx2); + dy2 = Math.min(bufferHeight, dy2); + g.drawImage(buffer, dx1, dy1, dx2, dy2, + dx1, dy1, dx2, dy2, root); + g.dispose(); + } + // Otherwise queue this request up, until all the RepaintManager work + // is done. + else + { + if (commitRequests.containsKey(root)) + SwingUtilities.computeUnion(area.x, area.y, area.width, + area.height, + (Rectangle) commitRequests.get(root)); + else + commitRequests.put(root, area); + } + } + } + + /** + * Commits the queued up back buffers to screen all at once. + */ + private void commitRemainingBuffers() + { + // We synchronize on dirtyComponents here because that is what + // paintDirtyRegions also synchronizes on while painting. + synchronized (dirtyComponents) { - doubleBuffer = component.createImage(proposedWidth, proposedHeight); + Set entrySet = commitRequests.entrySet(); + Iterator i = entrySet.iterator(); + while (i.hasNext()) + { + Map.Entry entry = (Map.Entry) i.next(); + Component root = (Component) entry.getKey(); + Rectangle area = (Rectangle) entry.getValue(); + commitBuffer(root, area); + i.remove(); + } } - return doubleBuffer; } /** diff --git a/libjava/classpath/javax/swing/ScrollPaneLayout.java b/libjava/classpath/javax/swing/ScrollPaneLayout.java index edf1f1f4292..b00b5c4e7ae 100644 --- a/libjava/classpath/javax/swing/ScrollPaneLayout.java +++ b/libjava/classpath/javax/swing/ScrollPaneLayout.java @@ -285,20 +285,20 @@ public class ScrollPaneLayout // Sun's implementation simply throws a ClassCastException if // parent is no JScrollPane, so do we. JScrollPane sc = (JScrollPane) parent; - Dimension viewportSize = viewport.getMinimumSize(); - int width = viewportSize.width; - int height = viewportSize.height; - if (hsb != null && hsb.isVisible()) - height += hsb.getMinimumSize().height; - if (vsb != null && vsb.isVisible()) - width += vsb.getMinimumSize().width; - if (rowHead != null && rowHead.isVisible()) - width += rowHead.getMinimumSize().width; - if (colHead != null && colHead.isVisible()) - height += colHead.getMinimumSize().height; Insets i = sc.getInsets(); - return new Dimension(width + i.left + i.right, - height + i.top + i.bottom); + Dimension viewportMinSize = sc.getViewport().getMinimumSize(); + + int width = i.left + i.right + viewportMinSize.width; + if (sc.getVerticalScrollBarPolicy() + != JScrollPane.VERTICAL_SCROLLBAR_NEVER) + width += sc.getVerticalScrollBar().getMinimumSize().width; + + int height = i.top + i.bottom + viewportMinSize.height; + if (sc.getHorizontalScrollBarPolicy() + != JScrollPane.HORIZONTAL_SCROLLBAR_NEVER) + height += sc.getHorizontalScrollBar().getMinimumSize().height; + + return new Dimension(width, height); } /** diff --git a/libjava/classpath/javax/swing/SpinnerDateModel.java b/libjava/classpath/javax/swing/SpinnerDateModel.java index c0de7d55c8e..e0ccab776fb 100644 --- a/libjava/classpath/javax/swing/SpinnerDateModel.java +++ b/libjava/classpath/javax/swing/SpinnerDateModel.java @@ -1,5 +1,5 @@ /* SpinnerDateModel.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. @@ -42,21 +42,37 @@ import java.io.Serializable; import java.util.Calendar; import java.util.Date; +import javax.swing.event.ChangeEvent; + /** - * SpinnerDateModel - * - * Implements a SpinnerModel for dates, rotating a calendar field such as - * month, year, day, week, hour, minute. + * A date model used by the {@link JSpinner} component. This implements a + * spinner model for dates, rotating a calendar field such as month, year, + * day, week, hour, minute. * * @author Sven de Marothy - * @version 0.1 (first implementation) + * @since 1.4 */ public class SpinnerDateModel extends AbstractSpinnerModel implements Serializable { + /** The current date. */ private Calendar date; + + /** + * 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 + * maximum). + */ private Comparable end; + + /** + * The calendar field used to calculate the previous or next date. + */ private int calendarField; /** @@ -66,8 +82,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel private static final long serialVersionUID = -4802518107105940612L; /** - * Constructs a SpinnerDateModel using the current date, - * no start or end limit, and Calendar.DAY_OF_MONTH as the calendar field. + * Constructs a <code>SpinnerDateModel</code> using the current date, + * no start or end limit, and {@link Calendar#DAY_OF_MONTH} as the calendar + * field. */ public SpinnerDateModel() { @@ -87,6 +104,12 @@ public class SpinnerDateModel extends AbstractSpinnerModel 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) + throw new IllegalArgumentException("Require value on or after start."); + if (end != null && value.compareTo(end) > 0) + throw new IllegalArgumentException("Require value on or before end."); date = Calendar.getInstance(); date.setTime(value); this.start = start; @@ -95,7 +118,10 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the value of the Calendar field to spin. + * Returns the {@link Calendar} field used to calculate the previous and + * next dates in the sequence. + * + * @return The date field code. */ public int getCalendarField() { @@ -103,8 +129,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the current date in the sequence. - * @return a <code>Date</code> object. + * Returns the current date. + * + * @return The current date. */ public Date getDate() { @@ -112,8 +139,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the starting limit of the SpinnerModel. - * @return a Date object, or <code>null</code> if there is no limit. + * Returns the start date, or <code>null</code> if there is no minimum date. + * + * @return The start date. */ public Comparable getStart() { @@ -121,8 +149,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the end limit of the SpinnerModel. - * @return a Date object, or <code>null</code> if there is no limit. + * Returns the end date, or <code>null</code> if there is no maximum date. + * + * @return The end date. */ public Comparable getEnd() { @@ -130,9 +159,10 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the current date in the sequence, - * this method returns the same as <code>getDate()</code>. - * @return a <code>Date</code> object. + * Returns the current date in the sequence (this method returns the same as + * {@link #getDate()}. + * + * @return The current date. */ public Object getValue() { @@ -141,8 +171,10 @@ public class SpinnerDateModel extends AbstractSpinnerModel /** * Returns the next date in the sequence, or <code>null</code> if the - * next date is equal to or past the end limit. - * @return a Date object, or <code>null</code>. + * next date is after the end date. 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. */ public Object getNextValue() { @@ -152,14 +184,17 @@ public class SpinnerDateModel extends AbstractSpinnerModel Date nextDate = nextCal.getTime(); if (end != null) if (end.compareTo(nextDate) < 0) - return null; + return null; return nextDate; } /** * Returns the previous date in the sequence, or <code>null</code> if the - * next date is equal to or past the end limit. - * @return a Date object, or <code>null</code>. + * previous date is prior to the start date. 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. */ public Object getPreviousValue() { @@ -167,16 +202,21 @@ public class SpinnerDateModel extends AbstractSpinnerModel prevCal.setTime(date.getTime()); prevCal.roll(calendarField, false); Date prevDate = prevCal.getTime(); - if (end != null) - if (end.compareTo(prevDate) > 0) - return null; + if (start != null) + if (start.compareTo(prevDate) > 0) + return null; return prevDate; } /** - * Sets the date field to change. It must be a valid Calendar field, - * excluding Calendar.ZONE_OFFSET and Calendar.DST_OFFSET. - * @param calendarField - the calendar field to set. + * Sets the date field to change when calculating the next and previous + * values. It must be a valid {@link Calendar} field, excluding + * {@link Calendar#ZONE_OFFSET} and {@link Calendar#DST_OFFSET}. + * + * @param calendarField the calendar field to set. + * + * @throws IllegalArgumentException if <code>calendarField</code> is not + * a valid code. */ public void setCalendarField(int calendarField) { @@ -187,51 +227,67 @@ public class SpinnerDateModel extends AbstractSpinnerModel if (this.calendarField != calendarField) { - this.calendarField = calendarField; - fireStateChanged(); + this.calendarField = calendarField; + fireStateChanged(); } } /** - * Sets the starting date limit for the sequence. - * - * @param start - a Date object of the limit date, - * or <code>null</code> for no limit. + * 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. + * + * @param start the new start date (<code>null</code> permitted). */ public void setStart(Comparable start) { if (this.start != start) { - this.start = start; - fireStateChanged(); + this.start = start; + fireStateChanged(); } } /** - * Sets the end date limit for the sequence. - * - * @param end - a Date object of the limit date, - * or <code>null</code> for no limit. + * 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. + * + * @param end the new end date (<code>null</code> permitted). */ public void setEnd(Comparable end) { if (this.end != end) { - this.end = end; - fireStateChanged(); + this.end = end; + fireStateChanged(); } } /** - * Sets the current date in the sequence. + * Sets the current date and, if the new value is different to the old + * value, sends a {@link ChangeEvent} to all registered listeners. * - * @param value - a Date object. + * @param value the new date (<code>null</code> not permitted, must be an + * instance of <code>Date</code>). + * + * @throws IllegalArgumentException if <code>value</code> is not an instance + * of <code>Date</code>. */ public void setValue(Object value) { if (! (value instanceof Date) || value == null) throw new IllegalArgumentException("Value not a date."); - date.setTime((Date) value); - fireStateChanged(); + + if (!date.getTime().equals(value)) + { + date.setTime((Date) value); + fireStateChanged(); + } } } diff --git a/libjava/classpath/javax/swing/SpinnerNumberModel.java b/libjava/classpath/javax/swing/SpinnerNumberModel.java index 2274c9ec038..389c536e47f 100644 --- a/libjava/classpath/javax/swing/SpinnerNumberModel.java +++ b/libjava/classpath/javax/swing/SpinnerNumberModel.java @@ -1,5 +1,5 @@ /* SpinnerNumberModel.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. @@ -39,11 +39,13 @@ package javax.swing; import java.io.Serializable; +import javax.swing.event.ChangeEvent; + /** - * SpinnerNumberModel + * A model used by the {@link JSpinner} component. * * @author Ka-Hing Cheung - * @version 1.0 + * @since 1.4 */ public class SpinnerNumberModel extends AbstractSpinnerModel implements Serializable @@ -53,16 +55,16 @@ public class SpinnerNumberModel extends AbstractSpinnerModel */ private static final long serialVersionUID = 7279176385485777821L; - /** DOCUMENT ME! */ + /** The current value. */ private Number value; - /** DOCUMENT ME! */ + /** The minimum value (or <code>null</code>). */ private Comparable minimum; - /** DOCUMENT ME! */ + /** The maximum value (or <code>null</code>). */ private Comparable maximum; - /** DOCUMENT ME! */ + /** The step size. */ private Number stepSize; /** @@ -75,14 +77,14 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Creates a <code>SpinnerNumberModel</code> with double precision + * Creates a <code>SpinnerNumberModel</code> with double precision. * * @param value the initial value * @param minimum the minimum value * @param maximum the maximum value * @param stepSize the step size - * @throws IllegalArgumentException if minimum <= value <= maximum does not - * hold + * @throws IllegalArgumentException if minimum <= value <= maximum does + * not hold. */ public SpinnerNumberModel(double value, double minimum, double maximum, double stepSize) @@ -92,14 +94,14 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Creates a <code>SpinnerNumberModel</code> with integer precision + * Creates a <code>SpinnerNumberModel</code> with integer precision. * * @param value the initial value * @param minimum the minimum value * @param maximum the maximum value * @param stepSize the step size - * @throws IllegalArgumentException if minimum <= value <= maximum does not - * hold + * @throws IllegalArgumentException if minimum <= value <= maximum does + * not hold. */ public SpinnerNumberModel(int value, int minimum, int maximum, int stepSize) { @@ -108,16 +110,19 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Creates a <code>SpinnerNumberModel</code> with <code>Number</code>s and - * <code>Comparable</code>s. + * Creates a <code>SpinnerNumberModel</code> with the given attributes. * - * @param value the initial value - * @param minimum the minimum value, if null there's no minimum - * @param maximum the maximum value, if null there's no maximum - * @param stepSize the step size + * @param value the initial value. + * @param minimum the minimum value (<code>null</code> permitted). + * @param maximum the maximum value (<code>null</code> permitted). + * @param stepSize the step size. * * @throws IllegalArgumentException if minimum <= value <= maximum * does not hold + * @throws IllegalArgumentException if <code>value</code> is + * <code>null</code>. + * @throws IllegalArgumentException if <code>stepSize</code> is + * <code>null</code>. */ public SpinnerNumberModel(Number value, Comparable minimum, Comparable maximum, Number stepSize) @@ -128,33 +133,14 @@ public class SpinnerNumberModel extends AbstractSpinnerModel throw new IllegalArgumentException("value may not be null"); if (minimum != null) { - if (minimum.compareTo(value) > 0) - throw new IllegalArgumentException("minimum is not <= value"); + if (minimum.compareTo(value) > 0) + throw new IllegalArgumentException("minimum is not <= value"); } - else - minimum = new Comparable() - { - public int compareTo(Object obj) - { - return -1; - } - }; - - if (maximum != null) { - if (maximum.compareTo(value) < 0) - throw new IllegalArgumentException("maximum is not >= value"); + if (maximum.compareTo(value) < 0) + throw new IllegalArgumentException("maximum is not >= value"); } - else - maximum = new Comparable() - { - public int compareTo(Object obj) - { - return 1; - } - }; - this.value = value; this.stepSize = stepSize; @@ -163,26 +149,31 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Sets the new value and fire a change event + * Sets the current value and, if the new value is different to the old + * value, sends a {@link ChangeEvent} to all registered listeners. * - * @param value the new value + * @param value the new value (<code>null</code> not permitted, must be an + * instance of <code>Number</code>). * - * @throws IllegalArgumentException if minimum <= value <= maximum - * does not hold + * @throws IllegalArgumentException if <code>value</code> is not an instance + * of <code>Number</code>. */ public void setValue(Object value) { if (! (value instanceof Number)) throw new IllegalArgumentException("value must be a Number"); - this.value = (Number) value; - fireStateChanged(); + if (!this.value.equals(value)) + { + this.value = (Number) value; + fireStateChanged(); + } } /** - * Gets the current value + * Returns the current value. * - * @return the current value + * @return The current value. */ public Object getValue() { @@ -190,10 +181,12 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Gets the next value without changing the current value, or null if the - * current value is maximum. + * Returns the next value, or <code>null</code> if adding the step size to + * the current value results in a value greater than the maximum value. + * The current value is not changed. * - * @return the next value + * @return The next value, or <code>null</code> if the current value is the + * maximum value represented by this model. */ public Object getNextValue() { @@ -211,15 +204,21 @@ public class SpinnerNumberModel extends AbstractSpinnerModel num = new Short((short) (value.shortValue() + stepSize.shortValue())); else num = new Byte((byte) (value.byteValue() + stepSize.byteValue())); - - return maximum.compareTo(num) >= 0 ? num : null; + + // check upper bound if set + if ((maximum != null) && maximum.compareTo(num) < 0) + num = null; + + return num; } /** - * Gets the previous value without changing the current value, or null if - * the current value is minimum. + * Returns the previous value, or <code>null</code> if subtracting the + * step size from the current value results in a value less than the minimum + * value. The current value is not changed. * - * @return the previous value + * @return The previous value, or <code>null</code> if the current value + * is the minimum value represented by this model. */ public Object getPreviousValue() { @@ -237,62 +236,110 @@ public class SpinnerNumberModel extends AbstractSpinnerModel num = new Short((short) (value.shortValue() - stepSize.shortValue())); else num = new Byte((byte) (value.byteValue() - stepSize.byteValue())); + + // check lower bound if set + if ((minimum != null) && minimum.compareTo(num) > 0) + num = null; - return minimum.compareTo(num) <= 0 ? num : null; + return num; } /** - * DOCUMENT ME! + * Returns the current value. * - * @return DOCUMENT ME! + * @return The current value. */ public Number getNumber() { return value; } + /** + * Returns the minimum value, or <code>null</code> if there is no minimum. + * + * @return The minimum value. + */ public Comparable getMinimum() { return minimum; } + /** + * Sets the minimum value and, if the new value is different to the old + * value, sends a {@link ChangeEvent} to all registered listeners. A + * <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. + * + * @param newMinimum the new minimum value (<code>null</code> permitted). + */ public void setMinimum(Comparable newMinimum) { - if (minimum != newMinimum) + if (minimum != null ? !minimum.equals(newMinimum) : newMinimum != null) { - minimum = newMinimum; - fireStateChanged(); + minimum = newMinimum; + fireStateChanged(); } } + /** + * Returns the maximum value, or <code>null</code> if there is no maximum. + * + * @return The maximum value. + */ public Comparable getMaximum() { return maximum; } + /** + * Sets the maximum value and, if the new value is different to the old + * value, sends a {@link ChangeEvent} to all registered listeners. A + * <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. + * + * @param newMaximum the new maximum (<code>null</code> permitted). + */ public void setMaximum(Comparable newMaximum) { - if (maximum != newMaximum) + if (maximum != null ? !maximum.equals(newMaximum) : newMaximum != null) { - maximum = newMaximum; - fireStateChanged(); + maximum = newMaximum; + fireStateChanged(); } } + /** + * Returns the step size. + * + * @return The step size. + */ public Number getStepSize() { return stepSize; } + /** + * Sets the step size and, if the new step size is different to the old + * step size, sends a {@link ChangeEvent} to all registered listeners. + * + * @param newStepSize the new step size (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>newStepSize</code> is + * <code>null</code>. + */ public void setStepSize(Number newStepSize) { if (newStepSize == null) throw new IllegalArgumentException(); - if (stepSize != newStepSize) + if (!stepSize.equals(newStepSize)) { - stepSize = newStepSize; - fireStateChanged(); + stepSize = newStepSize; + fireStateChanged(); } } } diff --git a/libjava/classpath/javax/swing/Spring.java b/libjava/classpath/javax/swing/Spring.java index 8f7105d496d..b9890c7147f 100644 --- a/libjava/classpath/javax/swing/Spring.java +++ b/libjava/classpath/javax/swing/Spring.java @@ -37,6 +37,9 @@ exception statement from your version. */ package javax.swing; +import java.awt.Component; +import java.awt.Dimension; + /** * Calculates the space between component edges, that are layed out by * {@link SpringLayout}. @@ -168,6 +171,139 @@ public abstract class Spring } /** + * Return a new Spring which computes its values by scaling + * the values of another spring by a constant factor. If the + * factor is negative, the minimum and maximum values of + * the argument spring will be interchanged. + * @param spring the spring to track + * @param factor the factor by which to scale + * @return a new multiplicative Spring + * @since 1.5 + */ + public static Spring scale(final Spring spring, final float factor) + { + if (spring == null) + throw new NullPointerException("spring argument is null"); + return new Spring() + { + public int getMaximumValue() + { + return (int) ((factor < 0 ? spring.getMinimumValue() + : spring.getMaximumValue()) + * factor); + } + + public int getMinimumValue() + { + return (int) ((factor < 0 ? spring.getMaximumValue() + : spring.getMinimumValue()) + * factor); + } + + public int getPreferredValue() + { + return (int) (spring.getPreferredValue() * factor); + } + + public int getValue() + { + return (int) (spring.getValue() * factor); + } + + public void setValue(int value) + { + spring.setValue((int) (value / factor)); + } + }; + } + + /** + * Return a new Spring which takes its values from the specified + * Component. In particular, the maximum value is taken from + * the maximumSize, the minimum value is taken from the minimumSize, + * the preferred value is taken from the preferredSize, and the + * value is taken from the component's current size. These values + * change as the component changes size. + * @param component the component + * @return a new Spring which tracks the component's width + * @since 1.5 + */ + public static Spring width(final Component component) + { + return new Spring() + { + public int getMaximumValue() + { + return component.getMaximumSize().width; + } + + public int getMinimumValue() + { + return component.getMinimumSize().width; + } + + public int getPreferredValue() + { + return component.getPreferredSize().width; + } + + public int getValue() + { + return component.getSize().width; + } + + public void setValue(int value) + { + Dimension d = component.getSize(); + component.setSize(value, d.height); + } + }; + } + + /** + * Return a new Spring which takes its values from the specified + * Component. In particular, the maximum value is taken from + * the maximumSize, the minimum value is taken from the minimumSize, + * the preferred value is taken from the preferredSize, and the + * value is taken from the component's current size. These values + * change as the component changes size. + * @param component the component + * @return a new Spring which tracks the component's height + * @since 1.5 + */ + public static Spring height(final Component component) + { + return new Spring() + { + public int getMaximumValue() + { + return component.getMaximumSize().height; + } + + public int getMinimumValue() + { + return component.getMinimumSize().height; + } + + public int getPreferredValue() + { + return component.getPreferredSize().height; + } + + public int getValue() + { + return component.getSize().height; + } + + public void setValue(int value) + { + Dimension d = component.getSize(); + component.setSize(d.width, value); + } + }; + } + + /** * A simple Spring, that holds constant values for min, pref and max. * * @author Roman Kennke (roman@ontographics.com) diff --git a/libjava/classpath/javax/swing/SpringLayout.java b/libjava/classpath/javax/swing/SpringLayout.java index 592cc0e02a9..8d46a736a58 100644 --- a/libjava/classpath/javax/swing/SpringLayout.java +++ b/libjava/classpath/javax/swing/SpringLayout.java @@ -1,5 +1,5 @@ /* SpringLayout.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -150,6 +150,25 @@ public class SpringLayout implements LayoutManager2 } /** + * Create a new Constraints object which tracks the indicated + * component. The x and y positions for this Constraints object + * are constant Springs created with the component's location at + * the time this constructor is called. The width and height + * of this Constraints are Springs created using + * {@link Spring#width(Component)} and {@link Spring#height(Component)}, + * respectively. + * @param component the component to track + * @since 1.5 + */ + public Constraints(Component component) + { + this(Spring.constant(component.getX()), + Spring.constant(component.getY()), + Spring.width(component), + Spring.height(component)); + } + + /** * Returns the constraint for the edge with the <code>edgeName</code>. * This is expected to be one of * {@link #EAST}, {@link #WEST}, {@link #NORTH} or {@link #SOUTH}. @@ -343,8 +362,8 @@ public class SpringLayout implements LayoutManager2 /** * Adds a layout component and a constraint object to this layout. - * This method is usually only called by a {@java.awt.Container}s add - * Method. + * This method is usually only called by a {@link java.awt.Container}s add + * method. * * @param component the component to be added. * @param constraint the constraint to be set. @@ -357,8 +376,8 @@ public class SpringLayout implements LayoutManager2 /** * Adds a layout component and a constraint object to this layout. - * This method is usually only called by a {@java.awt.Container}s add - * Method. This method does nothing, since SpringLayout does not manage + * This method is usually only called by a {@link java.awt.Container}s add + * method. This method does nothing, since SpringLayout does not manage * String-indexed components. * * @param name the name. diff --git a/libjava/classpath/javax/swing/SwingUtilities.java b/libjava/classpath/javax/swing/SwingUtilities.java index 2d859b7448e..6762ccd804a 100644 --- a/libjava/classpath/javax/swing/SwingUtilities.java +++ b/libjava/classpath/javax/swing/SwingUtilities.java @@ -83,31 +83,6 @@ public class SwingUtilities { // Do nothing. } - - /** - * Calculates the portion of the base rectangle which is inside the - * insets. - * - * @param base The rectangle to apply the insets to - * @param insets The insets to apply to the base rectangle - * @param ret A rectangle to use for storing the return value, or - * <code>null</code> - * - * @return The calculated area inside the base rectangle and its insets, - * either stored in ret or a new Rectangle if ret is <code>null</code> - * - * @see #calculateInnerArea - */ - public static Rectangle calculateInsetArea(Rectangle base, Insets insets, - Rectangle ret) - { - if (ret == null) - ret = new Rectangle(); - ret.setBounds(base.x + insets.left, base.y + insets.top, - base.width - (insets.left + insets.right), - base.height - (insets.top + insets.bottom)); - return ret; - } /** * Calculates the portion of the component's bounds which is inside the @@ -122,13 +97,18 @@ public class SwingUtilities * * @return The calculated area inside the component and its border * insets - * - * @see #calculateInsetArea */ public static Rectangle calculateInnerArea(JComponent c, Rectangle r) { Rectangle b = getLocalBounds(c); - return calculateInsetArea(b, c.getInsets(), r); + if (r == null) + r = new Rectangle(); + 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; + return r; } /** @@ -1021,11 +1001,16 @@ public class SwingUtilities * * @return The common Frame */ - static Frame getOwnerFrame() + static Window getOwnerFrame(Window owner) { - if (ownerFrame == null) - ownerFrame = new OwnerFrame(); - return ownerFrame; + Window result = owner; + if (result == null) + { + if (ownerFrame == null) + ownerFrame = new OwnerFrame(); + result = ownerFrame; + } + return result; } /** @@ -1262,26 +1247,31 @@ public class SwingUtilities } /** - * Calculates the intersection of two rectangles. + * Calculates the intersection of two rectangles. The result is stored + * in <code>rect</code>. This is basically the same + * like {@link Rectangle#intersection(Rectangle)}, only that it does not + * create new Rectangle instances. The tradeoff is that you loose any data in + * <code>rect</code>. * * @param x upper-left x coodinate of first rectangle * @param y upper-left y coodinate of first rectangle * @param w width of first rectangle * @param h height of first rectangle * @param rect a Rectangle object of the second rectangle - * @throws NullPointerException if rect is null. + * + * @throws NullPointerException if rect is null * * @return a rectangle corresponding to the intersection of the - * two rectangles. A zero rectangle is returned if the rectangles - * do not overlap. + * two rectangles. An empty rectangle is returned if the rectangles + * do not overlap */ public static Rectangle computeIntersection(int x, int y, int w, int h, Rectangle rect) { - int x2 = (int) rect.getX(); - int y2 = (int) rect.getY(); - int w2 = (int) rect.getWidth(); - int h2 = (int) rect.getHeight(); + int x2 = (int) rect.x; + int y2 = (int) rect.y; + int w2 = (int) rect.width; + int h2 = (int) rect.height; int dx = (x > x2) ? x : x2; int dy = (y > y2) ? y : y2; @@ -1289,9 +1279,11 @@ public class SwingUtilities int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); if (dw >= 0 && dh >= 0) - return new Rectangle(dx, dy, dw, dh); + rect.setBounds(dx, dy, dw, dh); + else + rect.setBounds(0, 0, 0, 0); - return new Rectangle(0, 0, 0, 0); + return rect; } /** @@ -1308,26 +1300,31 @@ public class SwingUtilities } /** - * Calculates the union of two rectangles. + * Calculates the union of two rectangles. The result is stored in + * <code>rect</code>. This is basically the same as + * {@link Rectangle#union(Rectangle)} except that it avoids creation of new + * Rectangle objects. The tradeoff is that you loose any data in + * <code>rect</code>. * * @param x upper-left x coodinate of first rectangle * @param y upper-left y coodinate of first rectangle * @param w width of first rectangle * @param h height of first rectangle * @param rect a Rectangle object of the second rectangle - * @throws NullPointerException if rect is null. + * + * @throws NullPointerException if rect is null * * @return a rectangle corresponding to the union of the - * two rectangles. A rectangle encompassing both is returned if the - * rectangles do not overlap. + * two rectangles; a rectangle encompassing both is returned if the + * rectangles do not overlap */ public static Rectangle computeUnion(int x, int y, int w, int h, Rectangle rect) { - int x2 = (int) rect.getX(); - int y2 = (int) rect.getY(); - int w2 = (int) rect.getWidth(); - int h2 = (int) rect.getHeight(); + int x2 = (int) rect.x; + int y2 = (int) rect.y; + int w2 = (int) rect.width; + int h2 = (int) rect.height; int dx = (x < x2) ? x : x2; int dy = (y < y2) ? y : y2; @@ -1335,9 +1332,10 @@ public class SwingUtilities int dh = (y + h > y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); if (dw >= 0 && dh >= 0) - return new Rectangle(dx, dy, dw, dh); - - return new Rectangle(0, 0, 0, 0); + rect.setBounds(dx, dy, dw, dh); + else + rect.setBounds(0, 0, 0, 0); + return rect; } /** diff --git a/libjava/classpath/javax/swing/Timer.java b/libjava/classpath/javax/swing/Timer.java index cf91c23e8ec..231b71d73bb 100644 --- a/libjava/classpath/javax/swing/Timer.java +++ b/libjava/classpath/javax/swing/Timer.java @@ -68,11 +68,11 @@ public class Timer public void run() { if (logTimers) - System.out.println("javax.swing.Timer -> queueEvent()"); + System.out.println("javax.swing.Timer -> queueEvent()"); queueEvent(); if (!repeats) - task = null; + task = null; } } @@ -141,8 +141,9 @@ public class Timer /** * The task that calls queueEvent(). When null this Timer is stopped. + * This is package private to avoid synthetic accessor method. */ - private Task task; + Task task; /** * This object manages a "queue" of virtual actionEvents, maintained as a diff --git a/libjava/classpath/javax/swing/ToolTipManager.java b/libjava/classpath/javax/swing/ToolTipManager.java index 289149fb603..c7de4db8330 100644 --- a/libjava/classpath/javax/swing/ToolTipManager.java +++ b/libjava/classpath/javax/swing/ToolTipManager.java @@ -40,9 +40,6 @@ package javax.swing; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.LayoutManager; -import java.awt.Panel; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; diff --git a/libjava/classpath/javax/swing/UIManager.java b/libjava/classpath/javax/swing/UIManager.java index fbf1c7c79cb..bf8739daca2 100644 --- a/libjava/classpath/javax/swing/UIManager.java +++ b/libjava/classpath/javax/swing/UIManager.java @@ -43,11 +43,11 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.Insets; import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.io.Serializable; import java.util.Locale; import javax.swing.border.Border; -import javax.swing.event.SwingPropertyChangeSupport; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.metal.MetalLookAndFeel; @@ -138,8 +138,8 @@ public class UIManager implements Serializable static UIDefaults userUIDefaults; /** Property change listener mechanism. */ - static SwingPropertyChangeSupport listeners - = new SwingPropertyChangeSupport(UIManager.class); + static PropertyChangeSupport listeners + = new PropertyChangeSupport(UIManager.class); static { diff --git a/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java b/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java index f99c0ac19f7..b65119a00bc 100644 --- a/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java +++ b/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java @@ -1,5 +1,5 @@ /* UnsupportedLookAndFeelException.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,11 +37,21 @@ exception statement from your version. */ package javax.swing; - +/** + * Thrown by the {@link UIManager#setLookAndFeel(LookAndFeel)} method when the + * specified look and feel is not supported on the current platform. + * + * @see LookAndFeel#isSupportedLookAndFeel() + */ public class UnsupportedLookAndFeelException extends Exception { - public UnsupportedLookAndFeelException(String a) + /** + * Creates a new exception instance with the specified message. + * + * @param s the exception message. + */ + public UnsupportedLookAndFeelException(String s) { - super(a); + super(s); } } diff --git a/libjava/classpath/javax/swing/ViewportLayout.java b/libjava/classpath/javax/swing/ViewportLayout.java index 79fd26c56df..674de959f6e 100644 --- a/libjava/classpath/javax/swing/ViewportLayout.java +++ b/libjava/classpath/javax/swing/ViewportLayout.java @@ -1,5 +1,5 @@ /* ViewportLayout.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. @@ -46,9 +46,16 @@ import java.awt.Rectangle; import java.io.Serializable; /** - * ViewportLayout - * @author Andrew Selkirk - * @author Graydon Hoare + * The default layout for {@link JViewport}. The viewport makes its view the + * same size as itself, but not smaller than its minimum size. + * + * If the port extends extends into space <em>past</em> the edge of the view, + * this layout manager moves the port up or to the left, in view space, by the + * amount of empty space (keep the lower and right edges lined up). + * + * @author Andrew Selkirk + * @author Graydon Hoare + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) */ public class ViewportLayout implements LayoutManager, Serializable { @@ -58,17 +65,31 @@ public class ViewportLayout implements LayoutManager, Serializable { // Nothing to do here. } - + + /** + * The method is not used with this manager. + */ public void addLayoutComponent(String name, Component c) { // Nothing to do here. } + /** + * The method is not used with this manager. + */ public void removeLayoutComponent(Component c) { // Nothing to do here. } - + + /** + * Get the preferred layout size. If the view implements + * {@link Scrollable}, this method returns + * {@link Scrollable#getPreferredScrollableViewportSize}. + * Otherwise, it returns {@link Component#getPreferredSize()}. + * + * @return the preferred layout size, as described about. + */ public Dimension preferredLayoutSize(Container parent) { JViewport vp = (JViewport)parent; @@ -83,14 +104,19 @@ public class ViewportLayout implements LayoutManager, Serializable return new Dimension(); } + /** + * Get the minimum layout size. Normally this method returns the value, + * returned by the view method {@link Component#getMinimumSize()}. + * + * If the view is not set, the zero size is returned. + * + * @param parent the viewport + * @return the minimum layout size. + */ public Dimension minimumLayoutSize(Container parent) { - JViewport vp = (JViewport)parent; - Component view = vp.getView(); - if (view != null) - return view.getMinimumSize(); - else - return new Dimension(); + // These values have been determined by the Mauve test for this method. + return new Dimension(4, 4); } /** @@ -101,15 +127,13 @@ public class ViewportLayout implements LayoutManager, Serializable * * <ol> * - * <li>If the port is larger than the view's minimum size, put the port - * at view position <code>(0,0)</code> and make the view's size equal to - * the port's.</li> - * * <li>If the port is smaller than the view, leave the view at its - * minimum size. also, do not move the port, <em>unless</em> the port + * 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> + * <li>In {@link JViewport#setViewSize(Dimension)}, the view size is never + * set smaller that its minimum size.</li> * * </ol> * @@ -118,7 +142,6 @@ public class ViewportLayout implements LayoutManager, Serializable * @see JViewport#getViewPosition * @see JViewport#setViewPosition */ - public void layoutContainer(Container parent) { // The way to interpret this function is basically to ignore the names @@ -141,23 +164,22 @@ public class ViewportLayout implements LayoutManager, Serializable Rectangle portBounds = port.getViewRect(); Dimension viewPref = view.getPreferredSize(); Dimension viewMinimum = view.getMinimumSize(); + 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 (portBounds.height >= viewMinimum.height) - portBounds.y = 0; - else - { - int overextension = portLowerRight.y - viewPref.height; - if (overextension > 0) - portBounds.y -= overextension; - } + + // 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 @@ -165,16 +187,13 @@ public class ViewportLayout implements LayoutManager, Serializable && ((Scrollable) view).getScrollableTracksViewportWidth()))) viewPref.width = portBounds.width; - if (portBounds.width >= viewMinimum.width) - portBounds.x = 0; - else - { - int overextension = portLowerRight.x - viewPref.width; - if (overextension > 0) - portBounds.x -= overextension; - } + // 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; - port.setViewPosition(portBounds.getLocation()); port.setViewSize(viewPref); + port.setViewPosition(portBounds.getLocation()); } } diff --git a/libjava/classpath/javax/swing/event/CaretEvent.java b/libjava/classpath/javax/swing/event/CaretEvent.java index c4870a8008f..7de05a81b74 100644 --- a/libjava/classpath/javax/swing/event/CaretEvent.java +++ b/libjava/classpath/javax/swing/event/CaretEvent.java @@ -1,5 +1,5 @@ /* CaretEvent.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,43 +37,34 @@ exception statement from your version. */ package javax.swing.event; -// Imports import java.util.EventObject; /** * CaretEvent * @author Andrew Selkirk */ -public abstract class CaretEvent extends EventObject { +public abstract class CaretEvent extends EventObject +{ - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * CaretEvent constructor - * @param source Source object - */ - public CaretEvent(Object source) { - super(source); - } // CaretEvent() + /** + * CaretEvent constructor + * @param source Source object + */ + public CaretEvent(Object source) + { + super(source); + } - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * Get caret location - * @returns the dot - */ - public abstract int getDot(); + /** + * Get caret location + * @return the dot + */ + public abstract int getDot(); - /** - * Get mark - * @returns the mark - */ - public abstract int getMark(); + /** + * Get mark + * @return the mark + */ + public abstract int getMark(); - -} // CaretEvent +} diff --git a/libjava/classpath/javax/swing/event/DocumentEvent.java b/libjava/classpath/javax/swing/event/DocumentEvent.java index 6cd8e61fee4..82230492520 100644 --- a/libjava/classpath/javax/swing/event/DocumentEvent.java +++ b/libjava/classpath/javax/swing/event/DocumentEvent.java @@ -1,5 +1,5 @@ /* DocumentEvent.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. @@ -54,25 +54,25 @@ public interface DocumentEvent { /** * getIndex - * @returns int + * @return int */ int getIndex(); /** * getElement - * @returns Element + * @return Element */ Element getElement(); /** * getChildrenRemoved - * @returns Element[] + * @return Element[] */ Element[] getChildrenRemoved(); /** * getChildrenAdded - * @returns Element[] + * @return Element[] */ Element[] getChildrenAdded(); @@ -81,7 +81,7 @@ public interface DocumentEvent /** * EventType */ - class EventType + final class EventType { /** * INSERT @@ -114,7 +114,7 @@ public interface DocumentEvent /** * toString - * @returns String + * @return String */ public String toString() { @@ -124,32 +124,32 @@ public interface DocumentEvent /** * getType - * @returns EventType + * @return EventType */ EventType getType(); /** * getOffset - * @returns int + * @return int */ int getOffset(); /** * getLength - * @returns int + * @return int */ int getLength(); /** * getDocument - * @returns Document + * @return Document */ Document getDocument(); /** * getChange * @param element TODO - * @returns ElementChange + * @return ElementChange */ ElementChange getChange(Element element); diff --git a/libjava/classpath/javax/swing/event/EventListenerList.java b/libjava/classpath/javax/swing/event/EventListenerList.java index 147d68ef184..a7fbec44d36 100644 --- a/libjava/classpath/javax/swing/event/EventListenerList.java +++ b/libjava/classpath/javax/swing/event/EventListenerList.java @@ -188,7 +188,7 @@ public class EventListenerList /** * Get a list of listenerType/listener pairs - * @returns Listener list + * @return Listener list */ public Object[] getListenerList() { @@ -214,7 +214,7 @@ public class EventListenerList * @throws NullPointerException if <code>c</code> is * <code>null</code>. * - * @returns an array of <code>c</code> whose elements are the + * @return an array of <code>c</code> whose elements are the * currently subscribed listeners of the specified type. If there * are no such listeners, an empty array is returned. * diff --git a/libjava/classpath/javax/swing/event/ListSelectionEvent.java b/libjava/classpath/javax/swing/event/ListSelectionEvent.java index e5e4c33bad9..d79cbfa507f 100644 --- a/libjava/classpath/javax/swing/event/ListSelectionEvent.java +++ b/libjava/classpath/javax/swing/event/ListSelectionEvent.java @@ -1,5 +1,5 @@ /* ListSelectionEvent.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,90 +37,99 @@ exception statement from your version. */ package javax.swing.event; -// Imports import java.util.EventObject; +import javax.swing.ListSelectionModel; + /** - * ListSelectionEvent + * An event that indicates a change to a list selection, including the source + * of the change (a {@link ListSelectionModel}) and the range of items in the + * list that have potentially changed their selection status. + * * @author Andrew Selkirk * @author Ronald Veldema */ -public class ListSelectionEvent extends EventObject { - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * firstIndex - */ - private int firstIndex = 0; - - /** - * lastIndex - */ - private int lastIndex = 0; - - /** - * isAdjusting - */ - private boolean isAdjusting = false; - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor ListSelectionEvent - * @param source Source - * @param firstIndex First index - * @param lastIndex Last index - * @param isAdjusting Is Adjusting? - */ - public ListSelectionEvent(Object source, int firstIndex, - int lastIndex, boolean isAdjusting) { - super(source); - this.firstIndex = firstIndex; - this.lastIndex = lastIndex; - this.isAdjusting = isAdjusting; - } // ListSelectionEvent() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getFirstIndex - * @returns firstIndex - */ - public int getFirstIndex() { - return firstIndex; - } // getFirstIndex() - - /** - * getLastIndex - * @returns lastIndex - */ - public int getLastIndex() { - return lastIndex; - } // getLastIndex() - - /** - * getValueIsAdjusting - * @returns isAdjusting - */ - public boolean getValueIsAdjusting() { - return isAdjusting; - } // getValueIsAdjusting() - - /** - * String representation - * @returns String representation - */ - public String toString() { - return null; // TODO - } // toString() - - -} // ListSelectionEvent +public class ListSelectionEvent extends EventObject +{ + + /** + * The index of the first list item in the range of items that has + * potentially had its selection status modified. + */ + private int firstIndex = 0; + + /** + * The index of the last list item in the range of items that has + * potentially had its selection status modified. + */ + private int lastIndex = 0; + + /** A flag that indicates that this event is one in a series of events. */ + private boolean isAdjusting = false; + + /** + * Creates a new <code>ListSelectionEvent</code>. + * + * @param source the event source (<code>null</code> not permitted). + * @param firstIndex the first index. + * @param lastIndex the last index. + * @param isAdjusting a flag indicating that this event is one in a series + * of events updating a selection. + * + * @throws IllegalArgumentException if <code>source</code> is + * <code>null</code>. + */ + public ListSelectionEvent(Object source, int firstIndex, + int lastIndex, boolean isAdjusting) + { + super(source); + this.firstIndex = firstIndex; + this.lastIndex = lastIndex; + this.isAdjusting = isAdjusting; + } + + /** + * Returns the first index. + * + * @return The first index. + */ + public int getFirstIndex() + { + return firstIndex; + } + + /** + * Returns the last index. + * + * @return The last index. + */ + public int getLastIndex() + { + return lastIndex; + } + + /** + * Returns the flag that indicates that this event is one in a series of + * events updating a selection. + * + * @return A boolean. + */ + public boolean getValueIsAdjusting() + { + return isAdjusting; + } + + /** + * Returns a string representation of the event, typically used for debugging + * purposes. + * + * @return A string representation of the event. + */ + public String toString() + { + return this.getClass().toString() + "[ source=" + source.toString() + + " firstIndex= " + firstIndex + " lastIndex= " + lastIndex + + " isAdjusting= " + isAdjusting + " ]"; + } + +} diff --git a/libjava/classpath/javax/swing/event/ListSelectionListener.java b/libjava/classpath/javax/swing/event/ListSelectionListener.java index 4ebf5830432..a21dc7365bc 100644 --- a/libjava/classpath/javax/swing/event/ListSelectionListener.java +++ b/libjava/classpath/javax/swing/event/ListSelectionListener.java @@ -1,5 +1,5 @@ /* ListSelectionListener.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,25 @@ exception statement from your version. */ package javax.swing.event; -// Imports import java.util.EventListener; +import javax.swing.ListSelectionModel; + /** - * ListSelectionListener public interface + * A listener that receives {@link ListSelectionEvent} notifications, + * typically from a {@link ListSelectionModel} when it is modified. + * * @author Andrew Selkirk * @author Ronald Veldema */ -public interface ListSelectionListener extends EventListener { - - /** - * Value changed - * @param event List Selection Event - */ - void valueChanged(ListSelectionEvent event); +public interface ListSelectionListener extends EventListener +{ + /** + * Receives notification of a {@link ListSelectionEvent}. + * + * @param event the event. + */ + void valueChanged(ListSelectionEvent event); -} // ListSelectionListener +}
\ No newline at end of file diff --git a/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java b/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java index 99761670629..6be11bcca71 100644 --- a/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java +++ b/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java @@ -1,5 +1,5 @@ /* MenuDragMouseEvent.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. @@ -48,68 +48,57 @@ import javax.swing.MenuSelectionManager; * MenuDragMouseEvent * @author Andrew Selkirk */ -public class MenuDragMouseEvent extends MouseEvent { +public class MenuDragMouseEvent extends MouseEvent +{ - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * path - */ - private MenuElement[] path = null; + /** + * path + */ + private MenuElement[] path = null; - /** - * manager - */ - private MenuSelectionManager manager = null; - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor MenuDragMouseEvent - * @param source Source - * @param id MouseEvent type - * @param when Time - * @param modifiers Key modifiers - * @param x Horizontal position - * @param y Vertical position - * @param clickCount Click count - * @param popupTrigger Popup trigger? - * @param path Path - * @param manager MenuSelectionManager - */ - public MenuDragMouseEvent(Component source, int id, long when, int modifiers, - int x, int y, int clickCount, boolean popupTrigger, - MenuElement[] path, MenuSelectionManager manager) { - super(source, id, when, modifiers, x, y, clickCount, popupTrigger); - this.path = path; - this.manager = manager; - } // MenuDragMouseEvent() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * Get path - * @returns path - */ - public MenuElement[] getPath() { - return path; - } // getPath() - - /** - * Get menu selection manager - * @returns manager - */ - public MenuSelectionManager getMenuSelectionManager() { - return manager; - } // getMenuSelectionManager() - - -} // MenuDragMouseEvent + /** + * manager + */ + private MenuSelectionManager manager = null; + + /** + * Constructor MenuDragMouseEvent + * @param source Source + * @param id MouseEvent type + * @param when Time + * @param modifiers Key modifiers + * @param x Horizontal position + * @param y Vertical position + * @param clickCount Click count + * @param popupTrigger Popup trigger? + * @param path Path + * @param manager MenuSelectionManager + */ + public MenuDragMouseEvent(Component source, int id, long when, int modifiers, + int x, int y, int clickCount, boolean popupTrigger, + MenuElement[] path, MenuSelectionManager manager) + { + super(source, id, when, modifiers, x, y, clickCount, popupTrigger); + this.path = path; + this.manager = manager; + } + + /** + * Get path + * @return path + */ + public MenuElement[] getPath() + { + return path; + } + + /** + * Get menu selection manager + * @return manager + */ + public MenuSelectionManager getMenuSelectionManager() + { + return manager; + } + +} diff --git a/libjava/classpath/javax/swing/event/MenuKeyEvent.java b/libjava/classpath/javax/swing/event/MenuKeyEvent.java index 511cb2254cd..3335850bced 100644 --- a/libjava/classpath/javax/swing/event/MenuKeyEvent.java +++ b/libjava/classpath/javax/swing/event/MenuKeyEvent.java @@ -1,5 +1,5 @@ /* MenuKeyEvent.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. @@ -48,66 +48,55 @@ import javax.swing.MenuSelectionManager; * MenuKeyEvent * @author Andrew Selkirk */ -public class MenuKeyEvent extends KeyEvent { +public class MenuKeyEvent extends KeyEvent +{ - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * path - */ - private MenuElement[] path = null; + /** + * path + */ + private MenuElement[] path = null; - /** - * manager - */ - private MenuSelectionManager manager = null; - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor MenuKeyEvent - * @param source Source - * @param id KeyEvent ID - * @param when Time - * @param modifiers Modifier keys - * @param keyCode Key code - * @param keyChar Key char - * @param path Path - * @param manager MenuSelectionManager - */ - public MenuKeyEvent(Component source, int id, long when, int modifiers, - int keyCode, char keyChar, MenuElement[] path, - MenuSelectionManager manager) { - super(source, id, when, modifiers, keyCode, keyChar); - this.path = path; - this.manager = manager; - } // MenuKeyEvent() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getPath - * @returns path - */ - public MenuElement[] getPath() { - return path; - } // getPath() - - /** - * getMenuSelectionManager - * @returns MenuSelectionManager - */ - public MenuSelectionManager getMenuSelectionManager() { - return manager; - } // getMenuSelectionManager() - - -} // MenuKeyEvent + /** + * manager + */ + private MenuSelectionManager manager = null; + + /** + * Constructor MenuKeyEvent + * @param source Source + * @param id KeyEvent ID + * @param when Time + * @param modifiers Modifier keys + * @param keyCode Key code + * @param keyChar Key char + * @param path Path + * @param manager MenuSelectionManager + */ + public MenuKeyEvent(Component source, int id, long when, int modifiers, + int keyCode, char keyChar, MenuElement[] path, + MenuSelectionManager manager) + { + super(source, id, when, modifiers, keyCode, keyChar); + this.path = path; + this.manager = manager; + } + + /** + * getPath + * @return path + */ + public MenuElement[] getPath() + { + return path; + } + + /** + * getMenuSelectionManager + * @return MenuSelectionManager + */ + public MenuSelectionManager getMenuSelectionManager() + { + return manager; + } + +} diff --git a/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java b/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java index 7e8ff0dc2e9..7fb8aa67d7a 100644 --- a/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java +++ b/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java @@ -1,5 +1,5 @@ /* SwingPropertyChangeSupport.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,48 +39,24 @@ package javax.swing.event; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeListenerProxy; import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.EventListener; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; /** * Provides a mechanism for registering {@link PropertyChangeListener}s and * forwarding {@link PropertyChangeEvent}s to those listeners. - * + * + * As of JDK1.5 this class is no longer in use. Use + * {@link PropertyChangeSupport} instead. + * * @author Andrew Selkirk */ public final class SwingPropertyChangeSupport - extends PropertyChangeSupport + extends PropertyChangeSupport { private static final long serialVersionUID = 7162625831330845068L; /** - * Storage for the listeners that are not linked to a specific property. - */ - private transient EventListenerList listeners; - - /** - * Storage for the listeners that are linked (by name) to a specific property. - * The hash table maps <code>String</code> objects (the property names) to - * {@link EventListenerList} instances (which record the listener(s) for the - * given property). - */ - private Hashtable propertyListeners; - - /** - * The object that is used as the default source for the - * {@link PropertyChangeEvent}s generated by this class. - */ - private Object source; - - /** * Creates a new instance. * * @param source the source (<code>null</code> not permitted). @@ -90,247 +66,5 @@ public final class SwingPropertyChangeSupport public SwingPropertyChangeSupport(Object source) { super(source); - this.source = source; - this.listeners = new EventListenerList(); - this.propertyListeners = new Hashtable(); } - - /** - * Registers <code>listener</code> to receive notification of any future - * {@link PropertyChangeEvent}s generated by this instance. - * - * @param listener the listener (<code>null</code> is ignored). - * - * @see #removePropertyChangeListener(PropertyChangeListener) - */ - public synchronized void addPropertyChangeListener(PropertyChangeListener - listener) - { - listeners.add(PropertyChangeListener.class, listener); - } - - /** - * Registers <code>listener</code> to receive notification of any future - * {@link PropertyChangeEvent}s generated by this instance for the named - * property. - * - * @param propertyName the property name. - * @param listener the listener. - * - * @see #removePropertyChangeListener(String, PropertyChangeListener) - */ - public synchronized void addPropertyChangeListener(String propertyName, - PropertyChangeListener listener) - { - EventListenerList list; - list = (EventListenerList) propertyListeners.get(propertyName); - if (list == null) - { - list = new EventListenerList(); - propertyListeners.put(propertyName, list); - } - list.add(PropertyChangeListener.class, listener); - } - - /** - * Removes <code>listener</code> from the list of registered listeners, so - * that it will no longer receive notification of property change events. - * - * @param listener the listener to remove. - */ - public synchronized void removePropertyChangeListener(PropertyChangeListener - listener) - { - listeners.remove(PropertyChangeListener.class, listener); - } - - /** - * Removes <code>listener</code> from the list of registered listeners for - * the named property, so that it will no longer receive notification of - * property change events. - * - * @param propertyName the property name. - * @param listener the listener to remove. - */ - public synchronized void removePropertyChangeListener(String propertyName, - PropertyChangeListener listener) - { - EventListenerList list; - list = (EventListenerList) propertyListeners.get(propertyName); - if (list == null) - return; - list.remove(PropertyChangeListener.class, listener); - if (list.getListenerCount() == 0) - { - propertyListeners.remove(propertyName); - } - } - - /** - * Returns an array of the {@link PropertyChangeListener}s registered with - * this <code>SwingPropertyChangeSupport</code> instance. - * - * @return The array of listeners. - * - * @since 1.4 - */ - public synchronized PropertyChangeListener[] getPropertyChangeListeners() - { - // fetch the named listeners first so we know how many there are - List namedListeners = new ArrayList(); - Set namedListenerEntries = propertyListeners.entrySet(); - Iterator iterator = namedListenerEntries.iterator(); - while (iterator.hasNext()) - { - Map.Entry e = (Map.Entry) iterator.next(); - String propertyName = (String) e.getKey(); - EventListenerList ell = (EventListenerList) e.getValue(); - if (ell != null) - { - Object[] list = ell.getListenerList(); - for (int i = 0; i < list.length; i += 2) - { - namedListeners.add(new PropertyChangeListenerProxy(propertyName, - (PropertyChangeListener) list[i + 1])); - } - } - } - - // create an array that can hold everything - int size = listeners.getListenerCount() + namedListeners.size(); - PropertyChangeListener[] result = new PropertyChangeListener[size]; - - // copy in the general listeners - Object[] list = listeners.getListenerList(); - int index = 0; - for (int i = 0; i < list.length; i += 2) - result[index++] = (PropertyChangeListener) list[i + 1]; - - // ...and the named listeners - Iterator iterator2 = namedListeners.iterator(); - while (iterator2.hasNext()) - result[index++] = (PropertyChangeListenerProxy) iterator2.next(); - - return result; - } - - /** - * Returns an array of all listeners that are registered to receive - * notification of changes to the named property. This includes the general - * listeners as well as those registered specifically for the named - * property. - * - * @param propertyName the property name. - * - * @return An array of all listeners for the named property. - */ - public synchronized PropertyChangeListener[] getPropertyChangeListeners( - String propertyName) - { - EventListenerList list - = (EventListenerList) propertyListeners.get(propertyName); - if (list == null) - return getPropertyChangeListeners(); - int size = listeners.getListenerCount() + list.getListenerCount(); - PropertyChangeListener[] result = new PropertyChangeListener[size]; - - // copy in the general listeners - int index = 0; - for (int i = 0; i < listeners.listenerList.length; i += 2) - { - result[index++] - = (PropertyChangeListener) listeners.listenerList[i + 1]; - } - - // copy in the specific listeners - Object[] specificListeners = list.getListenerList(); - for (int i = 0; i < specificListeners.length; i += 2) - { - result[index++] = (PropertyChangeListener) specificListeners[i + 1]; - } - return result; - } - - /** - * Creates a new {@link PropertyChangeEvent} using the given arguments (and - * the default <code>source</code> for this - * <code>SwingPropertyChangeSupport</code> instance) and forwards it to all - * registered listeners via the - * {@link PropertyChangeListener#propertyChange(PropertyChangeEvent)} method. - * <p> - * Note that if <code>oldValue</code> and <code>newValue</code> are non-null - * and equal, no listeners will be notified. - * - * @param propertyName the property name. - * @param oldValue the old value - * @param newValue the new value. - */ - public void firePropertyChange(String propertyName, Object oldValue, - Object newValue) - { - PropertyChangeEvent event; - event = new PropertyChangeEvent(source, propertyName, oldValue, newValue); - firePropertyChange(event); - } - - /** - * Forwards <code>event</code> to registered listeners. - * <p> - * Note that if the event's <code>getOldValue()</code> and - * <code>getNewValue()</code> methods return non-null and equal values, no - * listeners will be notified. - * - * @param event the event. - */ - public void firePropertyChange(PropertyChangeEvent event) - { - EventListenerList list; - EventListener[] listenerList; - int index; - PropertyChangeListener listener; - - // if the old and new values are non-null and equal, don't notify listeners - if (event.getOldValue() != null && event.getNewValue() != null && - event.getOldValue().equals(event.getNewValue())) - return; - - // Process Main Listener List - listenerList = listeners.getListeners(PropertyChangeListener.class); - for (index = 0; index < listenerList.length; index++) - { - listener = (PropertyChangeListener) listenerList[index]; - listener.propertyChange(event); - } - - // Process Property Listener List - list = (EventListenerList) propertyListeners.get(event.getPropertyName()); - if (list != null) - { - listenerList = list.getListeners(PropertyChangeListener.class); - for (index = 0; index < listenerList.length; index++) - { - listener = (PropertyChangeListener) listenerList[index]; - listener.propertyChange(event); - } - } - - } - - /** - * Tell whether the specified property is being listened on or not. This - * will only return <code>true</code> if there are listeners on all - * properties or if there is a listener specifically on this property. - * - * @param propertyName the property that may be listened on - * @return whether the property is being listened on - * @throws NullPointerException if propertyName is null - */ - public synchronized boolean hasListeners(String propertyName) - { - if (listeners.getListenerCount() > 0) - return true; - else - return (propertyListeners.get(propertyName) != null); - } - } diff --git a/libjava/classpath/javax/swing/event/TableColumnModelEvent.java b/libjava/classpath/javax/swing/event/TableColumnModelEvent.java index 2ca4148aadb..cff49130e35 100644 --- a/libjava/classpath/javax/swing/event/TableColumnModelEvent.java +++ b/libjava/classpath/javax/swing/event/TableColumnModelEvent.java @@ -1,5 +1,5 @@ /* TableColumnModelEvent.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. @@ -46,60 +46,48 @@ import javax.swing.table.TableColumnModel; * TableColumnModelEvent * @author Andrew Selkirk */ -public class TableColumnModelEvent extends EventObject { - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * fromIndex - */ - protected int fromIndex = 0; - - /** - * toIndex - */ - protected int toIndex = 0; - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor TableColumnModelEvent - * @param source Source TableColumnModel - * @param from From index - * @param to To index - */ - public TableColumnModelEvent(TableColumnModel source, - int from, int to) { - super(source); - fromIndex = from; - toIndex = to; - } // TableColumnModelEvent() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getFromIndex. - * @returns From index - */ - public int getFromIndex() { - return fromIndex; - } // getFromIndex() - - /** - * getToIndex. - * @returns To index - */ - public int getToIndex() { - return toIndex; - } // getToIndex() - - -} // TableColumnModelEvent +public class TableColumnModelEvent extends EventObject +{ + + /** + * fromIndex + */ + protected int fromIndex = 0; + + /** + * toIndex + */ + protected int toIndex = 0; + + /** + * Constructor TableColumnModelEvent + * @param source Source TableColumnModel + * @param from From index + * @param to To index + */ + public TableColumnModelEvent(TableColumnModel source, int from, int to) + { + super(source); + fromIndex = from; + toIndex = to; + } + + /** + * getFromIndex. + * @return From index + */ + public int getFromIndex() + { + return fromIndex; + } + + /** + * getToIndex. + * @return To index + */ + public int getToIndex() + { + return toIndex; + } + +}
\ No newline at end of file diff --git a/libjava/classpath/javax/swing/event/TableModelListener.java b/libjava/classpath/javax/swing/event/TableModelListener.java index c8d6e8f8dbc..21e5ea0474e 100644 --- a/libjava/classpath/javax/swing/event/TableModelListener.java +++ b/libjava/classpath/javax/swing/event/TableModelListener.java @@ -1,5 +1,5 @@ /* TableModelListener.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,16 +40,21 @@ package javax.swing.event; import java.util.EventListener; /** - * TableModelListener public interface + * A <code>TableModelListener</code> can register with a + * {@link javax.swing.table.TableModel} and receive notification of updates to + * the model. + * * @author Andrew Selkirk */ -public interface TableModelListener extends EventListener { - - /** - * Table changed - * @param event Table Model Event - */ - void tableChanged(TableModelEvent event); - - -} // TableModelListener +public interface TableModelListener extends EventListener +{ + + /** + * Called to notify the listener that the + * {@link javax.swing.table.TableModel} has been updated. + * + * @param event contains details of the update. + */ + void tableChanged(TableModelEvent event); + +} diff --git a/libjava/classpath/javax/swing/event/TreeExpansionEvent.java b/libjava/classpath/javax/swing/event/TreeExpansionEvent.java index c4b33134694..5820b339172 100644 --- a/libjava/classpath/javax/swing/event/TreeExpansionEvent.java +++ b/libjava/classpath/javax/swing/event/TreeExpansionEvent.java @@ -1,5 +1,5 @@ /* TreeExpansionEvent.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. @@ -46,44 +46,32 @@ import javax.swing.tree.TreePath; * TreeExpansionEvent * @author Andrew Selkirk */ -public class TreeExpansionEvent extends EventObject { - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * path - */ - protected TreePath path = null; - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor TreeExpansionEvent - * @param source Source object - * @param path Path - */ - public TreeExpansionEvent(Object source, TreePath path) { - super(source); - this.path = path; - } // TreeExpansionEvent() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getPath - * @returns Tree path - */ - public TreePath getPath() { - return path; - } // getPath() - - -} // TreeExpansionEvent +public class TreeExpansionEvent extends EventObject +{ + + /** + * path + */ + protected TreePath path = null; + + /** + * Constructor TreeExpansionEvent + * @param source Source object + * @param path Path + */ + public TreeExpansionEvent(Object source, TreePath path) + { + super(source); + this.path = path; + } + + /** + * getPath + * @return Tree path + */ + public TreePath getPath() + { + return path; + } + +} diff --git a/libjava/classpath/javax/swing/event/TreeModelEvent.java b/libjava/classpath/javax/swing/event/TreeModelEvent.java index 8fa28a7eadb..2d562a5c4a8 100644 --- a/libjava/classpath/javax/swing/event/TreeModelEvent.java +++ b/libjava/classpath/javax/swing/event/TreeModelEvent.java @@ -1,5 +1,5 @@ /* TreeModelEvent.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. @@ -46,128 +46,123 @@ import javax.swing.tree.TreePath; * TreeModelEvent * @author Andrew Selkirk */ -public class TreeModelEvent extends EventObject { - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * childIndices - */ - protected int[] childIndices = null; - - /** - * children - */ - protected Object[] children = null; - - /** - * path - */ - protected TreePath path = null; - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- +public class TreeModelEvent extends EventObject +{ + + /** + * childIndices + */ + protected int[] childIndices = null; + + /** + * children + */ + protected Object[] children = null; + + /** + * path + */ + protected TreePath path = null; - /** - * Constructor TreeModelEvent - * @param source Source object - * @param path - */ - public TreeModelEvent(Object source, Object[] path) { - super(source); - this.path = new TreePath(path); - } // TreeModelEvent() - - /** - * Constructor TreeModelEvent - * @param source Source object - * @param path path - * @param childIndices Child indices - * @param children Children - */ - public TreeModelEvent(Object source, Object[] path, - int[] childIndices, Object[] children) { - super(source); - this.path = new TreePath(path); - this.childIndices = childIndices; - this.children = children; - } // TreeModelEvent() - - /** - * Constructor TreeModelEvent - * @param source Source object - * @param path Path - */ - public TreeModelEvent(Object source, TreePath path) { - super(source); - this.path = path; - } // TreeModelEvent() - - /** - * Constructor TreeModelEvent - * @param source Source object - * @param path Path - * @param childIndices Child indices - * @param children Children - */ - public TreeModelEvent(Object source, TreePath path, - int[] childIndices, Object[] children) { - super(source); - this.path = path; - this.childIndices = childIndices; - this.children = children; - } // TreeModelEvent() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getChildIndices - * @returns child indices - */ - public int[] getChildIndices() { - return childIndices; - } // getChildIndices() - - /** - * getChildren - * @returns children - */ - public Object[] getChildren() { - return children; - } // getChildren() - - /** - * getPath - * @returns path - */ - public Object[] getPath() { - return path.getPath(); - } // getPath() - - /** - * getTreePath - * @returns TreePath - */ - public TreePath getTreePath() { - return path; - } // getTreePath() - - /** - * String representation - * @returns String representation - */ - public String toString() { - return getClass() + " [Source: " + getSource() + ", TreePath: " + getTreePath() + - ", Child Indicies: " + getChildIndices() + ", Children: " + getChildren() + - ", Path: " + getPath() +"]"; - } // toString() - - -} // TreeModelEvent + /** + * Constructor TreeModelEvent + * @param source Source object + * @param path + */ + public TreeModelEvent(Object source, Object[] path) + { + super(source); + this.path = new TreePath(path); + } + + /** + * Constructor TreeModelEvent + * @param source Source object + * @param path path + * @param childIndices Child indices + * @param children Children + */ + public TreeModelEvent(Object source, Object[] path, + int[] childIndices, Object[] children) + { + super(source); + this.path = new TreePath(path); + this.childIndices = childIndices; + this.children = children; + } + + /** + * Constructor TreeModelEvent + * @param source Source object + * @param path Path + */ + public TreeModelEvent(Object source, TreePath path) + { + super(source); + this.path = path; + } + + /** + * Constructor TreeModelEvent + * @param source Source object + * @param path Path + * @param childIndices Child indices + * @param children Children + */ + public TreeModelEvent(Object source, TreePath path, + int[] childIndices, Object[] children) + { + super(source); + this.path = path; + this.childIndices = childIndices; + this.children = children; + } + + /** + * getChildIndices + * @return child indices + */ + public int[] getChildIndices() + { + return childIndices; + } + + /** + * getChildren + * @return children + */ + public Object[] getChildren() + { + return children; + } + + /** + * getPath + * @return path + */ + public Object[] getPath() + { + return path.getPath(); + } + + /** + * getTreePath + * @return TreePath + */ + public TreePath getTreePath() + { + return path; + } + + /** + * String representation + * @return String representation + */ + public String toString() + { + return getClass() + " [Source: " + getSource() + ", TreePath: " + + getTreePath() + ", Child Indicies: " + getChildIndices() + + ", Children: " + getChildren() + ", Path: " + getPath() +"]"; + } + +} diff --git a/libjava/classpath/javax/swing/event/TreeSelectionEvent.java b/libjava/classpath/javax/swing/event/TreeSelectionEvent.java index 9b87667a387..1930677af9f 100644 --- a/libjava/classpath/javax/swing/event/TreeSelectionEvent.java +++ b/libjava/classpath/javax/swing/event/TreeSelectionEvent.java @@ -1,5 +1,5 @@ /* TreeSelectionEvent.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,10 +49,6 @@ import javax.swing.tree.TreePath; */ public class TreeSelectionEvent extends EventObject { - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - /** * paths */ @@ -73,11 +69,6 @@ public class TreeSelectionEvent extends EventObject { */ protected TreePath newLeadSelectionPath; - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - /** * Constructor TreeSelectionEvent * @param source TODO @@ -95,7 +86,7 @@ public class TreeSelectionEvent extends EventObject { this.areNew = areNew; this.oldLeadSelectionPath = oldLeadSelectionPath; this.newLeadSelectionPath = newLeadSelectionPath; - } // TreeSelectionEvent() + } /** * Constructor TreeSelectionEvent @@ -114,29 +105,24 @@ public class TreeSelectionEvent extends EventObject { this.areNew = new boolean[]{isNew}; this.oldLeadSelectionPath = oldLeadSelectionPath; this.newLeadSelectionPath = newLeadSelectionPath; - } // TreeSelectionEvent() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- + } /** - * @returns the first path element + * @return the first path element */ public TreePath getPath() { return paths[0]; - } // getPath() + } /** * - * @returns the paths with selection changed + * @return the paths with selection changed */ public TreePath[] getPaths() { return (TreePath[]) paths.clone(); - } // getPaths() + } /** * @return true if the first path is added to the selection, false otherwise @@ -144,7 +130,7 @@ public class TreeSelectionEvent extends EventObject { public boolean isAddedPath() { return areNew[0]; - } // isAddedPath() + } /** * @param path the path to check @@ -157,7 +143,7 @@ public class TreeSelectionEvent extends EventObject { return areNew[i]; return false; - } // isAddedPath() + } /** * @param index the index'th path @@ -166,7 +152,7 @@ public class TreeSelectionEvent extends EventObject { public boolean isAddedPath(int index) { return areNew[index]; - } // isAddedPath() + } /** * @return the previous lead selection path @@ -174,15 +160,15 @@ public class TreeSelectionEvent extends EventObject { public TreePath getOldLeadSelectionPath() { return oldLeadSelectionPath; - } // getOldLeadSelectionPath() + } /** - * @returns the current lead selection path + * @return the current lead selection path */ public TreePath getNewLeadSelectionPath() { return newLeadSelectionPath; - } // getNewLeadSelectionPath() + } /** * @param source the new event source @@ -193,7 +179,6 @@ public class TreeSelectionEvent extends EventObject { return new TreeSelectionEvent (source, paths, areNew, oldLeadSelectionPath, newLeadSelectionPath); - } // cloneWithSource() - + } -} // TreeSelectionEvent +} diff --git a/libjava/classpath/javax/swing/event/UndoableEditEvent.java b/libjava/classpath/javax/swing/event/UndoableEditEvent.java index 147c2e5b1c5..b59ceadc9c2 100644 --- a/libjava/classpath/javax/swing/event/UndoableEditEvent.java +++ b/libjava/classpath/javax/swing/event/UndoableEditEvent.java @@ -1,5 +1,5 @@ /* UndoableEditEvent.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. @@ -47,46 +47,34 @@ import javax.swing.undo.UndoableEdit; * @author Andrew Selkirk * @author Ronald Veldema */ -public class UndoableEditEvent extends EventObject { +public class UndoableEditEvent extends EventObject +{ private static final long serialVersionUID = 4418044561759134484L; - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * edit - */ - private UndoableEdit edit; - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor UndoableEditEvent - * @param source TODO - * @param edit TODO - */ - public UndoableEditEvent(Object source, UndoableEdit edit) { - super(source); - this.edit = edit; - } // UndoableEditEvent() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getEdit - * @returns UndoableEdit - */ - public UndoableEdit getEdit() { - return edit; - } // getEdit() - - -} // UndoableEditEvent + /** + * edit + */ + private UndoableEdit edit; + + /** + * Constructor UndoableEditEvent + * @param source TODO + * @param edit TODO + */ + public UndoableEditEvent(Object source, UndoableEdit edit) + { + super(source); + this.edit = edit; + } + + /** + * getEdit + * @return UndoableEdit + */ + public UndoableEdit getEdit() + { + return edit; + } + +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java b/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java index 5d4ce18932b..5e2cf2e48ca 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java @@ -299,9 +299,7 @@ public class BasicBorders public static Border getSplitPaneDividerBorder() { /* See comment in methods above for why this border is not shared. */ - return new SplitPaneDividerBorder( - UIManager.getColor("SplitPane.highlight"), - UIManager.getColor("SplitPane.darkShadow")); + return new SplitPaneDividerBorder(); } @@ -1518,34 +1516,15 @@ public class BasicBorders implements Border, UIResource, Serializable { /** - * The highlight color, which is drawn on the left or top edge - * depending on the orientation of the JSplitPanel. - */ - protected Color highlight; - - - /** - * The highlight color, which is drawn on the right or bottom edge - * depending on the orientation of the JSplitPanel. - */ - protected Color shadow; - - - /** * Constructs a new border for drawing the divider of a JSplitPane * in the Basic look and feel. The outer parts of the JSplitPane have * their own border class, <code>SplitPaneBorder</code>. - * - * @param shadow the shadow color. - * @param highlight the highlight color. */ - public SplitPaneDividerBorder(Color highlight, Color shadow) + public SplitPaneDividerBorder() { - this.highlight = (highlight != null) ? highlight : Color.white; - this.shadow = (shadow != null) ? shadow : Color.black; + // Nothing to do here. } - /** * Paints the border around the divider of a <code>JSplitPane</code>. * @@ -1564,6 +1543,8 @@ public class BasicBorders public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + Color highlight = UIManager.getColor("SplitPane.highlight"); + Color shadow = UIManager.getColor("SplitPane.shadow"); Color oldColor, dcol; int x2, y2; JSplitPane sp; @@ -1624,17 +1605,15 @@ public class BasicBorders return new Insets(1, 1, 1, 1); } - /** * Determines whether this border fills every pixel in its area * when painting. * - * @return <code>true</code> if both highlight and shadow - * color are fully opaque. + * @return <code>true</code> */ public boolean isBorderOpaque() { - return (highlight.getAlpha() == 255) && (shadow.getAlpha() == 255); + return true; } @@ -1785,4 +1764,5 @@ public class BasicBorders return insets; } } + } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java index 95e0dc98257..e45970ed02c 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java @@ -45,7 +45,6 @@ import javax.swing.JMenuItem; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.UIDefaults; -import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java index 5a872ae6368..f37cbd7b838 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java @@ -141,10 +141,9 @@ public class BasicColorChooserUI extends ColorChooserUI protected PropertyChangeListener propertyChangeListener; /** - * The JColorChooser. - * This is package-private to avoid an accessor method. + * The JColorChooser this is installed on. */ - JColorChooser chooser; + protected JColorChooser chooser; /** The JTabbedPane that is used. */ JTabbedPane pane; diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java index 08dab7f9f36..798101d0d85 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java @@ -69,6 +69,7 @@ import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.Timer; +import javax.swing.UIManager; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionEvent; @@ -193,8 +194,23 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup if (selectedIndex > comboBox.getMaximumRowCount()) scrollbar.setValue(getPopupHeightForRowCount(selectedIndex)); + // We put the autoclose-registration inside an InvocationEvent, so that + // the same event that triggered this show() call won't hide the popup + // immediately. + SwingUtilities.invokeLater + (new Runnable() + { + public void run() + { + // Register this popup to be autoclosed when user clicks outside the + // popup. + BasicLookAndFeel laf = (BasicLookAndFeel) UIManager.getLookAndFeel(); + laf.registerForAutoClose(BasicComboPopup.this); + }}); + // location specified is relative to comboBox super.show(comboBox, 0, cbBounds.height); + } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java b/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java index b9891e14401..98c9cb277f4 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java @@ -38,12 +38,21 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; import java.io.IOException; import java.io.StringReader; import javax.swing.JComponent; +import javax.swing.SwingConstants; +import javax.swing.event.DocumentEvent; import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.EditorKit; import javax.swing.text.Element; +import javax.swing.text.Position; import javax.swing.text.View; import javax.swing.text.ViewFactory; import javax.swing.text.html.HTMLDocument; @@ -59,6 +68,287 @@ public class BasicHTML { /** + * This class serves as the root view for HTML rendering components. + * Its purpose and implementation is similar to the BasicTextUI.RootView + * class, only that is implements some stuff differently due to the nature + * of not beeing inside a JTextComponent. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private static class HTMLRootView extends View + { + /** + * The real root view. + */ + private View view; + + /** + * The component on which to render the view. + */ + private JComponent component; + + /** + * The EditorKit. + */ + private EditorKit editorKit; + + /** + * The document to use. + */ + private Document document; + + /** + * Creates a new RootView. + */ + public HTMLRootView(JComponent c, View view, EditorKit kit, Document doc) + { + super(null); + component = c; + editorKit = kit; + document = doc; + setView(view); + } + + /** + * Returns the ViewFactory for this RootView. If the current EditorKit + * provides a ViewFactory, this is used. Otherwise the TextUI itself + * is returned as a ViewFactory. + * + * @return the ViewFactory for this RootView + */ + public ViewFactory getViewFactory() + { + return editorKit.getViewFactory(); + } + + /** + * Indicates that the preferences of one of the child view has changed. + * This calls revalidate on the text component. + * + * @param v the child view which's preference has changed + * @param width <code>true</code> if the width preference has changed + * @param height <code>true</code> if the height preference has changed + */ + public void preferenceChanged(View v, boolean width, boolean height) + { + component.revalidate(); + } + + /** + * Sets the real root view. + * + * @param v the root view to set + */ + public void setView(View v) + { + if (view != null) + view.setParent(null); + + if (v != null) + v.setParent(this); + + view = v; + } + + /** + * Returns the real root view, regardless of the index. + * + * @param index not used here + * + * @return the real root view, regardless of the index. + */ + public View getView(int index) + { + return view; + } + + /** + * Returns <code>1</code> since the RootView always contains one + * child, that is the real root of the View hierarchy. + * + * @return <code>1</code> since the RootView always contains one + * child, that is the real root of the View hierarchy + */ + public int getViewCount() + { + int count = 0; + if (view != null) + count = 1; + return count; + } + + /** + * Returns the <code>Container</code> that contains this view. This + * normally will be the text component that is managed by this TextUI. + * + * @return the <code>Container</code> that contains this view + */ + public Container getContainer() + { + return component; + } + + /** + * Returns the preferred span along the specified <code>axis</code>. + * This is delegated to the real root view. + * + * @param axis the axis for which the preferred span is queried + * + * @return the preferred span along the axis + */ + public float getPreferredSpan(int axis) + { + if (view != null) + return view.getPreferredSpan(axis); + + return Integer.MAX_VALUE; + } + + /** + * Paints the view. This is delegated to the real root view. + * + * @param g the <code>Graphics</code> context to paint to + * @param s the allocation for the View + */ + public void paint(Graphics g, Shape s) + { + if (view != null) + { + Rectangle b = s.getBounds(); + view.setSize(b.width, b.height); + view.paint(g, s); + } + } + + + /** + * Maps a position in the document into the coordinate space of the View. + * The output rectangle usually reflects the font height but has a width + * of zero. + * + * This is delegated to the real root view. + * + * @param position the position of the character in the model + * @param a the area that is occupied by the view + * @param bias either {@link Position.Bias#Forward} or + * {@link Position.Bias#Backward} depending on the preferred + * direction bias. If <code>null</code> this defaults to + * <code>Position.Bias.Forward</code> + * + * @return a rectangle that gives the location of the document position + * inside the view coordinate space + * + * @throws BadLocationException if <code>pos</code> is invalid + * @throws IllegalArgumentException if b is not one of the above listed + * valid values + */ + public Shape modelToView(int position, Shape a, Position.Bias bias) + throws BadLocationException + { + return view.modelToView(position, a, bias); + } + + /** + * Maps coordinates from the <code>View</code>'s space into a position + * in the document model. + * + * @param x the x coordinate in the view space + * @param y the y coordinate in the view space + * @param a the allocation of this <code>View</code> + * @param b the bias to use + * + * @return the position in the document that corresponds to the screen + * coordinates <code>x, y</code> + */ + public int viewToModel(float x, float y, Shape a, Position.Bias[] b) + { + return view.viewToModel(x, y, a, b); + } + + /** + * Notification about text insertions. These are forwarded to the + * real root view. + * + * @param ev the DocumentEvent describing the change + * @param shape the current allocation of the view's display + * @param vf the ViewFactory to use for creating new Views + */ + public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + view.insertUpdate(ev, shape, vf); + } + + /** + * Notification about text removals. These are forwarded to the + * real root view. + * + * @param ev the DocumentEvent describing the change + * @param shape the current allocation of the view's display + * @param vf the ViewFactory to use for creating new Views + */ + public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + view.removeUpdate(ev, shape, vf); + } + + /** + * Notification about text changes. These are forwarded to the + * real root view. + * + * @param ev the DocumentEvent describing the change + * @param shape the current allocation of the view's display + * @param vf the ViewFactory to use for creating new Views + */ + public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + view.changedUpdate(ev, shape, vf); + } + + /** + * Returns the document position that is (visually) nearest to the given + * document position <code>pos</code> in the given direction <code>d</code>. + * + * @param pos the document position + * @param b the bias for <code>pos</code> + * @param a the allocation for the view + * @param d the direction, must be either {@link SwingConstants#NORTH}, + * {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or + * {@link SwingConstants#EAST} + * @param biasRet an array of {@link Position.Bias} that can hold at least + * one element, which is filled with the bias of the return position + * on method exit + * + * @return the document position that is (visually) nearest to the given + * document position <code>pos</code> in the given direction + * <code>d</code> + * + * @throws BadLocationException if <code>pos</code> is not a valid offset in + * the document model + */ + public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, + int d, Position.Bias[] biasRet) + throws BadLocationException + { + return view.getNextVisualPositionFrom(pos, b, a, d, biasRet); + } + + public int getStartOffset() + { + return 0; + } + + public int getEndOffset() + { + return getDocument().getLength(); + } + + public Document getDocument() + { + return document; + } + } + + /** * The key that is used to store a HTML view in a JComponent's client * properties. */ @@ -116,7 +406,8 @@ public class BasicHTML ViewFactory vf = kit.getViewFactory(); Element root = doc.getDefaultRootElement(); View view = vf.create(root); - return view; + HTMLRootView rootView = new HTMLRootView(c, view, kit, doc); + return rootView; } /** @@ -132,13 +423,13 @@ public class BasicHTML { // We consider a string to be HTML if it contains both the '<' and '>' // character at least once. - return s.contains("<") && s.contains(">"); + return (s != null) && s.contains("<") && s.contains(">"); } /** * Stores a HTML renderer in <code>c</code>'s client property if * <code>text</code> is HTML, otherwise it clears the corresponding client - * property. This is useful for {@link java.swing.plaf.ComponentUI} + * property. This is useful for {@link javax.swing.plaf.ComponentUI} * implementations that are shared between it's components. * * @param c the component to update the renderer for diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java index f9653bd2edd..f6cbeec8879 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -54,8 +54,6 @@ import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.beans.PropertyVetoException; -import java.beans.VetoableChangeListener; import javax.swing.DefaultDesktopManager; import javax.swing.DesktopManager; @@ -94,7 +92,7 @@ public class BasicInternalFrameUI extends InternalFrameUI */ public void internalFrameActivated(InternalFrameEvent e) { - // FIXME: Implement. + frame.getGlassPane().setVisible(false); } /** @@ -124,7 +122,7 @@ public class BasicInternalFrameUI extends InternalFrameUI */ public void internalFrameDeactivated(InternalFrameEvent e) { - // FIXME: Implement. + frame.getGlassPane().setVisible(true); } /** @@ -464,8 +462,6 @@ public class BasicInternalFrameUI extends InternalFrameUI dims.width -= insets.left + insets.right; dims.height -= insets.top + insets.bottom; - frame.getRootPane().getGlassPane().setBounds(0, 0, dims.width, - dims.height); int nh = 0; int sh = 0; int ew = 0; @@ -526,18 +522,6 @@ public class BasicInternalFrameUI extends InternalFrameUI } /** - * This method returns the maximum layout size. - * - * @param c - * The Container to find a maximum layout size for. - * @return The maximum dimensions for the JInternalFrame. - */ - public Dimension maximumLayoutSize(Container c) - { - return preferredLayoutSize(c); - } - - /** * Th8is method returns the preferred layout size. * * @param c @@ -891,40 +875,12 @@ public class BasicInternalFrameUI extends InternalFrameUI * This helper class listens for PropertyChangeEvents from the * JInternalFrame. */ - public class InternalFramePropertyChangeListener implements - PropertyChangeListener, VetoableChangeListener + public class InternalFramePropertyChangeListener + implements PropertyChangeListener { /** * This method is called when one of the JInternalFrame's properties change. - * This method is to allow JInternalFrame to veto an attempt to close the - * internal frame. This allows JInternalFrame to honour its - * defaultCloseOperation if that is DO_NOTHING_ON_CLOSE. - */ - public void vetoableChange(PropertyChangeEvent e) - throws PropertyVetoException - { - if (e.getPropertyName().equals(JInternalFrame.IS_CLOSED_PROPERTY)) - { - if (frame.getDefaultCloseOperation() == JInternalFrame.HIDE_ON_CLOSE) - { - frame.setVisible(false); - frame.getDesktopPane().repaint(); - throw new PropertyVetoException( - "close operation is HIDE_ON_CLOSE\n", - e); - } - else if (frame.getDefaultCloseOperation() == JInternalFrame.DISPOSE_ON_CLOSE) - closeFrame(frame); - else - throw new PropertyVetoException( - "close operation is DO_NOTHING_ON_CLOSE\n", - e); - } - } - - /** - * This method is called when one of the JInternalFrame's properties change. * * @param evt * The PropertyChangeEvent. @@ -1091,13 +1047,6 @@ public class BasicInternalFrameUI extends InternalFrameUI */ protected PropertyChangeListener propertyChangeListener; - /** - * The VetoableChangeListener. Listens to PropertyChangeEvents - * from the JInternalFrame and allows the JInternalFrame to - * veto attempts to close it. - */ - private VetoableChangeListener internalFrameVetoableChangeListener; - /** The InternalFrameListener that listens to the JInternalFrame. */ private transient BasicInternalFrameListener internalFrameListener; @@ -1165,14 +1114,15 @@ public class BasicInternalFrameUI extends InternalFrameUI { frame = (JInternalFrame) c; - ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(false); - frame.getRootPane().getGlassPane().setVisible(true); - installDefaults(); installListeners(); installComponents(); installKeyboardActions(); + ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(false); + if (! frame.isSelected()) + frame.getRootPane().getGlassPane().setVisible(true); + frame.setOpaque(true); frame.invalidate(); } @@ -1205,8 +1155,6 @@ public class BasicInternalFrameUI extends InternalFrameUI frame.setLayout(internalFrameLayout); LookAndFeel.installBorder(frame, "InternalFrame.border"); frame.setFrameIcon(UIManager.getIcon("InternalFrame.icon")); - // InternalFrames are invisible by default. - frame.setVisible(false); } /** @@ -1238,13 +1186,11 @@ public class BasicInternalFrameUI extends InternalFrameUI borderListener = createBorderListener(frame); componentListener = createComponentListener(); propertyChangeListener = createPropertyChangeListener(); - internalFrameVetoableChangeListener = new InternalFramePropertyChangeListener(); frame.addMouseListener(borderListener); frame.addMouseMotionListener(borderListener); frame.addInternalFrameListener(internalFrameListener); frame.addPropertyChangeListener(propertyChangeListener); - frame.addVetoableChangeListener(internalFrameVetoableChangeListener); frame.getRootPane().getGlassPane().addMouseListener(glassPaneDispatcher); frame.getRootPane().getGlassPane().addMouseMotionListener(glassPaneDispatcher); } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java index fd4cff56895..d0964f4733e 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java @@ -53,6 +53,7 @@ import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.LabelUI; +import javax.swing.text.View; /** * This is the Basic Look and Feel class for the JLabel. One BasicLabelUI @@ -64,11 +65,22 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener protected static BasicLabelUI labelUI; /** + * These fields hold the rectangles for the whole label, + * the icon and the text. + */ + private Rectangle vr; + private Rectangle ir; + private Rectangle tr; + + /** * Creates a new BasicLabelUI object. */ public BasicLabelUI() { super(); + vr = new Rectangle(); + ir = new Rectangle(); + tr = new Rectangle(); } /** @@ -99,13 +111,11 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener public Dimension getPreferredSize(JComponent c) { JLabel lab = (JLabel) c; - Rectangle vr = new Rectangle(); - Rectangle ir = new Rectangle(); - Rectangle tr = new Rectangle(); Insets insets = lab.getInsets(); FontMetrics fm = lab.getFontMetrics(lab.getFont()); layoutCL(lab, fm, lab.getText(), lab.getIcon(), vr, ir, tr); - Rectangle cr = tr.union(ir); + Rectangle cr = SwingUtilities.computeUnion(tr.x, tr.y, tr.width, tr.height, + ir); return new Dimension(insets.left + cr.width + insets.right, insets.top + cr.height + insets.bottom); @@ -148,11 +158,6 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener public void paint(Graphics g, JComponent c) { JLabel b = (JLabel) c; - - Rectangle tr = new Rectangle(); - Rectangle ir = new Rectangle(); - Rectangle vr = new Rectangle(); - FontMetrics fm = g.getFontMetrics(); vr = SwingUtilities.calculateInnerArea(c, vr); @@ -168,13 +173,21 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener if (icon != null) icon.paintIcon(b, g, ir.x, ir.y); - if (text != null && !text.equals("")) - { - if (b.isEnabled()) - paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent()); - else - paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent()); - } + Object htmlRenderer = b.getClientProperty(BasicHTML.propertyKey); + if (htmlRenderer == null) + { + if (text != null && !text.equals("")) + { + if (b.isEnabled()) + paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent()); + else + paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent()); + } + } + else + { + ((View) htmlRenderer).paint(g, tr); + } } /** @@ -312,7 +325,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener */ protected void installComponents(JLabel c) { - //FIXME: fix javadoc + implement. + BasicHTML.updateRenderer(c, c.getText()); } /** @@ -322,7 +335,8 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener */ protected void uninstallComponents(JLabel c) { - //FIXME: fix javadoc + implement. + c.putClientProperty(BasicHTML.propertyKey, null); + c.putClientProperty(BasicHTML.documentBaseKey, null); } /** @@ -402,6 +416,11 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener */ public void propertyChange(PropertyChangeEvent e) { - // What to do here? + if (e.getPropertyName().equals("text")) + { + String text = (String) e.getNewValue(); + JLabel l = (JLabel) e.getSource(); + BasicHTML.updateRenderer(l, text); + } } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java index 00d157a62c4..19dfe21f889 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java @@ -64,6 +64,7 @@ import javax.swing.ListCellRenderer; import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.event.ListDataEvent; @@ -135,6 +136,7 @@ public class BasicListUI extends ListUI */ public void contentsChanged(ListDataEvent e) { + updateLayoutStateNeeded |= modelChanged; list.revalidate(); } @@ -145,6 +147,7 @@ public class BasicListUI extends ListUI */ public void intervalAdded(ListDataEvent e) { + updateLayoutStateNeeded |= modelChanged; list.revalidate(); } @@ -155,6 +158,7 @@ public class BasicListUI extends ListUI */ public void intervalRemoved(ListDataEvent e) { + updateLayoutStateNeeded |= modelChanged; list.revalidate(); } } @@ -541,17 +545,21 @@ public class BasicListUI extends ListUI */ public void propertyChange(PropertyChangeEvent e) { - if (e.getSource() == BasicListUI.this.list) + if (e.getPropertyName().equals("model")) { if (e.getOldValue() != null && e.getOldValue() instanceof ListModel) - ((ListModel) e.getOldValue()).removeListDataListener(BasicListUI.this.listDataListener); - + { + ListModel oldModel = (ListModel) e.getOldValue(); + oldModel.removeListDataListener(listDataListener); + } if (e.getNewValue() != null && e.getNewValue() instanceof ListModel) - ((ListModel) e.getNewValue()).addListDataListener(BasicListUI.this.listDataListener); + { + ListModel newModel = (ListModel) e.getNewValue(); + newModel.addListDataListener(BasicListUI.this.listDataListener); + } + + updateLayoutStateNeeded |= modelChanged; } - // Update the updateLayoutStateNeeded flag. - if (e.getPropertyName().equals("model")) - updateLayoutStateNeeded |= modelChanged; else if (e.getPropertyName().equals("selectionModel")) updateLayoutStateNeeded |= selectionModelChanged; else if (e.getPropertyName().equals("font")) @@ -720,14 +728,20 @@ public class BasicListUI extends ListUI int minIndex = Math.min(index1, index2); int maxIndex = Math.max(index1, index2); Point loc = indexToLocation(list, minIndex); - Rectangle bounds = new Rectangle(loc.x, loc.y, cellWidth, + + // When the layoutOrientation is VERTICAL, then the width == the list + // width. Otherwise the cellWidth field is used. + int width = cellWidth; + if (l.getLayoutOrientation() == JList.VERTICAL) + width = l.getWidth(); + + Rectangle bounds = new Rectangle(loc.x, loc.y, width, getCellHeight(minIndex)); for (int i = minIndex + 1; i <= maxIndex; i++) { Point hiLoc = indexToLocation(list, i); - Rectangle hibounds = new Rectangle(hiLoc.x, hiLoc.y, cellWidth, - getCellHeight(i)); - bounds = bounds.union(hibounds); + bounds = SwingUtilities.computeUnion(hiLoc.x, hiLoc.y, width, + getCellHeight(i), bounds); } return bounds; @@ -883,8 +897,6 @@ public class BasicListUI extends ListUI Dimension dim = flyweight.getPreferredSize(); cellWidth = Math.max(cellWidth, dim.width); } - if (list.getLayoutOrientation() == JList.VERTICAL) - cellWidth = Math.max(cellWidth, list.getSize().width); } } @@ -894,7 +906,7 @@ public class BasicListUI extends ListUI */ protected void maybeUpdateLayoutState() { - if (updateLayoutStateNeeded != 0 || !list.isValid()) + if (updateLayoutStateNeeded != 0) { updateLayoutState(); updateLayoutStateNeeded = 0; diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java index f5217be1ff6..3451224beeb 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -38,15 +38,24 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import java.awt.AWTEvent; import java.awt.Color; +import java.awt.Component; +import java.awt.Container; import java.awt.Dimension; import java.awt.Font; +import java.awt.Toolkit; +import java.awt.event.AWTEventListener; import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.Enumeration; +import java.util.Iterator; import java.util.ResourceBundle; +import java.util.Set; +import java.util.WeakHashMap; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; @@ -57,8 +66,11 @@ import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.BorderFactory; +import javax.swing.JPopupMenu; import javax.swing.KeyStroke; import javax.swing.LookAndFeel; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.border.BevelBorder; @@ -77,6 +89,96 @@ import javax.swing.plaf.InsetsUIResource; public abstract class BasicLookAndFeel extends LookAndFeel implements Serializable { + + /** + * Helps closing menu popups when the user clicks outside of any menu area. + * This is implemented as an AWTEventListener that listens on the event + * queue directly, grabs all mouse events from there and finds out of they + * are targetted at a menu/submenu/menubar or not. If not, + * the MenuSelectionManager is messaged to close the currently opened menus, + * if any. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class PopupHelper implements AWTEventListener + { + + /** + * Registered popups for autoclose. + */ + private WeakHashMap autoClosePopups = new WeakHashMap(); + + /** + * Receives an event from the event queue. + * + * @param event + */ + public void eventDispatched(AWTEvent event) + { + if (event instanceof MouseEvent) + { + MouseEvent mouseEvent = (MouseEvent) event; + if (mouseEvent.getID() == MouseEvent.MOUSE_PRESSED) + mousePressed(mouseEvent); + } + } + + /** + * Handles mouse pressed events from the event queue. + * + * @param ev the mouse pressed event + */ + private void mousePressed(MouseEvent ev) + { + // Autoclose all menus managed by the MenuSelectionManager. + MenuSelectionManager m = MenuSelectionManager.defaultManager(); + Component target = ev.getComponent(); + if (target instanceof Container) + target = ((Container) target).findComponentAt(ev.getPoint()); + if (! m.isComponentPartOfCurrentMenu(target)) + m.clearSelectedPath(); + + // Handle other registered popup instances, like ComboBox popups. + autoClosePopups(ev, target); + } + + /** + * Registers Popup and its content to be autoclosed when a mouseclick + * occurs outside of the popup. + * + * @param popup the popup to be autoclosed when clicked outside + */ + void registerForAutoClose(JPopupMenu popup) + { + autoClosePopups.put(popup, null); + } + + /** + * Automatically closes all popups that are not 'hit' by the mouse event. + * + * @param ev the mouse event + * @param target the target of the mouse event + */ + private void autoClosePopups(MouseEvent ev, Component target) + { + if (autoClosePopups.size() != 0) + { + Set popups = autoClosePopups.keySet(); + Iterator i = popups.iterator(); + while (i.hasNext()) + { + JPopupMenu popup = (JPopupMenu) i.next(); + if (!(target == popup + || SwingUtilities.isDescendingFrom(target, popup))) + { + popup.setVisible(false); + i.remove(); + } + } + } + } + } + /** * An action that can play an audio file. * @@ -137,6 +239,11 @@ public abstract class BasicLookAndFeel extends LookAndFeel static final long serialVersionUID = -6096995660290287879L; + /** + * Helps closing menu popups when user clicks outside of the menu area. + */ + private transient PopupHelper popupHelper; + private ActionMap audioActionMap; /** @@ -1023,6 +1130,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "SplitPane.dividerSize", new Integer(7), "SplitPane.highlight", new ColorUIResource(highLight), "SplitPane.shadow", new ColorUIResource(shadow), + "SplitPaneDivider.border", BasicBorders.getSplitPaneDividerBorder(), + "SplitPaneDivider.draggingColor", new ColorUIResource(Color.DARK_GRAY), "TabbedPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { "ctrl PAGE_DOWN","navigatePageDown", "ctrl PAGE_UP", "navigatePageUp", @@ -1520,4 +1629,36 @@ public abstract class BasicLookAndFeel extends LookAndFeel } } + /** + * Initializes the Look and Feel. + */ + public void initialize() + { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + popupHelper = new PopupHelper(); + toolkit.addAWTEventListener(popupHelper, AWTEvent.MOUSE_EVENT_MASK); + } + + /** + * Uninitializes the Look and Feel. + */ + public void uninitialize() + { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + toolkit.removeAWTEventListener(popupHelper); + popupHelper = null; + } + + /** + * Registers a JPopupMenu for autoclosing when a mouseclick occurs outside + * of the JPopupMenu. This must be called when the popup gets opened. The + * popup is unregistered from autoclosing as soon as it either got closed + * by this helper, or when it has been garbage collected. + * + * @param popup the popup menu to autoclose + */ + void registerForAutoClose(JPopupMenu popup) + { + popupHelper.registerForAutoClose(popup); + } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java index 63f0ce2068b..9166c49ee83 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -610,8 +610,7 @@ public class BasicMenuItemUI extends MenuItemUI Font f = m.getFont(); g.setFont(f); FontMetrics fm = g.getFontMetrics(f); - SwingUtilities.calculateInnerArea(m, br); - SwingUtilities.calculateInsetArea(br, m.getInsets(), vr); + SwingUtilities.calculateInnerArea(m, vr); paintBackground(g, m, background); /* diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java index e15a17bab28..6ecd06b3988 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -37,28 +37,20 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import java.awt.AWTEvent; import java.awt.Component; -import java.awt.Container; -import java.awt.Cursor; import java.awt.Dimension; -import java.awt.Point; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import javax.swing.BoxLayout; import javax.swing.JComponent; -import javax.swing.JLayeredPane; -import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.LookAndFeel; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; -import javax.swing.RootPaneContainer; import javax.swing.SwingUtilities; -import javax.swing.event.MouseInputListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.plaf.ComponentUI; @@ -73,9 +65,6 @@ public class BasicPopupMenuUI extends PopupMenuUI /* popupMenu for which this UI delegate is for*/ protected JPopupMenu popupMenu; - /* MouseInputListener listens to mouse events. Package private for inner classes. */ - static transient MouseInputListener mouseInputListener; - /* PopupMenuListener listens to popup menu events fired by JPopupMenu*/ private transient PopupMenuListener popupMenuListener; @@ -270,30 +259,9 @@ public class BasicPopupMenuUI extends PopupMenuUI // remove listener that listens to component events fired // by the top - level window that this popup belongs to. Component invoker = popupMenu.getInvoker(); - - RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities - .getRoot(invoker); + Component rootContainer = SwingUtilities.getRoot(invoker); if (rootContainer != null) - { - ((Container) rootContainer).removeComponentListener(topWindowListener); - - // If this popup menu is the last popup menu visible on the screen, - // then - // stop interrupting mouse events in the glass pane before hiding this - // last popup menu. - boolean topLevelMenu = (popupMenu.getInvoker() instanceof JMenu) - && ((JMenu) popupMenu.getInvoker()).isTopLevelMenu(); - - if (topLevelMenu || !(popupMenu.getInvoker() instanceof MenuElement)) - { - // set glass pane not to interrupt mouse events and remove - // mouseInputListener - Container glassPane = (Container) rootContainer.getGlassPane(); - glassPane.setVisible(false); - glassPane.removeMouseListener(mouseInputListener); - mouseInputListener = null; - } - } + rootContainer.removeComponentListener(topWindowListener); } /** @@ -307,20 +275,8 @@ public class BasicPopupMenuUI extends PopupMenuUI // ComponentEvents fired by it. We need to cancel this popup menu // if topWindow to which this popup belongs was resized or moved. Component invoker = popupMenu.getInvoker(); - RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities - .getRoot(invoker); - ((Container) rootContainer).addComponentListener(topWindowListener); - - // Set the glass pane to interrupt all mouse events originating in root - // container - if (mouseInputListener == null) - { - Container glassPane = (Container) rootContainer.getGlassPane(); - glassPane.setVisible(true); - mouseInputListener = new MouseInputHandler(rootContainer); - glassPane.addMouseListener(mouseInputListener); - glassPane.addMouseMotionListener(mouseInputListener); - } + Component rootContainer = SwingUtilities.getRoot(invoker); + rootContainer.addComponentListener(topWindowListener); // if this popup menu is a free floating popup menu, // then by default its first element should be always selected when @@ -399,275 +355,4 @@ public class BasicPopupMenuUI extends PopupMenuUI } } - /** - * MouseInputHandler listens to all mouse events originated in the root - * container. This class is responsible for closing menu hierarchy when the - * user presses mouse over any component that do not belong to the current - * menu hierarchy. This is acomplished by interrupting all mouse event in - * the glass pane and checking if other component was pressed while menu - * was open, before redestributing events further to intended components - */ - private class MouseInputHandler implements MouseInputListener - { - private JLayeredPane layeredPane; - private Container glassPane; - private Cursor nativeCursor; - private transient Component mouseEventTarget; - private transient Component pressedComponent; - private transient Component lastComponentEntered; - private transient Component tempComponent; - private transient int pressCount; - - /** - * Creates a new MouseInputHandler object. - * - * @param c the top most root container - */ - public MouseInputHandler(RootPaneContainer c) - { - layeredPane = c.getLayeredPane(); - glassPane = (Container) c.getGlassPane(); - } - - /** - * Handles mouse clicked event - * - * @param e Mouse event - */ - public void mouseClicked(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouseDragged event - * - * @param e MouseEvent - */ - public void mouseDragged(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouseEntered event - * - * @param e MouseEvent - */ - public void mouseEntered(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouseExited event - * - * @param e MouseEvent - */ - public void mouseExited(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouse moved event - * - * @param e MouseEvent - */ - public void mouseMoved(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouse pressed event - * - * @param e MouseEvent - */ - public void mousePressed(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouse released event - * - * @param e MouseEvent - */ - public void mouseReleased(MouseEvent e) - { - handleEvent(e); - } - - /* - * This method determines component that was intended to received mouse - * event, before it was interrupted within the glass pane. This method - * also redispatches mouse entered and mouse exited events to the - * appropriate components. This code is slightly modified code from - * Container.LightweightDispatcher class, which is private inside - * Container class and cannot be used here. - */ - public void acquireComponentForMouseEvent(MouseEvent me) - { - int x = me.getX(); - int y = me.getY(); - - // Find the candidate which should receive this event. - Component parent = layeredPane; - Component candidate = null; - Point p = me.getPoint(); - while ((candidate == null) && (parent != null)) - { - p = SwingUtilities.convertPoint(glassPane, p.x, p.y, parent); - candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y); - - if (candidate == null) - { - p = SwingUtilities.convertPoint(parent, p.x, p.y, - parent.getParent()); - parent = parent.getParent(); - } - } - - // If the only candidate we found was the native container itself, - // don't dispatch any event at all. We only care about the lightweight - // children here. - if (candidate == layeredPane) - candidate = null; - - // If our candidate is new, inform the old target we're leaving. - if ((lastComponentEntered != null) && lastComponentEntered.isShowing() - && (lastComponentEntered != candidate)) - { - // Old candidate could have been removed from - // the layeredPane so we check first. - if (SwingUtilities.isDescendingFrom(lastComponentEntered, layeredPane)) - { - Point tp = SwingUtilities.convertPoint(layeredPane, x, y, - lastComponentEntered); - MouseEvent exited = new MouseEvent(lastComponentEntered, - MouseEvent.MOUSE_EXITED, - me.getWhen(), - me.getModifiersEx(), tp.x, - tp.y, me.getClickCount(), - me.isPopupTrigger(), - me.getButton()); - - tempComponent = lastComponentEntered; - lastComponentEntered = null; - tempComponent.dispatchEvent(exited); - } - - lastComponentEntered = null; - } - - // If we have a candidate, maybe enter it. - if (candidate != null) - { - mouseEventTarget = candidate; - - if (candidate.isLightweight() && candidate.isShowing() - && (candidate != layeredPane) - && (candidate != lastComponentEntered)) - { - lastComponentEntered = mouseEventTarget; - - Point cp = SwingUtilities.convertPoint(layeredPane, x, y, - lastComponentEntered); - MouseEvent entered = new MouseEvent(lastComponentEntered, - MouseEvent.MOUSE_ENTERED, - me.getWhen(), - me.getModifiersEx(), cp.x, - cp.y, me.getClickCount(), - me.isPopupTrigger(), - me.getButton()); - lastComponentEntered.dispatchEvent(entered); - } - } - - if ((me.getID() == MouseEvent.MOUSE_RELEASED) - || ((me.getID() == MouseEvent.MOUSE_PRESSED) && (pressCount > 0)) - || (me.getID() == MouseEvent.MOUSE_DRAGGED)) - { - // If any of the following events occur while a button is held down, - // they should be dispatched to the same component to which the - // original MOUSE_PRESSED event was dispatched: - // - MOUSE_RELEASED - // - MOUSE_PRESSED: another button pressed while the first is held down - // - MOUSE_DRAGGED - if (SwingUtilities.isDescendingFrom(pressedComponent, layeredPane)) - mouseEventTarget = pressedComponent; - else if (me.getID() == MouseEvent.MOUSE_CLICKED) - { - // Don't dispatch CLICKED events whose target is not the same as the - // target for the original PRESSED event. - if (candidate != pressedComponent) - mouseEventTarget = null; - else if (pressCount == 0) - pressedComponent = null; - } - } - } - - /* - * This method handles mouse events interrupted by glassPane. It - * redispatches the mouse events appropriately to the intended components. - * The code in this method is also taken from - * Container.LightweightDispatcher class. The code is slightly modified - * to handle the case when mouse is released over non-menu component. In - * this case this method closes current menu hierarchy before - * redispatching the event further. - */ - public void handleEvent(AWTEvent e) - { - if (e instanceof MouseEvent) - { - MouseEvent me = (MouseEvent) e; - - acquireComponentForMouseEvent(me); - - // Avoid dispatching ENTERED and EXITED events twice. - if (mouseEventTarget != null && mouseEventTarget.isShowing() - && (e.getID() != MouseEvent.MOUSE_ENTERED) - && (e.getID() != MouseEvent.MOUSE_EXITED)) - { - MouseEvent newEvt = SwingUtilities.convertMouseEvent(glassPane, - me, - mouseEventTarget); - - mouseEventTarget.dispatchEvent(newEvt); - - // If mouse was clicked over the component that is not part - // of menu hierarchy,then must close the menu hierarchy */ - if (e.getID() == MouseEvent.MOUSE_RELEASED) - { - boolean partOfMenuHierarchy = false; - MenuSelectionManager manager = MenuSelectionManager - .defaultManager(); - - partOfMenuHierarchy = manager.isComponentPartOfCurrentMenu(mouseEventTarget); - - if (! partOfMenuHierarchy) - manager.clearSelectedPath(); - } - - switch (e.getID()) - { - case MouseEvent.MOUSE_PRESSED: - if (pressCount++ == 0) - pressedComponent = mouseEventTarget; - break; - case MouseEvent.MOUSE_RELEASED: - // Clear our memory of the original PRESSED event, only if - // we're not expecting a CLICKED event after this. If - // there is a CLICKED event after this, it will do clean up. - if ((--pressCount == 0) - && (mouseEventTarget != pressedComponent)) - pressedComponent = null; - break; - } - } - } - } - } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java index 8af5ff7f95c..f8f62e15651 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java @@ -45,7 +45,6 @@ import javax.swing.JMenuItem; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.UIDefaults; -import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java index 2a698e8a162..28e3b67c1a5 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java @@ -1,4 +1,4 @@ -/* BasicPanelUI.java -- +/* BasicRootPaneUI.java -- Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,7 +43,6 @@ import java.beans.PropertyChangeListener; import javax.swing.JComponent; import javax.swing.JRootPane; -import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.RootPaneUI; @@ -75,8 +74,7 @@ public class BasicRootPaneUI extends RootPaneUI */ protected void installDefaults(JRootPane rp) { - // Is this ok? - rp.setBackground(UIManager.getColor("control")); + // TODO: What to do here, if anything? (might be a hook method) } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java index a2f5b82dbec..c8713c934dd 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java @@ -653,19 +653,17 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) { - width += incrButton.getPreferredSize().getWidth(); - width += decrButton.getPreferredSize().getWidth(); - - width += (scrollbar.getMaximum() - scrollbar.getMinimum()); - height = UIManager.getInt("ScrollBar.width"); + width += incrButton.getPreferredSize().getWidth(); + width += decrButton.getPreferredSize().getWidth(); + width += 16; + height = UIManager.getInt("ScrollBar.width"); } else { - height += incrButton.getPreferredSize().getHeight(); - height += decrButton.getPreferredSize().getHeight(); - - height += (scrollbar.getMaximum() - scrollbar.getMinimum()); - width = UIManager.getInt("ScrollBar.width"); + height += incrButton.getPreferredSize().getHeight(); + height += decrButton.getPreferredSize().getHeight(); + height += 16; + width = UIManager.getInt("ScrollBar.width"); } Insets insets = scrollbar.getInsets(); @@ -721,18 +719,6 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, */ protected void installComponents() { - if (incrButton != null) - scrollbar.add(incrButton); - if (decrButton != null) - scrollbar.add(decrButton); - } - - /** - * This method installs the defaults for the scrollbar specified by the - * Basic Look and Feel. - */ - protected void installDefaults() - { int orientation = scrollbar.getOrientation(); switch (orientation) { @@ -746,6 +732,18 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, break; } + if (incrButton != null) + scrollbar.add(incrButton); + if (decrButton != null) + scrollbar.add(decrButton); + } + + /** + * This method installs the defaults for the scrollbar specified by the + * Basic Look and Feel. + */ + protected void installDefaults() + { LookAndFeel.installColors(scrollbar, "ScrollBar.background", "ScrollBar.foreground"); LookAndFeel.installBorder(scrollbar, "ScrollBar.border"); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java index 3b7399eafaa..6f7a41a1d96 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java @@ -1,5 +1,5 @@ -/* SpinnerUI.java -- - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +/* BasicSpinnerUI.java -- + Copyright (C) 2003, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,7 @@ package javax.swing.plaf.basic; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; +import java.awt.Font; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.event.ActionEvent; @@ -59,22 +60,21 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.SpinnerUI; /** - * DOCUMENT ME! + * A UI delegate for the {@link JSpinner} component. * * @author Ka-Hing Cheung * - * @see javax.swing.JSpinner * @since 1.4 */ public class BasicSpinnerUI extends SpinnerUI { /** - * Creates a new <code>ComponentUI</code> for the specified + * Creates a new <code>BasicSpinnerUI</code> for the specified * <code>JComponent</code> * - * @param c DOCUMENT ME! + * @param c the component (ignored). * - * @return a ComponentUI + * @return A new instance of {@link BasicSpinnerUI}. */ public static ComponentUI createUI(JComponent c) { @@ -144,14 +144,15 @@ public class BasicSpinnerUI extends SpinnerUI { return new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) - { - // FIXME: Add check for enabled property change. Need to - // disable the buttons. - if ("editor".equals(evt.getPropertyName())) - BasicSpinnerUI.this.replaceEditor((JComponent) evt.getOldValue(), - (JComponent) evt.getNewValue()); - } + public void propertyChange(PropertyChangeEvent event) + { + // FIXME: Add check for enabled property change. Need to + // disable the buttons. + if ("editor".equals(event.getPropertyName())) + BasicSpinnerUI.this.replaceEditor((JComponent) event.getOldValue(), + (JComponent) event.getNewValue()); + // FIXME: Handle 'font' property change + } }; } @@ -169,6 +170,12 @@ public class BasicSpinnerUI extends SpinnerUI LookAndFeel.installColorsAndFont(spinner, "Spinner.background", "Spinner.foreground", "Spinner.font"); LookAndFeel.installBorder(spinner, "Spinner.border"); + JComponent e = spinner.getEditor(); + if (e instanceof JSpinner.DefaultEditor) + { + JSpinner.DefaultEditor de = (JSpinner.DefaultEditor) e; + de.getTextField().setBorder(null); + } spinner.setLayout(createLayout()); spinner.setOpaque(true); } @@ -352,7 +359,8 @@ public class BasicSpinnerUI extends SpinnerUI private PropertyChangeListener listener = createPropertyChangeListener(); /** - * DOCUMENT ME! + * A layout manager for the {@link JSpinner} component. The spinner has + * three subcomponents: an editor, a 'next' button and a 'previous' button. */ private class DefaultLayoutManager implements LayoutManager { @@ -365,58 +373,52 @@ public class BasicSpinnerUI extends SpinnerUI { synchronized (parent.getTreeLock()) { - Insets i = parent.getInsets(); - boolean l2r = parent.getComponentOrientation().isLeftToRight(); - /* - -------------- -------------- - | | n | | n | | - | e | - | or | - | e | - | | p | | p | | - -------------- -------------- - */ - Dimension e = minSize(editor); - Dimension n = minSize(next); - Dimension p = minSize(previous); - Dimension s = spinner.getPreferredSize(); - - int x = l2r ? i.left : i.right; - int y = i.top; - int w = Math.max(p.width, n.width); - int h = Math.max(p.height, n.height); - h = Math.max(h, e.height / 2); - int e_width = s.width - w; - - if (l2r) - { - setBounds(editor, x, y + (s.height - e.height) / 2, e_width, - e.height); - x += e_width; - - setBounds(next, x, y, w, h); - y += h; - - setBounds(previous, x, y, w, h); - } - else - { - setBounds(next, x, y + (s.height - e.height) / 2, w, h); - y += h; - - setBounds(previous, x, y, w, h); - x += w; - y -= h; - - setBounds(editor, x, y, e_width, e.height); - } + Insets i = parent.getInsets(); + boolean l2r = parent.getComponentOrientation().isLeftToRight(); + /* + -------------- -------------- + | | n | | n | | + | e | - | or | - | e | + | | p | | p | | + -------------- -------------- + */ + Dimension e = prefSize(editor); + Dimension n = prefSize(next); + Dimension p = prefSize(previous); + Dimension s = spinner.getPreferredSize(); + + int x = l2r ? i.left : i.right; + int y = i.top; + int w = Math.max(p.width, n.width); + int h = e.height / 2; + int e_width = s.width - w - i.left - i.right; + + if (l2r) + { + setBounds(editor, x, y, e_width, 2 * h); + x += e_width; + setBounds(next, x, y, w, h); + y += h; + setBounds(previous, x, y, w, h); + } + else + { + setBounds(next, x, y + (s.height - e.height) / 2, w, h); + y += h; + setBounds(previous, x, y + (s.height - e.height) / 2, w, h); + x += w; + y -= h; + setBounds(editor, x, y, e_width, e.height); + } } } /** - * DOCUMENT ME! + * Calculates the minimum layout size. * - * @param parent DOCUMENT ME! + * @param parent the parent. * - * @return DOCUMENT ME! + * @return The minimum layout size. */ public Dimension minimumLayoutSize(Container parent) { @@ -424,36 +426,32 @@ public class BasicSpinnerUI extends SpinnerUI if (editor != null) { - Dimension tmp = editor.getMinimumSize(); - d.width += tmp.width; - d.height = tmp.height; + Dimension tmp = editor.getMinimumSize(); + d.width += tmp.width; + d.height = tmp.height; } int nextWidth = 0; int previousWidth = 0; - int otherHeight = 0; if (next != null) { - Dimension tmp = next.getMinimumSize(); - nextWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = next.getMinimumSize(); + nextWidth = tmp.width; } if (previous != null) { - Dimension tmp = previous.getMinimumSize(); - previousWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = previous.getMinimumSize(); + previousWidth = tmp.width; } - d.height = Math.max(d.height, otherHeight); d.width += Math.max(nextWidth, previousWidth); return d; } /** - * DOCUMENT ME! + * Returns the preferred layout size of the container. * * @param parent DOCUMENT ME! * @@ -465,31 +463,29 @@ public class BasicSpinnerUI extends SpinnerUI if (editor != null) { - Dimension tmp = editor.getPreferredSize(); - d.width += Math.max(tmp.width, 40); - d.height = tmp.height; + Dimension tmp = editor.getPreferredSize(); + d.width += Math.max(tmp.width, 40); + d.height = tmp.height; } int nextWidth = 0; int previousWidth = 0; - int otherHeight = 0; if (next != null) { - Dimension tmp = next.getPreferredSize(); - nextWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = next.getPreferredSize(); + nextWidth = tmp.width; } if (previous != null) { - Dimension tmp = previous.getPreferredSize(); - previousWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = previous.getPreferredSize(); + previousWidth = tmp.width; } - d.height = Math.max(d.height, otherHeight); d.width += Math.max(nextWidth, previousWidth); - + Insets insets = parent.getInsets(); + d.width = d.width + insets.left + insets.right; + d.height = d.height + insets.top + insets.bottom; return d; } @@ -501,11 +497,11 @@ public class BasicSpinnerUI extends SpinnerUI public void removeLayoutComponent(Component child) { if (child == editor) - editor = null; + editor = null; else if (child == next) - next = null; + next = null; else if (previous == child) - previous = null; + previous = null; } /** @@ -517,11 +513,11 @@ public class BasicSpinnerUI extends SpinnerUI public void addLayoutComponent(String name, Component child) { if ("Editor".equals(name)) - editor = child; + editor = child; else if ("Next".equals(name)) - next = child; + next = child; else if ("Previous".equals(name)) - previous = child; + previous = child; } /** @@ -531,36 +527,36 @@ public class BasicSpinnerUI extends SpinnerUI * * @return DOCUMENT ME! */ - private Dimension minSize(Component c) + private Dimension prefSize(Component c) { if (c == null) - return new Dimension(); + return new Dimension(); else - return c.getMinimumSize(); + return c.getPreferredSize(); } /** - * DOCUMENT ME! + * Sets the bounds for the specified component. * - * @param c DOCUMENT ME! - * @param x DOCUMENT ME! - * @param y DOCUMENT ME! - * @param w DOCUMENT ME! - * @param h DOCUMENT ME! + * @param c the component. + * @param x the x-coordinate for the top-left of the component bounds. + * @param y the y-coordinate for the top-left of the component bounds. + * @param w the width of the bounds. + * @param h the height of the bounds. */ private void setBounds(Component c, int x, int y, int w, int h) { if (c != null) - c.setBounds(x, y, w, h); + c.setBounds(x, y, w, h); } - /** DOCUMENT ME! */ + /** The editor component. */ private Component editor; - /** DOCUMENT ME! */ + /** The next button. */ private Component next; - /** DOCUMENT ME! */ + /** The previous button. */ private Component previous; } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java index ff17ff084c2..06d32984efb 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java @@ -38,7 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; @@ -161,31 +160,6 @@ public class BasicSplitPaneDivider extends Container */ transient int currentDividerLocation = 1; - /** DOCUMENT ME! */ - private transient Border tmpBorder = new Border() - { - public Insets getBorderInsets(Component c) - { - return new Insets(2, 2, 2, 2); - } - - public boolean isBorderOpaque() - { - return false; - } - - public void paintBorder(Component c, Graphics g, int x, int y, - int width, int height) - { - Color saved = g.getColor(); - g.setColor(Color.BLACK); - - g.drawRect(x + 2, y + 2, width - 4, height - 4); - - g.setColor(saved); - } - }; - /** * Constructs a new divider. * @@ -196,7 +170,6 @@ public class BasicSplitPaneDivider extends Container setLayout(new DividerLayout()); setBasicSplitPaneUI(ui); setDividerSize(splitPane.getDividerSize()); - setBorder(tmpBorder); } /** @@ -212,8 +185,6 @@ public class BasicSplitPaneDivider extends Container if (splitPane != null) { splitPane.removePropertyChangeListener(this); - splitPane.removeMouseListener(mouseHandler); - splitPane.removeMouseMotionListener(mouseHandler); removeMouseListener(mouseHandler); removeMouseMotionListener(mouseHandler); splitPane = null; @@ -227,8 +198,6 @@ public class BasicSplitPaneDivider extends Container if (splitPane != null) { splitPane.addPropertyChangeListener(this); - splitPane.addMouseListener(mouseHandler); - splitPane.addMouseMotionListener(mouseHandler); addMouseListener(mouseHandler); addMouseMotionListener(mouseHandler); hiddenDivider = splitPaneUI.getNonContinuousLayoutDivider(); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java index cf31e8b5df1..8a7c9d2a290 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -62,6 +62,7 @@ import javax.swing.LookAndFeel; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.SplitPaneUI; +import javax.swing.plaf.UIResource; /** * This is the Basic Look and Feel implementation of the SplitPaneUI class. @@ -253,20 +254,21 @@ public class BasicSplitPaneUI extends SplitPaneUI JSplitPane split = (JSplitPane) container; distributeExtraSpace(); Insets insets = split.getInsets(); - int width = getInitialLocation(insets); Dimension dims = split.getSize(); - for (int i = 0; i < components.length; i += 2) - { - if (components[i] == null) - continue; - setComponentToSize(components[i], sizes[i], width, insets, dims); - width += sizes[i]; - } - if (components[1] != null) - { - setComponentToSize(components[1], sizes[1], width, insets, dims); - width += sizes[1]; - } + int loc = getInitialLocation(insets); + int available = getAvailableSize(dims, insets); + sizes[0] = getDividerLocation(split) - loc; + sizes[1] = available - sizes[0] - sizes[2]; + // The size of the divider won't change. + + // Layout component#1. + setComponentToSize(components[0], sizes[0], loc, insets, dims); + // Layout divider. + loc += sizes[0]; + setComponentToSize(components[2], sizes[2], loc, insets, dims); + // Layout component#2. + loc += sizes[2]; + setComponentToSize(components[1], sizes[1], loc, insets, dims); } } @@ -388,6 +390,8 @@ public class BasicSplitPaneUI extends SplitPaneUI { for (int i = 0; i < components.length; i++) resetSizeAt(i); + setDividerLocation(splitPane, + getInitialLocation(splitPane.getInsets()) + sizes[0]); } /** @@ -451,21 +455,7 @@ public class BasicSplitPaneUI extends SplitPaneUI */ void distributeExtraSpace() { - int availSize = getAvailableSize(splitPane.getSize(), - splitPane.getInsets()); - int[] newSizes = new int[3]; - double weight = splitPane.getResizeWeight(); - - int oldLen = sizes[0] + sizes[1]; - - // dividers don't change size. - availSize -= sizes[2] + oldLen; - - int rightAlloc = (int) (availSize * (1 - weight)); - int leftAlloc = availSize - rightAlloc; - - sizes[0] += leftAlloc; - sizes[1] += rightAlloc; + // FIXME: This needs to be reimplemented correctly. } /** @@ -835,8 +825,6 @@ public class BasicSplitPaneUI extends SplitPaneUI if (prop <= 1 && prop >= 0) splitPane.setDividerLocation(prop); } - layoutManager.layoutContainer(splitPane); - splitPane.repaint(); // Don't have to deal with continuous_layout - only // necessary in dragging modes (and it's checked // every time you drag there) @@ -933,6 +921,8 @@ public class BasicSplitPaneUI extends SplitPaneUI /** The JSplitPane that this UI draws. */ protected JSplitPane splitPane; + private int dividerLocation; + /** * Creates a new BasicSplitPaneUI object. */ @@ -992,6 +982,7 @@ public class BasicSplitPaneUI extends SplitPaneUI "SplitPane.foreground"); LookAndFeel.installBorder(splitPane, "SplitPane.border"); divider = createDefaultDivider(); + divider.setBorder(UIManager.getBorder("SplitPaneDivider.border")); resetLayoutManager(); nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider(); splitPane.add(divider, JSplitPane.DIVIDER); @@ -1012,8 +1003,10 @@ public class BasicSplitPaneUI extends SplitPaneUI divider = null; nonContinuousLayoutDivider = null; - splitPane.setBackground(null); - splitPane.setBorder(null); + if (splitPane.getBackground() instanceof UIResource) + splitPane.setBackground(null); + if (splitPane.getBorder() instanceof UIResource) + splitPane.setBorder(null); } /** @@ -1219,7 +1212,8 @@ public class BasicSplitPaneUI extends SplitPaneUI if (nonContinuousLayoutDivider == null) { nonContinuousLayoutDivider = new Canvas(); - nonContinuousLayoutDivider.setBackground(Color.DARK_GRAY); + Color c = UIManager.getColor("SplitPaneDivider.draggingColor"); + nonContinuousLayoutDivider.setBackground(c); } return nonContinuousLayoutDivider; } @@ -1298,44 +1292,7 @@ public class BasicSplitPaneUI extends SplitPaneUI */ public void setDividerLocation(JSplitPane jc, int location) { - location = validLocation(location); - Container p = jc.getParent(); - Component right = jc.getRightComponent(); - Dimension rightPrefSize = right == null ? new Dimension(0, 0) - : right.getPreferredSize(); - Dimension size = jc.getSize(); - // check if the size has been set for the splitpane - if (size.width == 0 && size.height == 0) - size = jc.getPreferredSize(); - - if (getOrientation() == 0 && location > size.height) - { - location = size.height; - while (p != null) - { - p.setSize(p.getWidth(), p.getHeight() + rightPrefSize.height); - p = p.getParent(); - } - } - else if (location > size.width) - { - location = size.width; - while (p != null) - { - p.setSize(p.getWidth() + rightPrefSize.width, p.getHeight()); - p = p.getParent(); - } - } - - setLastDragLocation(getDividerLocation(splitPane)); - splitPane.setLastDividerLocation(getDividerLocation(splitPane)); - int[] tmpSizes = layoutManager.getSizes(); - tmpSizes[0] = location - - layoutManager.getInitialLocation(splitPane.getInsets()); - tmpSizes[1] = layoutManager.getAvailableSize(splitPane.getSize(), - splitPane.getInsets()) - - tmpSizes[0]; - layoutManager.setSizes(tmpSizes); + dividerLocation = location; splitPane.revalidate(); splitPane.repaint(); } @@ -1349,8 +1306,7 @@ public class BasicSplitPaneUI extends SplitPaneUI */ public int getDividerLocation(JSplitPane jc) { - return layoutManager.sizes[0] - + layoutManager.getInitialLocation(splitPane.getInsets()); + return dividerLocation; } /** @@ -1365,7 +1321,7 @@ public class BasicSplitPaneUI extends SplitPaneUI { int value = layoutManager.getInitialLocation(jc.getInsets()); if (layoutManager.components[0] != null) - value -= layoutManager.minimumSizeOfComponent(0); + value += layoutManager.minimumSizeOfComponent(0); return value; } @@ -1501,8 +1457,6 @@ public class BasicSplitPaneUI extends SplitPaneUI nonContinuousLayoutDivider.setVisible(true); nonContinuousLayoutDivider.setBounds(divider.getBounds()); } - splitPane.revalidate(); - splitPane.repaint(); } /** @@ -1544,11 +1498,9 @@ public class BasicSplitPaneUI extends SplitPaneUI nonContinuousLayoutDivider.setVisible(false); draggingHW = false; location = validLocation(location); - dragDividerTo(location); splitPane.setDividerLocation(location); splitPane.setLastDividerLocation(beginDragDividerLocation); beginDragDividerLocation = -1; - splitPane.repaint(); } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java index a8f52cef617..5b1e1ff0f60 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -451,6 +451,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants } } runCount = runs; + if (runCount > tabRuns.length) + expandTabRunsArray(); tabRuns[0] = 0; normalizeTabRuns(tabPlacement, tabCount, start, max); @@ -1025,6 +1027,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants } } runCount = runs; + if (runCount > tabRuns.length) + expandTabRunsArray(); padSelectedTab(tabPlacement, tabPane.getSelectedIndex()); } @@ -1733,9 +1737,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants int tabCount = tabPane.getTabCount(); int currRun = 1; - if (tabCount > runCount) - runCount = tabCount; - if (tabCount < 1) return; diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java index 9c8a5ef9598..1e8e39f38c2 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java @@ -39,14 +39,18 @@ exception statement from your version. */ package javax.swing.plaf.basic; import java.awt.Component; +import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import javax.swing.CellRendererPane; import javax.swing.JComponent; import javax.swing.LookAndFeel; +import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.event.MouseInputListener; @@ -57,62 +61,346 @@ import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; +/** + * Basic pluggable look and feel interface for JTableHeader. + */ public class BasicTableHeaderUI extends TableHeaderUI { - + /** + * The width of the space (in both direction) around the column boundary, + * where mouse cursor changes shape into "resize" + */ + static int COLUMN_BOUNDARY_TOLERANCE = 3; + public static ComponentUI createUI(JComponent h) { return new BasicTableHeaderUI(); } - + + /** + * The table header that is using this interface. + */ protected JTableHeader header; + + /** + * The mouse input listener, responsible for mouse manipulations with + * the table header. + */ protected MouseInputListener mouseInputListener; + + /** + * Paint the header cell. + */ protected CellRendererPane rendererPane; + + /** + * The header cell border. + */ protected Border cellBorder; - - public class MouseInputHandler implements MouseInputListener + + /** + * If not null, one of the columns is currently being dragged. + */ + Rectangle draggingHeaderRect; + + /** + * Handles column movement and rearrangement by mouse. The same instance works + * both as mouse listener and the mouse motion listner. + */ + public class MouseInputHandler + implements MouseInputListener { + /** + * If true, the cursor is being already shown in the alternative "resize" + * shape. + */ + boolean showingResizeCursor; + + /** + * The position, from where the cursor is dragged during resizing. Double + * purpose field (absolute value during resizing and relative offset during + * column dragging). + */ + int draggingFrom = - 1; + + /** + * The number of the column being dragged. + */ + int draggingColumnNumber; + + /** + * The previous preferred width of the column. + */ + int prevPrefWidth = - 1; + + /** + * The timer to coalesce column resizing events. + */ + Timer timer; + + /** + * Returns without action, part of the MouseInputListener interface. + */ public void mouseClicked(MouseEvent e) { - // TODO: Implement this properly. + // Nothing to do. } + /** + * If being in the resizing mode, handle resizing. + */ public void mouseDragged(MouseEvent e) { - // TODO: Implement this properly. + TableColumn resizeIt = header.getResizingColumn(); + if (resizeIt != null && header.getResizingAllowed()) + { + // The timer is intialised on demand. + if (timer == null) + { + // The purpose of timer is to coalesce events. If the queue + // is free, the repaint event is fired immediately. + timer = new Timer(1, new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + header.getTable().doLayout(); + } + }); + timer.setRepeats(false); + timer.setCoalesce(true); + } + resizeIt.setPreferredWidth(prevPrefWidth + e.getX() - draggingFrom); + timer.restart(); + } + else if (draggingHeaderRect != null && header.getReorderingAllowed()) + { + draggingHeaderRect.x = e.getX() + draggingFrom; + header.repaint(); + } } + /** + * Returns without action, part of the MouseInputListener interface. + */ public void mouseEntered(MouseEvent e) { - // TODO: Implement this properly. + // Nothing to do. } + /** + * Reset drag information of the column resizing. + */ public void mouseExited(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingColumn() != null && header.getResizingAllowed()) + endResizing(); + if (header.getDraggedColumn() != null && header.getReorderingAllowed()) + endDragging(null); } + /** + * Change the mouse cursor if the mouse if above the column boundary. + */ public void mouseMoved(MouseEvent e) { - // TODO: Implement this properly. + // When dragging, the functionality is handled by the mouseDragged. + if (e.getButton() == 0 && header.getResizingAllowed()) + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n < 2) + // It must be at least two columns to have at least one boundary. + // Otherwise, nothing to do. + return; + + boolean onBoundary = false; + + int x = e.getX(); + int a = x - COLUMN_BOUNDARY_TOLERANCE; + int b = x + COLUMN_BOUNDARY_TOLERANCE; + + int p = 0; + + Scan: for (int i = 0; i < n - 1; i++) + { + p += model.getColumn(i).getWidth(); + + if (p >= a && p <= b) + { + TableColumn column = model.getColumn(i); + onBoundary = true; + + draggingFrom = x; + prevPrefWidth = column.getWidth(); + header.setResizingColumn(column); + break Scan; + } + } + + if (onBoundary != showingResizeCursor) + { + // Change the cursor shape, if needed. + if (onBoundary) + { + + if (p < x) + header.setCursor(Cursor.getPredefinedCursor + (Cursor.W_RESIZE_CURSOR)); + else + header.setCursor(Cursor.getPredefinedCursor + (Cursor.E_RESIZE_CURSOR)); + } + else + { + header.setCursor(Cursor.getDefaultCursor()); + header.setResizingColumn(null); + } + + showingResizeCursor = onBoundary; + } + } } + /** + * Starts the dragging/resizing procedure. + */ public void mousePressed(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingAllowed()) + { + TableColumn resizingColumn = header.getResizingColumn(); + if (resizingColumn != null) + { + resizingColumn.setPreferredWidth(resizingColumn.getWidth()); + return; + } + } + + if (header.getReorderingAllowed()) + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n < 2) + // It must be at least two columns to change the column location. + return; + + boolean onBoundary = false; + + int x = e.getX(); + int p = 0; + int col = - 1; + + Scan: for (int i = 0; i < n; i++) + { + p += model.getColumn(i).getWidth(); + if (p > x) + { + col = i; + break Scan; + } + } + if (col < 0) + return; + + TableColumn dragIt = model.getColumn(col); + header.setDraggedColumn(dragIt); + + draggingFrom = (p - dragIt.getWidth()) - x; + draggingHeaderRect = new Rectangle(header.getHeaderRect(col)); + draggingColumnNumber = col; + } } + /** + * Set all column preferred width to the current width to prevend abrupt + * width changes during the next resize. + */ public void mouseReleased(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingColumn() != null && header.getResizingAllowed()) + endResizing(); + if (header.getDraggedColumn() != null && header.getReorderingAllowed()) + endDragging(e); + } + + /** + * Stop resizing session. + */ + void endResizing() + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n > 2) + { + TableColumn c; + for (int i = 0; i < n; i++) + { + c = model.getColumn(i); + c.setPreferredWidth(c.getWidth()); + } + } + header.setResizingColumn(null); + showingResizeCursor = false; + if (timer != null) + timer.stop(); + header.setCursor(Cursor.getDefaultCursor()); } - } + /** + * Stop the dragging session. + * + * @param e the "mouse release" mouse event, needed to determing the final + * location for the dragged column. + */ + void endDragging(MouseEvent e) + { + header.setDraggedColumn(null); + + // Return if the mouse have left the header area while pressed. + if (e == null) + { + header.repaint(draggingHeaderRect); + draggingHeaderRect = null; + return; + } + else + draggingHeaderRect = null; + + TableColumnModel model = header.getColumnModel(); + + // Find where have we dragged the column. + int x = e.getX(); + int p = 0; + int col = - 1; + int n = model.getColumnCount(); + + Scan: for (int i = 0; i < n; i++) + { + p += model.getColumn(i).getWidth(); + if (p > x) + { + col = i; + break Scan; + } + } + if (col >= 0) + header.getTable().moveColumn(draggingColumnNumber, col); + } + } + + /** + * Create and return the mouse input listener. + * + * @return the mouse listener ({@link MouseInputHandler}, if not overridden. + */ protected MouseInputListener createMouseInputListener() { return new MouseInputHandler(); } - + + /** + * Construct a new BasicTableHeaderUI, create mouse listeners. + */ public BasicTableHeaderUI() { mouseInputListener = createMouseInputListener(); @@ -131,9 +419,15 @@ public class BasicTableHeaderUI extends TableHeaderUI // TODO: Implement this properly. } + /** + * Add the mouse listener and the mouse motion listener to the table + * header. The listeners support table column resizing and rearrangement + * by mouse. + */ protected void installListeners() { header.addMouseListener(mouseInputListener); + header.addMouseMotionListener(mouseInputListener); } public void installUI(JComponent c) @@ -156,10 +450,14 @@ public class BasicTableHeaderUI extends TableHeaderUI { // TODO: Implement this properly. } - + + /** + * Remove the previously installed listeners. + */ protected void uninstallListeners() { header.removeMouseListener(mouseInputListener); + header.removeMouseMotionListener(mouseInputListener); } public void uninstallUI(JComponent c) @@ -168,7 +466,10 @@ public class BasicTableHeaderUI extends TableHeaderUI uninstallKeyboardActions(); uninstallDefaults(); } - + + /** + * Repaint the table header. + */ public void paint(Graphics gfx, JComponent c) { TableColumnModel cmod = header.getColumnModel(); @@ -206,10 +507,26 @@ public class BasicTableHeaderUI extends TableHeaderUI bounds.width, bounds.height); } } - + + // This displays a running rectangle that is much simplier than the total + // animation, as it is seen in Sun's application. + // TODO animate the collumn dragging like in Sun's jre. + if (draggingHeaderRect!=null) + { + gfx.setColor(header.getForeground()); + gfx.drawRect(draggingHeaderRect.x, draggingHeaderRect.y+2, + draggingHeaderRect.width-1, draggingHeaderRect.height-6); + } } - public Dimension getPreferredSize(JComponent c) + /** + * Get the preferred header size. + * + * @param ignored unused + * + * @return the preferred size of the associated header. + */ + public Dimension getPreferredSize(JComponent ignored) { TableColumnModel cmod = header.getColumnModel(); TableCellRenderer defaultRend = header.getDefaultRenderer(); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java index 18b69120d11..8360a9ec771 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java @@ -58,11 +58,11 @@ import java.beans.PropertyChangeListener; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.CellRendererPane; +import javax.swing.DefaultCellEditor; import javax.swing.DefaultListSelectionModel; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JTable; -import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.LookAndFeel; @@ -74,8 +74,8 @@ import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.TableUI; +import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; @@ -193,10 +193,31 @@ public class BasicTableUI extends TableUI colModel.setSelectionInterval(lo_col, hi_col); } } - - public void mouseClicked(MouseEvent e) + + /** + * For the double click, start the cell editor. + */ + public void mouseClicked(MouseEvent e) { - // TODO: What should be done here, if anything? + Point p = e.getPoint(); + int row = table.rowAtPoint(p); + int col = table.columnAtPoint(p); + if (table.isCellEditable(row, col)) + { + // If the cell editor is the default editor, we request the + // number of the required clicks from it. Otherwise, + // require two clicks (double click). + TableCellEditor editor = table.getCellEditor(row, col); + if (editor instanceof DefaultCellEditor) + { + DefaultCellEditor ce = (DefaultCellEditor) editor; + if (e.getClickCount() < ce.getClickCountToStart()) + return; + } + else if (e.getClickCount() < 2) + return; + table.editCellAt(row, col); + } } public void mouseDragged(MouseEvent e) @@ -354,7 +375,8 @@ public class BasicTableUI extends TableUI maxTotalColumnWidth += table.getColumnModel().getColumn(i).getMaxWidth(); if (maxTotalColumnWidth == 0 || table.getRowCount() == 0) return null; - return new Dimension(maxTotalColumnWidth, table.getRowCount()*table.getRowHeight()); + return new Dimension(maxTotalColumnWidth, table.getRowCount()* + (table.getRowHeight()+table.getRowMargin())); } /** @@ -380,7 +402,7 @@ public class BasicTableUI extends TableUI public Dimension getPreferredSize(JComponent comp) { int width = table.getColumnModel().getTotalColumnWidth(); - int height = table.getRowCount() * table.getRowHeight(); + int height = table.getRowCount() * (table.getRowHeight()+table.getRowMargin()); return new Dimension(width, height); } @@ -854,6 +876,10 @@ public class BasicTableUI extends TableUI rowModel.setAnchorSelectionIndex(rowLead); colModel.setAnchorSelectionIndex(colLead); } + else if (command.equals("stopEditing")) + { + table.editingStopped(new ChangeEvent(command)); + } else { // If we're here that means we bound this TableAction class @@ -1185,30 +1211,17 @@ public class BasicTableUI extends TableUI * system beginning at <code>(0,0)</code> in the upper left corner of the * table * @param rend A cell renderer to paint with - * @param data The data to provide to the cell renderer - * @param rowLead The lead selection for the rows of the table. - * @param colLead The lead selection for the columns of the table. */ void paintCell(Graphics g, int row, int col, Rectangle bounds, - TableCellRenderer rend, TableModel data, - int rowLead, int colLead) + TableCellRenderer rend) { Component comp = table.prepareRenderer(rend, row, col); rendererPane.paintComponent(g, comp, table, bounds); - - // FIXME: this is manual painting of the Caret, why doesn't the - // JTextField take care of this itself? - if (comp instanceof JTextField) - { - Rectangle oldClip = g.getClipBounds(); - g.translate(bounds.x, bounds.y); - g.clipRect(0, 0, bounds.width, bounds.height); - ((JTextField)comp).getCaret().paint(g); - g.translate(-bounds.x, -bounds.y); - g.setClip(oldClip); - } } + /** + * Paint the associated table. + */ public void paint(Graphics gfx, JComponent ignored) { int ncols = table.getColumnCount(); @@ -1217,59 +1230,72 @@ public class BasicTableUI extends TableUI return; Rectangle clip = gfx.getClipBounds(); - TableColumnModel cols = table.getColumnModel(); - - int height = table.getRowHeight(); - int x0 = 0, y0 = 0; - int x = x0; - int y = y0; - - Dimension gap = table.getIntercellSpacing(); - int ymax = clip.y + clip.height; - int xmax = clip.x + clip.width; + // Determine the range of cells that are within the clip bounds. + Point p1 = new Point(clip.x, clip.y); + int c0 = table.columnAtPoint(p1); + if (c0 == -1) + c0 = 0; + int r0 = table.rowAtPoint(p1); + if (r0 == -1) + r0 = 0; + Point p2 = new Point(clip.x + clip.width, clip.y + clip.height); + int cn = table.columnAtPoint(p2); + if (cn == -1) + cn = table.getColumnCount() - 1; + int rn = table.rowAtPoint(p2); + if (rn == -1) + rn = table.getRowCount() - 1; + + TableColumnModel cmodel = table.getColumnModel(); + int [] widths = new int[cn+1]; + for (int i = c0; i <=cn ; i++) + { + widths[i] = cmodel.getColumn(i).getWidth(); + } + + Rectangle bounds = table.getCellRect(r0, c0, false); + bounds.height = table.getRowHeight()+table.getRowMargin(); + + // The left boundary of the area being repainted. + int left = bounds.x; + + // The top boundary of the area being repainted. + int top = bounds.y; + + // The bottom boundary of the area being repainted. + int bottom; + + // The cell height. + int height = bounds.height; + // paint the cell contents - for (int c = 0; c < ncols && x < xmax; ++c) + Color grid = table.getGridColor(); + for (int r = r0; r <= rn; ++r) { - y = y0; - TableColumn col = cols.getColumn(c); - int width = col.getWidth(); - int halfGapWidth = gap.width / 2; - int halfGapHeight = gap.height / 2; - for (int r = 0; r < nrows && y < ymax; ++r) + for (int c = c0; c <= cn; ++c) { - Rectangle bounds = new Rectangle(x + halfGapWidth, - y + halfGapHeight + 1, - width - gap.width + 1, - height - gap.height); - if (bounds.intersects(clip)) - { - paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c), - table.getModel(), - table.getSelectionModel().getLeadSelectionIndex(), - table.getColumnModel().getSelectionModel().getLeadSelectionIndex()); - } - y += height; + bounds.width = widths[c]; + paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c)); + bounds.x += widths[c]; } - x += width; + bounds.y += height; + bounds.x = left; } - - // tighten up the x and y max bounds - ymax = y; - xmax = x; - - Color grid = table.getGridColor(); + + bottom = bounds.y; // paint vertical grid lines if (grid != null && table.getShowVerticalLines()) { - x = x0; Color save = gfx.getColor(); gfx.setColor(grid); - for (int c = 0; c < ncols && x < xmax; ++c) + int x = left; + + for (int c = c0; c <= cn; ++c) { - x += cols.getColumn(c).getWidth(); - gfx.drawLine(x, y0, x, ymax); + gfx.drawLine(x, top, x, bottom); + x += widths[c]; } gfx.setColor(save); } @@ -1277,13 +1303,13 @@ public class BasicTableUI extends TableUI // paint horizontal grid lines if (grid != null && table.getShowHorizontalLines()) { - y = y0; Color save = gfx.getColor(); gfx.setColor(grid); - for (int r = 0; r < nrows && y < ymax; ++r) + int y = top; + for (int r = r0; r <= rn; ++r) { + gfx.drawLine(left, y, p2.x, y); y += height; - gfx.drawLine(x0, y, xmax, y); } gfx.setColor(save); } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java index fc388948419..beb1a6dfeac 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java @@ -1,5 +1,5 @@ /* BasicTextUI.java -- - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -46,15 +46,11 @@ import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; -import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.InputMap; @@ -70,6 +66,7 @@ import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.TextUI; import javax.swing.plaf.UIResource; +import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; import javax.swing.text.Caret; import javax.swing.text.DefaultCaret; @@ -82,6 +79,7 @@ import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; import javax.swing.text.Keymap; import javax.swing.text.Position; +import javax.swing.text.Utilities; import javax.swing.text.View; import javax.swing.text.ViewFactory; @@ -161,11 +159,11 @@ public abstract class BasicTextUI extends TextUI * Indicates that the preferences of one of the child view has changed. * This calls revalidate on the text component. * - * @param view the child view which's preference has changed + * @param v the child view which's preference has changed * @param width <code>true</code> if the width preference has changed * @param height <code>true</code> if the height preference has changed */ - public void preferenceChanged(View view, boolean width, boolean height) + public void preferenceChanged(View v, boolean width, boolean height) { textComponent.revalidate(); } @@ -181,7 +179,7 @@ public abstract class BasicTextUI extends TextUI view.setParent(null); if (v != null) - v.setParent(null); + v.setParent(this); view = v; } @@ -207,10 +205,10 @@ public abstract class BasicTextUI extends TextUI */ public int getViewCount() { + int count = 0; if (view != null) - return 1; - else - return 0; + count = 1; + return count; } /** @@ -249,7 +247,11 @@ public abstract class BasicTextUI extends TextUI public void paint(Graphics g, Shape s) { if (view != null) - view.paint(g, s); + { + Rectangle b = s.getBounds(); + view.setSize(b.width, b.height); + view.paint(g, s); + } } @@ -277,7 +279,7 @@ public abstract class BasicTextUI extends TextUI public Shape modelToView(int position, Shape a, Position.Bias bias) throws BadLocationException { - return ((View) view).modelToView(position, a, bias); + return view.modelToView(position, a, bias); } /** @@ -363,12 +365,44 @@ public abstract class BasicTextUI extends TextUI { return view.getNextVisualPositionFrom(pos, b, a, d, biasRet); } + + /** + * Returns the startOffset of this view, which is always the beginning + * of the document. + * + * @return the startOffset of this view + */ + public int getStartOffset() + { + return 0; + } + + /** + * Returns the endOffset of this view, which is always the end + * of the document. + * + * @return the endOffset of this view + */ + public int getEndOffset() + { + return getDocument().getLength(); + } + + /** + * Returns the document associated with this view. + * + * @return the document associated with this view + */ + public Document getDocument() + { + return textComponent.getDocument(); + } } /** * Receives notifications when properties of the text component change. */ - class PropertyChangeHandler implements PropertyChangeListener + private class PropertyChangeHandler implements PropertyChangeListener { /** * Notifies when a property of the text component changes. @@ -448,7 +482,7 @@ public abstract class BasicTextUI extends TextUI /** * Receives notification when the model changes. */ - PropertyChangeHandler updateHandler = new PropertyChangeHandler(); + private PropertyChangeHandler updateHandler = new PropertyChangeHandler(); /** The DocumentEvent handler. */ DocumentHandler documentHandler = new DocumentHandler(); @@ -515,20 +549,19 @@ public abstract class BasicTextUI extends TextUI c.setOpaque(true); textComponent = (JTextComponent) c; - Document doc = textComponent.getDocument(); if (doc == null) { - doc = getEditorKit(textComponent).createDefaultDocument(); - textComponent.setDocument(doc); + doc = getEditorKit(textComponent).createDefaultDocument(); + textComponent.setDocument(doc); } - - textComponent.addPropertyChangeListener(updateHandler); - modelChanged(); - installDefaults(); installListeners(); installKeyboardActions(); + + // We need to trigger this so that the view hierarchy gets initialized. + modelChanged(); + } /** @@ -584,6 +617,7 @@ public abstract class BasicTextUI extends TextUI protected void installListeners() { textComponent.addFocusListener(focuslistener); + textComponent.addPropertyChangeListener(updateHandler); installDocumentListeners(); } @@ -621,6 +655,11 @@ public abstract class BasicTextUI extends TextUI */ protected Keymap createKeymap() { + // FIXME: It seems to me that this method implementation is wrong. It seems + // to fetch the focusInputMap and transform it to the KeyBinding/Keymap + // implemenation. I would think that it should be done the other way, + // fetching the keybindings (from prefix + ".bindings") and transform + // it to the newer InputMap/ActionMap implementation. JTextComponent.KeyBinding[] bindings = null; String prefix = getPropertyPrefix(); InputMapUIResource m = (InputMapUIResource) UIManager.get(prefix + ".focusInputMap"); @@ -637,10 +676,7 @@ public abstract class BasicTextUI extends TextUI } } if (bindings == null) - { - bindings = new JTextComponent.KeyBinding[0]; - UIManager.put(prefix + ".focusInputMap", bindings); - } + bindings = new JTextComponent.KeyBinding[0]; Keymap km = JTextComponent.addKeymap(getKeymapName(), JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP)); @@ -726,8 +762,6 @@ public abstract class BasicTextUI extends TextUI super.uninstallUI(component); rootView.setView(null); - textComponent.removePropertyChangeListener(updateHandler); - uninstallDefaults(); uninstallListeners(); uninstallKeyboardActions(); @@ -750,6 +784,7 @@ public abstract class BasicTextUI extends TextUI */ protected void uninstallListeners() { + textComponent.removePropertyChangeListener(updateHandler); textComponent.removeFocusListener(focuslistener); textComponent.getDocument().removeDocumentListener(documentHandler); } @@ -786,7 +821,9 @@ public abstract class BasicTextUI extends TextUI float w = v.getPreferredSpan(View.X_AXIS); float h = v.getPreferredSpan(View.Y_AXIS); - return new Dimension((int) w, (int) h); + Insets i = c.getInsets(); + return new Dimension((int) w + i.left + i.right, + (int) h + i.top + i.bottom); } /** @@ -817,18 +854,49 @@ public abstract class BasicTextUI extends TextUI } /** - * Paints the text component. + * Paints the text component. This acquires a read lock on the model and then + * calls {@link #paintSafely(Graphics)} in order to actually perform the + * painting. * * @param g the <code>Graphics</code> context to paint to * @param c not used here */ public final void paint(Graphics g, JComponent c) { - paintSafely(g); + try + { + Document doc = textComponent.getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument aDoc = (AbstractDocument) doc; + aDoc.readLock(); + } + + paintSafely(g); + } + finally + { + Document doc = textComponent.getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument aDoc = (AbstractDocument) doc; + aDoc.readUnlock(); + } + } } /** - * Actually performs the painting. + * This paints the text component while beeing sure that the model is not + * modified while painting. + * + * The following is performed in this order: + * <ol> + * <li>If the text component is opaque, the background is painted by + * calling {@link #paintBackground(Graphics)}.</li> + * <li>If there is a highlighter, the highlighter is painted.</li> + * <li>The view hierarchy is painted.</li> + * <li>The Caret is painter.</li> + * </ol> * * @param g the <code>Graphics</code> context to paint to */ @@ -840,9 +908,19 @@ public abstract class BasicTextUI extends TextUI if (textComponent.isOpaque()) paintBackground(g); - if (highlighter != null - && textComponent.getSelectionStart() != textComponent.getSelectionEnd()) - highlighter.paint(g); + // Try painting with the highlighter without checking whether there + // is a selection because a highlighter can be used to do more than + // marking selected text. + if (highlighter != null) + { + // Handle restoring of the color here to prevent + // drawing problems when the Highlighter implementor + // forgets to restore it. + Color oldColor = g.getColor(); + highlighter.paint(g); + g.setColor(oldColor); + } + rootView.paint(g, getVisibleEditorRect()); @@ -857,10 +935,23 @@ public abstract class BasicTextUI extends TextUI */ protected void paintBackground(Graphics g) { - // This method does nothing. All the background filling is done by the - // ComponentUI update method. However, the method is called by paint - // to provide a way for subclasses to draw something different (e.g. - // background images etc) on the background. + Color old = g.getColor(); + g.setColor(textComponent.getBackground()); + g.fillRect(0, 0, textComponent.getWidth(), textComponent.getHeight()); + g.setColor(old); + } + + /** + * Overridden for better control over background painting. This now simply + * calls {@link #paint} and this delegates the background painting to + * {@link #paintBackground}. + * + * @param g the graphics to use + * @param c the component to be painted + */ + public void update(Graphics g, JComponent c) + { + paint(g, c); } /** @@ -895,7 +986,84 @@ public abstract class BasicTextUI extends TextUI public void damageRange(JTextComponent t, int p0, int p1, Position.Bias firstBias, Position.Bias secondBias) { - // TODO: Implement me. + try + { + // Limit p0 and p1 to sane values to prevent unfriendly + // BadLocationExceptions. This makes it possible for the highlighter + // to send us illegal values which can happen when a large number + // of selected characters are removed (eg. by pressing delete + // or backspace). + // The reference implementation does not throw an exception, too. + p0 = Math.min(p0, t.getDocument().getLength()); + p1 = Math.min(p1, t.getDocument().getLength()); + + Rectangle l1 = modelToView(t, p0, firstBias); + Rectangle l2 = modelToView(t, p1, secondBias); + if (l1.y == l2.y) + t.repaint(l1.union(l2)); + else + { + // The two rectangles lie on different lines and we need a + // different algorithm to calculate the damaged area: + // 1. The line of p0 is damaged from the position of p0 + // to the right border. + // 2. All lines between the ones where p0 and p1 lie on + // are completely damaged. Use the allocation area to find + // out the bounds. + // 3. The final line is damaged from the left bound to the + // position of p1. + Insets insets = t.getInsets(); + + // Damage first line until the end. + l1.width = insets.right + t.getWidth() - l1.x; + t.repaint(l1); + + // Note: Utilities.getPositionBelow() may return the offset + // that was put in. In that case there is no next line and + // we should stop searching for one. + + int posBelow = Utilities.getPositionBelow(t, p0, l1.x); + if (posBelow < p1 && posBelow != -1 && posBelow != p0) + { + // Take the rectangle of the offset we just found and grow it + // to the maximum width. Retain y because this is our start + // height. + Rectangle grow = modelToView(t, posBelow); + grow.x = insets.left; + grow.width = t.getWidth() + insets.right; + + // Find further lines which have to be damaged completely. + int nextPosBelow = posBelow; + while (nextPosBelow < p1 && nextPosBelow != -1 && posBelow != nextPosBelow) + { + posBelow = nextPosBelow; + nextPosBelow = Utilities.getPositionBelow(t, posBelow, l1.x); + } + // Now posBelow is an offset on the last line which has to be damaged + // completely. (newPosBelow is on the same line as p1) + + // Retrieve the rectangle of posBelow and use its y and height + // value to calculate the final height of the multiple line + // spanning rectangle. + Rectangle end = modelToView(t, posBelow); + grow.height = end.y + end.height - grow.y; + + // Mark that area as damage. + t.repaint(grow); + } + + // Damage last line from its beginning to the position of p1. + l2.width += l2.x; + l2.x = insets.left; + t.repaint(l2); + } + } + catch (BadLocationException ex) + { + AssertionError err = new AssertionError("Unexpected bad location"); + err.initCause(ex); + throw err; + } } /** @@ -1061,7 +1229,6 @@ public abstract class BasicTextUI extends TextUI */ protected Rectangle getVisibleEditorRect() { - JTextComponent textComponent = getComponent(); int width = textComponent.getWidth(); int height = textComponent.getHeight(); @@ -1082,7 +1249,6 @@ public abstract class BasicTextUI extends TextUI protected final void setView(View view) { rootView.setView(view); - view.setParent(rootView); textComponent.revalidate(); textComponent.repaint(); } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java index f2ebcfca9ac..1c6e6c5e502 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java @@ -45,6 +45,7 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; +import java.awt.Label; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -114,9 +115,18 @@ import javax.swing.tree.TreeSelectionModel; * @see javax.swing.JTree * @author Lillian Angel (langel@redhat.com) * @author Sascha Brawer (brawer@dandelis.ch) + * @author Audrius Meskauskas (audriusa@bioinformatics.org) */ public class BasicTreeUI extends TreeUI { + /** + * The tree cell editing may be started by the single mouse click on the + * selected cell. To separate it from the double mouse click, the editing + * session starts after this time (in ms) after that single click, and only + * no other clicks were performed during that time. + */ + static int WAIT_TILL_EDITING = 900; + /** Collapse Icon for the tree. */ protected transient Icon collapsedIcon; @@ -225,12 +235,6 @@ public class BasicTreeUI extends TreeUI /** Set to true if the editor has a different size than the renderer. */ protected boolean editorHasDifferentSize; - /** The action listener for the editor's Timer. */ - Timer editorTimer = new EditorUpdateTimer(); - - /** The new value of the node after editing. */ - Object newVal; - /** The action bound to KeyStrokes. */ TreeAction action; @@ -266,6 +270,20 @@ public class BasicTreeUI extends TreeUI private TreeExpansionListener treeExpansionListener; private TreeModelListener treeModelListener; + + /** + * This timer fires the editing action after about 1200 ms if not reset during + * that time. It handles the editing start with the single mouse click + * (and not the double mouse click) on the selected tree node. + */ + Timer startEditTimer; + + /** + * The special value of the mouse event is sent indicating that this is not + * just the mouse click, but the mouse click on the selected node. Sending + * such event forces to start the cell editing session. + */ + static final MouseEvent EDIT = new MouseEvent(new Label(), 7,7,7,7,7,7, false); /** * Creates a new BasicTreeUI object. @@ -303,7 +321,7 @@ public class BasicTreeUI extends TreeUI { return new BasicTreeUI(); } - + /** * Returns the Hash color. * @@ -796,7 +814,10 @@ public class BasicTreeUI extends TreeUI public boolean stopEditing(JTree tree) { if (isEditing(tree)) - completeEditing(true, false, false); + { + completeEditing(false, false, true); + finish(); + } return !isEditing(tree); } @@ -807,9 +828,12 @@ public class BasicTreeUI extends TreeUI * is the tree to cancel the editing session on. */ public void cancelEditing(JTree tree) - { - if (isEditing(tree)) - completeEditing(false, true, false); + { + // There is no need to send the cancel message to the editor, + // as the cancellation event itself arrives from it. This would + // only be necessary when cancelling the editing programatically. + completeEditing(false, false, false); + finish(); } /** @@ -1213,6 +1237,7 @@ public class BasicTreeUI extends TreeUI protected void updateCachedPreferredSize() { int maxWidth = 0; + updateCurrentVisiblePath(); boolean isLeaf = false; if (currentVisiblePath != null) { @@ -1246,7 +1271,7 @@ public class BasicTreeUI extends TreeUI protected void pathWasExpanded(TreePath path) { validCachedPreferredSize = false; - tree.repaint(); + tree.repaint(); } /** @@ -1271,7 +1296,6 @@ public class BasicTreeUI extends TreeUI leftChildIndent = UIManager.getInt("Tree.leftChildIndent"); setRowHeight(UIManager.getInt("Tree.rowHeight")); tree.setRowHeight(getRowHeight()); - tree.requestFocusInWindow(false); tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand")); setExpandedIcon(UIManager.getIcon("Tree.expandedIcon")); setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon")); @@ -1621,7 +1645,14 @@ public class BasicTreeUI extends TreeUI } if (messageTree) - treeModel.valueForPathChanged(tree.getLeadSelectionPath(), newVal); + { + TreeCellEditor editor = getCellEditor(); + if (editor != null) + { + Object value = editor.getCellEditorValue(); + treeModel.valueForPathChanged(tree.getLeadSelectionPath(), value); + } + } } /** @@ -1636,44 +1667,48 @@ public class BasicTreeUI extends TreeUI */ protected boolean startEditing(TreePath path, MouseEvent event) { - int x; - int y; - if (event == null) - { - Rectangle bounds = getPathBounds(tree, path); - x = bounds.x; - y = bounds.y; - } - else - { - x = event.getX(); - y = event.getY(); - } + // Force to recalculate the maximal row height. + maxHeight = 0; + + // Force to recalculate the cached preferred size. + validCachedPreferredSize = false; updateCellEditor(); TreeCellEditor ed = getCellEditor(); - if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event)) + + if (ed != null + && (event == EDIT || ed.shouldSelectCell(event)) + && ed.isCellEditable(event)) { + Rectangle bounds = getPathBounds(tree, path); + + // Extend the right boundary till the tree width. + bounds.width = tree.getWidth() - bounds.x; + editingPath = path; editingRow = tree.getRowForPath(editingPath); - Object val = editingPath.getLastPathComponent(); - cellEditor.addCellEditorListener(cellEditorListener); + Object value = editingPath.getLastPathComponent(); + stopEditingInCompleteEditing = false; boolean expanded = tree.isExpanded(editingPath); isEditing = true; - editingComponent = ed.getTreeCellEditorComponent(tree, val, true, + editingComponent = ed.getTreeCellEditorComponent(tree, value, true, expanded, isLeaf(editingRow), editingRow); - editingComponent.getParent().setVisible(true); - editingComponent.getParent().validate(); - tree.add(editingComponent.getParent()); - editingComponent.getParent().validate(); - validCachedPreferredSize = false; - - ((JTextField) editingComponent).requestFocusInWindow(false); - editorTimer.start(); + + // Remove all previous components (if still present). Only one + // container with the editing component inside is allowed in the tree. + tree.removeAll(); + + // The editing component must be added to its container. We add the + // container, not the editing component itself. + Component container = editingComponent.getParent(); + container.setBounds(bounds); + tree.add(container); + editingComponent.requestFocus(); + return true; } return false; @@ -1922,7 +1957,7 @@ public class BasicTreeUI extends TreeUI tree.clearSelection(); if (tree.isEditing() && !e.getActionCommand().equals("startEditing")) - tree.cancelEditing(); + tree.stopEditing(); tree.scrollPathToVisible(lead); } @@ -1957,51 +1992,7 @@ public class BasicTreeUI extends TreeUI } } - /** - * The timer that updates the editor component. - */ - private class EditorUpdateTimer extends Timer implements ActionListener - { - /** - * Creates a new EditorUpdateTimer object with a default delay of 0.3 - * seconds. - */ - public EditorUpdateTimer() - { - super(300, null); - addActionListener(this); - } - - /** - * Lets the caret blink and repaints the table. - */ - public void actionPerformed(ActionEvent ev) - { - Caret c = ((JTextField) editingComponent).getCaret(); - if (c != null) - c.setVisible(!c.isVisible()); - tree.repaint(); - } - - /** - * Updates the blink delay according to the current caret. - */ - public void update() - { - stop(); - Caret c = ((JTextField) editingComponent).getCaret(); - if (c != null) - { - setDelay(c.getBlinkRate()); - if (((JTextField) editingComponent).isEditable()) - start(); - else - c.setVisible(false); - } - } - } - - /** + /** * Updates the preferred size when scrolling, if necessary. */ public class ComponentHandler extends ComponentAdapter implements @@ -2089,29 +2080,7 @@ public class BasicTreeUI extends TreeUI */ public void editingStopped(ChangeEvent e) { - editingPath = null; - editingRow = -1; - stopEditingInCompleteEditing = false; - if (editingComponent != null) - { - tree.remove(editingComponent.getParent()); - editingComponent = null; - } - if (cellEditor != null) - { - newVal = ((JTextField) getCellEditor().getCellEditorValue()).getText(); - completeEditing(false, false, true); - if (cellEditor instanceof DefaultTreeCellEditor) - tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor); - cellEditor.removeCellEditorListener(cellEditorListener); - setCellEditor(null); - createdCellEditor = false; - } - isEditing = false; - tree.requestFocusInWindow(false); - editorTimer.stop(); - validCachedPreferredSize = false; - tree.repaint(); + stopEditing(tree); } /** @@ -2123,25 +2092,7 @@ public class BasicTreeUI extends TreeUI */ public void editingCanceled(ChangeEvent e) { - editingPath = null; - editingRow = -1; - stopEditingInCompleteEditing = false; - if (editingComponent != null) - tree.remove(editingComponent.getParent()); - editingComponent = null; - if (cellEditor != null) - { - if (cellEditor instanceof DefaultTreeCellEditor) - tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor); - cellEditor.removeCellEditorListener(cellEditorListener); - setCellEditor(null); - createdCellEditor = false; - } - tree.requestFocusInWindow(false); - editorTimer.stop(); - isEditing = false; - validCachedPreferredSize = false; - tree.repaint(); + cancelEditing(tree); } }// CellEditorHandler @@ -2261,7 +2212,15 @@ public class BasicTreeUI extends TreeUI * is the mouse event that occured */ public void mousePressed(MouseEvent e) - { + { + // Any mouse click cancels the previous waiting edit action, initiated + // by the single click on the selected node. + if (startEditTimer != null) + { + startEditTimer.stop(); + startEditTimer = null; + } + Point click = e.getPoint(); TreePath path = getClosestPathForLocation(tree, click.x, click.y); @@ -2298,9 +2257,37 @@ public class BasicTreeUI extends TreeUI { if (inBounds) { - selectPath(tree, path); - if (e.getClickCount() == 2 && !isLeaf(row)) - toggleExpandState(path); + TreePath currentLead = tree.getLeadSelectionPath(); + if ( + currentLead != null && + currentLead.equals(path) && + e.getClickCount() == 1 && + tree.isEditable() + ) + { + // Schedule the editing session. + final TreePath editPath = path; + + if (startEditTimer != null) + startEditTimer.stop(); + + startEditTimer = new Timer(WAIT_TILL_EDITING, + new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + startEditing(editPath, EDIT); + } + }); + startEditTimer.setRepeats(false); + startEditTimer.start(); + } + else + { + selectPath(tree, path); + if (e.getClickCount() == 2 && !isLeaf(row)) + toggleExpandState(path); + } } if (cntlClick) @@ -2686,7 +2673,7 @@ public class BasicTreeUI extends TreeUI public class TreeHomeAction extends AbstractAction { - /** direction is either home or end */ + /** The direction, either home or end */ protected int direction; /** @@ -2983,7 +2970,7 @@ public class BasicTreeUI extends TreeUI public void valueChanged(TreeSelectionEvent event) { if (tree.isEditing()) - tree.cancelEditing(); + tree.stopEditing(); } }// TreeSelectionHandler @@ -3650,25 +3637,14 @@ public class BasicTreeUI extends TreeUI if (row != 0) bounds.x += gap; bounds.width = preferredSize.width + bounds.x; - if (editingComponent != null && editingPath != null && isEditing(tree) - && node.equals(editingPath.getLastPathComponent())) - { - rendererPane.paintComponent(g, editingComponent.getParent(), null, - bounds); - } - else - { - TreeCellRenderer dtcr = tree.getCellRenderer(); - if (dtcr == null) - dtcr = createDefaultCellRenderer(); - - Component c = dtcr.getTreeCellRendererComponent(tree, node, - selected, - isExpanded, isLeaf, - row, - tree.hasFocus()); - rendererPane.paintComponent(g, c, c.getParent(), bounds); - } + TreeCellRenderer dtcr = tree.getCellRenderer(); + if (dtcr == null) + dtcr = createDefaultCellRenderer(); + + Component c = dtcr.getTreeCellRendererComponent(tree, node, selected, + isExpanded, isLeaf, + row, tree.hasFocus()); + rendererPane.paintComponent(g, c, c.getParent(), bounds); } } @@ -3801,4 +3777,21 @@ public class BasicTreeUI extends TreeUI } return null; } + + /** + * Finish the editing session. + */ + void finish() + { + editingPath = null; + editingRow = -1; + stopEditingInCompleteEditing = false; + isEditing = false; + tree.removeAll(); + validCachedPreferredSize = false; + + // Repaint the region, where was the editing component. + tree.repaint(editingComponent.getParent().getBounds()); + editingComponent = null; + } } // BasicTreeUI diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java index 28143d51ecd..99c90acdbee 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java @@ -1,5 +1,5 @@ /* MetalBorders.java - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -249,30 +249,27 @@ public class MetalBorders /** * Returns the insets of the <code>ButtonBorder</code>. * - * @param c the component for which the border is used + * @param c the component for which the border is used (ignored). * - * @return The insets of the ButtonBorder + * @return The insets of the <code>ButtonBorder</code>. */ public Insets getBorderInsets(Component c) { - return getBorderInsets(c, null); + return borderInsets; } /** * Returns the insets of the <code>ButtonBorder</code> in the specified * <code>newInsets</code> object. * - * @param c the component for which the border is used - * @param newInsets the insets object where to put the values (if - * <code>null</code>, a new instance is created). + * @param c the component for which the border is used (ignored). + * @param newInsets the insets object where to put the values ( + * <code>null</code> not permitted). * - * @return The insets. + * @return The <code>newInsets</code> reference. */ public Insets getBorderInsets(Component c, Insets newInsets) { - if (newInsets == null) - newInsets = new Insets(0, 0, 0, 0); - newInsets.bottom = borderInsets.bottom; newInsets.left = borderInsets.left; newInsets.right = borderInsets.right; @@ -352,6 +349,8 @@ public class MetalBorders public static class Flush3DBorder extends AbstractBorder implements UIResource { + private static final Insets borderInsets = new Insets(2, 2, 2, 2); + /** * Creates a new border instance. */ @@ -369,26 +368,25 @@ public class MetalBorders */ public Insets getBorderInsets(Component c) { - return getBorderInsets(c, null); + return borderInsets; } /** * Returns the border insets. * * @param c the component (ignored). - * @return The border insets. + * @param newInsets an existing insets instance, that will be populated + * with the border insets and returned as the result + * (<code>null</code> not permitted). + * + * @return The <code>newInsets</code> reference. */ public Insets getBorderInsets(Component c, Insets newInsets) { - if (newInsets == null) - newInsets = new Insets(2, 2, 2, 2); - else - { - newInsets.top = 2; - newInsets.left = 2; - newInsets.bottom = 2; - newInsets.right = 2; - } + newInsets.top = borderInsets.top; + newInsets.left = borderInsets.left; + newInsets.bottom = borderInsets.bottom; + newInsets.right = borderInsets.right; return newInsets; } @@ -427,6 +425,8 @@ public class MetalBorders public static class PaletteBorder extends AbstractBorder implements UIResource { + private static final Insets borderInsets = new Insets(1, 1, 1, 1); + /** * Creates a new <code>PaletteBorder</code>. */ @@ -444,29 +444,25 @@ public class MetalBorders */ public Insets getBorderInsets(Component c) { - return getBorderInsets(c, null); + return borderInsets; } /** * Returns the border insets. * * @param c the component (ignored). - * @param newInsets the insets object that, if non-<code>null</code>, will - * be populated with the result from this method. - * - * @return The border insets. + * @param newInsets an existing insets instance, that will be populated + * with the border insets and returned as the result + * (<code>null</code> not permitted). + * + * @return The <code>newInsets</code> reference. */ public Insets getBorderInsets(Component c, Insets newInsets) { - if (newInsets == null) - newInsets = new Insets(1, 1, 1, 1); - else - { - newInsets.top = 1; - newInsets.left = 1; - newInsets.bottom = 1; - newInsets.right = 1; - } + newInsets.top = borderInsets.top; + newInsets.left = borderInsets.left; + newInsets.bottom = borderInsets.bottom; + newInsets.right = borderInsets.right; return newInsets; } @@ -555,6 +551,8 @@ public class MetalBorders public static class InternalFrameBorder extends AbstractBorder implements UIResource { + private static final Insets borderInsets = new Insets(5, 5, 5, 5); + /** * Creates a new border instance. */ @@ -572,26 +570,25 @@ public class MetalBorders */ public Insets getBorderInsets(Component c) { - return getBorderInsets(c, null); + return borderInsets; } /** * Returns the border insets. * * @param c the component (ignored). - * @return The border insets. + * @param newInsets an existing insets instance, that will be populated + * with the border insets and returned as the result + * (<code>null</code> not permitted). + * + * @return The <code>newInsets</code> reference. */ public Insets getBorderInsets(Component c, Insets newInsets) { - if (newInsets == null) - newInsets = new Insets(5, 5, 5, 5); - else - { - newInsets.top = 5; - newInsets.left = 5; - newInsets.bottom = 5; - newInsets.right = 5; - } + newInsets.top = borderInsets.top; + newInsets.left = borderInsets.left; + newInsets.bottom = borderInsets.bottom; + newInsets.right = borderInsets.right; return newInsets; } @@ -763,7 +760,7 @@ public class MetalBorders implements UIResource { /** The border insets. */ - protected static Insets borderInsets = new Insets(1, 1, 1, 1); + protected static Insets borderInsets = new Insets(2, 2, 2, 2); /** * Creates a new border instance. diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java index 967c40d29ad..cb94c87b846 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java @@ -1545,8 +1545,6 @@ public class MetalFileChooserUI fileListPanel = new JPanel(new BorderLayout()); fileList = new JList(getModel()); scrollPane = new JScrollPane(fileList); - scrollPane.setVerticalScrollBarPolicy - (JScrollPane.VERTICAL_SCROLLBAR_NEVER); fileList.setLayoutOrientation(JList.VERTICAL_WRAP); fileList.setCellRenderer(new FileRenderer()); } @@ -1557,7 +1555,10 @@ public class MetalFileChooserUI scrollPane.getViewport().setView(fileList); } fileListPanel.add(scrollPane); - + // This size was determined using BeanShell and dumping the JFileChooser + // component hierarchy. Sun has an internal FilePane class in there, but + // that probably doesn't matter atm. + fileListPanel.setPreferredSize(new Dimension(405, 135)); return fileListPanel; } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java index c60b55c9e7b..e84644615ce 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -1171,6 +1171,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel "Spinner.arrowButtonInsets", new InsetsUIResource(0, 0, 0, 0), "Spinner.background", getControl(), + "Spinner.border", MetalBorders.getTextFieldBorder(), "Spinner.font", new FontUIResource("Dialog", Font.BOLD, 12), "Spinner.foreground", getControl(), @@ -1342,4 +1343,16 @@ public class MetalLookAndFeel extends BasicLookAndFeel { return theme; } + + /** + * Returns <code>true</code> because the Metal look + * and feel supports window decorations for toplevel + * containers. + * + * @return <code>true</code> + */ + public boolean getSupportsWindowDecorations() + { + return true; + } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java index faed80382d0..23051e9bcea 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java @@ -1,5 +1,5 @@ /* MetalRootPaneUI.java - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,23 +38,842 @@ exception statement from your version. */ package javax.swing.plaf.metal; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.LayoutManager2; +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.beans.PropertyChangeEvent; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JButton; import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; import javax.swing.JRootPane; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicRootPaneUI; /** - * A UI delegate for the {@link JRootPane} component. This class is not fully - * implemented. + * A UI delegate for the {@link JRootPane} component. This implementation + * supports the JRootPane <code>windowDecorationStyle</code> property. * + * @author Roman Kennke (kennke@aicas.com) + * * @since 1.4 */ public class MetalRootPaneUI extends BasicRootPaneUI { - // FIXME: maybe replace by a Map of instances when this becomes stateful - /** The shared UI instance for MetalRootPaneUIs */ + /** + * The border that is used on JRootPane when the windowDecorationStyle + * property of the JRootPane is set to a different value than NONE. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private static class MetalFrameBorder + extends AbstractBorder + { + /** + * Returns the border insets. + * + * @param c the component + * @param newInsets the insets to be filled with the return value, may be + * <code>null</code> in which case a new object is created + * + * @return the border insets + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + if (newInsets == null) + newInsets = new Insets(5, 5, 5, 5); + else + { + newInsets.top = 5; + newInsets.left = 5; + newInsets.bottom = 5; + newInsets.right = 5; + } + return newInsets; + } + + /** + * Returns the border insets. + * + * @param c the component + * + * @return the border insets + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Paints the border for the specified component. + * + * @param c the component + * @param g the graphics device + * @param x the x-coordinate + * @param y the y-coordinate + * @param w the width + * @param h the height + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + JRootPane f = (JRootPane) c; + Window frame = SwingUtilities.getWindowAncestor(f); + if (frame.isActive()) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // Fill the border background. + g.fillRect(x, y, w, 5); + g.fillRect(x, y, 5, h); + g.fillRect(x + w - 5, y, 5, h); + g.fillRect(x, y + h - 5, w, 5); + + // Draw a dot in each corner. + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x, y, 1, 1); + g.fillRect(x + w - 1, y, 1, 1); + g.fillRect(x + w - 1, y + h - 1, 1, 1); + g.fillRect(x, y + h - 1, 1, 1); + + // Draw the lines. + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 14, y + 2, x + w - 15, y + 2); + g.drawLine(x + 14, y + h - 3, x + w - 15, y + h - 3); + g.drawLine(x + 2, y + 14, x + 2, y + h - 15); + g.drawLine(x + w - 3, y + 14, x + w - 3, y + h - 15); + + // Draw the line highlights. + if (frame.isActive()) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x + 15, y + 3, x + w - 14, y + 3); + g.drawLine(x + 15, y + h - 2, x + w - 14, y + h - 2); + g.drawLine(x + 3, y + 15, x + 3, y + h - 14); + g.drawLine(x + w - 2, y + 15, x + w - 2, y + h - 14); + } + } + + /** + * The component that renders the title bar for frames. This duplicates + * most of {@link MetalInternalFrameTitlePane}. It is not reasonably possible + * to reuse that class because that is bound to the JInternalFrame and we + * need to handle JFrames/JRootPanes here. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private static class MetalTitlePane extends JComponent + { + /** + * The Action responsible for closing the JInternalFrame. + */ + private class CloseAction extends AbstractAction + { + /** + * Creates a new action. + */ + public CloseAction() + { + super("Close"); + } + + /** + * This method is called when something closes the frame. + * + * @param e the ActionEvent + */ + public void actionPerformed(ActionEvent e) + { + Window frame = SwingUtilities.getWindowAncestor(rootPane); + if (frame instanceof JFrame) + { + JFrame jframe = (JFrame) frame; + switch (jframe.getDefaultCloseOperation()) + { + case JFrame.EXIT_ON_CLOSE: + jframe.setVisible(false); + jframe.dispose(); + System.exit(0); + break; + case JFrame.DISPOSE_ON_CLOSE: + jframe.setVisible(false); + jframe.dispose(); + break; + case JFrame.HIDE_ON_CLOSE: + jframe.setVisible(false); + break; + case JFrame.DO_NOTHING_ON_CLOSE: + default: + break; + } + } + else if (frame instanceof JDialog) + { + JDialog jdialog = (JDialog) frame; + switch (jdialog.getDefaultCloseOperation()) + { + case JFrame.DISPOSE_ON_CLOSE: + jdialog.setVisible(false); + jdialog.dispose(); + break; + case JFrame.HIDE_ON_CLOSE: + jdialog.setVisible(false); + break; + case JFrame.DO_NOTHING_ON_CLOSE: + default: + break; + } + } + } + } + + /** + * 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. + */ + private class PaneButton extends JButton + { + /** + * Creates a new PaneButton object with the given Action. + * + * @param a The Action that the button uses. + */ + public PaneButton(Action a) + { + super(a); + setMargin(new Insets(0, 0, 0, 0)); + } + + /** + * This method returns true if the Component can be focused. + * + * @return false. + */ + public boolean isFocusable() + { + // These buttons cannot be given focus. + return false; + } + + } + + /** + * The layout for the JRootPane when the <code>windowDecorationStyle</code> + * property is set. In addition to the usual JRootPane.RootLayout behaviour + * this lays out the titlePane. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class MetalTitlePaneLayout implements LayoutManager + { + /** + * Creates a new <code>TitlePaneLayout</code> object. + */ + public MetalTitlePaneLayout() + { + // Do nothing. + } + + /** + * Adds a Component to the Container. + * + * @param name The name to reference the added Component by. + * @param c The Component to add. + */ + public void addLayoutComponent(String name, Component c) + { + // Do nothing. + } + + /** + * This method is called to lay out the children of the Title Pane. + * + * @param c The Container to lay out. + */ + public void layoutContainer(Container c) + { + + Dimension size = c.getSize(); + Insets insets = c.getInsets(); + int width = size.width - insets.left - insets.right; + int height = size.height - insets.top - insets.bottom; + + int loc = width - insets.right - 1; + int top = insets.top + 2; + int buttonHeight = height - 4; + if (closeButton.isVisible()) + { + int buttonWidth = closeIcon.getIconWidth(); + loc -= buttonWidth + 2; + closeButton.setBounds(loc, top, buttonWidth, buttonHeight); + loc -= 6; + } + + if (maxButton.isVisible()) + { + int buttonWidth = maxIcon.getIconWidth(); + loc -= buttonWidth + 4; + maxButton.setBounds(loc, top, buttonWidth, buttonHeight); + } + + if (iconButton.isVisible()) + { + int buttonWidth = minIcon.getIconWidth(); + loc -= buttonWidth + 4; + iconButton.setBounds(loc, top, buttonWidth, buttonHeight); + loc -= 2; + } + + Dimension titlePreferredSize = title.getPreferredSize(); + title.setBounds(insets.left + 5, insets.top, + Math.min(titlePreferredSize.width, loc - insets.left - 10), + height); + + } + + /** + * This method returns the minimum size of the given Container given the + * children that it has. + * + * @param c The Container to get a minimum size for. + * + * @return The minimum size of the Container. + */ + public Dimension minimumLayoutSize(Container c) + { + return preferredLayoutSize(c); + } + + /** + * Returns the preferred size of the given Container taking + * into account the children that it has. + * + * @param c The Container to lay out. + * + * @return The preferred size of the Container. + */ + public Dimension preferredLayoutSize(Container c) + { + return new Dimension(22, 22); + } + + /** + * Removes a Component from the Container. + * + * @param c The Component to remove. + */ + public void removeLayoutComponent(Component c) + { + // Nothing to do here. + } + } + + JRootPane rootPane; + + /** The button that closes the JInternalFrame. */ + JButton closeButton; + + /** The button that iconifies the JInternalFrame. */ + JButton iconButton; + + /** The button that maximizes the JInternalFrame. */ + JButton maxButton; + + Icon minIcon; + + /** The icon displayed in the maximize button. */ + Icon maxIcon; + + /** The icon displayed in the iconify button. */ + private Icon iconIcon; + + /** The icon displayed in the close button. */ + Icon closeIcon; + + /** + * The background color of the TitlePane when the JInternalFrame is not + * selected. + */ + private Color notSelectedTitleColor; + + /** + * The background color of the TitlePane when the JInternalFrame is + * selected. + */ + private Color selectedTitleColor; + + /** + * The label used to display the title. This label is not added to the + * TitlePane. + */ + JLabel title; + + /** The action associated with closing the JInternalFrame. */ + private Action closeAction; + + /** The action associated with iconifying the JInternalFrame. */ + private Action iconifyAction; + + /** The action associated with maximizing the JInternalFrame. */ + private Action maximizeAction; + + /** The JMenuBar that is located at the top left of the Title Pane. */ + private JMenuBar menuBar; + + /** The JMenu inside the menuBar. */ + protected JMenu windowMenu; + + MetalTitlePane(JRootPane rp) + { + rootPane = rp; + setLayout(createLayout()); + title = new JLabel(); + title.setHorizontalAlignment(SwingConstants.LEFT); + title.setHorizontalTextPosition(SwingConstants.LEFT); + title.setOpaque(false); + installTitlePane(); + } + + protected LayoutManager createLayout() + { + return new MetalTitlePaneLayout(); + } + + /** + * This method installs the TitlePane onto the JInternalFrameTitlePane. It + * also creates any children components that need to be created and adds + * listeners to the appropriate components. + */ + protected void installTitlePane() + { + installDefaults(); + installListeners(); + createActions(); + assembleSystemMenu(); + createButtons(); + setButtonIcons(); + addSubComponents(); + enableActions(); + } + + private void enableActions() + { + // TODO: Implement this. + } + + private void addSubComponents() + { + add(menuBar); + add(closeButton); + add(iconButton); + add(maxButton); + } + + private void installListeners() + { + Window window = SwingUtilities.getWindowAncestor(rootPane); + window.addWindowFocusListener(new WindowFocusListener() + { + public void windowGainedFocus(WindowEvent ev) + { + repaint(); + } + public void windowLostFocus(WindowEvent ev) + { + repaint(); + } + }); + } + + private void createActions() + { + closeAction = new CloseAction(); + } + + private void assembleSystemMenu() + { + menuBar = createSystemMenuBar(); + windowMenu = createSystemMenu(); + menuBar.add(windowMenu); + addSystemMenuItems(windowMenu); + enableActions(); + } + + protected JMenuBar createSystemMenuBar() + { + if (menuBar == null) + menuBar = new JMenuBar(); + menuBar.removeAll(); + return menuBar; + } + + protected JMenu createSystemMenu() + { + if (windowMenu == null) + windowMenu = new JMenu(); + windowMenu.removeAll(); + return windowMenu; + } + + private void addSystemMenuItems(JMenu menu) + { + // TODO: Implement this. + } + + protected void createButtons() + { + closeButton = new PaneButton(closeAction); + closeButton.setText(null); + iconButton = new PaneButton(iconifyAction); + iconButton.setText(null); + maxButton = new PaneButton(maximizeAction); + maxButton.setText(null); + closeButton.setBorderPainted(false); + closeButton.setContentAreaFilled(false); + iconButton.setBorderPainted(false); + iconButton.setContentAreaFilled(false); + maxButton.setBorderPainted(false); + maxButton.setContentAreaFilled(false); + } + + protected void setButtonIcons() + { + if (closeIcon != null && closeButton != null) + closeButton.setIcon(closeIcon); + if (iconIcon != null && iconButton != null) + iconButton.setIcon(iconIcon); + if (maxIcon != null && maxButton != null) + maxButton.setIcon(maxIcon); + } + + /** + * Paints a representation of the current state of the internal frame. + * + * @param g the graphics device. + */ + public void paintComponent(Graphics g) + { + Window frame = SwingUtilities.getWindowAncestor(rootPane); + Color savedColor = g.getColor(); + paintTitleBackground(g); + paintChildren(g); + Dimension d = getSize(); + if (frame.isActive()) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // put a dot in each of the top corners + g.drawLine(0, 0, 0, 0); + g.drawLine(d.width - 1, 0, d.width - 1, 0); + + g.drawLine(0, d.height - 1, d.width - 1, d.height - 1); + + // draw the metal pattern + if (UIManager.get("InternalFrame.activeTitleGradient") != null + && frame.isActive()) + { + MetalUtils.paintGradient(g, 0, 0, getWidth(), getHeight(), + SwingConstants.VERTICAL, + "InternalFrame.activeTitleGradient"); + } + + Rectangle b = title.getBounds(); + int startX = b.x + b.width + 5; + int endX = startX; + if (iconButton.isVisible()) + endX = Math.max(iconButton.getX(), endX); + else if (maxButton.isVisible()) + endX = Math.max(maxButton.getX(), endX); + else if (closeButton.isVisible()) + endX = Math.max(closeButton.getX(), endX); + endX -= 7; + if (endX > startX) + MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, getHeight() - 6, Color.white, Color.gray); + g.setColor(savedColor); + } + + /** + * This method paints the TitlePane's background. + * + * @param g The Graphics object to paint with. + */ + protected void paintTitleBackground(Graphics g) + { + Window frame = SwingUtilities.getWindowAncestor(rootPane); + + if (!isOpaque()) + return; + + Color saved = g.getColor(); + Dimension dims = getSize(); + + Color bg = getBackground(); + if (frame.isActive()) + bg = selectedTitleColor; + else + bg = notSelectedTitleColor; + g.setColor(bg); + g.fillRect(0, 0, dims.width, dims.height); + g.setColor(saved); + } + + /** + * This method installs the defaults determined by the look and feel. + */ + private void installDefaults() + { + title.setFont(UIManager.getFont("InternalFrame.titleFont")); + selectedTitleColor = UIManager.getColor("InternalFrame.activeTitleBackground"); + notSelectedTitleColor = UIManager.getColor("InternalFrame.inactiveTitleBackground"); + closeIcon = UIManager.getIcon("InternalFrame.closeIcon"); + iconIcon = UIManager.getIcon("InternalFrame.iconifyIcon"); + maxIcon = UIManager.getIcon("InternalFrame.maximizeIcon"); + minIcon = MetalIconFactory.getInternalFrameAltMaximizeIcon(16); + Frame frame = (Frame) SwingUtilities.getWindowAncestor(rootPane); + title = new JLabel(frame.getTitle(), + MetalIconFactory.getInternalFrameDefaultMenuIcon(), + SwingConstants.LEFT); + } + } + + private static class MetalRootLayout + implements LayoutManager2 + { + + /** + * The cached layout info for the glass pane. + */ + private Rectangle glassPaneBounds; + + /** + * The cached layout info for the layered pane. + */ + private Rectangle layeredPaneBounds; + + /** + * The cached layout info for the content pane. + */ + private Rectangle contentPaneBounds; + + /** + * The cached layout info for the menu bar. + */ + private Rectangle menuBarBounds; + + /** + * The cached layout info for the title pane. + */ + private Rectangle titlePaneBounds; + + /** + * The cached preferred size. + */ + private Dimension prefSize; + + public void addLayoutComponent(Component component, Object constraints) + { + // Nothing to do here. + } + + public Dimension maximumLayoutSize(Container target) + { + return preferredLayoutSize(target); + } + + public float getLayoutAlignmentX(Container target) + { + return 0.0F; + } + + public float getLayoutAlignmentY(Container target) + { + return 0.0F; + } + + public void invalidateLayout(Container target) + { + synchronized (this) + { + glassPaneBounds = null; + layeredPaneBounds = null; + contentPaneBounds = null; + menuBarBounds = null; + titlePaneBounds = null; + prefSize = null; + } + } + + public void addLayoutComponent(String name, Component component) + { + // Nothing to do here. + } + + public void removeLayoutComponent(Component component) + { + // TODO Auto-generated method stub + + } + + public Dimension preferredLayoutSize(Container parent) + { + 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); + + // We must synchronize here, otherwise we cannot guarantee that the + // prefSize is still non-null when returning. + synchronized (this) + { + if (prefSize == null) + { + Insets i = parent.getInsets(); + prefSize = new Dimension(i.left + i.right, i.top + i.bottom); + Dimension contentPrefSize = contentPane.getPreferredSize(); + prefSize.width += contentPrefSize.width; + prefSize.height += contentPrefSize.height + + titlePane.getPreferredSize().height; + if (menuBar != null) + { + Dimension menuBarSize = menuBar.getPreferredSize(); + if (menuBarSize.width > contentPrefSize.width) + prefSize.width += menuBarSize.width - contentPrefSize.width; + prefSize.height += menuBarSize.height; + } + } + // Return a copy here so the cached value won't get trashed by some + // other component. + return new Dimension(prefSize); + } + } + + public Dimension minimumLayoutSize(Container parent) + { + return preferredLayoutSize(parent); + } + + public void layoutContainer(Container parent) + { + 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 glassPane = rp.getGlassPane(); + + if (glassPaneBounds == null || layeredPaneBounds == null + || contentPaneBounds == null || menuBarBounds == null) + { + Insets i = rp.getInsets(); + int containerWidth = parent.getBounds().width - i.left - i.right; + int containerHeight = parent.getBounds().height - i.top - i.bottom; + + // 1. The glassPane fills entire viewable region (bounds - insets). + // 2. The layeredPane filles entire viewable region. + // 3. The titlePane is placed at the upper edge of the layeredPane. + // 4. The menuBar is positioned at the upper edge of layeredPane. + // 5. The contentPane fills viewable region minus menuBar minus + // titlePane, if present. + + // +-------------------------------+ + // | JLayeredPane | + // | +--------------------------+ | + // | | titlePane + | + // | +--------------------------+ | + // | +--------------------------+ | + // | | menuBar | | + // | +--------------------------+ | + // | +--------------------------+ | + // | |contentPane | | + // | | | | + // | | | | + // | | | | + // | +--------------------------+ | + // +-------------------------------+ + + // Setup titlePaneBounds. + if (titlePaneBounds == null) + titlePaneBounds = new Rectangle(); + titlePaneBounds.width = containerWidth; + titlePaneBounds.height = titlePane.getPreferredSize().height; + + // Setup menuBarBounds. + if (menuBarBounds == null) + menuBarBounds = new Rectangle(); + menuBarBounds.setBounds(0, + titlePaneBounds.y + titlePaneBounds.height, + containerWidth, 0); + if (menuBar != null) + { + Dimension menuBarSize = menuBar.getPreferredSize(); + if (menuBarSize.height > containerHeight) + menuBarBounds.height = containerHeight; + else + menuBarBounds.height = menuBarSize.height; + } + + // Setup contentPaneBounds. + if (contentPaneBounds == null) + contentPaneBounds = new Rectangle(); + contentPaneBounds.setBounds(0, + menuBarBounds.y + menuBarBounds.height, + containerWidth, + containerHeight - menuBarBounds.y + - menuBarBounds.height); + glassPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight); + layeredPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight); + } + + // Layout components. + glassPane.setBounds(glassPaneBounds); + layeredPane.setBounds(layeredPaneBounds); + if (menuBar != null) + menuBar.setBounds(menuBarBounds); + contentPane.setBounds(contentPaneBounds); + titlePane.setBounds(titlePaneBounds); + } + + } + + /** + * The shared UI instance for MetalRootPaneUIs. + */ private static MetalRootPaneUI instance = null; /** @@ -78,4 +897,84 @@ public class MetalRootPaneUI instance = new MetalRootPaneUI(); return instance; } + + /** + * Installs this UI to the root pane. If the + * <code>windowDecorationsStyle</code> property is set on the root pane, + * the Metal window decorations are installed on the root pane. + * + * @param c + */ + public void installUI(JComponent c) + { + super.installUI(c); + JRootPane rp = (JRootPane) c; + if (rp.getWindowDecorationStyle() != JRootPane.NONE) + installWindowDecorations(rp); + } + + /** + * Uninstalls the UI from the root pane. This performs the superclass + * behaviour and uninstalls the window decorations that have possibly been + * installed by {@link #installUI}. + * + * @param c the root pane + */ + public void uninstallUI(JComponent c) + { + JRootPane rp = (JRootPane) c; + if (rp.getWindowDecorationStyle() != JRootPane.NONE) + uninstallWindowDecorations(rp); + super.uninstallUI(c); + } + + /** + * Receives notification if any of the JRootPane's property changes. In + * particular this catches changes to the <code>windowDecorationStyle</code> + * property and installs the window decorations accordingly. + * + * @param ev the property change event + */ + public void propertyChange(PropertyChangeEvent ev) + { + String propertyName = ev.getPropertyName(); + if (propertyName.equals("windowDecorationStyle")) + { + JRootPane rp = (JRootPane) ev.getSource(); + if (rp.getWindowDecorationStyle() != JRootPane.NONE) + installWindowDecorations(rp); + else + uninstallWindowDecorations(rp); + } + } + + /** + * Installs the window decorations to the root pane. This sets up a border, + * a title pane and a layout manager that can layout the root pane with that + * title pane. + * + * @param rp the root pane. + */ + private void installWindowDecorations(JRootPane rp) + { + rp.setBorder(new MetalFrameBorder()); + rp.setLayout(new MetalRootLayout()); + // We should have a contentPane already. + assert rp.getLayeredPane().getComponentCount() == 1 + : "We should have a contentPane already"; + rp.getLayeredPane().add(new MetalTitlePane(rp), + JLayeredPane.FRAME_CONTENT_LAYER); + } + + /** + * Uninstalls the window decorations from the root pane. This should rarely + * be necessary, but we do it anyway. + * + * @param rp the root pane + */ + private void uninstallWindowDecorations(JRootPane rp) + { + rp.setBorder(null); + rp.getLayeredPane().remove(1); + } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java index 0ff501f89a9..155bb814689 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java @@ -41,6 +41,7 @@ package javax.swing.plaf.metal; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; +import java.awt.Insets; import java.awt.Rectangle; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -48,6 +49,7 @@ import java.beans.PropertyChangeListener; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JScrollBar; +import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicScrollBarUI; @@ -465,11 +467,60 @@ public class MetalScrollBarUI extends BasicScrollBarUI */ protected Dimension getMinimumThumbSize() { - if (isFreeStanding) - return MIN_THUMB_SIZE_FREE_STANDING; + Dimension retVal; + if (scrollbar != null) + { + if (isFreeStanding) + retVal = MIN_THUMB_SIZE_FREE_STANDING; + else + retVal = MIN_THUMB_SIZE; + } else - return MIN_THUMB_SIZE; + retVal = new Dimension(0, 0); + return retVal; } - + + /** + * Returns the <code>preferredSize</code> for the specified scroll bar. + * For a vertical scrollbar the height is the sum of the preferred heights + * of the buttons plus <code>30</code>. The width is fetched from the + * <code>UIManager</code> property <code>ScrollBar.width</code>. + * + * For horizontal scrollbars the width is the sum of the preferred widths + * of the buttons plus <code>30</code>. The height is fetched from the + * <code>UIManager</code> property <code>ScrollBar.height</code>. + * + * @param c the scrollbar for which to calculate the preferred size + * + * @return the <code>preferredSize</code> for the specified scroll bar + */ + public Dimension getPreferredSize(JComponent c) + { + int height; + int width; + height = width = 0; + + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + { + width += incrButton.getPreferredSize().getWidth(); + width += decrButton.getPreferredSize().getWidth(); + width += 30; + height = UIManager.getInt("ScrollBar.width"); + } + else + { + height += incrButton.getPreferredSize().getHeight(); + height += decrButton.getPreferredSize().getHeight(); + height += 30; + width = UIManager.getInt("ScrollBar.width"); + } + + Insets insets = scrollbar.getInsets(); + + height += insets.top + insets.bottom; + width += insets.left + insets.right; + + return new Dimension(width, height); + } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java index 34a964cb339..9c592bd5116 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java @@ -42,11 +42,13 @@ import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; +import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Point; import javax.swing.JSplitPane; import javax.swing.SwingConstants; +import javax.swing.border.Border; import javax.swing.plaf.basic.BasicArrowButton; import javax.swing.plaf.basic.BasicSplitPaneDivider; @@ -93,6 +95,12 @@ class MetalSplitPaneDivider extends BasicSplitPaneDivider public void paint(Graphics g) { Dimension s = getSize(); + + // Paint border if one exists. + Border border = getBorder(); + if (border != null) + border.paintBorder(this, g, 0, 0, s.width, s.height); + MetalUtils.fillMetalPattern(splitPane, g, 2, 2, s.width - 4, s.height - 4, light, dark); if (splitPane.isOneTouchExpandable()) diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java index 50112ce2161..b9d5ea76434 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java @@ -37,6 +37,8 @@ exception statement from your version. */ package javax.swing.plaf.metal; +import gnu.classpath.SystemProperties; + import java.awt.Color; import java.awt.Component; import java.awt.Graphics; @@ -88,7 +90,8 @@ class MetalUtils static void fillMetalPattern(Component c, Graphics g, int x, int y, int w, int h, Color light, Color dark) { - if (g instanceof Graphics2D) + if (g instanceof Graphics2D + && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") != null) fillMetalPattern2D((Graphics2D) g, x, y, w, h, light, dark); else { diff --git a/libjava/classpath/javax/swing/plaf/synth/ColorType.java b/libjava/classpath/javax/swing/plaf/synth/ColorType.java new file mode 100644 index 00000000000..954e309e1d6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/synth/ColorType.java @@ -0,0 +1,130 @@ +/* ColorType.java -- En enumeration of color types + 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.plaf.synth; + +/** + * A typesafe enumeration of color types. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class ColorType +{ + + /** + * A constant used to identify the foreground color of a component. + */ + public static final ColorType FOREGROUND = new ColorType("Foreground"); + + /** + * A constant used to identify the background color of a component. + */ + public static final ColorType BACKGROUND = new ColorType("Background"); + + /** + * A constant used to identify the foreground color of text of a component. + */ + public static final ColorType TEXT_FOREGROUND + = new ColorType("TextForeground"); + + /** + * A constant used to identify the background color of text of a component. + */ + public static final ColorType TEXT_BACKGROUND + = new ColorType("TextBackground"); + + /** + * A constant used to identify the focus color of a component. + */ + public static final ColorType FOCUS = new ColorType("Focus"); + + /** + * The maximum number of color types. + */ + public static final int MAX_COUNT = 5; + + /** + * A counter used to assign an ID to the created color types. + */ + private static int count = 0; + + /** + * The ID of the color type. + */ + private int id; + + /** + * The description of the color type. + */ + private String description; + + /** + * Creates a new <code>Color</code> color type with the specified + * description. + * + * @param desc the textual description of the color type + */ + protected ColorType(String desc) + { + description = desc; + id = count; + count++; + } + + /** + * Returns the unique ID of the color type. + * + * @return the unique ID of the color type + */ + public final int getID() + { + return id; + } + + /** + * Returns the textual description of the color type. + * + * @return the textual description of the color type + */ + public String toString() + { + return description; + } +} diff --git a/libjava/classpath/javax/swing/plaf/synth/Region.java b/libjava/classpath/javax/swing/plaf/synth/Region.java new file mode 100644 index 00000000000..7ede65fc87b --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/synth/Region.java @@ -0,0 +1,474 @@ +/* Region.java -- Describes a region within a component + 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.plaf.synth; + +/** + * Describes a region of a component or the complete component. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class Region +{ + + // FIXME: What should ui be for the non-component regions that have + // subregion==false? + + /** + * Specifies an arrow button region. + */ + public static final Region ARROW_BUTTON = + new Region("ArrowButton", null, false); + + /** + * Specifies the region of a standard button. + */ + public static final Region BUTTON = + new Region("Button", "ButtonUI", false); + + /** + * Specifies the region of a check box. + */ + public static final Region CHECK_BOX = + new Region("CheckBox", "CheckBoxUI", false); + + /** + * Specifies the region of a check box menu item. + */ + public static final Region CHECK_BOX_MENU_ITEM = + new Region("CheckBoxMenuItem", "CheckBoxMenuItemUI", false); + + /** + * Specifies the region of a colorchooser. + */ + public static final Region COLOR_CHOOSER = + new Region("ColorChooser", "ColorChooserUI", false); + + /** + * Specifies the region of a combo box. + */ + public static final Region COMBO_BOX = + new Region("ComboBox", "ComboBoxUI", false); + + /** + * Specifies the region of a desktop pane. + */ + public static final Region DESKTOP_PANE = + new Region("DesktopPane", "DesktopPaneUI", false); + + /** + * Specifies the region of a desktop icon. + */ + public static final Region DESKTOP_ICON = + new Region("DesktopIcon", "DesktopIconUI", false); + + /** + * Specifies the region of an editor pane. + */ + public static final Region EDITOR_PANE = + new Region("EditorPane", "EditorPaneUI", false); + + /** + * Specifies the region of a file chooser. + */ + public static final Region FILECHOOSER = + new Region("FileChooser", "FileChooserUI", false); + + /** + * Specifies the region of a formatted text field. + */ + public static final Region FormattedTextField = + new Region("FormattedTextField", "FormattedTextFieldUI", false); + + /** + * Specifies the region of an internal frame. + */ + public static final Region INTERNAL_FRAME = + new Region("InternalFrame", "InternalFrameUI", false); + + /** + * Specifies the region of the title pane of an internal frame. + */ + public static final Region INTERNAL_FRAME_TITLE_PANE = + new Region("InternalFrameTitlePane", "InternalFrameTitlePaneUI", false); + + /** + * Specifies the region of a label. + */ + public static final Region LABEL = + new Region("Label", "LabelUI", false); + + /** + * Specifies the region of a list. + */ + public static final Region LIST = + new Region("List", "ListUI", false); + + /** + * Specifies the region of a menu. + */ + public static final Region MENU = + new Region("Menu", "MenuUI", false); + + /** + * Specifies the region of a menu bar. + */ + public static final Region MENU_BAR = + new Region("MenuBar", "MenuBarUI", false); + + /** + * Specifies the region of a menu item. + */ + public static final Region MENU_ITEM = + new Region("MenuItem", "MenuItemUI", false); + + /** + * Specifies the region of a menu item accelerator. This is a subregion + * of menu item. + */ + public static final Region MENU_ITEM_ACCELERATOR = + new Region("MenuItemAccelerator", null, true); + + /** + * Specifies the region of an option pane. + */ + public static final Region OPTION_PANE = + new Region("OptionPane", "OptionPaneUI", false); + + /** + * Specifies the region of a panel. + */ + public static final Region PANEL = + new Region("Panel", "PanelUI", false); + + /** + * Specifies the region of a password field. + */ + public static final Region PASSWORD_FIELD = + new Region("PasswordField", "PasswordFieldUI", false); + + /** + * Specifies the region of a popup menu. + */ + public static final Region POPUP_MENU = + new Region("PopupMenu", "PopupMenuUI", false); + + /** + * Specifies the region of a popup menu separator. + */ + public static final Region POPUP_MENU_SEPARATOR = + new Region("PopupMenuSeparator", null, false); + + /** + * Specifies the region of a progress bar. + */ + public static final Region PROGRESS_BAR = + new Region("ProgressBar", "ProgressBarUI", false); + + /** + * Specifies the region of a radio button. + */ + public static final Region RADIO_BUTTON = + new Region("RadioButton", "RadioButtonUI", false); + + /** + * Specifies the region of a radio button menu item. + */ + public static final Region RADIO_BUTTON_MENU_ITEM = + new Region("RadioButtonMenuItem", "RadioButtonMenuItemUI", false); + + /** + * Specifies the region of a root pane. + */ + public static final Region ROOT_PANE = + new Region("RootPane", "RootPaneUI", false); + + /** + * Specifies the region of a scroll bar. + */ + public static final Region SCROLL_BAR = + new Region("ScrollBar", "ScrollBarUI", false); + + /** + * Specifies the region of a scroll bar track. This is a subregion of + * scroll bars. + */ + public static final Region SCROLL_BAR_TRACK = + new Region("ScrollBarTrack", null, true); + + /** + * Specifies the region of a scroll bar thumb. This is a subregion of + * scroll bars. + */ + public static final Region SCROLL_BAR_THUMB = + new Region("ScrollBarThumb", null, true); + + /** + * Specifies the region of a scroll pane. + */ + public static final Region SCROLL_PANE = + new Region("ScrollPane", "ScrollPaneUI", false); + + /** + * Specifies the region of a separator. + */ + public static final Region SEPARATOR = + new Region("Separator", "SeparatorUI", false); + + /** + * Specifies the region of a slider. + */ + public static final Region SLIDER = + new Region("Slider", "SliderUI", false); + + /** + * Specifies the region of a slider track. This is a subregion of a slider. + */ + public static final Region SLIDER_TRACK = + new Region("SliderTrack", null, true); + + /** + * Specifies the region of a slider thumb. This is a subregion of a slider. + */ + public static final Region SLIDER_THUMB = + new Region("SliderThumb", null, true); + + /** + * Specifies the region of a spinner. + */ + public static final Region SPINNER = + new Region("Spinner", "SpinnerUI", false); + + /** + * Specifies the region of a split pane. + */ + public static final Region SPLIT_PANE = + new Region("SplitPane", "SplitPaneUI", false); + + /** + * Specifies the region of a split pane divider. This is a subregion of + * a split pane. + */ + public static final Region SPLIT_PANE_DIVIDER = + new Region("SplitPaneDivider", null, true); + + /** + * Specifies the region of a tabbed pane. + */ + public static final Region TABBED_PANE = + new Region("TabbedPane", "TabbedPaneUI", false); + + /** + * This specifies the region of a tab of a tabbed pane. This is a subregion + * of a tabbed pane. + */ + public static final Region TABBED_PANE_TAB = + new Region("TabbedPaneTab", null, true); + + /** + * This specifies the region underneath the tabs of a tabbed pane. This is a + * subregion of a tabbed pane. + */ + public static final Region TABBED_PANE_TAB_AREA = + new Region("TabbedPaneTabArea", null, true); + + /** + * This specifies the region for the content of a tabbed pane. This is a + * subregion of a tabbed pane. + */ + public static final Region TABBED_PANE_CONTENT = + new Region("TabbedPaneContent", null, true); + + /** + * Specifies the region of a table. + */ + public static final Region TABLE = + new Region("Table", "TableUI", false); + + /** + * Specifies the region of a table header. + */ + public static final Region TABLE_HEADER = + new Region("TableHeader", "TableHeaderUI", false); + + /** + * Specifies the region of a text area. + */ + public static final Region TEXT_AREA = + new Region("TextArea", "TextAreaUI", false); + + /** + * Specifies the region of a text field. + */ + public static final Region TEXT_FIELD = + new Region("TextField", "TextFieldUI", false); + + /** + * Specifies the region of a text pane. + */ + public static final Region TEXT_PANE = + new Region("TextPane", "TextPaneUI", false); + + /** + * Specifies the region of a toggle button. + */ + public static final Region TOGGLE_BUTTON = + new Region("ToggleButton", "ToggleButtonUI", false); + + /** + * Specifies the region of a tool bar. + */ + public static final Region TOOL_BAR = + new Region("ToolBar", "ToolBarUI", false); + + /** + * Specifies the content region of a tool bar. This is a subregion of a tool + * bar. + */ + public static final Region TOOL_BAR_CONTENT = + new Region("ToolBarContent", null, true); + + /** + * Specifies the drag window region of a tool bar. This is a subregion of a + * tool bar. + */ + public static final Region TOOL_BAR_DRAG_WINDOW = + new Region("ToolBarDragWindow", null, false); + + /** + * Specifies the region of a tool tip. + */ + public static final Region TOOL_TIP = + new Region("ToolTip", "ToolTipUI", false); + + /** + * Specifies the region of a separator of a tool bar. This is a subregion of + * a tool bar. + */ + public static final Region TOOL_BAR_SEPARATOR = + new Region("ToolBarSeparator", null, false); + + /** + * Specifies the region of a tree. + */ + public static final Region TREE = + new Region("Tree", "TreeUI", false); + + /** + * Specifies the region of a tree cell. This is a subregion of a tree. + */ + public static final Region TREE_CELL = + new Region("TreeCell", null, true); + + /** + * Specifies the region of a viewport. + */ + public static final Region VIEWPORT = + new Region("Viewport", "ViewportUI", false); + + + /** + * The UI class id for the region. This is package private because this will + * be used by other classes in that package. + */ + String ui; + + /** + * The name of the region. + */ + private String name; + + /** + * If this region is a subregion or not. + */ + private boolean subregion; + + /** + * Creates a new <code>Region</code> with the specified name and ui ID. + * The <code>ui</code> must be the same what + * {@link javax.swing.JComponent#getUIClassID()} returns for toplevel regions. For + * subregions this should be <code>null</code>. + * + * @param name the name of the region + * @param ui the UI class ID of the region or <code>null</code> for + * subregions + * @param subregion <code>true</code> if this region is a subregion, + * <code>false</code> otherwise + */ + protected Region(String name, String ui, boolean subregion) + { + this.name = name; + this.ui = ui; + this.subregion = subregion; + } + + /** + * Returns <code>true</code> if this region describes a subregion of a + * component, <code>false</code> if it describes a component region itself. + * + * @return <code>true</code> if this region describes a subregion of a + * component, <code>false</code> if it describes a component region + * itself + */ + public boolean isSubregion() + { + return subregion; + } + + /** + * Returns the name of the region. + * + * @return the name of the region + */ + public String getName() + { + return name; + } + + /** + * Returns the name of the region. + * + * @return the name of the region + */ + public String toString() + { + return name; + } +} diff --git a/libjava/classpath/javax/xml/stream/events/EndEntity.java b/libjava/classpath/javax/swing/plaf/synth/SynthConstants.java index b5c32d716f2..306024c00b0 100644 --- a/libjava/classpath/javax/xml/stream/events/EndEntity.java +++ b/libjava/classpath/javax/swing/plaf/synth/SynthConstants.java @@ -1,5 +1,5 @@ -/* EndEntity.java -- - Copyright (C) 2005 Free Software Foundation, Inc. +/* SynthConstants.java -- A couple of constants used by Synth + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,19 +35,51 @@ 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.stream.events; + +package javax.swing.plaf.synth; /** - * An end-entity event. + * A couple of constants used by the Synth Look and Feel. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 */ -public interface EndEntity - extends XMLEvent +public interface SynthConstants { + /** + * A primary state indicating that a component is enabled. + */ + static final int ENABLED = 1; /** - * Returns the entity name. + * A primary state indicating that a component is disabled. */ - String getName(); - -} + static final int DISABLED = 8; + + /** + * A primary state indicating that the mouse is over a region. + */ + static final int MOUSE_OVER = 2; + + /** + * A primary state indicating that the component is in a pressed state (which + * does not necessarily mean that the mouse is pressed over the component). + */ + static final int PRESSED = 4; + /** + * Indicates that a region has focus. + */ + static final int FOCUSED = 256; + + /** + * Indicates that a region is selected. + */ + static final int SELECTED = 512; + + /** + * Indicates that a region is in its default state. + */ + static final int DEFAULT = 1024; +} diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthContext.java b/libjava/classpath/javax/swing/plaf/synth/SynthContext.java new file mode 100644 index 00000000000..83536dae948 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/synth/SynthContext.java @@ -0,0 +1,134 @@ +/* SynthContext.java -- Contextual information about a region + 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.plaf.synth; + +import javax.swing.JComponent; + +/** + * Contains some contextual information about a region. The information passed + * in objects of this class can only be considered valid during the method call + * that it was passed to. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class SynthContext +{ + + /** + * The component. + */ + private JComponent component; + + /** + * The region of the component. + */ + private Region region; + + /** + * The style of the component. + */ + private SynthStyle style; + + /** + * The state of the component. + */ + private int state; + + /** + * Creates a new <code>SynthContext</code> object. + * + * @param component the component for which this context is used + * @param region the region of the component + * @param style the style associated with the component + * @param state a or'ed bitmask of the constants from {@link SynthConstants} + */ + public SynthContext(JComponent component, Region region, SynthStyle style, + int state) + { + this.component = component; + this.region = region; + this.style = style; + this.state = state; + } + + /** + * Returns the component that contains the region. + * + * @return the component that contains the region + */ + public JComponent getComponent() + { + return component; + } + + /** + * Returns the region that identifies this state. + * + * @return the region that identifies this state + */ + public Region getRegion() + { + return region; + } + + /** + * Returns the style of the region. + * + * @return the style of the region + */ + public SynthStyle getStyle() + { + return style; + } + + /** + * Returns the state of the component. This is a or'ed bitmask of the + * constants defined in {@link SynthConstants}. + * + * @return the state of the component + * + * @see SynthConstants + */ + public int getComponentState() + { + return state; + } +} diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java b/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java new file mode 100644 index 00000000000..a68b6f6ec2f --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java @@ -0,0 +1,283 @@ +/* SynthGraphicsUtils.java -- Wrapper for graphics primitives used in Synth + 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.plaf.synth; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.Icon; +import javax.swing.SwingUtilities; + +/** + * Wrapper for graphics primitives used in Synth. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class SynthGraphicsUtils + +{ + /** + * Creates a new <code>SynthGraphicsUtils</code> object. + */ + public SynthGraphicsUtils() + { + // Nothing to do here. + } + + /** + * Draws a line from (x1,y1) to (x2,y2). + * + * @param ctx the synth context, identifies the region + * @param paintKey identifies the portion of the component to be painted, may + * be <code>null</code> + * @param g the graphics context to use for painting + * @param x1 the x coordinate of the start point + * @param y1 the y coordinate of the start point + * @param x2 the x coordinate of the end point + * @param y2 the y coordinate of the end point + */ + public void drawLine(SynthContext ctx, Object paintKey, Graphics g, int x1, + int y1, int x2, int y2) + { + // TODO: Correct? + g.drawLine(x1, y1, x2, y2); + } + + /** + * Lays out a label and (if non-null) an icon. The calculated coordinates are + * then stored in <code>viewR</code>, <code>iconR</code> and + * <code>textR</code>. + * + * The alignment and position parameters may be one of the alignment or + * position constants defined in {@link javax.swing.SwingConstants}. + * + * @param ctx the synth context, identifies the current region + * @param fm the font metrics to use to fetch the text measures + * @param text the text to lay out, may be <code>null</code> + * @param icon the icon to lay out, may be <code>null</code> + * @param hAlign the horizontal alignment of the label + * @param vAlign the vertical alignment of the label + * @param hTextPos the horizontal text position + * @param vTextPos the vertical text position + * @param viewR the view rectangle (return parameter) + * @param iconR the icon rectangle (return parameter) + * @param textR the text rectangle (return parameter) + * @param iconTextGap the gap between text and label + * + * @return the label text, may be shortened + */ + public String layoutText(SynthContext ctx, FontMetrics fm, String text, + Icon icon, int hAlign, int vAlign, int hTextPos, + int vTextPos, Rectangle viewR, Rectangle iconR, + Rectangle textR, int iconTextGap) + { + return SwingUtilities.layoutCompoundLabel(fm, text, icon, vAlign, hAlign, + vTextPos, hTextPos, viewR, iconR, + textR, iconTextGap); + } + + /** + * Returns the width of the string <code>text</code> for the specified font + * and font metrics. + * + * @param ctx identifies the current region + * @param font the font + * @param fm the font metrics to use + * @param text the text to be measured + * + * @return the width of the string <code>text</code> for the specified font + * and font metrics + */ + public int computeStringWidth(SynthContext ctx, Font font, FontMetrics fm, + String text) + { + return fm.stringWidth(text); + } + + /** + * Calculates the minimums size that is needed to render the label with + * <code>text</code> and <code>icon</code> correctly. + * + * @param ctx identifies the current region + * @param font the font to use + * @param text the label text + * @param icon the label icon + * @param hAlign the horizontal alignment + * @param vAlign the vertical alignment + * @param hTextPosition the horizontal text position + * @param vTextPosition the vertical text position + * @param iconTextGap the gap between icon and text + * @param mnemonicIndex index to the mnemonic character within + * <code>text</code> + * + * @return the minimums size that is needed to render the label with + * <code>text</code> and <code>icon</code> correctly + */ + public Dimension getMinimumSize(SynthContext ctx, Font font, String text, + Icon icon, int hAlign, int vAlign, + int hTextPosition,int vTextPosition, + int iconTextGap,int mnemonicIndex) + { + // FIXME: Implement this correctly. + return new Dimension(0, 0); + } + + /** + * Calculates the preferred size that is needed to render the label with + * <code>text</code> and <code>icon</code> correctly. + * + * @param ctx identifies the current region + * @param font the font to use + * @param text the label text + * @param icon the label icon + * @param hAlign the horizontal alignment + * @param vAlign the vertical alignment + * @param hTextPosition the horizontal text position + * @param vTextPosition the vertical text position + * @param iconTextGap the gap between icon and text + * @param mnemonicIndex index to the mnemonic character within + * <code>text</code> + * + * @return the preferred size that is needed to render the label with + * <code>text</code> and <code>icon</code> correctly + */ + public Dimension getPreferredSize(SynthContext ctx, Font font, String text, + Icon icon, int hAlign, int vAlign, + int hTextPosition,int vTextPosition, + int iconTextGap,int mnemonicIndex) + { + // FIXME: Implement this correctly. + return new Dimension(0, 0); + } + + /** + * Calculates the maximum size that is needed to render the label with + * <code>text</code> and <code>icon</code> correctly. + * + * @param ctx identifies the current region + * @param font the font to use + * @param text the label text + * @param icon the label icon + * @param hAlign the horizontal alignment + * @param vAlign the vertical alignment + * @param hTextPosition the horizontal text position + * @param vTextPosition the vertical text position + * @param iconTextGap the gap between icon and text + * @param mnemonicIndex index to the mnemonic character within + * <code>text</code> + * + * @return the maximum size that is needed to render the label with + * <code>text</code> and <code>icon</code> correctly + */ + public Dimension getMaximumSize(SynthContext ctx, Font font, String text, + Icon icon, int hAlign, int vAlign, + int hTextPosition,int vTextPosition, + int iconTextGap,int mnemonicIndex) + { + // FIXME: Implement this correctly. + return new Dimension(0, 0); + } + + /** + * Returns the maximum character height of the font from the component of the + * passed in <code>context</code>. + * + * @param context identifies the current component and region + * + * @return the maximum character height of the font from the component of the + * passed in <code>context</code> + */ + public int getMaximumCharHeight(SynthContext context) + { + Component comp = context.getComponent(); + Font font = comp.getFont(); + return comp.getFontMetrics(font).getHeight(); + } + + /** + * Renders the specified <code>text</code> within the <code>bounds</code>. + * + * @param ctx identifies the component and region + * @param g the graphics context for drawing the tetx + * @param text the text to be rendered + * @param bounds the bounds within which the text should be rendered + * @param mnemonicIndex the index of the mnemonic character within + * <code>text</code> + */ + public void paintText(SynthContext ctx, Graphics g, String text, + Rectangle bounds, int mnemonicIndex) + { + // FIXME: This is very primitive and should be improved to paint the + // mnemonic char. + g.drawString(text, bounds.x, bounds.y); + } + + /** + * Renders the specified <code>text</code> at the specified location. + * + * @param ctx identifies the component and region + * @param g the graphics context for drawing the tetx + * @param text the text to be rendered + * @param x the X location where the text should be rendered + * @param y the Y location where the text should be rendered + * @param mnemonicIndex the index of the mnemonic character within + * <code>text</code> + */ + public void paintText(SynthContext ctx, Graphics g, String text, + int x, int y, int mnemonicIndex) + { + // FIXME: This is very primitive and should be improved to paint the + // mnemonic char. + g.drawString(text, x, y); + } + + public void paintText(SynthContext ctx, Graphics g, String text, Icon icon, + int hAlign, int vAlign, int hTextPosition, + int vTextPosition, int iconTextGap, int mnemonicIndex, + int textOffset) + { + // FIXME: Implement this correctly. + } +} diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java b/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java new file mode 100644 index 00000000000..8d0596d416e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java @@ -0,0 +1,272 @@ +/* SynthLookAndFeel.java -- A skinnable Swing look and feel + 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.plaf.synth; + +import java.awt.Component; +import java.io.InputStream; +import java.text.ParseException; + +import javax.swing.JComponent; +import javax.swing.UIDefaults; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicLookAndFeel; + + +/** + * A look and feel that can be customized either by providing a file to + * {@link #load} or by setting a {@link SynthStyleFactory} using + * {@link #setStyleFactory}. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class SynthLookAndFeel + extends BasicLookAndFeel +{ + + /** + * The style factory that will be used by the UI classes to load their + * style sets from. + */ + private static SynthStyleFactory styleFactory; + + /** + * Creates a new instance of <code>SynthLookAndFeel</code>. In order to use + * the Synth look and feel you either need to call {@link #load} to load a + * set of styles from an XML file, or you need to call + * {@link #setStyleFactory} to provide your own style factory. + */ + public SynthLookAndFeel() + { + // FIXME: What to do here, if anything? + } + + /** + * Sets the style factory that the UI classes of Synth will use to load their + * sets of styles. + * + * @param sf the style factory to set + */ + public static void setStyleFactory(SynthStyleFactory sf) + { + styleFactory = sf; + } + + /** + * Returns the current style factory that the UI classes of Synth will use to + * load their sets of styles. + * + * @return the current style factory + */ + public static SynthStyleFactory getStyleFactory() + { + return styleFactory; + } + + /** + * Returns the style for the specified component and region. + * + * @param c the component for which to return the style + * @param r the region of the component for which to return the style + * + * @return the style for the specified component and region + */ + public static SynthStyle getStyle(JComponent c, Region r) + { + return getStyleFactory().getStyle(c, r); + } + + /** + * Updates all style information of the component and it's children. + * + * @param c the componenent for which to update the style + */ + public static void updateStyles(Component c) + { + // FIXME: Implement this properly. + } + + /** + * Returns the region for a given Swing component. + * + * @param c the Swing component for which to fetch the region + * + * @return the region for a given Swing component + */ + public static Region getRegion(JComponent c) + { + // 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. + return null; + } + + /** + * Creates the Synth look and feel component UI instance for the given + * component. + * + * @param c the component for which to create a UI instance + * + * @return the Synth look and feel component UI instance for the given + * component + */ + public static ComponentUI createUI(JComponent c) + { + // FIXME: This can be implemented as soon as we have the component UI + // classes in place. + return null; + } + + /** + * Initializes this look and feel. + */ + public void initialize() + { + super.initialize(); + // TODO: Implement at least the following here: + // if (styleFactory != null) + // styleFactory = new DefaultStyleFactory(); + } + + /** + * Uninitializes the look and feel. + */ + public void uninitialize() + { + super.uninitialize(); + // TODO: What to do here? + } + + /** + * Returns the UI defaults of this look and feel. + * + * @return the UI defaults of this look and feel + */ + public UIDefaults getDefaults() + { + // FIXME: This is certainly wrong. The defaults should be fetched/merged + // from the file from which the l&f is loaded. + return super.getDefaults(); + } + + /** + * FIXME: DOCUMENT ME! + * + * @return FIXME + */ + public boolean shouldUpdateStyleOnAncestorChanged() + { + return false; + } + + /** + * Loads a set of {@link SynthStyle}s that are used for the look and feel of + * the components. The <code>resourceBase</code> parameter is used to resolve + * references against, like icons and other files. + * + * @param in the input stream from where to load the styles + * @param resourceBase the base against which references are resolved. + * + * @throws ParseException if the input stream cannot be parsed + * @throws IllegalArgumentException if one of the parameters is + * <code>null</code> + */ + // 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 + { + // FIXME: Implement this correctly. + } + + /** + * Returns a textual description of the Synth look and feel. This returns + * "Synt look and feel". + * + * @return a textual description of the Synth look and feel + */ + public String getDescription() + { + return "Synth look and feel"; + } + + /** + * Returns the ID of the Synth look and feel. This returns "Synth". + * + * @return the ID of the Synth look and feel + */ + public String getID() + { + return "Synth"; + } + + /** + * Returns the name of the Synth look and feel. This returns + * "Synt look and feel". + * + * @return the name of the Synth look and feel + */ + public String getName() + { + return "Synth look and feel"; + } + + /** + * Returns <code>false</code> since the Synth look and feel is not a native + * look and feel. + * + * @return <code>false</code> + */ + public boolean isNativeLookAndFeel() + { + return false; + } + + /** + * Returns <code>true</code> since the Synth look and feel is always a + * supported look and feel. + * + * @return <code>true</code> + */ + public boolean isSupportedLookAndFeel() + { + return true; + } + +} diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java b/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java new file mode 100644 index 00000000000..0d63c6db76f --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java @@ -0,0 +1,80 @@ +/* SynthPainter.java -- An abstract painter for synth components + 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.plaf.synth; + +import java.awt.Graphics; + +/** + * The abstract definition of a delegate that takes the responsibility of + * painting for the components. + * + * This class is defined to be abstract and all methods are no-ops. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public abstract class SynthPainter +{ + + /** + * Creates a new <code>SynthPainter</code> object. + */ + public SynthPainter() + { + // Nothing to do here. + } + + /** + * Paints the background 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 paintArrowButtonBackground(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 new file mode 100644 index 00000000000..e0a8dbcc7b9 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java @@ -0,0 +1,144 @@ +/* SynthStyle.java -- A set of style properties + 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.plaf.synth; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Insets; + +import javax.swing.Icon; + +/** + * A set of style properties that can be installed on a component. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public abstract class SynthStyle +{ + + /** + * Creates a new <code>SynthStyle</code> object. + */ + public SynthStyle() + { + // FIXME: Implement this correctly. + } + + public SynthGraphicsUtils getGraphicsUtils(SynthContext ctx) + { + // FIXME: Implement this correctly. + return null; + } + + public Color getColor(SynthContext ctx, ColorType type) + { + // FIXME: Implement this correctly. + return null; + } + + public abstract Color getColorForState(SynthContext ctx, ColorType type); + + public Font getFont(SynthContext ctx) + { + // FIXME: Implement this correctly. + return null; + } + + public abstract Font getFontForState(SynthContext ctx); + + public Insets getInsets(SynthContext ctx) + { + // FIXME: Implement this correctly. + return null; + } + + public SynthPainter getPainted(SynthContext ctx) + { + // FIXME: Implement this correctly. + return null; + } + + public boolean isOpaque(SynthContext ctx) + { + // FIXME: Implement this correctly. + return true; + } + + public Object get(SynthContext ctx, Object key) + { + // FIXME: Implement this correctly. + return null; + } + + public void installDefaults(SynthContext ctx) + { + // FIXME: Implement this correctly. + } + + public void uninstallDefaults(SynthContext ctx) + { + // FIXME: Implement this correctly. + } + + public int getInt(SynthContext ctx, Object key, int defaultValue) + { + // FIXME: Implement this correctly. + return -1; + } + + public boolean getBoolean(SynthContext ctx, Object key, boolean defaultValue) + { + // FIXME: Implement this correctly. + return false; + } + + public Icon getIcon(SynthContext ctx, Object key) + { + // FIXME: Implement this correctly. + return null; + } + + public String getString(SynthContext ctx, Object key, String defaultValue) + { + // FIXME: Implement this correctly. + return null; + } +} diff --git a/libjava/classpath/javax/xml/stream/XMLIterator.java b/libjava/classpath/javax/swing/plaf/synth/SynthStyleFactory.java index e12bffafdcc..569753d8ad7 100644 --- a/libjava/classpath/javax/xml/stream/XMLIterator.java +++ b/libjava/classpath/javax/swing/plaf/synth/SynthStyleFactory.java @@ -1,5 +1,5 @@ -/* XMLIterator.java -- - Copyright (C) 2005 Free Software Foundation, Inc. +/* SynthStyleFactory.java -- A factory for SynthStyles + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,27 +35,30 @@ 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.stream; -import javax.xml.stream.events.XMLEvent; +package javax.swing.plaf.synth; -/** - * Simple iterator for XML events. - */ -public interface XMLIterator +import javax.swing.JComponent; + +public abstract class SynthStyleFactory { /** - * Returns the next XML event. + * Creates a new <code>SynthStyleFactory</code>. */ - XMLEvent next() - throws XMLStreamException; + public SynthStyleFactory() + { + // Nothing to do here. + } /** - * Indicates whether there are more XML events to be read. + * Returns a {@link SynthStyle} for the specified region of the specified + * component. + * + * @param c the component for which to create a style + * @param id the region of the component + * + * @return a style for the specified region of the specified component */ - boolean hasNext() - throws XMLStreamException; - + public abstract SynthStyle getStyle(JComponent c, Region id); } - diff --git a/libjava/classpath/javax/xml/stream/XMLFilter.java b/libjava/classpath/javax/swing/plaf/synth/package.html index 7e7698df12c..b977e468c90 100644 --- a/libjava/classpath/javax/xml/stream/XMLFilter.java +++ b/libjava/classpath/javax/swing/plaf/synth/package.html @@ -1,5 +1,6 @@ -/* XMLFilter.java -- - Copyright (C) 2005 Free Software Foundation, Inc. +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.plaf.metal package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -33,14 +34,14 @@ 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. */ +exception statement from your version. --> -package javax.xml.stream; - -/** - * Marker interface for stream and event filters. - */ -public interface XMLFilter -{ -} +<html> +<head><title>GNU Classpath - javax.swing.plaf.synth</title></head> +<body> +<p>Provides a look and feel that can be customized by and XML file or by + providing a custom {@link SynthStyleFactory}. +</p> +</body> +</html> diff --git a/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java b/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java index 233528c7d67..0d9b62567f6 100644 --- a/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java +++ b/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java @@ -127,7 +127,8 @@ public class DefaultTableCellRenderer extends JLabel * Get the string value of the object and pass it to setText(). * * @param table the JTable - * @param value the value of the object + * @param value the value of the object. For the text content, + * null is rendered as an empty cell. * @param isSelected is the cell selected? * @param hasFocus has the cell the focus? * @param row the row to render @@ -140,13 +141,7 @@ public class DefaultTableCellRenderer extends JLabel boolean hasFocus, int row, int column) { - if (value != null) - { - if (value instanceof JTextField) - return new JTextField(((JTextField)value).getText()); - super.setText(value.toString()); - } - + setValue(value); setOpaque(true); if (table == null) @@ -274,6 +269,10 @@ public class DefaultTableCellRenderer extends JLabel */ protected void setValue(Object value) { - super.setText((value!=null) ? value.toString() : ""); + if (value != null) + setText(value.toString()); + else + // null is rendered as an empty cell. + setText(""); } } diff --git a/libjava/classpath/javax/swing/table/DefaultTableModel.java b/libjava/classpath/javax/swing/table/DefaultTableModel.java index 6844f2a27ec..c281caa0791 100644 --- a/libjava/classpath/javax/swing/table/DefaultTableModel.java +++ b/libjava/classpath/javax/swing/table/DefaultTableModel.java @@ -486,7 +486,10 @@ public class DefaultTableModel extends AbstractTableModel } /** - * Returns the name of the specified column. + * Get the name of the column. If the column has the column identifier set, + * the return value is the result of the .toString() method call on that + * identifier. If the identifier is not explicitly set, the returned value + * is calculated by {@link AbstractTableModel#getColumnName(int)}. * * @param column the column index. * diff --git a/libjava/classpath/javax/swing/table/JTableHeader.java b/libjava/classpath/javax/swing/table/JTableHeader.java index 163509a45c2..4e8dcd7b7ef 100644 --- a/libjava/classpath/javax/swing/table/JTableHeader.java +++ b/libjava/classpath/javax/swing/table/JTableHeader.java @@ -67,6 +67,11 @@ import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.plaf.TableHeaderUI; +/** + * Represents the table header. The header displays the column header values, + * is always visible event if the rest of the table scrolls up and down and + * supports column reordering and resizing with mouse. + */ public class JTableHeader extends JComponent implements TableColumnModelListener, Accessible { @@ -306,7 +311,10 @@ public class JTableHeader extends JComponent } }; } - + + /** + * Use serialVersionUid for interoperability. + */ private static final long serialVersionUID = 5144633983372967710L; /** @@ -409,9 +417,10 @@ public class JTableHeader extends JComponent } /** - * Get the value of the {@link #draggedColumn} property. + * Get the column that is currently being dragged. This is used when + * handling the column reordering with mouse. * - * @return The current value of the property + * @return the column being dragged, null if none. */ public TableColumn getDraggedColumn() { @@ -429,29 +438,34 @@ public class JTableHeader extends JComponent } /** - * Get the value of the {@link #reorderingAllowed} property. + * Check if it is possible to reorder the table columns by dragging column + * header with mouse. The table reordering is enabled by default, but can be + * disabled with {@link #setReorderingAllowed(boolean)}. * - * @return The current value of the property - */ + * @return true if reordering is allowed, false otherwise. + */ public boolean getReorderingAllowed() { return reorderingAllowed; } /** - * Get the value of the {@link #resizingAllowed} property. + * Check if it is possible to resize the table columns by dragging the column + * boundary in the table header with mouse. The resizing is enabled + * by default, but can be disabled with {@link #setResizingAllowed(boolean)}. * - * @return The current value of the property - */ + * @return true if resizing is allowed, false otherwise. + */ public boolean getResizingAllowed() { return resizingAllowed; } /** - * Get the value of the {@link #resizingColumn} property. + * Get the column that is currently being resized. This is used when + * handling the column resizing with mouse. * - * @return The current value of the property + * @return the column being currently resized, null if none. */ public TableColumn getResizingColumn() { @@ -459,9 +473,9 @@ public class JTableHeader extends JComponent } /** - * Get the value of the {@link #table} property. + * Get the table, having this header. * - * @return The current value of the property + * @return the table, having this header. */ public JTable getTable() { @@ -501,13 +515,15 @@ public class JTableHeader extends JComponent } /** - * Set the value of the {@link #draggedColumn} property. + * Set the column that is currently being dragged. This is used when + * dragging the column with mouse. Setting to null will stop the + * dragging session immediately. * - * @param d The new value of the property + * @param draggingIt the column being currently dragged, null if none. */ - public void setDraggedColumn(TableColumn d) + public void setDraggedColumn(TableColumn draggingIt) { - draggedColumn = d; + draggedColumn = draggingIt; } /** @@ -531,33 +547,39 @@ public class JTableHeader extends JComponent } /** - * Set the value of the {@link #reorderingAllowed} property. + * Set the table ability to reorder columns by dragging column header + * with mouse. The table reordering is enabled by default, but can be + * disabled with this method. * - * @param r The new value of the property + * @param allowed true if reordering is allowed, false otherwise. */ - public void setReorderingAllowed(boolean r) + public void setReorderingAllowed(boolean allowed) { - reorderingAllowed = r; + reorderingAllowed = allowed; } /** - * Set the value of the {@link #resizingAllowed} property. + * Set the table ability to resize columns by dragging the column + * boundary in the table header with mouse. The resizing is enabled + * by default, but can be disabled using this method. * - * @param r The new value of the property + * @param allowed true if resizing is allowed, false otherwise. */ - public void setResizingAllowed(boolean r) + public void setResizingAllowed(boolean allowed) { - resizingAllowed = r; + resizingAllowed = allowed; } /** - * Set the value of the {@link #resizingColumn} property. + * The the column that is currently being resized. This property is used + * when handling table resizing with mouse. Setting to null would stop + * the resizing session immediately. * - * @param r The new value of the property + * @param resizingIt the column being currently resized */ - public void setResizingColumn(TableColumn r) + public void setResizingColumn(TableColumn resizingIt) { - resizingColumn = r; + resizingColumn = resizingIt; } /** @@ -609,7 +631,14 @@ public class JTableHeader extends JComponent { this.cellRenderer = cellRenderer; } - + + /** + * Get the rectangle, occupied by the header of the given column. + * + * @param column the column, for that the header area is requested. + * + * @return the column header area. + */ public Rectangle getHeaderRect(int column) { Rectangle r = getTable().getCellRect(-1, column, false); diff --git a/libjava/classpath/javax/swing/text/AbstractDocument.java b/libjava/classpath/javax/swing/text/AbstractDocument.java index c7353885e12..a3e8c463bd3 100644 --- a/libjava/classpath/javax/swing/text/AbstractDocument.java +++ b/libjava/classpath/javax/swing/text/AbstractDocument.java @@ -538,18 +538,24 @@ public abstract class AbstractDocument implements Document, Serializable DefaultDocumentEvent event = new DefaultDocumentEvent(offset, text.length(), DocumentEvent.EventType.INSERT); - - writeLock(); - UndoableEdit undo = content.insertString(offset, text); - if (undo != null) - event.addEdit(undo); - insertUpdate(event, attributes); - writeUnlock(); + try + { + writeLock(); + UndoableEdit undo = content.insertString(offset, text); + if (undo != null) + event.addEdit(undo); + + insertUpdate(event, attributes); - fireInsertUpdate(event); - if (undo != null) - fireUndoableEditUpdate(new UndoableEditEvent(this, undo)); + fireInsertUpdate(event); + if (undo != null) + fireUndoableEditUpdate(new UndoableEditEvent(this, undo)); + } + finally + { + writeUnlock(); + } } /** @@ -640,6 +646,12 @@ public abstract class AbstractDocument implements Document, Serializable // more times than you've previously called lock, but it doesn't make // sure that the threads calling unlock were the same ones that called lock + // If the current thread holds the write lock, and attempted to also obtain + // a readLock, then numReaders hasn't been incremented and we don't need + // to unlock it here. + if (currentWriter == Thread.currentThread()) + return; + // FIXME: the reference implementation throws a // javax.swing.text.StateInvariantError here if (numReaders == 0) @@ -675,18 +687,21 @@ public abstract class AbstractDocument implements Document, Serializable new DefaultDocumentEvent(offset, length, DocumentEvent.EventType.REMOVE); - removeUpdate(event); - - boolean shouldFire = content.getString(offset, length).length() != 0; - - writeLock(); - UndoableEdit temp = content.remove(offset, length); - writeUnlock(); - - postRemoveUpdate(event); - - if (shouldFire) - fireRemoveUpdate(event); + try + { + writeLock(); + + // The order of the operations below is critical! + removeUpdate(event); + UndoableEdit temp = content.remove(offset, length); + + postRemoveUpdate(event); + fireRemoveUpdate(event); + } + finally + { + writeUnlock(); + } } /** @@ -841,7 +856,7 @@ public abstract class AbstractDocument implements Document, Serializable */ protected void writeLock() { - if (currentWriter!= null && currentWriter.equals(Thread.currentThread())) + if (currentWriter != null && currentWriter.equals(Thread.currentThread())) return; synchronized (documentCV) { @@ -1330,11 +1345,11 @@ public abstract class AbstractDocument implements Document, Serializable public Object getAttribute(Object key) { Object result = attributes.getAttribute(key); - if (result == null && element_parent != null) + if (result == null) { - AttributeSet parentSet = element_parent.getAttributes(); - if (parentSet != null) - result = parentSet.getAttribute(key); + AttributeSet resParent = getResolveParent(); + if (resParent != null) + result = resParent.getAttribute(key); } return result; } @@ -1371,9 +1386,7 @@ public abstract class AbstractDocument implements Document, Serializable */ public AttributeSet getResolveParent() { - if (attributes.getResolveParent() != null) - return attributes.getResolveParent(); - return element_parent.getAttributes(); + return attributes.getResolveParent(); } /** @@ -1573,6 +1586,18 @@ public abstract class AbstractDocument implements Document, Serializable private Element[] children = new Element[0]; /** + * The cached startOffset value. This is used in the case when a + * BranchElement (temporarily) has no child elements. + */ + private int startOffset; + + /** + * The cached endOffset value. This is used in the case when a + * BranchElement (temporarily) has no child elements. + */ + private int endOffset; + + /** * Creates a new <code>BranchElement</code> with the specified * parent and attributes. * @@ -1583,6 +1608,8 @@ public abstract class AbstractDocument implements Document, Serializable public BranchElement(Element parent, AttributeSet attributes) { super(parent, attributes); + startOffset = -1; + endOffset = -1; } /** @@ -1655,7 +1682,7 @@ public abstract class AbstractDocument implements Document, Serializable // return 0 if (offset < getStartOffset()) return 0; - + // XXX: There is surely a better algorithm // as beginning from first element each time. for (int index = 0; index < children.length - 1; ++index) @@ -1695,9 +1722,15 @@ public abstract class AbstractDocument implements Document, Serializable */ public int getEndOffset() { - if (getElementCount() == 0) - throw new NullPointerException("This BranchElement has no children."); - return children[children.length - 1].getEndOffset(); + if (children.length == 0) + { + if (endOffset == -1) + throw new NullPointerException("BranchElement has no children."); + } + else + endOffset = children[children.length - 1].getEndOffset(); + + return endOffset; } /** @@ -1718,13 +1751,20 @@ public abstract class AbstractDocument implements Document, Serializable * * @return the start offset of this element inside the document model * - * @throws NullPointerException if this branch element has no children + * @throws NullPointerException if this branch element has no children and + * no startOffset value has been cached */ public int getStartOffset() { - if (getElementCount() == 0) - throw new NullPointerException("This BranchElement has no children."); - return children[0].getStartOffset(); + if (children.length == 0) + { + if (startOffset == -1) + throw new NullPointerException("BranchElement has no children."); + } + else + startOffset = children[0].getStartOffset(); + + return startOffset; } /** @@ -2022,13 +2062,29 @@ public abstract class AbstractDocument implements Document, Serializable /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = -8906306331347768017L; - /** Manages the start offset of this element. */ - Position startPos; + /** + * Manages the start offset of this element. + */ + private Position startPos; + + /** + * Manages the end offset of this element. + */ + private Position endPos; - /** Manages the end offset of this element. */ - Position endPos; + /** + * This gets possible added to the startOffset when a startOffset + * outside the document range is requested. + */ + private int startDelta; /** + * This gets possible added to the endOffset when a endOffset + * outside the document range is requested. + */ + private int endDelta; + + /** * Creates a new <code>LeafElement</code>. * * @param parent the parent of this <code>LeafElement</code> @@ -2040,20 +2096,18 @@ public abstract class AbstractDocument implements Document, Serializable int end) { super(parent, attributes); - { - try + int len = content.length(); + startDelta = 0; + if (start > len) + startDelta = start - len; + endDelta = 0; + if (end > len) + endDelta = end - len; + try { - if (parent != null) - { - startPos = parent.getDocument().createPosition(start); - endPos = parent.getDocument().createPosition(end); - } - else - { - startPos = createPosition(start); - endPos = createPosition(end); + startPos = createPosition(start - startDelta); + endPos = createPosition(end - endDelta); } - } catch (BadLocationException ex) { AssertionError as; @@ -2064,7 +2118,6 @@ public abstract class AbstractDocument implements Document, Serializable as.initCause(ex); throw as; } - } } /** @@ -2136,7 +2189,7 @@ public abstract class AbstractDocument implements Document, Serializable */ public int getEndOffset() { - return endPos.getOffset(); + return endPos.getOffset() + endDelta; } /** @@ -2162,7 +2215,7 @@ public abstract class AbstractDocument implements Document, Serializable */ public int getStartOffset() { - return startPos.getOffset(); + return startPos.getOffset() + startDelta; } /** diff --git a/libjava/classpath/javax/swing/text/AsyncBoxView.java b/libjava/classpath/javax/swing/text/AsyncBoxView.java new file mode 100644 index 00000000000..1988bbadcc8 --- /dev/null +++ b/libjava/classpath/javax/swing/text/AsyncBoxView.java @@ -0,0 +1,1480 @@ +/* AsyncBoxView.java -- A box view that performs layout asynchronously + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.ArrayList; + +import javax.swing.event.DocumentEvent; +import javax.swing.text.Position.Bias; + +/** + * A {@link View} implementation that lays out its child views in a box, either + * vertically or horizontally. The difference to {@link BoxView} is that the + * layout is performed in an asynchronous manner. This helps to keep the + * eventqueue free from non-GUI related tasks. + * + * This view is currently not used in standard text components. In order to + * use it you would have to implement a special {@link EditorKit} with a + * {@link ViewFactory} that returns this view. For example: + * + * <pre> + * static class AsyncEditorKit extends StyledEditorKit implements ViewFactory + * { + * public View create(Element el) + * { + * if (el.getName().equals(AbstractDocument.SectionElementName)) + * return new AsyncBoxView(el, View.Y_AXIS); + * return super.getViewFactory().create(el); + * } + * public ViewFactory getViewFactory() { + * return this; + * } + * } + * </pre> + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.3 + */ +public class AsyncBoxView + extends View +{ + + /** + * Manages the effective position of child views. That keeps the visible + * layout stable while the AsyncBoxView might be changing until the layout + * thread decides to publish the new layout. + */ + public class ChildLocator + { + + /** + * The last valid location. + */ + protected ChildState lastValidOffset; + + /** + * The last allocation. + */ + protected Rectangle lastAlloc; + + /** + * A Rectangle used for child allocation calculation to avoid creation + * of lots of garbage Rectangle objects. + */ + protected Rectangle childAlloc; + + /** + * Creates a new ChildLocator. + */ + public ChildLocator() + { + lastAlloc = new Rectangle(); + childAlloc = new Rectangle(); + } + + /** + * Receives notification that a child has changed. This is called by + * child state objects that have changed it's major span. + * + * This sets the {@link #lastValidOffset} field to <code>cs</code> if + * the new child state's view start offset is smaller than the start offset + * of the current child state's view or when <code>lastValidOffset</code> + * is <code>null</code>. + * + * @param cs the child state object that has changed + */ + public synchronized void childChanged(ChildState cs) + { + if (lastValidOffset == null + || cs.getChildView().getStartOffset() + < lastValidOffset.getChildView().getStartOffset()) + { + lastValidOffset = cs; + } + } + + /** + * Returns the view index of the view that occupies the specified area, or + * <code>-1</code> if there is no such child view. + * + * @param x the x coordinate (relative to <code>a</code>) + * @param y the y coordinate (relative to <code>a</code>) + * @param a the current allocation of this view + * + * @return the view index of the view that occupies the specified area, or + * <code>-1</code> if there is no such child view + */ + public int getViewIndexAtPoint(float x, float y, Shape a) + { + setAllocation(a); + float targetOffset = (getMajorAxis() == X_AXIS) ? x - lastAlloc.x + : y - lastAlloc.y; + int index = getViewIndexAtVisualOffset(targetOffset); + return index; + } + + /** + * Returns the current allocation for a child view. This updates the + * offsets for all children <em>before</em> the requested child view. + * + * @param index the index of the child view + * @param a the current allocation of this view + * + * @return the current allocation for a child view + */ + public synchronized Shape getChildAllocation(int index, Shape a) + { + if (a == null) + return null; + setAllocation(a); + ChildState cs = getChildState(index); + if (cs.getChildView().getStartOffset() + > lastValidOffset.getChildView().getStartOffset()) + { + updateChildOffsetsToIndex(index); + } + Shape ca = getChildAllocation(index); + return ca; + } + + /** + * Paints all child views. + * + * @param g the graphics context to use + */ + public synchronized void paintChildren(Graphics g) + { + Rectangle clip = g.getClipBounds(); + float targetOffset = (getMajorAxis() == X_AXIS) ? clip.x - lastAlloc.x + : clip.y - lastAlloc.y; + int index = getViewIndexAtVisualOffset(targetOffset); + int n = getViewCount(); + float offs = getChildState(index).getMajorOffset(); + for (int i = index; i < n; i++) + { + ChildState cs = getChildState(i); + cs.setMajorOffset(offs); + Shape ca = getChildAllocation(i); + if (ca.intersects(clip)) + { + synchronized (cs) + { + View v = cs.getChildView(); + v.paint(g, ca); + } + } + else + { + // done painting intersection + break; + } + offs += cs.getMajorSpan(); + } + } + + /** + * Returns the current allocation of the child view with the specified + * index. Note that this will <em>not</em> update any location information. + * + * @param index the index of the requested child view + * + * @return the current allocation of the child view with the specified + * index + */ + protected Shape getChildAllocation(int index) + { + ChildState cs = getChildState(index); + if (! cs.isLayoutValid()) + cs.run(); + + if (getMajorAxis() == X_AXIS) + { + childAlloc.x = lastAlloc.x + (int) cs.getMajorOffset(); + childAlloc.y = lastAlloc.y + (int) cs.getMinorOffset(); + childAlloc.width = (int) cs.getMajorSpan(); + childAlloc.height = (int) cs.getMinorSpan(); + } + else + { + childAlloc.y = lastAlloc.y + (int) cs.getMajorOffset(); + childAlloc.x = lastAlloc.x + (int) cs.getMinorOffset(); + childAlloc.height = (int) cs.getMajorSpan(); + childAlloc.width = (int) cs.getMinorSpan(); + } + return childAlloc; + } + + /** + * Sets the current allocation for this view. + * + * @param a the allocation to set + */ + protected void setAllocation(Shape a) + { + if (a instanceof Rectangle) + lastAlloc.setBounds((Rectangle) a); + else + lastAlloc.setBounds(a.getBounds()); + + setSize(lastAlloc.width, lastAlloc.height); + } + + /** + * Returns the index of the view at the specified offset along the major + * layout axis. + * + * @param targetOffset the requested offset + * + * @return the index of the view at the specified offset along the major + * layout axis + */ + protected int getViewIndexAtVisualOffset(float targetOffset) + { + int n = getViewCount(); + if (n > 0) + { + if (lastValidOffset == null) + lastValidOffset = getChildState(0); + if (targetOffset > majorSpan) + return 0; + else if (targetOffset > lastValidOffset.getMajorOffset()) + return updateChildOffsets(targetOffset); + else + { + float offs = 0f; + for (int i = 0; i < n; i++) + { + ChildState cs = getChildState(i); + float nextOffs = offs + cs.getMajorSpan(); + if (targetOffset < nextOffs) + return i; + offs = nextOffs; + } + } + } + return n - 1; + } + + /** + * Updates all the child view offsets up to the specified targetOffset. + * + * @param targetOffset the offset up to which the child view offsets are + * updated + * + * @return the index of the view at the specified offset + */ + private int updateChildOffsets(float targetOffset) + { + int n = getViewCount(); + int targetIndex = n - 1;; + int pos = lastValidOffset.getChildView().getStartOffset(); + int startIndex = getViewIndexAtPosition(pos, Position.Bias.Forward); + float start = lastValidOffset.getMajorOffset(); + float lastOffset = start; + for (int i = startIndex; i < n; i++) + { + ChildState cs = getChildState(i); + cs.setMajorOffset(lastOffset); + lastOffset += cs.getMajorSpan(); + if (targetOffset < lastOffset) + { + targetIndex = i; + lastValidOffset = cs; + break; + } + } + return targetIndex; + } + + /** + * Updates the offsets of the child views up to the specified index. + * + * @param index the index up to which the offsets are updated + */ + private void updateChildOffsetsToIndex(int index) + { + int pos = lastValidOffset.getChildView().getStartOffset(); + int startIndex = getViewIndexAtPosition(pos, Position.Bias.Forward); + float lastOffset = lastValidOffset.getMajorOffset(); + for (int i = startIndex; i <= index; i++) + { + ChildState cs = getChildState(i); + cs.setMajorOffset(lastOffset); + lastOffset += cs.getMajorSpan(); + } + } + } + + /** + * Represents the layout state of a child view. + */ + public class ChildState + implements Runnable + { + + /** + * The child view for this state record. + */ + private View childView; + + /** + * Indicates if the minor axis requirements of this child view are valid + * or not. + */ + private boolean minorValid; + + /** + * Indicates if the major axis requirements of this child view are valid + * or not. + */ + private boolean majorValid; + + /** + * Indicates if the current child size is valid. This is package private + * to avoid synthetic accessor method. + */ + boolean childSizeValid; + + /** + * The child views minimumSpan. This is package private to avoid accessor + * method. + */ + float minimum; + + /** + * The child views preferredSpan. This is package private to avoid accessor + * method. + */ + float preferred; + + /** + * The current span of the child view along the major axis. + */ + private float majorSpan; + + /** + * The current offset of the child view along the major axis. + */ + private float majorOffset; + + /** + * The current span of the child view along the minor axis. + */ + private float minorSpan; + + /** + * The current offset of the child view along the major axis. + */ + private float minorOffset; + + /** + * The child views maximumSpan. + */ + private float maximum; + + /** + * Creates a new <code>ChildState</code> object for the specified child + * view. + * + * @param view the child view for which to create the state record + */ + public ChildState(View view) + { + childView = view; + } + + /** + * Returns the child view for which this <code>ChildState</code> represents + * the layout state. + * + * @return the child view for this child state object + */ + public View getChildView() + { + return childView; + } + + /** + * Returns <code>true</code> if the current layout information is valid, + * <code>false</code> otherwise. + * + * @return <code>true</code> if the current layout information is valid, + * <code>false</code> otherwise + */ + public boolean isLayoutValid() + { + return minorValid && majorValid && childSizeValid; + } + + /** + * Performs the layout update for the child view managed by this + * <code>ChildState</code>. + */ + public void run() + { + Document doc = getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument abstractDoc = (AbstractDocument) doc; + abstractDoc.readLock(); + } + + try + { + + if (!(minorValid && majorValid && childSizeValid) + && childView.getParent() == AsyncBoxView.this) + { + synchronized(AsyncBoxView.this) + { + changing = this; + } + update(); + synchronized(AsyncBoxView.this) + { + changing = null; + } + // Changing the major axis may cause the minor axis + // requirements to have changed, so we need to do this again. + update(); + } + } + finally + { + if (doc instanceof AbstractDocument) + { + AbstractDocument abstractDoc = (AbstractDocument) doc; + abstractDoc.readUnlock(); + } + } + } + + /** + * Performs the actual update after the run methods has made its checks + * and locked the document. + */ + private void update() + { + int majorAxis = getMajorAxis(); + boolean minorUpdated = false; + synchronized (this) + { + if (! minorValid) + { + int minorAxis = getMinorAxis(); + minimum = childView.getMinimumSpan(minorAxis); + preferred = childView.getPreferredSpan(minorAxis); + maximum = childView.getMaximumSpan(minorAxis); + minorValid = true; + minorUpdated = true; + } + } + if (minorUpdated) + minorRequirementChange(this); + + boolean majorUpdated = false; + float delta = 0.0F; + synchronized (this) + { + if (! majorValid) + { + float oldSpan = majorSpan; + majorSpan = childView.getPreferredSpan(majorAxis); + delta = majorSpan - oldSpan; + majorValid = true; + majorUpdated = true; + } + } + if (majorUpdated) + { + majorRequirementChange(this, delta); + locator.childChanged(this); + } + + synchronized (this) + { + if (! childSizeValid) + { + float w; + float h; + if (majorAxis == X_AXIS) + { + w = majorSpan; + h = getMinorSpan(); + } + else + { + w = getMinorSpan(); + h = majorSpan; + } + childSizeValid = true; + childView.setSize(w, h); + } + } + } + + /** + * Returns the span of the child view along the minor layout axis. + * + * @return the span of the child view along the minor layout axis + */ + public float getMinorSpan() + { + float retVal; + if (maximum < minorSpan) + retVal = maximum; + else + retVal = Math.max(minimum, minorSpan); + return retVal; + } + + /** + * Returns the offset of the child view along the minor layout axis. + * + * @return the offset of the child view along the minor layout axis + */ + public float getMinorOffset() + { + float retVal; + if (maximum < minorSpan) + { + float align = childView.getAlignment(getMinorAxis()); + retVal = ((minorSpan - maximum) * align); + } + else + retVal = 0f; + + return retVal; + } + + /** + * Returns the span of the child view along the major layout axis. + * + * @return the span of the child view along the major layout axis + */ + + public float getMajorSpan() + { + return majorSpan; + } + + /** + * Returns the offset of the child view along the major layout axis. + * + * @return the offset of the child view along the major layout axis + */ + public float getMajorOffset() + { + return majorOffset; + } + + /** + * Sets the offset of the child view along the major layout axis. This + * should only be called by the ChildLocator of that child view. + * + * @param offset the offset to set + */ + public void setMajorOffset(float offset) + { + majorOffset = offset; + } + + /** + * Mark the preferences changed for that child. This forwards to + * {@link AsyncBoxView#preferenceChanged}. + * + * @param width <code>true</code> if the width preference has changed + * @param height <code>true</code> if the height preference has changed + */ + public void preferenceChanged(boolean width, boolean height) + { + if (getMajorAxis() == X_AXIS) + { + if (width) + majorValid = false; + if (height) + minorValid = false; + } + else + { + if (width) + minorValid = false; + if (height) + majorValid = false; + } + childSizeValid = false; + } + } + + /** + * Flushes the requirements changes upwards asynchronously. + */ + private class FlushTask implements Runnable + { + /** + * Starts the flush task. This obtains a readLock on the document + * and then flushes all the updates using + * {@link AsyncBoxView#flushRequirementChanges()} after updating the + * requirements. + */ + public void run() + { + try + { + // Acquire a lock on the document. + Document doc = getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument abstractDoc = (AbstractDocument) doc; + abstractDoc.readLock(); + } + + int n = getViewCount(); + if (minorChanged && (n > 0)) + { + LayoutQueue q = getLayoutQueue(); + ChildState min = getChildState(0); + ChildState pref = getChildState(0); + for (int i = 1; i < n; i++) + { + ChildState cs = getChildState(i); + if (cs.minimum > min.minimum) + min = cs; + if (cs.preferred > pref.preferred) + pref = cs; + } + synchronized (AsyncBoxView.this) + { + minReq = min; + prefReq = pref; + } + } + + flushRequirementChanges(); + } + finally + { + // Release the lock on the document. + Document doc = getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument abstractDoc = (AbstractDocument) doc; + abstractDoc.readUnlock(); + } + } + } + + } + + /** + * The major layout axis. + */ + private int majorAxis; + + /** + * The top inset. + */ + private float topInset; + + /** + * The bottom inset. + */ + private float bottomInset; + + /** + * The left inset. + */ + private float leftInset; + + /** + * Indicates if the major span should be treated as beeing estimated or not. + */ + private boolean estimatedMajorSpan; + + /** + * The right inset. + */ + private float rightInset; + + /** + * The children and their layout statistics. + */ + private ArrayList childStates; + + /** + * The currently changing child state. May be null if there is no child state + * updating at the moment. This is package private to avoid a synthetic + * accessor method inside ChildState. + */ + ChildState changing; + + /** + * Represents the minimum requirements. This is used in + * {@link #getMinimumSpan(int)}. + */ + ChildState minReq; + + /** + * Represents the minimum requirements. This is used in + * {@link #getPreferredSpan(int)}. + */ + ChildState prefReq; + + /** + * Indicates that the major axis requirements have changed. + */ + private boolean majorChanged; + + /** + * Indicates that the minor axis requirements have changed. This is package + * private to avoid synthetic accessor method. + */ + boolean minorChanged; + + /** + * The current span along the major layout axis. This is package private to + * avoid synthetic accessor method. + */ + float majorSpan; + + /** + * The current span along the minor layout axis. This is package private to + * avoid synthetic accessor method. + */ + float minorSpan; + + /** + * This tasked is placed on the layout queue to flush updates up to the + * parent view. + */ + private Runnable flushTask; + + /** + * The child locator for this view. + */ + protected ChildLocator locator; + + /** + * Creates a new <code>AsyncBoxView</code> that represents the specified + * element and layouts its children along the specified axis. + * + * @param elem the element + * @param axis the layout axis + */ + public AsyncBoxView(Element elem, int axis) + { + super(elem); + majorAxis = axis; + childStates = new ArrayList(); + flushTask = new FlushTask(); + locator = new ChildLocator(); + minorSpan = Short.MAX_VALUE; + } + + /** + * Returns the major layout axis. + * + * @return the major layout axis + */ + public int getMajorAxis() + { + return majorAxis; + } + + /** + * Returns the minor layout axis, that is the axis orthogonal to the major + * layout axis. + * + * @return the minor layout axis + */ + public int getMinorAxis() + { + return majorAxis == X_AXIS ? Y_AXIS : X_AXIS; + } + + /** + * Returns the view at the specified <code>index</code>. + * + * @param index the index of the requested child view + * + * @return the view at the specified <code>index</code> + */ + public View getView(int index) + { + View view = null; + synchronized(childStates) + { + if ((index >= 0) && (index < childStates.size())) + { + ChildState cs = (ChildState) childStates.get(index); + view = cs.getChildView(); + } + } + return view; + } + + /** + * Returns the number of child views. + * + * @return the number of child views + */ + public int getViewCount() + { + synchronized(childStates) + { + return childStates.size(); + } + } + + /** + * Returns the view index of the child view that represents the specified + * model position. + * + * @param pos the model position for which we search the view index + * @param bias the bias + * + * @return the view index of the child view that represents the specified + * model position + */ + public int getViewIndex(int pos, Position.Bias bias) + { + int retVal = -1; + + if (bias == Position.Bias.Backward) + pos = Math.max(0, pos - 1); + + // TODO: A possible optimization would be to implement a binary search + // here. + int numChildren = childStates.size(); + if (numChildren > 0) + { + for (int i = 0; i < numChildren; ++i) + { + View child = ((ChildState) childStates.get(i)).getChildView(); + if (child.getStartOffset() <= pos && child.getEndOffset() > pos) + { + retVal = i; + break; + } + } + } + return retVal; + } + + /** + * Returns the top inset. + * + * @return the top inset + */ + public float getTopInset() + { + return topInset; + } + + /** + * Sets the top inset. + * + * @param top the top inset + */ + public void setTopInset(float top) + { + topInset = top; + } + + /** + * Returns the bottom inset. + * + * @return the bottom inset + */ + public float getBottomInset() + { + return bottomInset; + } + + /** + * Sets the bottom inset. + * + * @param bottom the bottom inset + */ + public void setBottomInset(float bottom) + { + bottomInset = bottom; + } + + /** + * Returns the left inset. + * + * @return the left inset + */ + public float getLeftInset() + { + return leftInset; + } + + /** + * Sets the left inset. + * + * @param left the left inset + */ + public void setLeftInset(float left) + { + leftInset = left; + } + + /** + * Returns the right inset. + * + * @return the right inset + */ + public float getRightInset() + { + return rightInset; + } + + /** + * Sets the right inset. + * + * @param right the right inset + */ + public void setRightInset(float right) + { + rightInset = right; + } + + /** + * Loads the child views of this view. This is triggered by + * {@link #setParent(View)}. + * + * @param f the view factory to build child views with + */ + protected void loadChildren(ViewFactory f) + { + Element e = getElement(); + int n = e.getElementCount(); + if (n > 0) + { + View[] added = new View[n]; + for (int i = 0; i < n; i++) + { + added[i] = f.create(e.getElement(i)); + } + replace(0, 0, added); + } + } + + /** + * Returns the span along an axis that is taken up by the insets. + * + * @param axis the axis + * + * @return the span along an axis that is taken up by the insets + * + * @since 1.4 + */ + protected float getInsetSpan(int axis) + { + float span; + if (axis == X_AXIS) + span = leftInset + rightInset; + else + span = topInset + bottomInset; + return span; + } + + /** + * Sets the <code>estimatedMajorSpan</code> property that determines if + * the major span should be treated as beeing estimated. + * + * @param estimated if the major span should be treated as estimated or not + * + * @since 1.4 + */ + public void setEstimatedMajorSpan(boolean estimated) + { + estimatedMajorSpan = estimated; + } + + /** + * Determines whether the major span should be treated as estimated or as + * beeing accurate. + * + * @return <code>true</code> if the major span should be treated as + * estimated, <code>false</code> if the major span should be treated + * as accurate + * + * @since 1.4 + */ + public boolean getEstimatedMajorSpan() + { + return estimatedMajorSpan; + } + + /** + * Receives notification from the child states that the requirements along + * the minor axis have changed. + * + * @param cs the child state from which this notification is messaged + */ + protected synchronized void minorRequirementChange(ChildState cs) + { + minorChanged = true; + } + + /** + * Receives notification from the child states that the requirements along + * the major axis have changed. + * + * @param cs the child state from which this notification is messaged + */ + protected void majorRequirementChange(ChildState cs, float delta) + { + if (! estimatedMajorSpan) + majorSpan += delta; + majorChanged = true; + } + + /** + * Sets the parent for this view. This calls loadChildren if + * <code>parent</code> is not <code>null</code> and there have not been any + * child views initializes. + * + * @param parent the new parent view; <code>null</code> if this view is + * removed from the view hierarchy + * + * @see View#setParent(View) + */ + public void setParent(View parent) + { + super.setParent(parent); + if ((parent != null) && (getViewCount() == 0)) + { + ViewFactory f = getViewFactory(); + loadChildren(f); + } + } + + /** + * Sets the size of this view. This is ususally called before {@link #paint} + * is called to make sure the view has a valid layout. + * + * This implementation queues layout requests for every child view if the + * minor axis span has changed. (The major axis span is requested to never + * change for this view). + * + * @param width the width of the view + * @param height the height of the view + */ + public void setSize(float width, float height) + { + float targetSpan; + if (majorAxis == X_AXIS) + targetSpan = height - getTopInset() - getBottomInset(); + else + targetSpan = width - getLeftInset() - getRightInset(); + + if (targetSpan != minorSpan) + { + minorSpan = targetSpan; + + int n = getViewCount(); + LayoutQueue q = getLayoutQueue(); + for (int i = 0; i < n; i++) + { + ChildState cs = getChildState(i); + cs.childSizeValid = false; + q.addTask(cs); + } + q.addTask(flushTask); + } + } + + /** + * Replaces child views with new child views. + * + * This creates ChildState objects for all the new views and adds layout + * requests for them to the layout queue. + * + * @param offset the offset at which to remove/insert + * @param length the number of child views to remove + * @param views the new child views to insert + */ + public void replace(int offset, int length, View[] views) + { + synchronized(childStates) + { + LayoutQueue q = getLayoutQueue(); + for (int i = 0; i < length; i++) + childStates.remove(offset); + + for (int i = views.length - 1; i >= 0; i--) + childStates.add(offset, createChildState(views[i])); + + // We need to go through the new child states _after_ they have been + // added to the childStates list, otherwise the layout tasks may find + // an incomplete child list. That means we have to loop through + // them again, but what else can we do? + if (views.length != 0) + { + for (int i = 0; i < views.length; i++) + { + ChildState cs = (ChildState) childStates.get(i + offset); + cs.getChildView().setParent(this); + q.addTask(cs); + } + q.addTask(flushTask); + } + } + } + + /** + * Paints the view. This requests the {@link ChildLocator} to paint the views + * after setting the allocation on it. + * + * @param g the graphics context to use + * @param s the allocation for this view + */ + public void paint(Graphics g, Shape s) + { + synchronized (locator) + { + locator.setAllocation(s); + locator.paintChildren(g); + } + } + + /** + * Returns the preferred span of this view along the specified layout axis. + * + * @return the preferred span of this view along the specified layout axis + */ + public float getPreferredSpan(int axis) + { + float retVal; + if (majorAxis == axis) + retVal = majorSpan; + + else if (prefReq != null) + { + View child = prefReq.getChildView(); + retVal = child.getPreferredSpan(axis); + } + + // If we have no layout information yet, then return insets + 30 as + // an estimation. + else + { + if (axis == X_AXIS) + retVal = getLeftInset() + getRightInset() + 30; + else + retVal = getTopInset() + getBottomInset() + 30; + } + return retVal; + } + + /** + * Maps a model location to view coordinates. + * + * @param pos the model location + * @param a the current allocation of this view + * @param b the bias + * + * @return the view allocation for the specified model location + */ + public Shape modelToView(int pos, Shape a, Bias b) + throws BadLocationException + { + int index = getViewIndexAtPosition(pos, b); + Shape ca = locator.getChildAllocation(index, a); + + ChildState cs = getChildState(index); + synchronized (cs) + { + View cv = cs.getChildView(); + Shape v = cv.modelToView(pos, ca, b); + return v; + } + } + + /** + * Maps view coordinates to a model location. + * + * @param x the x coordinate (relative to <code>a</code>) + * @param y the y coordinate (relative to <code>a</code>) + * @param b holds the bias of the model location on method exit + * + * @return the model location for the specified view location + */ + public int viewToModel(float x, float y, Shape a, Bias[] b) + { + int pos; + int index; + Shape ca; + + synchronized (locator) + { + index = locator.getViewIndexAtPoint(x, y, a); + ca = locator.getChildAllocation(index, a); + } + + ChildState cs = getChildState(index); + synchronized (cs) + { + View v = cs.getChildView(); + pos = v.viewToModel(x, y, ca, b); + } + return pos; + } + + /** + * Returns the child allocation for the child view with the specified + * <code>index</code>. + * + * @param index the index of the child view + * @param a the current allocation of this view + * + * @return the allocation of the child view + */ + public Shape getChildAllocation(int index, Shape a) + { + Shape ca = locator.getChildAllocation(index, a); + return ca; + } + + /** + * Returns the maximum span of this view along the specified axis. + * This is implemented to return the <code>preferredSpan</code> for the + * major axis (that means the box can't be resized along the major axis) and + * {@link Short#MAX_VALUE} for the minor axis. + * + * @param axis the axis + * + * @return the maximum span of this view along the specified axis + */ + public float getMaximumSpan(int axis) + { + float max; + if (axis == majorAxis) + max = getPreferredSpan(axis); + else + max = Short.MAX_VALUE; + return max; + } + + /** + * Returns the minimum span along the specified axis. + */ + public float getMinimumSpan(int axis) + { + float min; + if (axis == majorAxis) + min = getPreferredSpan(axis); + else + { + if (minReq != null) + { + View child = minReq.getChildView(); + min = child.getMinimumSpan(axis); + } + else + { + // No layout information yet. Return insets + 5 as some kind of + // estimation. + if (axis == X_AXIS) + min = getLeftInset() + getRightInset() + 5; + else + min = getTopInset() + getBottomInset() + 5; + } + } + return min; + } + + /** + * Receives notification that one of the child views has changed its + * layout preferences along one or both axis. + * + * This queues a layout request for that child view if necessary. + * + * @param view the view that has changed its preferences + * @param width <code>true</code> if the width preference has changed + * @param height <code>true</code> if the height preference has changed + */ + public synchronized void preferenceChanged(View view, boolean width, + boolean height) + { + if (view == null) + getParent().preferenceChanged(this, width, height); + else + { + if (changing != null) + { + View cv = changing.getChildView(); + if (cv == view) + { + changing.preferenceChanged(width, height); + return; + } + } + int index = getViewIndexAtPosition(view.getStartOffset(), + Position.Bias.Forward); + ChildState cs = getChildState(index); + cs.preferenceChanged(width, height); + LayoutQueue q = getLayoutQueue(); + q.addTask(cs); + q.addTask(flushTask); + } + } + + /** + * Updates the layout for this view. This is implemented to trigger + * {link ChildLocator#childChanged} for the changed view, if there is + * any. + * + * @param ec the element change, may be <code>null</code> if there were + * no changes to the element of this view + * @param e the document event + * @param a the current allocation of this view + */ + protected void updateLayout(DocumentEvent.ElementChange ec, + DocumentEvent e, Shape a) + { + if (ec != null) + { + int index = Math.max(ec.getIndex() - 1, 0); + ChildState cs = getChildState(index); + locator.childChanged(cs); + } + } + + + /** + * Returns the <code>ChildState</code> object associated with the child view + * at the specified <code>index</code>. + * + * @param index the index of the child view for which to query the state + * + * @return the child state for the specified child view + */ + protected ChildState getChildState(int index) { + synchronized (childStates) + { + return (ChildState) childStates.get(index); + } + } + + /** + * Returns the <code>LayoutQueue</code> used for layouting the box view. + * This simply returns {@link LayoutQueue#getDefaultQueue()}. + * + * @return the <code>LayoutQueue</code> used for layouting the box view + */ + protected LayoutQueue getLayoutQueue() + { + return LayoutQueue.getDefaultQueue(); + } + + /** + * Returns the child view index of the view that represents the specified + * position in the document model. + * + * @param pos the position in the model + * @param b the bias + * + * @return the child view index of the view that represents the specified + * position in the document model + */ + protected synchronized int getViewIndexAtPosition(int pos, Position.Bias b) + { + if (b == Position.Bias.Backward) + pos = Math.max(0, pos - 1); + Element elem = getElement(); + return elem.getElementIndex(pos); + } + + /** + * Creates a <code>ChildState</code> object for the specified view. + * + * @param v the view for which to create a child state object + * + * @return the created child state + */ + protected ChildState createChildState(View v) + { + return new ChildState(v); + } + + /** + * Flushes the requirements changes upwards to the parent view. This is + * called from the layout thread. + */ + protected synchronized void flushRequirementChanges() + { + if (majorChanged || minorChanged) + { + View p = getParent(); + if (p != null) + { + boolean horizontal; + boolean vertical; + if (majorAxis == X_AXIS) + { + horizontal = majorChanged; + vertical = minorChanged; + } + else + { + vertical = majorChanged; + horizontal = minorChanged; + } + + p.preferenceChanged(this, horizontal, vertical); + majorChanged = false; + minorChanged = false; + + Component c = getContainer(); + if (c != null) + c.repaint(); + } + } + } +} diff --git a/libjava/classpath/javax/swing/text/BoxView.java b/libjava/classpath/javax/swing/text/BoxView.java index 5c9587dfe5d..b5907dcbbe6 100644 --- a/libjava/classpath/javax/swing/text/BoxView.java +++ b/libjava/classpath/javax/swing/text/BoxView.java @@ -43,6 +43,7 @@ import java.awt.Rectangle; import java.awt.Shape; import javax.swing.SizeRequirements; +import javax.swing.event.DocumentEvent; /** * An implementation of {@link CompositeView} that arranges its children in @@ -58,49 +59,37 @@ public class BoxView /** * The axis along which this <code>BoxView</code> is laid out. */ - int myAxis; + private int myAxis; /** - * Indicates wether the layout in X_AXIS is valid. + * Indicates if the layout is valid along X_AXIS or Y_AXIS. */ - boolean xLayoutValid; + private boolean[] layoutValid = new boolean[2]; /** - * Indicates whether the layout in Y_AXIS is valid. + * The spans along the X_AXIS and Y_AXIS. */ - boolean yLayoutValid; + private int[][] spans = new int[2][]; /** - * The spans in X direction of the children. + * The offsets of the children along the X_AXIS and Y_AXIS. */ - int[] spansX; + private int[][] offsets = new int[2][]; /** - * The spans in Y direction of the children. + * The size requirements along the X_AXIS and Y_AXIS. */ - int[] spansY; + private SizeRequirements[] requirements = new SizeRequirements[2]; /** - * The offsets of the children in X direction relative to this BoxView's - * inner bounds. + * The current span along X_AXIS or Y_AXIS. */ - int[] offsetsX; + private int[] span = new int[2]; /** - * The offsets of the children in Y direction relative to this BoxView's - * inner bounds. + * The SizeRequirements of the child views along the X_AXIS and Y_AXIS. */ - int[] offsetsY; - - /** - * The current width. - */ - int width; - - /** - * The current height. - */ - int height; + private SizeRequirements[][] childReqs = new SizeRequirements[2][]; /** * Creates a new <code>BoxView</code> for the given @@ -114,23 +103,26 @@ public class BoxView { super(element); myAxis = axis; - xLayoutValid = false; - yLayoutValid = false; + layoutValid[0] = false; + layoutValid[1] = false; + span[0] = 0; + span[1] = 0; + requirements[0] = new SizeRequirements(); + requirements[1] = new SizeRequirements(); // Initialize the cache arrays. - spansX = new int[0]; - spansY = new int[0]; - offsetsX = new int[0]; - offsetsY = new int[0]; - - width = 0; - height = 0; + spans[0] = new int[0]; + spans[1] = new int[0]; + offsets[0] = new int[0]; + offsets[1] = new int[0]; } /** * Returns the axis along which this <code>BoxView</code> is laid out. * * @return the axis along which this <code>BoxView</code> is laid out + * + * @since 1.3 */ public int getAxis() { @@ -144,6 +136,8 @@ public class BoxView * {@link View#Y_AXIS}. * * @param axis the axis along which this <code>BoxView</code> is laid out + * + * @since 1.3 */ public void setAxis(int axis) { @@ -163,20 +157,14 @@ public class BoxView * {@link View#Y_AXIS}. * * @param axis an <code>int</code> value + * + * @since 1.3 */ public void layoutChanged(int axis) { - switch (axis) - { - case X_AXIS: - xLayoutValid = false; - break; - case Y_AXIS: - yLayoutValid = false; - break; - default: - throw new IllegalArgumentException("Invalid axis parameter."); - } + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Invalid axis parameter."); + layoutValid[axis] = false; } /** @@ -190,22 +178,14 @@ public class BoxView * * @return <code>true</code> if the layout along the specified * <code>axis</code> is valid, <code>false</code> otherwise + * + * @since 1.4 */ protected boolean isLayoutValid(int axis) { - boolean valid = false; - switch (axis) - { - case X_AXIS: - valid = xLayoutValid; - break; - case Y_AXIS: - valid = yLayoutValid; - break; - default: - throw new IllegalArgumentException("Invalid axis parameter."); - } - return valid; + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Invalid axis parameter."); + return layoutValid[axis]; } /** @@ -242,40 +222,44 @@ public class BoxView */ public void replace(int offset, int length, View[] views) { + int numViews = 0; + if (views != null) + numViews = views.length; + // Resize and copy data for cache arrays. // The spansX cache. int oldSize = getViewCount(); - int[] newSpansX = new int[oldSize - length + views.length]; - System.arraycopy(spansX, 0, newSpansX, 0, offset); - System.arraycopy(spansX, offset + length, newSpansX, - offset + views.length, + int[] newSpansX = new int[oldSize - length + numViews]; + System.arraycopy(spans[X_AXIS], 0, newSpansX, 0, offset); + System.arraycopy(spans[X_AXIS], offset + length, newSpansX, + offset + numViews, oldSize - (offset + length)); - spansX = newSpansX; + spans[X_AXIS] = newSpansX; // The spansY cache. - int[] newSpansY = new int[oldSize - length + views.length]; - System.arraycopy(spansY, 0, newSpansY, 0, offset); - System.arraycopy(spansY, offset + length, newSpansY, - offset + views.length, + int[] newSpansY = new int[oldSize - length + numViews]; + System.arraycopy(spans[Y_AXIS], 0, newSpansY, 0, offset); + System.arraycopy(spans[Y_AXIS], offset + length, newSpansY, + offset + numViews, oldSize - (offset + length)); - spansY = newSpansY; + spans[Y_AXIS] = newSpansY; // The offsetsX cache. - int[] newOffsetsX = new int[oldSize - length + views.length]; - System.arraycopy(offsetsX, 0, newOffsetsX, 0, offset); - System.arraycopy(offsetsX, offset + length, newOffsetsX, - offset + views.length, + int[] newOffsetsX = new int[oldSize - length + numViews]; + System.arraycopy(offsets[X_AXIS], 0, newOffsetsX, 0, offset); + System.arraycopy(offsets[X_AXIS], offset + length, newOffsetsX, + offset + numViews, oldSize - (offset + length)); - offsetsX = newOffsetsX; + offsets[X_AXIS] = newOffsetsX; // The offsetsY cache. - int[] newOffsetsY = new int[oldSize - length + views.length]; - System.arraycopy(offsetsY, 0, newOffsetsY, 0, offset); - System.arraycopy(offsetsY, offset + length, newOffsetsY, - offset + views.length, + int[] newOffsetsY = new int[oldSize - length + numViews]; + System.arraycopy(offsets[Y_AXIS], 0, newOffsetsY, 0, offset); + System.arraycopy(offsets[Y_AXIS], offset + length, newOffsetsY, + offset + numViews, oldSize - (offset + length)); - offsetsY = newOffsetsY; + offsets[Y_AXIS] = newOffsetsY; // Actually perform the replace. super.replace(offset, length, views); @@ -294,13 +278,10 @@ public class BoxView */ public void paint(Graphics g, Shape a) { - // Adjust size if the size is changed. - Rectangle bounds = a.getBounds(); - - if (bounds.width != getWidth() || bounds.height != getHeight()) - setSize(bounds.width, bounds.height); - Rectangle inside = getInsideAllocation(a); + // TODO: Used for debugging. + //g.drawRect(inside.x, inside.y, inside.width, inside.height); + Rectangle copy = new Rectangle(inside); int count = getViewCount(); for (int i = 0; i < count; ++i) @@ -323,22 +304,50 @@ public class BoxView */ public float getPreferredSpan(int axis) { - SizeRequirements sr = new SizeRequirements(); - int pref = baselineRequirements(axis, sr).preferred; - return (float) pref; + updateRequirements(axis); + return requirements[axis].preferred; } + /** + * Returns the maximum span of this view along the specified axis. + * This returns <code>Integer.MAX_VALUE</code> for the minor axis + * and the preferred span for the major axis. + * + * @param axis the axis + * + * @return the maximum span of this view along the specified axis + */ public float getMaximumSpan(int axis) { - if (axis == getAxis()) - return getPreferredSpan(axis); + float max; + if (axis == myAxis) + max = getPreferredSpan(axis); else - return Integer.MAX_VALUE; + max = Integer.MAX_VALUE; + return max; } /** - * Calculates the size requirements for this <code>BoxView</code> along - * the specified axis. + * Returns the minimum span of this view along the specified axis. + * This calculates the minimum span using + * {@link #calculateMajorAxisRequirements} or + * {@link #calculateMinorAxisRequirements} (depending on the axis) and + * returns the resulting minimum span. + * + * @param axis the axis + * + * @return the minimum span of this view along the specified axis + */ + public float getMinimumSpan(int axis) + { + updateRequirements(axis); + return requirements[axis].minimum; + } + + /** + * This method is obsolete and no longer in use. It is replaced by + * {@link #calculateMajorAxisRequirements(int, SizeRequirements)} and + * {@link #calculateMinorAxisRequirements(int, SizeRequirements)}. * * @param axis the axis that is examined * @param sr the <code>SizeRequirements</code> object to hold the result, @@ -350,12 +359,45 @@ public class BoxView protected SizeRequirements baselineRequirements(int axis, SizeRequirements sr) { - SizeRequirements result; - if (axis == myAxis) - result = calculateMajorAxisRequirements(axis, sr); - else - result = calculateMinorAxisRequirements(axis, sr); - return result; + updateChildRequirements(axis); + + SizeRequirements res = sr; + if (res == null) + res = new SizeRequirements(); + + float minLeft = 0; + float minRight = 0; + float prefLeft = 0; + float prefRight = 0; + float maxLeft = 0; + float maxRight = 0; + for (int i = 0; i < childReqs[axis].length; i++) + { + float myMinLeft = childReqs[axis][i].minimum * childReqs[axis][i].alignment; + float myMinRight = childReqs[axis][i].minimum - myMinLeft; + minLeft = Math.max(myMinLeft, minLeft); + minRight = Math.max(myMinRight, minRight); + float myPrefLeft = childReqs[axis][i].preferred * childReqs[axis][i].alignment; + float myPrefRight = childReqs[axis][i].preferred - myPrefLeft; + prefLeft = Math.max(myPrefLeft, prefLeft); + prefRight = Math.max(myPrefRight, prefRight); + float myMaxLeft = childReqs[axis][i].maximum * childReqs[axis][i].alignment; + float myMaxRight = childReqs[axis][i].maximum - myMaxLeft; + maxLeft = Math.max(myMaxLeft, maxLeft); + maxRight = Math.max(myMaxRight, maxRight); + } + int minSize = (int) (minLeft + minRight); + int prefSize = (int) (prefLeft + prefRight); + int maxSize = (int) (maxLeft + maxRight); + float align = prefLeft / (prefRight + prefLeft); + if (Float.isNaN(align)) + align = 0; + + res.alignment = align; + res.maximum = maxSize; + res.preferred = prefSize; + res.minimum = minSize; + return res; } /** @@ -370,10 +412,13 @@ public class BoxView protected void baselineLayout(int span, int axis, int[] offsets, int[] spans) { - if (axis == myAxis) - layoutMajorAxis(span, axis, offsets, spans); - else - layoutMinorAxis(span, axis, offsets, spans); + updateChildRequirements(axis); + updateRequirements(axis); + + // Calculate the spans and offsets using the SizeRequirements uility + // methods. + SizeRequirements.calculateAlignedPositions(span, requirements[axis], + childReqs[axis], offsets, spans); } /** @@ -390,8 +435,34 @@ public class BoxView protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements sr) { - SizeRequirements[] childReqs = getChildRequirements(axis); - return SizeRequirements.getTiledSizeRequirements(childReqs); + updateChildRequirements(axis); + + SizeRequirements result = sr; + if (result == null) + result = new SizeRequirements(); + + long minimum = 0; + long preferred = 0; + long maximum = 0; + for (int i = 0; i < children.length; i++) + { + minimum += childReqs[axis][i].minimum; + preferred += childReqs[axis][i].preferred; + maximum += childReqs[axis][i].maximum; + } + // Overflow check. + if (minimum > Integer.MAX_VALUE) + minimum = Integer.MAX_VALUE; + if (preferred > Integer.MAX_VALUE) + preferred = Integer.MAX_VALUE; + if (maximum > Integer.MAX_VALUE) + maximum = Integer.MAX_VALUE; + + result.minimum = (int) minimum; + result.preferred = (int) preferred; + result.maximum = (int) maximum; + result.alignment = 0.5F; + return result; } /** @@ -407,11 +478,49 @@ public class BoxView * the specified axis */ protected SizeRequirements calculateMinorAxisRequirements(int axis, - SizeRequirements sr) + SizeRequirements sr) { - SizeRequirements[] childReqs = getChildRequirements(axis); - return SizeRequirements.getAlignedSizeRequirements(childReqs); + updateChildRequirements(axis); + + SizeRequirements res = sr; + if (res == null) + res = new SizeRequirements(); + + float minLeft = 0; + float minRight = 0; + float prefLeft = 0; + float prefRight = 0; + float maxLeft = 0; + float maxRight = 0; + for (int i = 0; i < childReqs[axis].length; i++) + { + float myMinLeft = childReqs[axis][i].minimum * childReqs[axis][i].alignment; + float myMinRight = childReqs[axis][i].minimum - myMinLeft; + minLeft = Math.max(myMinLeft, minLeft); + minRight = Math.max(myMinRight, minRight); + float myPrefLeft = childReqs[axis][i].preferred * childReqs[axis][i].alignment; + float myPrefRight = childReqs[axis][i].preferred - myPrefLeft; + prefLeft = Math.max(myPrefLeft, prefLeft); + prefRight = Math.max(myPrefRight, prefRight); + float myMaxLeft = childReqs[axis][i].maximum * childReqs[axis][i].alignment; + float myMaxRight = childReqs[axis][i].maximum - myMaxLeft; + maxLeft = Math.max(myMaxLeft, maxLeft); + maxRight = Math.max(myMaxRight, maxRight); + } + int minSize = (int) (minLeft + minRight); + int prefSize = (int) (prefLeft + prefRight); + int maxSize = (int) (maxLeft + maxRight); + float align = prefLeft / (prefRight + prefLeft); + if (Float.isNaN(align)) + align = 0; + + res.alignment = align; + res.maximum = maxSize; + res.preferred = prefSize; + res.minimum = minSize; + return res; } + /** * Returns <code>true</code> if the specified point lies before the @@ -511,10 +620,10 @@ public class BoxView if (! isAllocationValid()) layout(a.width, a.height); - a.x += offsetsX[index]; - a.y += offsetsY[index]; - a.width = spansX[index]; - a.height = spansY[index]; + a.x += offsets[X_AXIS][index]; + a.y += offsets[Y_AXIS][index]; + a.width = spans[X_AXIS][index]; + a.height = spans[Y_AXIS][index]; } /** @@ -528,8 +637,49 @@ public class BoxView */ protected void layout(int width, int height) { - baselineLayout(width, X_AXIS, offsetsX, spansX); - baselineLayout(height, Y_AXIS, offsetsY, spansY); + int[] newSpan = new int[]{ width, height }; + int count = getViewCount(); + + // Update minor axis as appropriate. We need to first update the minor + // axis layout because that might affect the children's preferences along + // the major axis. + int minorAxis = myAxis == X_AXIS ? Y_AXIS : X_AXIS; + if ((! isLayoutValid(minorAxis)) || newSpan[minorAxis] != span[minorAxis]) + { + layoutValid[minorAxis] = false; + span[minorAxis] = newSpan[minorAxis]; + layoutMinorAxis(span[minorAxis], minorAxis, offsets[minorAxis], + spans[minorAxis]); + + // Update the child view's sizes. + for (int i = 0; i < count; ++i) + { + getView(i).setSize(spans[X_AXIS][i], spans[Y_AXIS][i]); + } + layoutValid[minorAxis] = true; + } + + + // Update major axis as appropriate. + if ((! isLayoutValid(myAxis)) || newSpan[myAxis] != span[myAxis]) + { + layoutValid[myAxis] = false; + span[myAxis] = newSpan[myAxis]; + layoutMajorAxis(span[myAxis], myAxis, offsets[myAxis], + spans[myAxis]); + + // Update the child view's sizes. + for (int i = 0; i < count; ++i) + { + getView(i).setSize(spans[X_AXIS][i], spans[Y_AXIS][i]); + } + layoutValid[myAxis] = true; + } + + if (layoutValid[myAxis] == false) + System.err.println("WARNING: Major axis layout must be valid after layout"); + if (layoutValid[minorAxis] == false) + System.err.println("Minor axis layout must be valid after layout"); } /** @@ -544,12 +694,15 @@ public class BoxView protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { - SizeRequirements[] childReqs = getChildRequirements(axis); + updateChildRequirements(axis); + updateRequirements(axis); + // Calculate the spans and offsets using the SizeRequirements uility // methods. - SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs, + SizeRequirements.calculateTiledPositions(targetSpan, requirements[axis], + childReqs[axis], offsets, spans); - validateLayout(axis); + } /** @@ -564,18 +717,14 @@ public class BoxView protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { - SizeRequirements[] childReqs = getChildRequirements(axis); + updateChildRequirements(axis); + updateRequirements(axis); + // Calculate the spans and offsets using the SizeRequirements uility // methods. - // TODO: This might be an opportunity for performance optimization. Here - // we could use a cached instance of SizeRequirements instead of passing - // null to baselineRequirements. However, this would involve rewriting - // the baselineRequirements() method to not use the SizeRequirements - // utility method, since they cannot reuse a cached instance. - SizeRequirements total = baselineRequirements(axis, null); - SizeRequirements.calculateAlignedPositions(targetSpan, total, childReqs, - offsets, spans); - validateLayout(axis); + SizeRequirements.calculateAlignedPositions(targetSpan, requirements[axis], + childReqs[axis], offsets, + spans); } /** @@ -597,7 +746,7 @@ public class BoxView */ public int getWidth() { - return width; + return span[X_AXIS]; } /** @@ -607,7 +756,7 @@ public class BoxView */ public int getHeight() { - return height; + return span[Y_AXIS]; } /** @@ -619,54 +768,7 @@ public class BoxView */ public void setSize(float width, float height) { - if (this.width != (int) width) - layoutChanged(X_AXIS); - if (this.height != (int) height) - layoutChanged(Y_AXIS); - - this.width = (int) width; - this.height = (int) height; - - Rectangle outside = new Rectangle(0, 0, this.width, this.height); - Rectangle inside = getInsideAllocation(outside); - if (!isAllocationValid()) - layout(inside.width, inside.height); - } - - /** - * Sets the layout to valid for a specific axis. - * - * @param axis the axis for which to validate the layout - */ - void validateLayout(int axis) - { - if (axis == X_AXIS) - xLayoutValid = true; - if (axis == Y_AXIS) - yLayoutValid = true; - } - - /** - * Returns the size requirements of this view's children for the major - * axis. - * - * @return the size requirements of this view's children for the major - * axis - */ - SizeRequirements[] getChildRequirements(int axis) - { - // Allocate SizeRequirements for each child view. - int count = getViewCount(); - SizeRequirements[] childReqs = new SizeRequirements[count]; - for (int i = 0; i < count; ++i) - { - View view = getView(i); - childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis), - (int) view.getPreferredSpan(axis), - (int) view.getMaximumSpan(axis), - view.getAlignment(axis)); - } - return childReqs; + layout((int) width, (int) height); } /** @@ -682,10 +784,9 @@ public class BoxView */ protected int getSpan(int axis, int childIndex) { - if (axis == X_AXIS) - return spansX[childIndex]; - else - return spansY[childIndex]; + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Illegal axis argument"); + return spans[axis][childIndex]; } /** @@ -701,10 +802,9 @@ public class BoxView */ protected int getOffset(int axis, int childIndex) { - if (axis == X_AXIS) - return offsetsX[childIndex]; - else - return offsetsY[childIndex]; + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Illegal axis argument"); + return offsets[axis][childIndex]; } /** @@ -719,10 +819,15 @@ public class BoxView */ public float getAlignment(int axis) { + float align; if (axis == myAxis) - return 0.5F; + align = 0.5F; else - return baselineRequirements(axis, null).alignment; + { + updateRequirements(axis); + align = requirements[axis].alignment; + } + return align; } /** @@ -732,12 +837,12 @@ public class BoxView * @param height indicates that the preferred height of the child changed. * @param child the child View. */ - public void preferenceChanged (View child, boolean width, boolean height) + public void preferenceChanged(View child, boolean width, boolean height) { if (width) - xLayoutValid = false; + layoutValid[X_AXIS] = false; if (height) - yLayoutValid = false; + layoutValid[Y_AXIS] = false; super.preferenceChanged(child, width, height); } @@ -751,11 +856,118 @@ public class BoxView throws BadLocationException { // Make sure everything is allocated properly and then call super - if (!isAllocationValid()) + if (! isAllocationValid()) { Rectangle bounds = a.getBounds(); - setSize(bounds.width, bounds.height); + layout(bounds.width, bounds.height); } return super.modelToView(pos, a, bias); } + + /** + * Returns the resize weight of this view. A value of <code>0</code> or less + * means this view is not resizeable. Positive values make the view + * resizeable. This implementation returns <code>0</code> for the major + * axis and <code>1</code> for the minor axis of this box view. + * + * @param axis the axis + * + * @return the resizability of this view along the specified axis + * + * @throws IllegalArgumentException if <code>axis</code> is invalid + */ + public int getResizeWeight(int axis) + { + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Illegal axis argument"); + int weight = 1; + if (axis == myAxis) + weight = 0; + return weight; + } + + /** + * Returns the child allocation for the child view with the specified + * <code>index</code>. If the layout is invalid, this returns + * <code>null</code>. + * + * @param index the child view index + * @param a the allocation to this view + * + * @return the child allocation for the child view with the specified + * <code>index</code> or <code>null</code> if the layout is invalid + * or <code>a</code> is null + */ + public Shape getChildAllocation(int index, Shape a) + { + Shape ret = null; + if (isAllocationValid() && a != null) + ret = super.getChildAllocation(index, a); + return ret; + } + + protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e, + Shape a, ViewFactory vf) + { + // FIXME: What to do here? + super.forwardUpdate(ec, e, a, vf); + } + + public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) + { + // FIXME: What to do here? + return super.viewToModel(x, y, a, bias); + } + + protected boolean flipEastAndWestEnds(int position, Position.Bias bias) + { + // FIXME: What to do here? + return super.flipEastAndWestAtEnds(position, bias); + } + + /** + * Updates the child requirements along the specified axis. The requirements + * are only updated if the layout for the specified axis is marked as + * invalid. + * + * @param axis the axis to be updated + */ + private void updateChildRequirements(int axis) + { + if (! isLayoutValid(axis)) + { + int numChildren = getViewCount(); + if (childReqs[axis] == null || childReqs[axis].length != numChildren) + childReqs[axis] = new SizeRequirements[numChildren]; + for (int i = 0; i < numChildren; ++i) + { + View child = getView(i); + childReqs[axis][i] = + new SizeRequirements((int) child.getMinimumSpan(axis), + (int) child.getPreferredSpan(axis), + (int) child.getMaximumSpan(axis), + child.getAlignment(axis)); + } + } + } + + /** + * Updates the view's cached requirements along the specified axis if + * necessary. The requirements are only updated if the layout for the + * specified axis is marked as invalid. + * + * @param axis the axis + */ + private void updateRequirements(int axis) + { + if (! layoutValid[axis]) + { + if (axis == myAxis) + requirements[axis] = calculateMajorAxisRequirements(axis, + requirements[axis]); + else + requirements[axis] = calculateMinorAxisRequirements(axis, + requirements[axis]); + } + } } diff --git a/libjava/classpath/javax/swing/text/ComponentView.java b/libjava/classpath/javax/swing/text/ComponentView.java index 2846f8b536b..a7d237ab73a 100644 --- a/libjava/classpath/javax/swing/text/ComponentView.java +++ b/libjava/classpath/javax/swing/text/ComponentView.java @@ -228,8 +228,9 @@ public class ComponentView extends View * * @param p the parent view to set */ - void setParentImpl(View p) + private void setParentImpl(View p) { + super.setParent(p); if (p != null) { Component c = getComponent(); diff --git a/libjava/classpath/javax/swing/text/CompositeView.java b/libjava/classpath/javax/swing/text/CompositeView.java index cd664521542..a10aca7e625 100644 --- a/libjava/classpath/javax/swing/text/CompositeView.java +++ b/libjava/classpath/javax/swing/text/CompositeView.java @@ -218,20 +218,43 @@ public abstract class CompositeView throws BadLocationException { int childIndex = getViewIndex(pos, bias); + Shape ret = null; if (childIndex != -1) { View child = getView(childIndex); - Rectangle r = a.getBounds(); - childAllocation(childIndex, r); - Shape result = child.modelToView(pos, r, bias); - if (result == null) - throw new AssertionError("" + child.getClass().getName() - + ".modelToView() must not return null"); - return result; + 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 - throw new BadLocationException("No child view for the specified location", - pos); + ret = createDefaultLocation(a, bias); + return ret; + } + + /** + * A helper method for {@link #modelToView(int, Position.Bias, int, + * Position.Bias, Shape)}. This creates a default location when there is + * no child view that can take responsibility for mapping the position to + * view coordinates. Depending on the specified bias this will be the + * left or right edge of this view's allocation. + * + * @param a the allocation for this view + * @param bias the bias + * + * @return a default location + */ + private Shape createDefaultLocation(Shape a, Position.Bias bias) + { + Rectangle alloc = a.getBounds(); + Rectangle location = new Rectangle(alloc.x, alloc.y, 1, alloc.height); + if (bias == Position.Bias.Forward) + location.x = alloc.x + alloc.width; + return location; } /** @@ -350,7 +373,8 @@ public abstract class CompositeView */ public int getViewIndex(int pos, Position.Bias b) { - // FIXME: Handle bias somehow. + if (b == Position.Bias.Backward && pos != 0) + pos -= 1; return getViewIndexAtPosition(pos); } diff --git a/libjava/classpath/javax/swing/text/DefaultCaret.java b/libjava/classpath/javax/swing/text/DefaultCaret.java index 776ef69e5b3..f2a68c00db1 100644 --- a/libjava/classpath/javax/swing/text/DefaultCaret.java +++ b/libjava/classpath/javax/swing/text/DefaultCaret.java @@ -148,14 +148,16 @@ public class DefaultCaret extends Rectangle */ public void removeUpdate(DocumentEvent event) { - if (policy == ALWAYS_UPDATE || - (SwingUtilities.isEventDispatchThread() && - policy == UPDATE_WHEN_ON_EDT)) + if (policy == ALWAYS_UPDATE + || (SwingUtilities.isEventDispatchThread() + && policy == UPDATE_WHEN_ON_EDT)) { int dot = getDot(); setDot(dot - event.getLength()); } - else if (policy == NEVER_UPDATE) + else if (policy == NEVER_UPDATE + || (! SwingUtilities.isEventDispatchThread() + && policy == UPDATE_WHEN_ON_EDT)) { int docLength = event.getDocument().getLength(); if (getDot() > docLength) @@ -364,7 +366,8 @@ public class DefaultCaret extends Rectangle * <ul> * <li>If we receive a double click, the caret position (dot) is set * to the position associated to the mouse click and the word at - * this location is selected.</li> + * this location is selected. If there is no word at the pointer + * the gap is selected instead.</li> * <li>If we receive a triple click, the caret position (dot) is set * to the position associated to the mouse click and the line at * this location is selected.</li> @@ -374,7 +377,50 @@ public class DefaultCaret extends Rectangle */ public void mouseClicked(MouseEvent event) { - // TODO: Implement double- and triple-click behaviour here. + int count = event.getClickCount(); + + if (count >= 2) + { + int newDot = getComponent().viewToModel(event.getPoint()); + JTextComponent t = getComponent(); + + try + { + if (count == 3) + t.select(Utilities.getRowStart(t, newDot), Utilities.getRowEnd(t, newDot)); + else + { + int nextWord = Utilities.getNextWord(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)); + else + { + 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); + // Otherwise select the word under the mouse pointer. + else + t.select(previousWord, previousWordEnd); + } + } + } + catch(BadLocationException ble) + { + // TODO: Swallowing ok here? + } + + dot = newDot; + } + } /** @@ -409,7 +455,10 @@ public class DefaultCaret extends Rectangle */ public void mousePressed(MouseEvent event) { - positionCaret(event); + if (event.isShiftDown()) + moveCaret(event); + else + positionCaret(event); } /** @@ -575,7 +624,39 @@ public class DefaultCaret extends Rectangle { return mark; } - + + private void clearHighlight() + { + Highlighter highlighter = textComponent.getHighlighter(); + + if (highlighter == null) + return; + + if (selectionVisible) + { + try + { + if (highlightEntry == null) + highlightEntry = highlighter.addHighlight(0, 0, getSelectionPainter()); + else + highlighter.changeHighlight(highlightEntry, 0, 0); + } + catch (BadLocationException e) + { + // This should never happen. + throw new InternalError(); + } + } + else + { + if (highlightEntry != null) + { + highlighter.removeHighlight(highlightEntry); + highlightEntry = null; + } + } + } + private void handleHighlight() { Highlighter highlighter = textComponent.getHighlighter(); @@ -586,7 +667,7 @@ public class DefaultCaret extends Rectangle int p0 = Math.min(dot, mark); int p1 = Math.max(dot, mark); - if (selectionVisible && p0 != p1) + if (selectionVisible) { try { @@ -659,7 +740,10 @@ public class DefaultCaret extends Rectangle if (comp == null) return; - int dot = getDot(); + // Make sure the dot has a sane position. + dot = Math.min(dot, textComponent.getDocument().getLength()); + dot = Math.max(dot, 0); + Rectangle rect = null; try @@ -668,10 +752,10 @@ public class DefaultCaret extends Rectangle } catch (BadLocationException e) { - AssertionError ae; - ae = new AssertionError("Unexpected bad caret location: " + dot); - ae.initCause(e); - throw ae; + AssertionError ae; + ae = new AssertionError("Unexpected bad caret location: " + dot); + ae.initCause(e); + throw ae; } if (rect == null) @@ -812,7 +896,11 @@ public class DefaultCaret extends Rectangle { if (dot >= 0) { - this.dot = dot; + Document doc = textComponent.getDocument(); + if (doc != null) + this.dot = Math.min(dot, doc.getLength()); + this.dot = Math.max(this.dot, 0); + handleHighlight(); adjustVisibility(this); appear(); @@ -836,8 +924,9 @@ public class DefaultCaret extends Rectangle if (doc != null) this.dot = Math.min(dot, doc.getLength()); this.dot = Math.max(this.dot, 0); - this.mark = dot; - handleHighlight(); + this.mark = this.dot; + + clearHighlight(); adjustVisibility(this); appear(); } diff --git a/libjava/classpath/javax/swing/text/DefaultEditorKit.java b/libjava/classpath/javax/swing/text/DefaultEditorKit.java index 88094b898f7..c0056963c78 100644 --- a/libjava/classpath/javax/swing/text/DefaultEditorKit.java +++ b/libjava/classpath/javax/swing/text/DefaultEditorKit.java @@ -707,16 +707,14 @@ public class DefaultEditorKit extends EditorKit 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++; - t.setCaretPosition(cur); + 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) { @@ -729,17 +727,16 @@ public class DefaultEditorKit extends EditorKit public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); - try + 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--; - t.setCaretPosition(cur); + 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) { @@ -756,11 +753,17 @@ public class DefaultEditorKit extends EditorKit { try { - int pos = t.getCaret().getDot(); - if (pos < t.getDocument().getEndPosition().getOffset()) - { - t.getDocument().remove(t.getCaret().getDot(), 1); - } + 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) { @@ -778,11 +781,18 @@ public class DefaultEditorKit extends EditorKit { try { - int pos = t.getCaret().getDot(); - if (pos > t.getDocument().getStartPosition().getOffset()) + int pos = t.getSelectionStart(); + int len = t.getSelectionEnd() - pos; + + if (len > 0) + t.getDocument().remove(pos, len); + else if (pos > 0) { - t.getDocument().remove(pos - 1, 1); - t.getCaret().setDot(pos - 1); + pos--; + t.getDocument().remove(pos, 1); + Caret c = t.getCaret(); + c.setDot(pos); + c.setMagicCaretPosition(t.modelToView(pos).getLocation()); } } catch (BadLocationException e) @@ -799,8 +809,21 @@ public class DefaultEditorKit extends EditorKit JTextComponent t = getTextComponent(event); if (t != null) { - t.getCaret().setDot(Math.max(t.getCaret().getDot() - 1, - t.getDocument().getStartPosition().getOffset())); + 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. + } + } } } }, @@ -811,8 +834,74 @@ public class DefaultEditorKit extends EditorKit JTextComponent t = getTextComponent(event); if (t != null) { - t.getCaret().setDot(Math.min(t.getCaret().getDot() + 1, - t.getDocument().getEndPosition().getOffset())); + 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? } } }, @@ -823,8 +912,21 @@ public class DefaultEditorKit extends EditorKit JTextComponent t = getTextComponent(event); if (t != null) { - t.getCaret().moveDot(Math.max(t.getCaret().getDot() - 1, - t.getDocument().getStartPosition().getOffset())); + 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. + } + } } } }, @@ -835,11 +937,167 @@ public class DefaultEditorKit extends EditorKit JTextComponent t = getTextComponent(event); if (t != null) { - t.getCaret().moveDot(Math.min(t.getCaret().getDot() + 1, - t.getDocument().getEndPosition().getOffset())); + 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. + } + } + } }; /** diff --git a/libjava/classpath/javax/swing/text/DefaultFormatter.java b/libjava/classpath/javax/swing/text/DefaultFormatter.java index 493699dacba..e42b1698af8 100644 --- a/libjava/classpath/javax/swing/text/DefaultFormatter.java +++ b/libjava/classpath/javax/swing/text/DefaultFormatter.java @@ -219,7 +219,6 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter commitsOnValidEdit = true; overwriteMode = true; allowsInvalid = true; - valueClass = Object.class; } /** @@ -368,7 +367,11 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter Object value = string; Class valueClass = getValueClass(); if (valueClass == null) - valueClass = getFormattedTextField().getValue().getClass(); + { + JFormattedTextField jft = getFormattedTextField(); + if (jft != null) + valueClass = jft.getValue().getClass(); + } if (valueClass != null) try { diff --git a/libjava/classpath/javax/swing/text/DefaultHighlighter.java b/libjava/classpath/javax/swing/text/DefaultHighlighter.java index 40ea4f80aab..33b5fcab8bf 100644 --- a/libjava/classpath/javax/swing/text/DefaultHighlighter.java +++ b/libjava/classpath/javax/swing/text/DefaultHighlighter.java @@ -1,5 +1,5 @@ /* DefaultHighlighter.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,9 +40,12 @@ package javax.swing.text; import java.awt.Color; import java.awt.Graphics; +import java.awt.Insets; import java.awt.Rectangle; import java.awt.Shape; -import java.util.Vector; +import java.util.ArrayList; + +import javax.swing.plaf.TextUI; public class DefaultHighlighter extends LayeredHighlighter { @@ -84,7 +87,7 @@ public class DefaultHighlighter extends LayeredHighlighter // This should never occur. return; } - + if (r0 == null || r1 == null) return; @@ -100,7 +103,7 @@ public class DefaultHighlighter extends LayeredHighlighter paintHighlight(g, r0); return; } - + // First line, from p0 to end-of-line. r0.width = rect.x + rect.width - r0.x; paintHighlight(g, r0); @@ -109,15 +112,19 @@ public class DefaultHighlighter extends LayeredHighlighter // have the same height -- not a good assumption with JEditorPane/JTextPane). r0.y += r0.height; r0.x = rect.x; - + r0.width = rect.width; + while (r0.y < r1.y) { paintHighlight(g, r0); r0.y += r0.height; } - // Last line, from beginnin-of-line to p1. - paintHighlight(g, r1); + // 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); } public Shape paintLayer(Graphics g, int p0, int p1, Shape bounds, @@ -127,7 +134,7 @@ public class DefaultHighlighter extends LayeredHighlighter } } - private class HighlightEntry + private class HighlightEntry implements Highlighter.Highlight { int p0; int p1; @@ -140,12 +147,12 @@ public class DefaultHighlighter extends LayeredHighlighter this.painter = painter; } - public int getStartPosition() + public int getStartOffset() { return p0; } - public int getEndPosition() + public int getEndOffset() { return p1; } @@ -163,7 +170,7 @@ public class DefaultHighlighter extends LayeredHighlighter new DefaultHighlightPainter(null); private JTextComponent textComponent; - private Vector highlights = new Vector(); + private ArrayList highlights = new ArrayList(); private boolean drawsLayeredHighlights = true; public DefaultHighlighter() @@ -208,12 +215,20 @@ public class DefaultHighlighter extends LayeredHighlighter checkPositions(p0, p1); HighlightEntry entry = new HighlightEntry(p0, p1, painter); highlights.add(entry); + + textComponent.getUI().damageRange(textComponent, p0, p1); + return entry; } public void removeHighlight(Object tag) { highlights.remove(tag); + + HighlightEntry entry = (HighlightEntry) tag; + textComponent.getUI().damageRange(textComponent, + entry.p0, + entry.p1); } public void removeAllHighlights() @@ -223,16 +238,93 @@ public class DefaultHighlighter extends LayeredHighlighter public Highlighter.Highlight[] getHighlights() { - return null; + return (Highlighter.Highlight[]) + highlights.toArray(new Highlighter.Highlight[highlights.size()]); } - public void changeHighlight(Object tag, int p0, int p1) + public void changeHighlight(Object tag, int n0, int n1) throws BadLocationException { - checkPositions(p0, p1); + int o0, o1; + + checkPositions(n0, n1); HighlightEntry entry = (HighlightEntry) tag; - entry.p0 = p0; - entry.p1 = p1; + o0 = entry.p0; + o1 = entry.p1; + + // Prevent useless write & repaint operations. + if (o0 == n0 && o1 == n1) + return; + + entry.p0 = n0; + entry.p1 = n1; + + TextUI ui = textComponent.getUI(); + + // Special situation where the old area has to be cleared simply. + if (n0 == n1) + ui.damageRange(textComponent, o0, o1); + // Calculates the areas where a change is really neccessary + else if ((o1 > n0 && o1 <= n1) + || (n1 > o0 && n1 <= o1)) + { + // [fds, fde) - the first damage region + // [sds, sde] - the second damage region + int fds, sds; + int fde, sde; + + // Calculate first damaged region. + if(o0 < n0) + { + // Damaged region will be cleared as + // the old highlight region starts first. + fds = o0; + fde = n0; + } + else + { + // Damaged region will be painted as + // the new highlight region starts first. + fds = n0; + fde = o0; + } + + if (o1 < n1) + { + // Final region will be painted as the + // old highlight region finishes first + sds = o1; + sde = n1; + } + else + { + // Final region will be cleared as the + // new highlight region finishes first. + sds = n1; + sde = o1; + } + + // If there is no undamaged region in between + // call damageRange only once. + if (fde == sds) + ui.damageRange(textComponent, fds, sde); + else + { + if (fds != fde) + ui.damageRange(textComponent, fds, fde); + + if (sds != sde) + ui.damageRange(textComponent, sds, sde); + } + } + else + { + // The two regions do not overlap. So mark + // both areas as damaged. + ui.damageRange(textComponent, o0, o1); + ui.damageRange(textComponent, n0, n1); + } + } public void paintLayeredHighlights(Graphics g, int p0, int p1, @@ -244,13 +336,21 @@ public class DefaultHighlighter extends LayeredHighlighter public void paint(Graphics g) { + int size = highlights.size(); + // Check if there are any highlights. - if (highlights.size() == 0) + if (size == 0) return; + + // Prepares the rectangle of the inner drawing area. + Insets insets = textComponent.getInsets(); + Shape bounds = + new Rectangle(insets.left, + insets.top, + textComponent.getWidth() - insets.left - insets.right, + textComponent.getHeight() - insets.top - insets.bottom); - Shape bounds = textComponent.getBounds(); - - for (int index = 0; index < highlights.size(); ++index) + for (int index = 0; index < size; ++index) { HighlightEntry entry = (HighlightEntry) highlights.get(index); entry.painter.paint(g, entry.p0, entry.p1, bounds, textComponent); diff --git a/libjava/classpath/javax/swing/text/DefaultStyledDocument.java b/libjava/classpath/javax/swing/text/DefaultStyledDocument.java index 46b82259b65..625ba4c3dcc 100644 --- a/libjava/classpath/javax/swing/text/DefaultStyledDocument.java +++ b/libjava/classpath/javax/swing/text/DefaultStyledDocument.java @@ -53,27 +53,25 @@ import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.UndoableEdit; /** - * The default implementation of {@link StyledDocument}. - * - * The document is modeled as an {@link Element} tree, which has - * a {@link SectionElement} as single root, which has one or more - * {@link AbstractDocument.BranchElement}s as paragraph nodes - * and each paragraph node having one or more + * The default implementation of {@link StyledDocument}. The document is + * modeled as an {@link Element} tree, which has a {@link SectionElement} as + * single root, which has one or more {@link AbstractDocument.BranchElement}s + * as paragraph nodes and each paragraph node having one or more * {@link AbstractDocument.LeafElement}s as content nodes. - * + * * @author Michael Koch (konqueror@gmx.de) * @author Roman Kennke (roman@kennke.org) */ -public class DefaultStyledDocument extends AbstractDocument - implements StyledDocument +public class DefaultStyledDocument extends AbstractDocument implements + StyledDocument { + /** * An {@link UndoableEdit} that can undo attribute changes to an element. - * + * * @author Roman Kennke (kennke@aicas.com) */ - public static class AttributeUndoableEdit - extends AbstractUndoableEdit + public static class AttributeUndoableEdit extends AbstractUndoableEdit { /** * A copy of the old attributes. @@ -98,11 +96,13 @@ public class DefaultStyledDocument extends AbstractDocument /** * Creates a new <code>AttributeUndoableEdit</code>. - * - * @param el the element that changes attributes - * @param newAtts the new attributes - * @param replacing if the new attributes replace the old or only append to - * them + * + * @param el + * the element that changes attributes + * @param newAtts + * the new attributes + * @param replacing + * if the new attributes replace the old or only append to them */ public AttributeUndoableEdit(Element el, AttributeSet newAtts, boolean replacing) @@ -149,21 +149,19 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Carries specification information for new {@link Element}s that should - * be created in {@link ElementBuffer}. This allows the parsing process - * to be decoupled from the <code>Element</code> creation process. + * Carries specification information for new {@link Element}s that should be + * created in {@link ElementBuffer}. This allows the parsing process to be + * decoupled from the <code>Element</code> creation process. */ public static class ElementSpec { /** - * This indicates a start tag. This is a possible value for - * {@link #getType}. + * This indicates a start tag. This is a possible value for {@link #getType}. */ public static final short StartTagType = 1; /** - * This indicates an end tag. This is a possible value for - * {@link #getType}. + * This indicates an end tag. This is a possible value for {@link #getType}. */ public static final short EndTagType = 2; @@ -175,22 +173,19 @@ public class DefaultStyledDocument extends AbstractDocument /** * This indicates that the data associated with this spec should be joined - * with what precedes it. This is a possible value for - * {@link #getDirection}. + * with what precedes it. This is a possible value for {@link #getDirection}. */ public static final short JoinPreviousDirection = 4; /** * This indicates that the data associated with this spec should be joined - * with what follows it. This is a possible value for - * {@link #getDirection}. + * with what follows it. This is a possible value for {@link #getDirection}. */ public static final short JoinNextDirection = 5; /** - * This indicates that the data associated with this spec should be used - * to create a new element. This is a possible value for - * {@link #getDirection}. + * This indicates that the data associated with this spec should be used to + * create a new element. This is a possible value for {@link #getDirection}. */ public static final short OriginateDirection = 6; @@ -234,9 +229,11 @@ public class DefaultStyledDocument extends AbstractDocument /** * Creates a new <code>ElementSpec</code> with no content, length or * offset. This is most useful for start and end tags. - * - * @param a the attributes for the element to be created - * @param type the type of the tag + * + * @param a + * the attributes for the element to be created + * @param type + * the type of the tag */ public ElementSpec(AttributeSet a, short type) { @@ -247,27 +244,34 @@ public class DefaultStyledDocument extends AbstractDocument * Creates a new <code>ElementSpec</code> that specifies the length but * not the offset of an element. Such <code>ElementSpec</code>s are * processed sequentially from a known starting point. - * - * @param a the attributes for the element to be created - * @param type the type of the tag - * @param len the length of the element + * + * @param a + * the attributes for the element to be created + * @param type + * the type of the tag + * @param len + * the length of the element */ public ElementSpec(AttributeSet a, short type, int len) { this(a, type, null, 0, len); } - + /** * Creates a new <code>ElementSpec</code> with document content. - * - * @param a the attributes for the element to be created - * @param type the type of the tag - * @param txt the actual content - * @param offs the offset into the <code>txt</code> array - * @param len the length of the element + * + * @param a + * the attributes for the element to be created + * @param type + * the type of the tag + * @param txt + * the actual content + * @param offs + * the offset into the <code>txt</code> array + * @param len + * the length of the element */ - public ElementSpec(AttributeSet a, short type, char[] txt, int offs, - int len) + public ElementSpec(AttributeSet a, short type, char[] txt, int offs, int len) { attributes = a; this.type = type; @@ -279,8 +283,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Sets the type of the element. - * - * @param type the type of the element to be set + * + * @param type + * the type of the element to be set */ public void setType(short type) { @@ -289,7 +294,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the type of the element. - * + * * @return the type of the element */ public short getType() @@ -299,8 +304,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Sets the direction of the element. - * - * @param dir the direction of the element to be set + * + * @param dir + * the direction of the element to be set */ public void setDirection(short dir) { @@ -309,7 +315,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the direction of the element. - * + * * @return the direction of the element */ public short getDirection() @@ -319,7 +325,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the attributes of the element. - * + * * @return the attributes of the element */ public AttributeSet getAttributes() @@ -329,7 +335,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the actual content of the element. - * + * * @return the actual content of the element */ public char[] getArray() @@ -339,7 +345,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the offset of the content. - * + * * @return the offset of the content */ public int getOffset() @@ -349,7 +355,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the length of the content. - * + * * @return the length of the content */ public int getLength() @@ -361,7 +367,7 @@ public class DefaultStyledDocument extends AbstractDocument * Returns a String representation of this <code>ElementSpec</code> * describing the type, direction and length of this * <code>ElementSpec</code>. - * + * * @return a String representation of this <code>ElementSpec</code> */ public String toString() @@ -413,7 +419,8 @@ public class DefaultStyledDocument extends AbstractDocument /** * Performs all <em>structural</code> changes to the <code>Element</code> - * hierarchy. + * hierarchy. This class was implemented with much help from the document: + * http://java.sun.com/products/jfc/tsc/articles/text/element_buffer/index.html. */ public class ElementBuffer implements Serializable { @@ -426,25 +433,20 @@ public class DefaultStyledDocument extends AbstractDocument /** Holds the offset for structural changes. */ private int offset; + /** Holds the end offset for structural changes. */ + private int endOffset; + /** Holds the length of structural changes. */ private int length; - - /** Holds the end offset for structural changes. **/ - private int endOffset; - /** - * The number of inserted end tags. This is a counter which always gets - * incremented when an end tag is inserted. This is evaluated before - * content insertion to go up the element stack. - */ - private int numEndTags; + /** Holds the position of the change. */ + private int pos; - /** - * The number of inserted start tags. This is a counter which always gets - * incremented when an end tag is inserted. This is evaluated before - * content insertion to go up the element stack. - */ - private int numStartTags; + /** Holds the element that was last fractured. */ + private Element lastFractured; + + /** True if a fracture was not created during a insertFracture call. */ + private boolean fracNotCreated; /** * The current position in the element tree. This is used for bulk inserts @@ -453,14 +455,6 @@ public class DefaultStyledDocument extends AbstractDocument private Stack elementStack; /** - * Holds fractured elements during insertion of end and start tags. - * Inserting an end tag may lead to fracturing of the current paragraph - * element. The elements that have been cut off may be added to the - * next paragraph that is created in the next start tag. - */ - Element[] fracture; - - /** * The ElementChange that describes the latest changes. */ DefaultDocumentEvent documentEvent; @@ -468,8 +462,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Creates a new <code>ElementBuffer</code> for the specified * <code>root</code> element. - * - * @param root the root element for this <code>ElementBuffer</code> + * + * @param root + * the root element for this <code>ElementBuffer</code> */ public ElementBuffer(Element root) { @@ -479,7 +474,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the root element of this <code>ElementBuffer</code>. - * + * * @return the root element of this <code>ElementBuffer</code> */ public Element getRootElement() @@ -488,21 +483,23 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Updates the element structure of the document in response to removal of - * content. It removes the affected {@link Element}s from the document - * structure. - * - * This method sets some internal parameters and delegates the work - * to {@link #removeUpdate}. - * - * @param offs the offset from which content is remove - * @param len the length of the removed content - * @param ev the document event that records the changes + * Removes the content. This method sets some internal parameters and + * delegates the work to {@link #removeUpdate}. + * + * @param offs + * the offset from which content is remove + * @param len + * the length of the removed content + * @param ev + * the document event that records the changes */ public void remove(int offs, int len, DefaultDocumentEvent ev) { + if (len == 0) + return; offset = offs; length = len; + pos = offset; documentEvent = ev; removeUpdate(); } @@ -519,9 +516,9 @@ public class DefaultStyledDocument extends AbstractDocument Element[] empty = new Element[0]; int removeStart = -1; int removeEnd = -1; - for (int i = startParagraph; i < endParagraph; i++) + for (int i = startParagraph; i < endParagraph; i++) { - Element paragraph = root.getElement(i); + BranchElement paragraph = (BranchElement) root.getElement(i); int contentStart = paragraph.getElementIndex(offset); int contentEnd = paragraph.getElementIndex(offset + length); if (contentStart == paragraph.getStartOffset() @@ -546,10 +543,8 @@ public class DefaultStyledDocument extends AbstractDocument Element[] removed = new Element[removeLen]; for (int j = contentStart; j < contentEnd; j++) removed[j] = paragraph.getElement(j); - ((BranchElement) paragraph).replace(contentStart, removeLen, - empty); - documentEvent.addEdit(new ElementEdit(paragraph, contentStart, - removed, empty)); + Edit edit = getEditForParagraphAndIndex(paragraph, contentStart); + edit.addRemovedElements(removed); } } // Now we remove paragraphs from the root that have been tagged for @@ -560,265 +555,234 @@ public class DefaultStyledDocument extends AbstractDocument Element[] removed = new Element[removeLen]; for (int i = removeStart; i < removeEnd; i++) removed[i] = root.getElement(i); - ((BranchElement) root).replace(removeStart, removeLen, empty); - documentEvent.addEdit(new ElementEdit(root, removeStart, removed, - empty)); + Edit edit = getEditForParagraphAndIndex((BranchElement) root, + removeStart); + edit.addRemovedElements(removed); } } /** - * Modifies the element structure so that the specified interval starts - * and ends at an element boundary. Content and paragraph elements - * are split and created as necessary. - * - * This also updates the <code>DefaultDocumentEvent</code> to reflect the - * structural changes. - * - * The bulk work is delegated to {@link #changeUpdate()}. - * - * @param offset the start index of the interval to be changed - * @param length the length of the interval to be changed - * @param ev the <code>DefaultDocumentEvent</code> describing the change - */ - public void change(int offset, int length, DefaultDocumentEvent ev) - { - this.offset = offset; - this.length = length; - documentEvent = ev; - changeUpdate(); - } - - /** - * Performs the actual work for {@link #change}. - * The elements at the interval boundaries are split up (if necessary) - * so that the interval boundaries are located at element boundaries. + * Performs the actual work for {@link #change}. The elements at the + * interval boundaries are split up (if necessary) so that the interval + * boundaries are located at element boundaries. */ protected void changeUpdate() { // Split up the element at the start offset if necessary. Element el = getCharacterElement(offset); - Element[] res = split(el, offset, 0); + Element[] res = split(el, offset, 0, el.getElementIndex(offset)); BranchElement par = (BranchElement) el.getParentElement(); + int index = par.getElementIndex(offset); + Edit edit = getEditForParagraphAndIndex(par, index); if (res[1] != null) { - int index = par.getElementIndex(offset); Element[] removed; Element[] added; if (res[0] == null) { removed = new Element[0]; - added = new Element[]{ res[1] }; + added = new Element[] { res[1] }; index++; } else { - removed = new Element[]{ el }; - added = new Element[]{ res[0], res[1] }; + removed = new Element[] { el }; + added = new Element[] { res[0], res[1] }; } - par.replace(index, removed.length, added); - addEdit(par, index, removed, added); + edit.addRemovedElements(removed); + + edit.addAddedElements(added); } int endOffset = offset + length; el = getCharacterElement(endOffset); - res = split(el, endOffset, 0); + res = split(el, endOffset, 0, el.getElementIndex(endOffset)); par = (BranchElement) el.getParentElement(); - if (res[1] != null) + if (res[0] != null) { - int index = par.getElementIndex(offset); Element[] removed; Element[] added; if (res[1] == null) { removed = new Element[0]; - added = new Element[]{ res[1] }; + added = new Element[] { res[1] }; } else { - removed = new Element[]{ el }; - added = new Element[]{ res[0], res[1] }; + removed = new Element[] { el }; + added = new Element[] { res[0], res[1] }; } - par.replace(index, removed.length, added); - addEdit(par, index, removed, added); + edit.addRemovedElements(removed); + edit.addAddedElements(added); } } /** - * Splits an element if <code>offset</code> is not alread at its boundary. + * Modifies the element structure so that the specified interval starts and + * ends at an element boundary. Content and paragraph elements are split and + * created as necessary. This also updates the + * <code>DefaultDocumentEvent</code> to reflect the structural changes. + * The bulk work is delegated to {@link #changeUpdate()}. + * + * @param offset + * the start index of the interval to be changed + * @param length + * the length of the interval to be changed + * @param ev + * the <code>DefaultDocumentEvent</code> describing the change + */ + public void change(int offset, int length, DefaultDocumentEvent ev) + { + if (length == 0) + return; + this.offset = offset; + this.pos = offset; + this.length = length; + documentEvent = ev; + changeUpdate(); + } + + /** + * Creates and returns a deep clone of the specified <code>clonee</code> + * with the specified parent as new parent. * - * @param el the Element to possibly split - * @param offset the offset at which to possibly split - * @param space the amount of space to create between the splitted parts + * This method can only clone direct instances of {@link BranchElement} + * or {@link LeafElement}. * - * @return An array of elements which represent the split result. This - * array has two elements, the two parts of the split. The first - * element might be null, which means that the element which should - * be splitted can remain in place. The second element might also - * be null, which means that the offset is already at an element - * boundary and the element doesn't need to be splitted. - * + * @param parent the new parent + * @param clonee the element to be cloned + * + * @return the cloned element with the new parent */ - private Element[] split(Element el, int offset, int space) + public Element clone(Element parent, Element clonee) { - // If we are at an element boundary, then return an empty array. - if ((offset == el.getStartOffset() || offset == el.getEndOffset()) - && space == 0 && el.isLeaf()) - return new Element[2]; - - // If the element is an instance of BranchElement, then we recursivly - // call this method to perform the split. - Element[] res = new Element[2]; - if (el instanceof BranchElement) + Element clone = clonee; + // We can only handle AbstractElements here. + if (clonee instanceof BranchElement) { - int index = el.getElementIndex(offset); - Element child = el.getElement(index); - Element[] result = split(child, offset, space); - Element[] removed; - Element[] added; - Element[] newAdded; - - int count = el.getElementCount(); - if (!(result[1] == null)) - { - // This is the case when we can keep the first element. - if (result[0] == null) - { - removed = new Element[count - index - 1]; - newAdded = new Element[count - index - 1]; - added = new Element[]{}; - } - // This is the case when we may not keep the first element. - else - { - removed = new Element[count - index]; - newAdded = new Element[count - index]; - added = new Element[]{result[0]}; - } - newAdded[0] = result[1]; - for (int i = index; i < count; i++) - { - Element el2 = el.getElement(i); - int ind = i - count + removed.length; - removed[ind] = el2; - if (ind != 0) - newAdded[ind] = el2; - } - - ((BranchElement) el).replace(index, removed.length, added); - addEdit(el, index, removed, added); - BranchElement newPar = - (BranchElement) createBranchElement(el.getParentElement(), - el.getAttributes()); - newPar.replace(0, 0, newAdded); - res = new Element[]{ null, newPar }; - } - else + BranchElement branchEl = (BranchElement) clonee; + BranchElement branchClone = + new BranchElement(parent, branchEl.getAttributes()); + // Also clone all of the children. + int numChildren = branchClone.getElementCount(); + Element[] cloneChildren = new Element[numChildren]; + for (int i = 0; i < numChildren; ++i) { - removed = new Element[count - index]; - for (int i = index; i < count; ++i) - removed[i - index] = el.getElement(i); - added = new Element[0]; - ((BranchElement) el).replace(index, removed.length, - added); - addEdit(el, index, removed, added); - BranchElement newPar = - (BranchElement) createBranchElement(el.getParentElement(), - el.getAttributes()); - newPar.replace(0, 0, removed); - res = new Element[]{ null, newPar }; + cloneChildren[i] = clone(branchClone, + branchClone.getElement(i)); } + branchClone.replace(0, 0, cloneChildren); + clone = branchClone; } - else if (el instanceof LeafElement) + else if (clonee instanceof LeafElement) { - BranchElement par = (BranchElement) el.getParentElement(); - Element el1 = createLeafElement(par, el.getAttributes(), - el.getStartOffset(), offset); - Element el2 = createLeafElement(par, el.getAttributes(), - offset + space, el.getEndOffset()); - res = new Element[]{ el1, el2 }; + clone = new LeafElement(parent, clonee.getAttributes(), + clonee.getStartOffset(), + clonee.getEndOffset()); } - return res; + return clone; } /** * Inserts new <code>Element</code> in the document at the specified - * position. - * - * Most of the work is done by {@link #insertUpdate}, after some fields - * have been prepared for it. - * - * @param offset the location in the document at which the content is - * inserted - * @param length the length of the inserted content - * @param data the element specifications for the content to be inserted - * @param ev the document event that is updated to reflect the structural - * changes + * position. Most of the work is done by {@link #insertUpdate}, after some + * fields have been prepared for it. + * + * @param offset + * the location in the document at which the content is inserted + * @param length + * the length of the inserted content + * @param data + * the element specifications for the content to be inserted + * @param ev + * the document event that is updated to reflect the structural + * changes */ public void insert(int offset, int length, ElementSpec[] data, DefaultDocumentEvent ev) { if (length == 0) return; + this.offset = offset; - this.length = length; + this.pos = offset; this.endOffset = offset + length; + this.length = length; documentEvent = ev; - // Push the root and the paragraph at offset onto the element stack. - elementStack.clear(); - elementStack.push(root); - elementStack.push(root.getElement(root.getElementIndex(offset))); - numEndTags = 0; - numStartTags = 0; + + edits.removeAllElements(); + elementStack.removeAllElements(); + lastFractured = null; + fracNotCreated = false; insertUpdate(data); + // This for loop applies all the changes that were made and updates the + // DocumentEvent. + int size = edits.size(); + for (int i = 0; i < size; i++) + { + Edit curr = (Edit) edits.get(i); + BranchElement e = (BranchElement) curr.e; + Element[] removed = curr.getRemovedElements(); + Element[] added = curr.getAddedElements(); + // FIXME: We probably shouldn't create the empty Element[] in the + // first place. + if (removed.length > 0 || added.length > 0) + { + if (curr.index + removed.length <= e.getElementCount()) + { + e.replace(curr.index, removed.length, added); + ElementEdit ee = new ElementEdit(e, curr.index, removed, added); + ev.addEdit(ee); + } + else + { + System.err.println("WARNING: Tried to replace elements "); + System.err.print("beyond boundaries: elementCount: "); + System.err.println(e.getElementCount()); + System.err.print("index: " + curr.index); + System.err.println(", removed.length: " + removed.length); + } + } + } } /** - * Performs the actual structural change for {@link #insert}. This - * creates a bunch of {@link Element}s as specified by <code>data</code> - * and inserts it into the document as specified in the arguments to - * {@link #insert}. - * - * @param data the element specifications for the elements to be inserte - */ + * Inserts new content + * + * @param data + * the element specifications for the elements to be inserted + */ protected void insertUpdate(ElementSpec[] data) { - if (data[0].getType() == ElementSpec.EndTagType) + // Push the root and the paragraph at offset onto the element stack. + Element current = root; + int index; + while (!current.isLeaf()) { - // fracture deepest child here - BranchElement paragraph = (BranchElement) elementStack.peek(); - Element curr = paragraph.getParentElement(); - int index = curr.getElementIndex(offset); - while (!curr.isLeaf()) - { - index = curr.getElementIndex(offset); - curr = curr.getElement(index); - } - Element parent = curr.getParentElement(); - Element newEl1 = createLeafElement(parent, - curr.getAttributes(), - curr.getStartOffset(), offset); - Element grandParent = parent.getParentElement(); - BranchElement nextBranch = - (BranchElement) grandParent.getElement - (grandParent.getElementIndex(parent.getEndOffset())); - Element firstLeaf = nextBranch.getElement(0); - while (!firstLeaf.isLeaf()) - { - firstLeaf = firstLeaf.getElement(0); - } - BranchElement parent2 = (BranchElement) firstLeaf.getParentElement(); - Element newEl2 = - createLeafElement(parent2, - firstLeaf.getAttributes(), - offset, firstLeaf.getEndOffset()); - parent2.replace(0, 1, new Element[] { newEl2 }); - - - ((BranchElement) parent). - replace(index, 1, new Element[] { newEl1 }); + index = current.getElementIndex(offset); + elementStack.push(current); + current = current.getElement(index); } - for (int i = 0; i < data.length; i++) + int i = 0; + int type = data[0].getType(); + if (type == ElementSpec.ContentType) + { + // If the first tag is content we must treat it separately to allow + // for joining properly to previous Elements and to ensure that + // no extra LeafElements are erroneously inserted. + insertFirstContentTag(data); + pos += data[0].length; + i = 1; + } + else + { + createFracture(data); + i = 0; + } + + // Handle each ElementSpec individually. + for (; i < data.length; i++) { BranchElement paragraph = (BranchElement) elementStack.peek(); switch (data[i].getType()) @@ -827,19 +791,41 @@ public class DefaultStyledDocument extends AbstractDocument switch (data[i].getDirection()) { case ElementSpec.JoinFractureDirection: + // Fracture the tree and ensure the appropriate element + // is on top of the stack. + fracNotCreated = false; insertFracture(data[i]); + if (fracNotCreated) + { + if (lastFractured != null) + elementStack.push(lastFractured.getParentElement()); + else + elementStack.push(paragraph.getElement(0)); + } break; case ElementSpec.JoinNextDirection: - int index = paragraph.getElementIndex(offset); - elementStack.push(paragraph.getElement(index)); - break; - case ElementSpec.OriginateDirection: - Element current = (Element) elementStack.peek(); - Element newParagraph = - insertParagraph((BranchElement) current, offset); - elementStack.push(newParagraph); + // Push the next paragraph element onto the stack so + // future insertions are added to it. + int ix = paragraph.getElementIndex(pos) + 1; + elementStack.push(paragraph.getElement(ix)); break; default: + Element br = null; + if (data.length > i + 1) + { + // leaves will be added to paragraph later + int x = 0; + if (paragraph.getElementCount() > 0) + x = paragraph.getElementIndex(pos) + 1; + Edit e = getEditForParagraphAndIndex(paragraph, x); + br = (BranchElement) createBranchElement(paragraph, + data[i].getAttributes()); + e.added.add(br); + elementStack.push(br); + } + else + // need to add leaves to paragraph now + br = insertParagraph(paragraph, pos); break; } break; @@ -848,50 +834,27 @@ public class DefaultStyledDocument extends AbstractDocument break; case ElementSpec.ContentType: insertContentTag(data[i]); + offset = pos; break; } } - endEdit(); } - - /** - * Finishes an insertion by possibly evaluating the outstanding start and - * end tags. However, this is only performed if the event has received any - * modifications. - */ - private void endEdit() - { - if (documentEvent.modified) - prepareContentInsertion(); - } - + /** - * Evaluates the number of inserted end tags and performs the corresponding - * structural changes. + * Inserts a new paragraph. + * + * @param par - + * the parent + * @param offset - + * the offset + * @return the new paragraph */ - private void prepareContentInsertion() - { - while (numEndTags > 0) - { - elementStack.pop(); - numEndTags--; - } - - while (numStartTags > 0) - { - Element current = (Element) elementStack.peek(); - Element newParagraph = - insertParagraph((BranchElement) current, offset); - elementStack.push(newParagraph); - numStartTags--; - } - } - private Element insertParagraph(BranchElement par, int offset) { - Element current = par.getElement(par.getElementIndex(offset)); - Element[] res = split(current, offset, 0); int index = par.getElementIndex(offset); + Element current = par.getElement(index); + Element[] res = split(current, offset, 0, 0); + Edit e = getEditForParagraphAndIndex(par, index + 1); Element ret; if (res[1] != null) { @@ -902,334 +865,757 @@ public class DefaultStyledDocument extends AbstractDocument removed = new Element[0]; if (res[1] instanceof BranchElement) { - added = new Element[]{ res[1] }; + added = new Element[] { res[1] }; ret = res[1]; } else { ret = createBranchElement(par, null); - added = new Element[]{ ret, res[1] }; + added = new Element[] { ret, res[1] }; } index++; } else { - removed = new Element[]{ current }; + removed = new Element[] { current }; if (res[1] instanceof BranchElement) { ret = res[1]; - added = new Element[]{ res[0], res[1] }; + added = new Element[] { res[0], res[1] }; } else { ret = createBranchElement(par, null); - added = new Element[]{ res[0], ret, res[1] }; + added = new Element[] { res[0], ret, res[1] }; } } - par.replace(index, removed.length, added); - addEdit(par, index, removed, added); + + e.addAddedElements(added); + e.addRemovedElements(removed); } else { ret = createBranchElement(par, null); - Element[] added = new Element[]{ ret }; - par.replace(index, 0, added); - addEdit(par, index, new Element[0], added); + e.addAddedElement(ret); } return ret; } /** - * Inserts a fracture into the document structure. + * Inserts the first tag into the document. * - * @param tag - the element spec. + * @param data - + * the data to be inserted. */ - private void insertFracture(ElementSpec tag) + private void insertFirstContentTag(ElementSpec[] data) { - // This is the parent of the paragraph about to be fractured. We will - // create a new child of this parent. - BranchElement parent = (BranchElement) elementStack.peek(); - int parentIndex = parent.getElementIndex(offset); - - // This is the old paragraph. We must remove all its children that - // occur after offset and move them to a new paragraph. We must - // also recreate its child that occurs at offset to have the proper - // end offset. The remainder of this child will also go in the new - // paragraph. - BranchElement previous = (BranchElement) parent.getElement(parentIndex); - - // This is the new paragraph. - BranchElement newBranch = - (BranchElement) createBranchElement(parent, previous.getAttributes()); - - - // The steps we must take to properly fracture are: - // 1. Recreate the LeafElement at offset to have the correct end offset. - // 2. Create a new LeafElement with the remainder of the LeafElement in - // #1 ==> this is whatever was in that LeafElement to the right of the - // inserted newline. - // 3. Find the paragraph at offset and remove all its children that - // occur _after_ offset. These will be moved to the newly created - // paragraph. - // 4. Move the LeafElement created in #2 and all the LeafElements removed - // in #3 to the newly created paragraph. - // 5. Add the new paragraph to the parent. - int previousIndex = previous.getElementIndex(offset); - int numReplaced = previous.getElementCount() - previousIndex; - Element previousLeaf = previous.getElement(previousIndex); - AttributeSet prevLeafAtts = previous.getAttributes(); - - // This recreates the child at offset to have the proper end offset. - // (Step 1). - Element newPreviousLeaf = - createLeafElement(previous, - prevLeafAtts, previousLeaf.getStartOffset(), - offset); - // This creates the new child, which is the remainder of the old child. - // (Step 2). - - Element firstLeafInNewBranch = - createLeafElement(newBranch, prevLeafAtts, - offset, previousLeaf.getEndOffset()); - - // Now we move the new LeafElement and all the old children that occurred - // after the offset to the new paragraph. (Step 4). - Element[] newLeaves = new Element[numReplaced]; - newLeaves[0] = firstLeafInNewBranch; - for (int i = 1; i < numReplaced; i++) - newLeaves[i] = previous.getElement(previousIndex + i); - newBranch.replace(0, 0, newLeaves); - addEdit(newBranch, 0, null, newLeaves); - - // Now we remove the children after the offset from the previous - // paragraph. (Step 3). - int removeSize = previous.getElementCount() - previousIndex; - Element[] add = new Element[] { newPreviousLeaf }; - Element[] remove = new Element[removeSize]; - for (int j = 0; j < removeSize; j++) - remove[j] = previous.getElement(previousIndex + j); - previous.replace(previousIndex, removeSize, add); - addEdit(previous, previousIndex, remove, add); - - // Finally we add the new paragraph to the parent. (Step 5). - Element[] nb = new Element[] { newBranch }; - int index = parentIndex + 1; - parent.replace(index, 0, nb); - addEdit(parent, index, null, nb); + ElementSpec first = data[0]; + BranchElement paragraph = (BranchElement) elementStack.peek(); + int index = paragraph.getElementIndex(pos); + Element current = paragraph.getElement(index); + int newEndOffset = pos + first.length; + boolean onlyContent = data.length == 1; + Edit edit = getEditForParagraphAndIndex(paragraph, index); + switch (first.getDirection()) + { + case ElementSpec.JoinPreviousDirection: + if (current.getEndOffset() != newEndOffset && !onlyContent) + { + Element newEl1 = createLeafElement(paragraph, + current.getAttributes(), + current.getStartOffset(), + newEndOffset); + edit.addAddedElement(newEl1); + edit.addRemovedElement(current); + offset = newEndOffset; + } + break; + case ElementSpec.JoinNextDirection: + if (pos != 0) + { + Element newEl1 = createLeafElement(paragraph, + current.getAttributes(), + current.getStartOffset(), + pos); + edit.addAddedElement(newEl1); + Element next = paragraph.getElement(index + 1); + + if (onlyContent) + newEl1 = createLeafElement(paragraph, next.getAttributes(), + pos, next.getEndOffset()); + else + { + newEl1 = createLeafElement(paragraph, next.getAttributes(), + pos, newEndOffset); + pos = newEndOffset; + } + edit.addAddedElement(newEl1); + edit.addRemovedElement(current); + edit.addRemovedElement(next); + } + break; + default: + if (current.getStartOffset() != pos) + { + Element newEl = createLeafElement(paragraph, + current.getAttributes(), + current.getStartOffset(), + pos); + edit.addAddedElement(newEl); + } + edit.addRemovedElement(current); + Element newEl1 = createLeafElement(paragraph, first.getAttributes(), + pos, newEndOffset); + edit.addAddedElement(newEl1); + if (current.getEndOffset() != endOffset) + recreateLeaves(newEndOffset, paragraph, onlyContent); + else + offset = newEndOffset; + break; + } } - + /** * Inserts a content element into the document structure. * - * @param tag the element spec + * @param tag - + * the element spec */ private void insertContentTag(ElementSpec tag) { - prepareContentInsertion(); + BranchElement paragraph = (BranchElement) elementStack.peek(); int len = tag.getLength(); int dir = tag.getDirection(); AttributeSet tagAtts = tag.getAttributes(); - if (dir == ElementSpec.JoinPreviousDirection) - { - // The mauve tests to this class show that a JoinPrevious insertion - // does not add any edits to the document event. To me this means - // that nothing is done here. The previous element naturally should - // expand so that it covers the new characters. - } - else if (dir == ElementSpec.JoinNextDirection) + + if (dir == ElementSpec.JoinNextDirection) { - // FIXME: - // Have to handle JoinNext differently depending on whether - // or not it comes after a fracture. If comes after a fracture, - // the insertFracture method takes care of everything and nothing - // needs to be done here. Otherwise, we need to adjust the - // Element structure. For now, I check if the elementStack's - // top Element is the immediate parent of the LeafElement at - // offset - if so, we did not come immediately after a - // fracture. This seems awkward and should probably be improved. - // We may be doing too much in insertFracture because we are - // adjusting the offsets, the correct thing to do may be to - // create a new branch element and push it on to element stack - // and then this method here can be more general. - - BranchElement paragraph = (BranchElement) elementStack.peek(); - int index = paragraph.getElementIndex(offset); + int index = paragraph.getElementIndex(pos); Element target = paragraph.getElement(index); - if (target.isLeaf() && paragraph.getElementCount() > (index + 1)) + Edit edit = getEditForParagraphAndIndex(paragraph, index); + + if (paragraph.getStartOffset() > pos) + { + Element first = paragraph.getElement(0); + Element newEl = createLeafElement(paragraph, + first.getAttributes(), pos, + first.getEndOffset()); + edit.addAddedElement(newEl); + edit.addRemovedElement(first); + } + else if (paragraph.getElementCount() > (index + 1) + && (pos == target.getStartOffset() && !target.equals(lastFractured))) { Element next = paragraph.getElement(index + 1); - Element newEl1 = createLeafElement(paragraph, - target.getAttributes(), - target.getStartOffset(), - offset); - Element newEl2 = createLeafElement(paragraph, - next.getAttributes(), offset, - next.getEndOffset()); - Element[] add = new Element[] { newEl1, newEl2 }; - paragraph.replace (index, 2, add); - addEdit(paragraph, index, new Element[] { target, next }, add); + Element newEl = createLeafElement(paragraph, + next.getAttributes(), pos, + next.getEndOffset()); + edit.addAddedElement(newEl); + edit.addRemovedElement(next); + edit.addRemovedElement(target); + } + else + { + BranchElement parent = (BranchElement) paragraph.getParentElement(); + int i = parent.getElementIndex(pos); + BranchElement next = (BranchElement) parent.getElement(i + 1); + AttributeSet atts = tag.getAttributes(); + + if (next != null) + { + Element nextLeaf = next.getElement(0); + Edit e = getEditForParagraphAndIndex(next, 0); + Element newEl2 = createLeafElement(next, atts, pos, nextLeaf.getEndOffset()); + e.addAddedElement(newEl2); + e.addRemovedElement(nextLeaf); + } } } - else if (dir == ElementSpec.OriginateDirection) + else { - BranchElement paragraph = (BranchElement) elementStack.peek(); - int index = paragraph.getElementIndex(offset); - Element current = paragraph.getElement(index); + int end = pos + len; + Element leaf = createLeafElement(paragraph, tag.getAttributes(), pos, end); - Element[] added; - Element[] removed = new Element[] {current}; - Element[] splitRes = split(current, offset, length); - if (splitRes[0] == null) + // Check for overlap with other leaves/branches + if (paragraph.getElementCount() > 0) { - added = new Element[2]; - added[0] = createLeafElement(paragraph, tagAtts, - offset, endOffset); - added[1] = splitRes[1]; - removed = new Element[0]; - index++; - } - else if (current.getStartOffset() == offset) - { - // This is if the new insertion happens immediately before - // the <code>current</code> Element. In this case there are 2 - // resulting Elements. - added = new Element[2]; - added[0] = createLeafElement(paragraph, tagAtts, offset, - endOffset); - added[1] = splitRes[1]; - } - else if (current.getEndOffset() == endOffset) - { - // This is if the new insertion happens right at the end of - // the <code>current</code> Element. In this case there are - // 2 resulting Elements. - added = new Element[2]; - added[0] = splitRes[0]; - added[1] = createLeafElement(paragraph, tagAtts, offset, - endOffset); + int index = paragraph.getElementIndex(pos); + Element target = paragraph.getElement(index); + boolean onlyContent = target.isLeaf(); + + BranchElement toRec = paragraph; + if (!onlyContent) + toRec = (BranchElement) target; + + // Check if we should place the leaf before or after target + if (pos > target.getStartOffset()) + index++; + + Edit edit = getEditForParagraphAndIndex(paragraph, index); + edit.addAddedElement(leaf); + + if (end != toRec.getEndOffset()) + { + recreateLeaves(end, toRec, onlyContent); + + if (onlyContent) + edit.addRemovedElement(target); + } } else - { - // This is if the new insertion is in the middle of the - // <code>current</code> Element. In this case - // there will be 3 resulting Elements. - added = new Element[3]; - added[0] = splitRes[0]; - added[1] = createLeafElement(paragraph, tagAtts, offset, - endOffset); - added[2] = splitRes[1]; - } - paragraph.replace(index, removed.length, added); - addEdit(paragraph, index, removed, added); + paragraph.replace(0, 0, new Element[] { leaf }); } - offset += len; + + pos += len; } - + /** - * Creates a copy of the element <code>clonee</code> that has the parent - * <code>parent</code>. - * @param parent the parent of the newly created Element - * @param clonee the Element to clone - * @return the cloned Element + * This method fractures the child at offset. + * + * @param data + * the ElementSpecs used for the entire insertion */ - public Element clone (Element parent, Element clonee) + private void createFracture(ElementSpec[] data) { - // If the Element we want to clone is a leaf, then simply copy it - if (clonee.isLeaf()) - return createLeafElement(parent, clonee.getAttributes(), - clonee.getStartOffset(), clonee.getEndOffset()); + BranchElement paragraph = (BranchElement) elementStack.peek(); + int index = paragraph.getElementIndex(offset); + Element child = paragraph.getElement(index); + Edit edit = getEditForParagraphAndIndex(paragraph, index); + AttributeSet atts = child.getAttributes(); - // Otherwise create a new BranchElement with the desired parent and - // the clonee's attributes - BranchElement result = (BranchElement) createBranchElement(parent, clonee.getAttributes()); - - // And clone all the of clonee's children - Element[] children = new Element[clonee.getElementCount()]; - for (int i = 0; i < children.length; i++) - children[i] = clone(result, clonee.getElement(i)); - - // Make the cloned children the children of the BranchElement - result.replace(0, 0, children); - return result; + if (offset != 0) + { + Element newEl1 = createLeafElement(paragraph, atts, + child.getStartOffset(), offset); + edit.addAddedElement(newEl1); + edit.addRemovedElement(child); + } } /** - * Adds an ElementChange for a given element modification to the document - * event. If there already is an ElementChange registered for this element, - * this method tries to merge the ElementChanges together. However, this - * is only possible if the indices of the new and old ElementChange are - * equal. - * - * @param e the element - * @param i the index of the change - * @param removed the removed elements, or <code>null</code> - * @param added the added elements, or <code>null</code> + * Recreates a specified part of a the tree after a new leaf + * has been inserted. + * + * @param start - where to start recreating from + * @param paragraph - the paragraph to recreate + * @param onlyContent - true if this is the only content + */ + private void recreateLeaves(int start, BranchElement paragraph, boolean onlyContent) + { + int index = paragraph.getElementIndex(start); + Element child = paragraph.getElement(index); + AttributeSet atts = child.getAttributes(); + + if (!onlyContent) + { + BranchElement newBranch = (BranchElement) createBranchElement(paragraph, + atts); + Element newLeaf = createLeafElement(newBranch, atts, start, + child.getEndOffset()); + newBranch.replace(0, 0, new Element[] { newLeaf }); + + BranchElement parent = (BranchElement) paragraph.getParentElement(); + int parSize = parent.getElementCount(); + Edit edit = getEditForParagraphAndIndex(parent, parSize); + edit.addAddedElement(newBranch); + + int paragraphSize = paragraph.getElementCount(); + Element[] removed = new Element[paragraphSize - (index + 1)]; + int s = 0; + for (int j = index + 1; j < paragraphSize; j++) + removed[s++] = paragraph.getElement(j); + + edit = getEditForParagraphAndIndex(paragraph, index); + edit.addRemovedElements(removed); + Element[] added = recreateAfterFracture(removed, newBranch, 0, child.getEndOffset()); + newBranch.replace(1, 0, added); + + lastFractured = newLeaf; + pos = newBranch.getEndOffset(); + } + else + { + Element newLeaf = createLeafElement(paragraph, atts, start, + child.getEndOffset()); + Edit edit = getEditForParagraphAndIndex(paragraph, index); + edit.addAddedElement(newLeaf); + } + } + + /** + * Splits an element if <code>offset</code> is not already at its + * boundary. + * + * @param el + * the Element to possibly split + * @param offset + * the offset at which to possibly split + * @param space + * the amount of space to create between the splitted parts + * @param editIndex + * the index of the edit to use + * @return An array of elements which represent the split result. This array + * has two elements, the two parts of the split. The first element + * might be null, which means that the element which should be + * splitted can remain in place. The second element might also be + * null, which means that the offset is already at an element + * boundary and the element doesn't need to be splitted. */ - private void addEdit(Element e, int i, Element[] removed, Element[] added) + private Element[] split(Element el, int offset, int space, int editIndex) { - // Perform sanity check first. - DocumentEvent.ElementChange ec = documentEvent.getChange(e); + // If we are at an element boundary, then return an empty array. + if ((offset == el.getStartOffset() || offset == el.getEndOffset()) + && space == 0 && el.isLeaf()) + return new Element[2]; - // Merge the existing stuff with the new stuff. - Element[] oldAdded = ec == null ? null: ec.getChildrenAdded(); - Element[] newAdded; - if (oldAdded != null && added != null) + // If the element is an instance of BranchElement, then we + // recursivly + // call this method to perform the split. + Element[] res = new Element[2]; + if (el instanceof BranchElement) { - if (ec.getIndex() <= i) + int index = el.getElementIndex(offset); + Element child = el.getElement(index); + Element[] result = split(child, offset, space, editIndex); + Element[] removed; + Element[] added; + Element[] newAdded; + + int count = el.getElementCount(); + if (result[1] != null) { - int index = i - ec.getIndex(); - // Merge adds together. - newAdded = new Element[oldAdded.length + added.length]; - System.arraycopy(oldAdded, 0, newAdded, 0, index); - System.arraycopy(added, 0, newAdded, index, added.length); - System.arraycopy(oldAdded, index, newAdded, index + added.length, - oldAdded.length - index); - i = ec.getIndex(); + // This is the case when we can keep the first element. + if (result[0] == null) + { + removed = new Element[count - index - 1]; + newAdded = new Element[count - index - 1]; + added = new Element[] {}; + + } + // This is the case when we may not keep the first + // element. + else + { + removed = new Element[count - index]; + newAdded = new Element[count - index]; + added = new Element[] { result[0] }; + } + newAdded[0] = result[1]; + for (int i = index; i < count; i++) + { + Element el2 = el.getElement(i); + int ind = i - count + removed.length; + removed[ind] = el2; + if (ind != 0) + newAdded[ind] = el2; + } + + Edit edit = getEditForParagraphAndIndex((BranchElement) el, editIndex); + edit.addRemovedElements(removed); + edit.addAddedElements(added); + + BranchElement newPar = + (BranchElement) createBranchElement(el.getParentElement(), + el.getAttributes()); + newPar.replace(0, 0, newAdded); + res = new Element[] { null, newPar }; } else - throw new AssertionError("Not yet implemented case."); + { + removed = new Element[count - index]; + for (int i = index; i < count; ++i) + removed[i - index] = el.getElement(i); + + Edit edit = getEditForParagraphAndIndex((BranchElement) el, editIndex); + edit.addRemovedElements(removed); + + BranchElement newPar = (BranchElement) createBranchElement(el.getParentElement(), + el.getAttributes()); + newPar.replace(0, 0, removed); + res = new Element[] { null, newPar }; + } } - else if (added != null) - newAdded = added; - else if (oldAdded != null) - newAdded = oldAdded; - else - newAdded = new Element[0]; + else if (el instanceof LeafElement) + { + BranchElement par = (BranchElement) el.getParentElement(); + Element el1 = createLeafElement(par, el.getAttributes(), + el.getStartOffset(), offset); + + Element el2 = createLeafElement(par, el.getAttributes(), + offset + space, + el.getEndOffset()); + res = new Element[] { el1, el2 }; + } + return res; + } - Element[] oldRemoved = ec == null ? null: ec.getChildrenRemoved(); - Element[] newRemoved; - if (oldRemoved != null && removed != null) + /** + * Inserts a fracture into the document structure. + * + * @param tag - + * the element spec. + */ + private void insertFracture(ElementSpec tag) + { + // insert the fracture at offset. + BranchElement parent = (BranchElement) elementStack.peek(); + int parentIndex = parent.getElementIndex(pos); + AttributeSet parentAtts = parent.getAttributes(); + Element toFracture = parent.getElement(parentIndex); + int parSize = parent.getElementCount(); + Edit edit = getEditForParagraphAndIndex(parent, parentIndex); + Element frac = toFracture; + int leftIns = 0; + int indexOfFrac = toFracture.getElementIndex(pos); + int size = toFracture.getElementCount(); + + // gets the leaf that falls along the fracture + frac = toFracture.getElement(indexOfFrac); + while (!frac.isLeaf()) + frac = frac.getElement(frac.getElementIndex(pos)); + + AttributeSet atts = frac.getAttributes(); + int fracStart = frac.getStartOffset(); + int fracEnd = frac.getEndOffset(); + if (pos >= fracStart && pos < fracEnd) { - if (ec.getIndex() <= i) + // recreate left-side of branch and all its children before offset + // add the fractured leaves to the right branch + BranchElement rightBranch = + (BranchElement) createBranchElement(parent, parentAtts); + + // Check if left branch has already been edited. If so, we only + // need to create the right branch. + BranchElement leftBranch = null; + Element[] added = null; + if (edit.added.size() > 0 || edit.removed.size() > 0) { - int index = i - ec.getIndex(); - // Merge removes together. - newRemoved = new Element[oldRemoved.length + removed.length]; - System.arraycopy(oldAdded, 0, newRemoved, 0, index); - System.arraycopy(removed, 0, newRemoved, index, removed.length); - System.arraycopy(oldRemoved, index, newRemoved, - index + removed.length, - oldRemoved.length - index); - i = ec.getIndex(); + added = new Element[] { rightBranch }; + + // don't try to remove left part of tree + parentIndex++; } else - throw new AssertionError("Not yet implemented case."); + { + leftBranch = + (BranchElement) createBranchElement(parent, parentAtts); + added = new Element[] { leftBranch, rightBranch }; + + // add fracture to leftBranch + if (fracStart != pos) + { + Element leftFracturedLeaf = + createLeafElement(leftBranch, atts, fracStart, pos); + leftBranch.replace(leftIns, 0, + new Element[] { leftFracturedLeaf }); + } + } + + if (!toFracture.isLeaf()) + { + // add all non-fracture elements to the branches + if (indexOfFrac > 0 && leftBranch != null) + { + Element[] add = new Element[indexOfFrac]; + for (int i = 0; i < indexOfFrac; i++) + add[i] = toFracture.getElement(i); + leftIns = add.length; + leftBranch.replace(0, 0, add); + } + + int count = size - indexOfFrac - 1; + if (count > 0) + { + Element[] add = new Element[count]; + int j = 0; + int i = indexOfFrac + 1; + while (j < count) + add[j++] = toFracture.getElement(i++); + rightBranch.replace(0, 0, add); + } + } + + // add to fracture to rightBranch + // Check if we can join the right frac leaf with the next leaf + int rm = 0; + int end = fracEnd; + Element next = rightBranch.getElement(0); + if (next != null && next.isLeaf() + && next.getAttributes().isEqual(atts)) + { + end = next.getEndOffset(); + rm = 1; + } + + Element rightFracturedLeaf = createLeafElement(rightBranch, atts, + pos, end); + rightBranch.replace(0, rm, new Element[] { rightFracturedLeaf }); + + // recreate those elements after parentIndex and add/remove all + // new/old elements to parent + int remove = parSize - parentIndex; + Element[] removed = new Element[0]; + Element[] added2 = new Element[0]; + if (remove > 0) + { + removed = new Element[remove]; + int s = 0; + for (int j = parentIndex; j < parSize; j++) + removed[s++] = parent.getElement(j); + edit.addRemovedElements(removed); + added2 = recreateAfterFracture(removed, parent, 1, + rightBranch.getEndOffset()); + } + + edit.addAddedElements(added); + edit.addAddedElements(added2); + elementStack.push(rightBranch); + lastFractured = rightFracturedLeaf; } - else if (removed != null) - newRemoved = removed; - else if (oldRemoved != null) - newRemoved = oldRemoved; else - newRemoved = new Element[0]; + fracNotCreated = true; + } + + /** + * Recreates all the elements from the parent to the element on the top of + * the stack, starting from startFrom with the starting offset of + * startOffset. + * + * @param recreate - + * the elements to recreate + * @param parent - + * the element to add the new elements to + * @param startFrom - + * where to start recreating from + * @param startOffset - + * the offset of the first element + * @return the array of added elements + */ + private Element[] recreateAfterFracture(Element[] recreate, + BranchElement parent, int startFrom, + int startOffset) + { + Element[] added = new Element[recreate.length - startFrom]; + int j = 0; + for (int i = startFrom; i < recreate.length; i++) + { + Element curr = recreate[i]; + int len = curr.getEndOffset() - curr.getStartOffset(); + if (curr instanceof LeafElement) + added[j] = createLeafElement(parent, curr.getAttributes(), + startOffset, startOffset + len); + else + { + BranchElement br = + (BranchElement) createBranchElement(parent, + curr.getAttributes()); + int bSize = curr.getElementCount(); + for (int k = 0; k < bSize; k++) + { + Element bCurr = curr.getElement(k); + Element[] add = recreateAfterFracture(new Element[] { bCurr }, br, 0, + startOffset); + br.replace(0, 0, add); + + } + added[j] = br; + } + startOffset += len; + j++; + } + + return added; + } + } + + /** + * This method looks through the Vector of Edits to see if there is already an + * Edit object associated with the given paragraph. If there is, then we + * return it. Otherwise we create a new Edit object, add it to the vector, and + * return it. Note: this method is package private to avoid accessors. + * + * @param index + * the index associated with the Edit we want to create + * @param para + * the paragraph associated with the Edit we want + * @return the found or created Edit object + */ + Edit getEditForParagraphAndIndex(BranchElement para, int index) + { + Edit curr; + int size = edits.size(); + for (int i = 0; i < size; i++) + { + curr = (Edit) edits.elementAt(i); + if (curr.e.equals(para)) + return curr; + } + curr = new Edit(para, index, null, null); + edits.add(curr); + + return curr; + } + /** + * Instance of all editing information for an object in the Vector. This class + * is used to add information to the DocumentEvent associated with an + * insertion/removal/change as well as to store the changes that need to be + * made so they can be made all at the same (appropriate) time. + */ + class Edit + { + /** The element to edit . */ + Element e; + + /** The index of the change. */ + int index; + + /** The removed elements. */ + Vector removed = new Vector(); + + /** The added elements. */ + Vector added = new Vector(); + + /** + * Return an array containing the Elements that have been removed from the + * paragraph associated with this Edit. + * + * @return an array of removed Elements + */ + public Element[] getRemovedElements() + { + int size = removed.size(); + Element[] removedElements = new Element[size]; + for (int i = 0; i < size; i++) + removedElements[i] = (Element) removed.elementAt(i); + return removedElements; + } + + /** + * Return an array containing the Elements that have been added to the + * paragraph associated with this Edit. + * + * @return an array of added Elements + */ + public Element[] getAddedElements() + { + int size = added.size(); + Element[] addedElements = new Element[size]; + for (int i = 0; i < size; i++) + addedElements[i] = (Element) added.elementAt(i); + return addedElements; + } + + /** + * Checks if e is already in the vector. + * + * @param e - the Element to look for + * @param v - the vector to search + * @return true if e is in v. + */ + private boolean contains(Vector v, Element e) + { + if (e == null) + return false; + + int i = v.size(); + for (int j = 0; j < i; j++) + { + Element e1 = (Element) v.get(j); + if ((e1 != null) && (e1.getAttributes().isEqual(e.getAttributes())) + && (e1.getName().equals(e.getName())) + && (e1.getStartOffset() == e.getStartOffset()) + && (e1.getEndOffset() == e.getEndOffset()) + && (e1.getParentElement().equals(e.getParentElement())) + && (e1.getElementCount() == e.getElementCount())) + return true; + } + return false; + } + + /** + * Adds one Element to the vector of removed Elements. + * + * @param e + * the Element to add + */ + public void addRemovedElement(Element e) + { + if (!contains(removed, e)) + removed.add(e); + } + + /** + * Adds each Element in the given array to the vector of removed Elements + * + * @param e + * the array containing the Elements to be added + */ + public void addRemovedElements(Element[] e) + { + if (e == null || e.length == 0) + return; + for (int i = 0; i < e.length; i++) + { + if (!contains(removed, e[i])) + removed.add(e[i]); + } + } - // Replace the existing edit for the element with the merged. - documentEvent.addEdit(new ElementEdit(e, i, newRemoved, newAdded)); + /** + * Adds one Element to the vector of added Elements. + * + * @param e + * the Element to add + */ + public void addAddedElement(Element e) + { + if (!contains(added, e)) + added.add(e); + } + + /** + * Adds each Element in the given array to the vector of added Elements. + * + * @param e + * the array containing the Elements to be added + */ + public void addAddedElements(Element[] e) + { + if (e == null || e.length == 0) + return; + for (int i = 0; i < e.length; i++) + { + if (!contains(added, e[i])) + added.add(e[i]); + } + } + + /** + * Creates a new Edit object with the given parameters + * + * @param e + * the paragraph Element associated with this Edit + * @param i + * the index within the paragraph where changes are started + * @param removed + * an array containing Elements that should be removed from the + * paragraph Element + * @param added + * an array containing Elements that should be added to the + * paragraph Element + */ + public Edit(Element e, int i, Element[] removed, Element[] added) + { + this.e = e; + this.index = i; + addRemovedElements(removed); + addAddedElements(added); } } /** - * An element type for sections. This is a simple BranchElement with - * a unique name. + * An element type for sections. This is a simple BranchElement with a unique + * name. */ protected class SectionElement extends BranchElement { @@ -1244,7 +1630,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the name of the element. This method always returns * "section". - * + * * @return the name of the element */ public String getName() @@ -1256,18 +1642,18 @@ public class DefaultStyledDocument extends AbstractDocument /** * Receives notification when any of the document's style changes and calls * {@link DefaultStyledDocument#styleChanged(Style)}. - * + * * @author Roman Kennke (kennke@aicas.com) */ - private class StyleChangeListener - implements ChangeListener + private class StyleChangeListener implements ChangeListener { /** * Receives notification when any of the document's style changes and calls * {@link DefaultStyledDocument#styleChanged(Style)}. - * - * @param event the change event + * + * @param event + * the change event */ public void stateChanged(ChangeEvent event) { @@ -1296,6 +1682,11 @@ public class DefaultStyledDocument extends AbstractDocument private StyleChangeListener styleChangeListener; /** + * Vector that contains all the edits. Maybe replace by a HashMap. + */ + Vector edits = new Vector(); + + /** * Creates a new <code>DefaultStyledDocument</code>. */ public DefaultStyledDocument() @@ -1304,10 +1695,11 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Creates a new <code>DefaultStyledDocument</code> that uses the - * specified {@link StyleContext}. - * - * @param context the <code>StyleContext</code> to use + * Creates a new <code>DefaultStyledDocument</code> that uses the specified + * {@link StyleContext}. + * + * @param context + * the <code>StyleContext</code> to use */ public DefaultStyledDocument(StyleContext context) { @@ -1315,14 +1707,16 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Creates a new <code>DefaultStyledDocument</code> that uses the - * specified {@link StyleContext} and {@link Content} buffer. - * - * @param content the <code>Content</code> buffer to use - * @param context the <code>StyleContext</code> to use + * Creates a new <code>DefaultStyledDocument</code> that uses the specified + * {@link StyleContext} and {@link Content} buffer. + * + * @param content + * the <code>Content</code> buffer to use + * @param context + * the <code>StyleContext</code> to use */ public DefaultStyledDocument(AbstractDocument.Content content, - StyleContext context) + StyleContext context) { super(content, context); buffer = new ElementBuffer(createDefaultRoot()); @@ -1330,10 +1724,9 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Adds a style into the style hierarchy. Unspecified style attributes - * can be resolved in the <code>parent</code> style, if one is specified. - * - * While it is legal to add nameless styles (<code>nm == null</code), + * Adds a style into the style hierarchy. Unspecified style attributes can be + * resolved in the <code>parent</code> style, if one is specified. While it + * is legal to add nameless styles (<code>nm == null</code), * you must be aware that the client application is then responsible * for managing the style hierarchy, since unnamed styles cannot be * looked up by their name. @@ -1360,14 +1753,12 @@ public class DefaultStyledDocument extends AbstractDocument /** * Create the default root element for this kind of <code>Document</code>. - * + * * @return the default root element for this kind of <code>Document</code> */ protected AbstractDocument.AbstractElement createDefaultRoot() { Element[] tmp; - // FIXME: Create a SecionElement here instead of a BranchElement. - // Use createBranchElement() and createLeafElement instead. SectionElement section = new SectionElement(); BranchElement paragraph = new BranchElement(section, null); @@ -1375,7 +1766,7 @@ public class DefaultStyledDocument extends AbstractDocument tmp[0] = paragraph; section.replace(0, 0, tmp); - LeafElement leaf = new LeafElement(paragraph, null, 0, 1); + Element leaf = new LeafElement(paragraph, null, 0, 1); tmp = new Element[1]; tmp[0] = leaf; paragraph.replace(0, 0, tmp); @@ -1384,14 +1775,14 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Returns the <code>Element</code> that corresponds to the character - * at the specified position. - * - * @param position the position of which we query the corresponding - * <code>Element</code> - * - * @return the <code>Element</code> that corresponds to the character - * at the specified position + * Returns the <code>Element</code> that corresponds to the character at the + * specified position. + * + * @param position + * the position of which we query the corresponding + * <code>Element</code> + * @return the <code>Element</code> that corresponds to the character at the + * specified position */ public Element getCharacterElement(int position) { @@ -1402,15 +1793,15 @@ public class DefaultStyledDocument extends AbstractDocument int index = element.getElementIndex(position); element = element.getElement(index); } - + return element; } /** * Extracts a background color from a set of attributes. - * - * @param attributes the attributes from which to get a background color - * + * + * @param attributes + * the attributes from which to get a background color * @return the background color that correspond to the attributes */ public Color getBackground(AttributeSet attributes) @@ -1421,7 +1812,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the default root element. - * + * * @return the default root element */ public Element getDefaultRootElement() @@ -1431,9 +1822,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Extracts a font from a set of attributes. - * - * @param attributes the attributes from which to get a font - * + * + * @param attributes + * the attributes from which to get a font * @return the font that correspond to the attributes */ public Font getFont(AttributeSet attributes) @@ -1441,12 +1832,12 @@ public class DefaultStyledDocument extends AbstractDocument StyleContext context = (StyleContext) getAttributeContext(); return context.getFont(attributes); } - + /** * Extracts a foreground color from a set of attributes. - * - * @param attributes the attributes from which to get a foreground color - * + * + * @param attributes + * the attributes from which to get a foreground color * @return the foreground color that correspond to the attributes */ public Color getForeground(AttributeSet attributes) @@ -1457,9 +1848,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the logical <code>Style</code> for the specified position. - * - * @param position the position from which to query to logical style - * + * + * @param position + * the position from which to query to logical style * @return the logical <code>Style</code> for the specified position */ public Style getLogicalStyle(int position) @@ -1474,37 +1865,32 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Returns the paragraph element for the specified position. - * If the position is outside the bounds of the document's root element, - * then the closest element is returned. That is the last paragraph if + * Returns the paragraph element for the specified position. If the position + * is outside the bounds of the document's root element, then the closest + * element is returned. That is the last paragraph if * <code>position >= endIndex</code> or the first paragraph if * <code>position < startIndex</code>. - * - * @param position the position for which to query the paragraph element - * + * + * @param position + * the position for which to query the paragraph element * @return the paragraph element for the specified position */ public Element getParagraphElement(int position) { - BranchElement root = (BranchElement) getDefaultRootElement(); - int start = root.getStartOffset(); - int end = root.getEndOffset(); - if (position >= end) - position = end - 1; - else if (position < start) - position = start; - - Element par = root.positionToElement(position); - - assert par != null : "The paragraph element must not be null"; - return par; + Element e = getDefaultRootElement(); + while (!e.isLeaf()) + e = e.getElement(e.getElementIndex(position)); + + if (e != null) + return e.getParentElement(); + return e; } /** * Looks up and returns a named <code>Style</code>. - * - * @param nm the name of the <code>Style</code> - * + * + * @param nm + * the name of the <code>Style</code> * @return the found <code>Style</code> of <code>null</code> if no such * <code>Style</code> exists */ @@ -1516,8 +1902,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Removes a named <code>Style</code> from the style hierarchy. - * - * @param nm the name of the <code>Style</code> to be removed + * + * @param nm + * the name of the <code>Style</code> to be removed */ public void removeStyle(String nm) { @@ -1528,31 +1915,32 @@ public class DefaultStyledDocument extends AbstractDocument /** * Sets text attributes for the fragment specified by <code>offset</code> * and <code>length</code>. - * - * @param offset the start offset of the fragment - * @param length the length of the fragment - * @param attributes the text attributes to set - * @param replace if <code>true</code>, the attributes of the current - * selection are overridden, otherwise they are merged + * + * @param offset + * the start offset of the fragment + * @param length + * the length of the fragment + * @param attributes + * the text attributes to set + * @param replace + * if <code>true</code>, the attributes of the current selection + * are overridden, otherwise they are merged */ public void setCharacterAttributes(int offset, int length, - AttributeSet attributes, - boolean replace) + AttributeSet attributes, boolean replace) { // Exit early if length is 0, so no DocumentEvent is created or fired. if (length == 0) return; try { - // Must obtain a write lock for this method. writeLock() and + // Must obtain a write lock for this method. writeLock() and // writeUnlock() should always be in try/finally block to make // sure that locking happens in a balanced manner. writeLock(); - DefaultDocumentEvent ev = - new DefaultDocumentEvent( - offset, - length, - DocumentEvent.EventType.CHANGE); + DefaultDocumentEvent ev = new DefaultDocumentEvent(offset, + length, + DocumentEvent.EventType.CHANGE); // Modify the element structure so that the interval begins at an // element @@ -1563,13 +1951,13 @@ public class DefaultStyledDocument extends AbstractDocument // Visit all paragraph elements within the specified interval int end = offset + length; Element curr; - for (int pos = offset; pos < end; ) + for (int pos = offset; pos < end;) { // Get the CharacterElement at offset pos. curr = getCharacterElement(pos); if (pos == curr.getEndOffset()) break; - + MutableAttributeSet a = (MutableAttributeSet) curr.getAttributes(); ev.addEdit(new AttributeUndoableEdit(curr, attributes, replace)); // If replace is true, remove all the old attributes. @@ -1588,12 +1976,14 @@ public class DefaultStyledDocument extends AbstractDocument writeUnlock(); } } - + /** * Sets the logical style for the paragraph at the specified position. - * - * @param position the position at which the logical style is added - * @param style the style to set for the current paragraph + * + * @param position + * the position at which the logical style is added + * @param style + * the style to set for the current paragraph */ public void setLogicalStyle(int position, Style style) { @@ -1603,60 +1993,59 @@ public class DefaultStyledDocument extends AbstractDocument if (el == null) return; try - { - writeLock(); - if (el instanceof AbstractElement) - { - AbstractElement ael = (AbstractElement) el; - ael.setResolveParent(style); - int start = el.getStartOffset(); - int end = el.getEndOffset(); - DefaultDocumentEvent ev = - new DefaultDocumentEvent ( - start, - end - start, - DocumentEvent.EventType.CHANGE); - // FIXME: Add an UndoableEdit to this event and fire it. - fireChangedUpdate(ev); - } - else - throw new - AssertionError("paragraph elements are expected to be" - + "instances of AbstractDocument.AbstractElement"); - } + { + writeLock(); + if (el instanceof AbstractElement) + { + AbstractElement ael = (AbstractElement) el; + ael.setResolveParent(style); + int start = el.getStartOffset(); + int end = el.getEndOffset(); + DefaultDocumentEvent ev = new DefaultDocumentEvent(start, + end - start, + DocumentEvent.EventType.CHANGE); + fireChangedUpdate(ev); + fireUndoableEditUpdate(new UndoableEditEvent(this, ev)); + } + else + throw new AssertionError( + "paragraph elements are expected to be" + + "instances of AbstractDocument.AbstractElement"); + } finally - { - writeUnlock(); - } + { + writeUnlock(); + } } /** * Sets text attributes for the paragraph at the specified fragment. - * - * @param offset the beginning of the fragment - * @param length the length of the fragment - * @param attributes the text attributes to set - * @param replace if <code>true</code>, the attributes of the current - * selection are overridden, otherwise they are merged + * + * @param offset + * the beginning of the fragment + * @param length + * the length of the fragment + * @param attributes + * the text attributes to set + * @param replace + * if <code>true</code>, the attributes of the current selection + * are overridden, otherwise they are merged */ public void setParagraphAttributes(int offset, int length, - AttributeSet attributes, - boolean replace) + AttributeSet attributes, boolean replace) { try { - // Must obtain a write lock for this method. writeLock() and + // Must obtain a write lock for this method. writeLock() and // writeUnlock() should always be in try/finally blocks to make // sure that locking occurs in a balanced manner. writeLock(); - + // Create a DocumentEvent to use for changedUpdate(). - DefaultDocumentEvent ev = - new DefaultDocumentEvent ( - offset, - length, - DocumentEvent.EventType.CHANGE); - + DefaultDocumentEvent ev = new DefaultDocumentEvent(offset, + length, + DocumentEvent.EventType.CHANGE); + // Have to iterate through all the _paragraph_ elements that are // contained or partially contained in the interval // (offset, offset + length). @@ -1665,7 +2054,7 @@ public class DefaultStyledDocument extends AbstractDocument int endElement = rootElement.getElementIndex(offset + length - 1); if (endElement < startElement) endElement = startElement; - + for (int i = startElement; i <= endElement; i++) { Element par = rootElement.getElement(i); @@ -1688,11 +2077,13 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Called in response to content insert actions. This is used to - * update the element structure. - * - * @param ev the <code>DocumentEvent</code> describing the change - * @param attr the attributes for the change + * Called in response to content insert actions. This is used to update the + * element structure. + * + * @param ev + * the <code>DocumentEvent</code> describing the change + * @param attr + * the attributes for the change */ protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr) { @@ -1703,8 +2094,7 @@ public class DefaultStyledDocument extends AbstractDocument int offset = ev.getOffset(); int length = ev.getLength(); int endOffset = offset + length; - AttributeSet paragraphAttributes = - getParagraphElement(endOffset).getAttributes(); + AttributeSet paragraphAttributes = getParagraphElement(endOffset).getAttributes(); Segment txt = new Segment(); try { @@ -1723,91 +2113,75 @@ public class DefaultStyledDocument extends AbstractDocument short finalStartDirection = ElementSpec.OriginateDirection; boolean prevCharWasNewline = false; Element prev = getCharacterElement(offset); - Element next = getCharacterElement(endOffset); + Element next = getCharacterElement(endOffset); Element prevParagraph = getParagraphElement(offset); Element paragraph = getParagraphElement(endOffset); - + int segmentEnd = txt.offset + txt.count; - + // Check to see if we're inserting immediately after a newline. if (offset > 0) { try - { - String s = getText(offset - 1, 1); - if (s.equals("\n")) - { - finalStartDirection = - handleInsertAfterNewline(specs, offset, endOffset, - prevParagraph, - paragraph, - paragraphAttributes); - - prevCharWasNewline = true; - // Find the final start tag from the ones just created. - for (int i = 0; i < specs.size(); i++) - if (((ElementSpec) specs.get(i)).getType() - == ElementSpec.StartTagType) - finalStartTag = (ElementSpec)specs.get(i); - } - } + { + String s = getText(offset - 1, 1); + if (s.equals("\n")) + { + finalStartDirection = handleInsertAfterNewline(specs, offset, + endOffset, + prevParagraph, + paragraph, + paragraphAttributes); + + prevCharWasNewline = true; + // Find the final start tag from the ones just created. + for (int i = 0; i < specs.size(); i++) + if (((ElementSpec) specs.get(i)).getType() == ElementSpec.StartTagType) + finalStartTag = (ElementSpec) specs.get(i); + } + } catch (BadLocationException ble) - { - // This shouldn't happen. - AssertionError ae = new AssertionError(); - ae.initCause(ble); - throw ae; - } + { + // This shouldn't happen. + AssertionError ae = new AssertionError(); + ae.initCause(ble); + throw ae; + } } - for (int i = txt.offset; i < segmentEnd; ++i) { len++; if (txt.array[i] == '\n') { // Add the ElementSpec for the content. - specs.add(new ElementSpec(attr, ElementSpec.ContentType, len)); + specs.add(new ElementSpec(attr, ElementSpec.ContentType, len)); // Add ElementSpecs for the newline. specs.add(new ElementSpec(null, ElementSpec.EndTagType)); finalStartTag = new ElementSpec(paragraphAttributes, - ElementSpec.StartTagType); + ElementSpec.StartTagType); specs.add(finalStartTag); len = 0; } } // Create last element if last character hasn't been a newline. - if (len > 0) + if (len > 0) specs.add(new ElementSpec(attr, ElementSpec.ContentType, len)); - // Set the direction of the last spec of type StartTagType. - // If we are inserting after a newline then this value comes from + // Set the direction of the last spec of type StartTagType. + // If we are inserting after a newline then this value comes from // handleInsertAfterNewline. if (finalStartTag != null) - { + { if (prevCharWasNewline) finalStartTag.setDirection(finalStartDirection); else if (prevParagraph.getEndOffset() != endOffset) - { - try - { - String last = getText(endOffset - 1, 1); - if (!last.equals("\n")) - finalStartTag.setDirection(ElementSpec.JoinFractureDirection); - } - catch (BadLocationException ble) - { - // This shouldn't happen. - AssertionError ae = new AssertionError(); - ae.initCause(ble); - throw ae; - } - } + finalStartTag.setDirection(ElementSpec.JoinFractureDirection); else { - // If there is an element AFTER this one, then set the + // If there is an element AFTER this one, then set the // direction to JoinNextDirection. Element parent = prevParagraph.getParentElement(); int index = parent.getElementIndex(offset); @@ -1816,19 +2190,18 @@ public class DefaultStyledDocument extends AbstractDocument finalStartTag.setDirection(ElementSpec.JoinNextDirection); } } - + // If we are at the last index, then check if we could probably be // joined with the next element. // This means: - // - we must be a ContentTag - // - if there is a next Element, we must have the same attributes - // - if there is no next Element, but one will be created, - // we must have the same attributes as the higher-level run. + // - we must be a ContentTag + // - if there is a next Element, we must have the same attributes + // - if there is no next Element, but one will be created, + // we must have the same attributes as the higher-level run. ElementSpec last = (ElementSpec) specs.lastElement(); if (last.getType() == ElementSpec.ContentType) { - Element currentRun = - prevParagraph.getElement(prevParagraph.getElementIndex(offset)); + Element currentRun = prevParagraph.getElement(prevParagraph.getElementIndex(offset)); if (currentRun.getEndOffset() == endOffset) { if (endOffset < getLength() && next.getAttributes().isEqual(attr) @@ -1838,62 +2211,58 @@ public class DefaultStyledDocument extends AbstractDocument else { if (finalStartTag != null - && finalStartTag.getDirection() == - ElementSpec.JoinFractureDirection + && finalStartTag.getDirection() == ElementSpec.JoinFractureDirection && currentRun.getAttributes().isEqual(attr)) { last.setDirection(ElementSpec.JoinNextDirection); } } } - + // If we are at the first new element, then check if it could be // joined with the previous element. ElementSpec first = (ElementSpec) specs.firstElement(); if (prev.getAttributes().isEqual(attr) && first.getType() == ElementSpec.ContentType) first.setDirection(ElementSpec.JoinPreviousDirection); - - ElementSpec[] elSpecs = - (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]); + ElementSpec[] elSpecs = (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]); buffer.insert(offset, length, elSpecs, ev); } /** - * A helper method to set up the ElementSpec buffer for the special - * case of an insertion occurring immediately after a newline. - * @param specs the ElementSpec buffer to initialize. + * A helper method to set up the ElementSpec buffer for the special case of an + * insertion occurring immediately after a newline. + * + * @param specs + * the ElementSpec buffer to initialize. */ short handleInsertAfterNewline(Vector specs, int offset, int endOffset, - Element prevParagraph, Element paragraph, - AttributeSet a) + Element prevParagraph, Element paragraph, + AttributeSet a) { if (prevParagraph.getParentElement() == paragraph.getParentElement()) { specs.add(new ElementSpec(a, ElementSpec.EndTagType)); specs.add(new ElementSpec(a, ElementSpec.StartTagType)); - if (prevParagraph.getEndOffset() != endOffset) + if (paragraph.getStartOffset() != endOffset) return ElementSpec.JoinFractureDirection; // If there is an Element after this one, use JoinNextDirection. Element parent = paragraph.getParentElement(); - if (parent.getElementCount() > parent.getElementIndex(offset) + 1) + if (parent.getElementCount() > (parent.getElementIndex(offset) + 1)) return ElementSpec.JoinNextDirection; } - else - { - // TODO: What to do here? - } return ElementSpec.OriginateDirection; } - + /** * Updates the document structure in response to text removal. This is - * forwarded to the {@link ElementBuffer} of this document. Any changes to - * the document structure are added to the specified document event and - * sent to registered listeners. - * - * @param ev the document event that records the changes to the document + * forwarded to the {@link ElementBuffer} of this document. Any changes to the + * document structure are added to the specified document event and sent to + * registered listeners. + * + * @param ev + * the document event that records the changes to the document */ protected void removeUpdate(DefaultDocumentEvent ev) { @@ -1903,7 +2272,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns an enumeration of all style names. - * + * * @return an enumeration of all style names */ public Enumeration getStyleNames() @@ -1914,61 +2283,35 @@ public class DefaultStyledDocument extends AbstractDocument /** * Called when any of this document's styles changes. - * - * @param style the style that changed + * + * @param style + * the style that changed */ protected void styleChanged(Style style) { // Nothing to do here. This is intended to be overridden by subclasses. } - void printElements (Element start, int pad) - { - for (int i = 0; i < pad; i++) - System.out.print(" "); - if (pad == 0) - System.out.println ("ROOT ELEMENT ("+start.getStartOffset()+", "+start.getEndOffset()+")"); - else if (start instanceof AbstractDocument.BranchElement) - System.out.println ("BranchElement ("+start.getStartOffset()+", "+start.getEndOffset()+")"); - else - { - { - try - { - System.out.println ("LeafElement ("+start.getStartOffset()+", " - + start.getEndOffset()+"): "+ - start.getDocument(). - getText(start.getStartOffset(), - start.getEndOffset() - - start.getStartOffset())); - } - catch (BadLocationException ble) - { - } - } - } - for (int i = 0; i < start.getElementCount(); i ++) - printElements (start.getElement(i), pad+3); - } - /** * Inserts a bulk of structured content at once. - * - * @param offset the offset at which the content should be inserted - * @param data the actual content spec to be inserted + * + * @param offset + * the offset at which the content should be inserted + * @param data + * the actual content spec to be inserted */ protected void insert(int offset, ElementSpec[] data) - throws BadLocationException + throws BadLocationException { if (data == null || data.length == 0) return; try { // writeLock() and writeUnlock() should always be in a try/finally - // block so that locking balance is guaranteed even if some + // block so that locking balance is guaranteed even if some // exception is thrown. writeLock(); - + // First we collect the content to be inserted. StringBuffer contentBuffer = new StringBuffer(); for (int i = 0; i < data.length; i++) @@ -1986,15 +2329,14 @@ public class DefaultStyledDocument extends AbstractDocument // If there was no content inserted then exit early. if (length == 0) return; - + UndoableEdit edit = content.insertString(offset, contentBuffer.toString()); // Create the DocumentEvent with the ElementEdit added - DefaultDocumentEvent ev = - new DefaultDocumentEvent(offset, - length, - DocumentEvent.EventType.INSERT); + DefaultDocumentEvent ev = new DefaultDocumentEvent(offset, + length, + DocumentEvent.EventType.INSERT); ev.addEdit(edit); // Finally we must update the document structure and fire the insert @@ -2012,20 +2354,66 @@ public class DefaultStyledDocument extends AbstractDocument /** * Initializes the <code>DefaultStyledDocument</code> with the specified * data. - * - * @param data the specification of the content with which the document is - * initialized + * + * @param data + * the specification of the content with which the document is + * initialized */ protected void create(ElementSpec[] data) { + writeLock(); try { - // Clear content. - content.remove(0, content.length()); - // Clear buffer and root element. - buffer = new ElementBuffer(createDefaultRoot()); - // Insert the data. - insert(0, data); + // Clear content if there is some. + int len = getLength(); + if (len > 0) + remove(0, len); + + // Now we insert the content. + StringBuilder b = new StringBuilder(); + for (int i = 0; i < data.length; ++i) + { + ElementSpec el = data[i]; + if (el.getArray() != null && el.getLength() > 0) + b.append(el.getArray(), el.getOffset(), el.getLength()); + } + Content content = getContent(); + UndoableEdit cEdit = content.insertString(0, b.toString()); + + DefaultDocumentEvent ev = + new DefaultDocumentEvent(0, b.length(), + DocumentEvent.EventType.INSERT); + ev.addEdit(cEdit); + + // We do a little trick here to get the new structure: We instantiate + // a new ElementBuffer with a new root element, insert into that root + // and then reparent the newly created elements to the old root + // element. + BranchElement createRoot = + (BranchElement) createBranchElement(null, null); + Element dummyLeaf = createLeafElement(createRoot, null, 0, 1); + createRoot.replace(0, 0, new Element[]{ dummyLeaf }); + ElementBuffer createBuffer = new ElementBuffer(createRoot); + createBuffer.insert(0, b.length(), data, new DefaultDocumentEvent(0, b.length(), DocumentEvent.EventType.INSERT)); + // Now the new root is the first child of the createRoot. + Element newRoot = createRoot.getElement(0); + BranchElement root = (BranchElement) getDefaultRootElement(); + Element[] added = new Element[newRoot.getElementCount()]; + for (int i = 0; i < added.length; ++i) + { + added[i] = newRoot.getElement(i); + ((AbstractElement) added[i]).element_parent = root; + } + Element[] removed = new Element[root.getElementCount()]; + for (int i = 0; i < removed.length; ++i) + removed[i] = root.getElement(i); + + // Replace the old elements in root with the new and update the event. + root.replace(0, removed.length, added); + ev.addEdit(new ElementEdit(root, 0, removed, added)); + + fireInsertUpdate(ev); + fireUndoableEditUpdate(new UndoableEditEvent(this, ev)); } catch (BadLocationException ex) { @@ -2033,10 +2421,9 @@ public class DefaultStyledDocument extends AbstractDocument err.initCause(ex); throw err; } - } - - static boolean attributeSetsAreSame (AttributeSet a, AttributeSet b) - { - return (a == null && b == null) || (a != null && a.isEqual(b)); + finally + { + writeUnlock(); + } } } diff --git a/libjava/classpath/javax/swing/text/DefaultTextUI.java b/libjava/classpath/javax/swing/text/DefaultTextUI.java index e7ff01845e6..c347668b996 100644 --- a/libjava/classpath/javax/swing/text/DefaultTextUI.java +++ b/libjava/classpath/javax/swing/text/DefaultTextUI.java @@ -45,6 +45,7 @@ import javax.swing.plaf.basic.BasicTextUI; * all text components is now {@link BasicTextUI}. * * @author Roman Kennke (kennke@aicas.com) + * @deprecated as of 1.5 use {@link BasicTextUI} instead */ public abstract class DefaultTextUI extends BasicTextUI { diff --git a/libjava/classpath/javax/swing/text/FlowView.java b/libjava/classpath/javax/swing/text/FlowView.java index 6d4b9cd3174..8be8f41e939 100644 --- a/libjava/classpath/javax/swing/text/FlowView.java +++ b/libjava/classpath/javax/swing/text/FlowView.java @@ -38,14 +38,10 @@ exception statement from your version. */ package javax.swing.text; -import java.awt.Container; -import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; -import java.util.Iterator; -import java.util.Vector; -import javax.swing.SwingConstants; +import javax.swing.SizeRequirements; import javax.swing.event.DocumentEvent; /** @@ -89,7 +85,7 @@ public abstract class FlowView extends BoxView */ public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) { - layout(fv); + // The default implementation does nothing. } /** @@ -105,7 +101,7 @@ public abstract class FlowView extends BoxView */ public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) { - layout(fv); + // The default implementation does nothing. } /** @@ -121,7 +117,7 @@ public abstract class FlowView extends BoxView */ public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) { - layout(fv); + // The default implementation does nothing. } /** @@ -131,7 +127,7 @@ public abstract class FlowView extends BoxView * * @return the logical view of the managed <code>FlowView</code> */ - public View getLogicalView(FlowView fv) + protected View getLogicalView(FlowView fv) { return fv.layoutPool; } @@ -166,43 +162,60 @@ public abstract class FlowView extends BoxView * Lays out one row of the flow view. This is called by {@link #layout} * to fill one row with child views until the available span is exhausted. * + * The default implementation fills the row by calling + * {@link #createView(FlowView, int, int, int)} until the available space + * is exhausted, a forced break is encountered or there are no more views + * in the logical view. If the available space is exhausted, + * {@link #adjustRow(FlowView, int, int, int)} is called to fit the row + * into the available span. + * * @param fv the flow view for which we perform the layout * @param rowIndex the index of the row - * @param pos the start position for the row + * @param pos the model position for the beginning of the row * * @return the start position of the next row */ protected int layoutRow(FlowView fv, int rowIndex, int pos) { - int spanLeft = fv.getFlowSpan(rowIndex); - if (spanLeft <= 0) - return -1; - - int offset = pos; View row = fv.getView(rowIndex); - int flowAxis = fv.getFlowAxis(); + int axis = fv.getFlowAxis(); + int span = fv.getFlowSpan(rowIndex); + int x = fv.getFlowStart(rowIndex); + int offset = pos; + View logicalView = getLogicalView(fv); + // Special case when span == 0. We need to layout the row as if it had + // a span of Integer.MAX_VALUE. + if (span == 0) + span = Integer.MAX_VALUE; - while (spanLeft > 0) + while (span > 0) { - View child = createView(fv, offset, spanLeft, rowIndex); - if (child == null) - { - offset = -1; - break; - } - - int span = (int) child.getPreferredSpan(flowAxis); - if (span > spanLeft) - { - offset = -1; - break; - } - - row.append(child); - spanLeft -= span; - offset = child.getEndOffset(); + if (logicalView.getViewIndex(offset, Position.Bias.Forward) == -1) + break; + View view = createView(fv, offset, span, rowIndex); + if (view == null) + break; + int viewSpan = (int) view.getPreferredSpan(axis); + row.append(view); + int breakWeight = view.getBreakWeight(axis, x, span); + if (breakWeight >= View.ForcedBreakWeight) + break; + x += viewSpan; + span -= viewSpan; + offset += (view.getEndOffset() - view.getStartOffset()); } - return offset; + if (span < 0) + { + int flowStart = fv.getFlowStart(axis); + int flowSpan = fv.getFlowSpan(axis); + adjustRow(fv, rowIndex, flowSpan, flowStart); + int rowViewCount = row.getViewCount(); + if (rowViewCount > 0) + offset = row.getView(rowViewCount - 1).getEndOffset(); + else + offset = -1; + } + return offset != pos ? offset : -1; } /** @@ -212,189 +225,106 @@ public abstract class FlowView extends BoxView * available span and can be broken down) or <code>null</code> (if it does * not fit in the available span and also cannot be broken down). * + * The default implementation fetches the logical view at the specified + * <code>startOffset</code>. If that view has a different startOffset than + * specified in the argument, a fragment is created using + * {@link View#createFragment(int, int)} that has the correct startOffset + * and the logical view's endOffset. + * * @param fv the flow view - * @param offset the start offset for the view to be created + * @param startOffset the start offset for the view to be created * @param spanLeft the available span * @param rowIndex the index of the row * * @return a view to fill the row with, or <code>null</code> if there * is no view or view fragment that fits in the available span */ - protected View createView(FlowView fv, int offset, int spanLeft, + protected View createView(FlowView fv, int startOffset, int spanLeft, int rowIndex) { - // Find the logical element for the given offset. - View logicalView = getLogicalView(fv); - - int viewIndex = logicalView.getViewIndex(offset, Position.Bias.Forward); - if (viewIndex == -1) - return null; - - View child = logicalView.getView(viewIndex); - int flowAxis = fv.getFlowAxis(); - int span = (int) child.getPreferredSpan(flowAxis); - - if (span <= spanLeft) - return child; - else if (child.getBreakWeight(flowAxis, offset, spanLeft) - > BadBreakWeight) - // FIXME: What to do with the pos parameter here? - return child.breakView(flowAxis, offset, 0, spanLeft); - else - return null; - } - } - - /** - * This special subclass of <code>View</code> is used to represent - * the logical representation of this view. It does not support any - * visual representation, this is handled by the physical view implemented - * in the <code>FlowView</code>. - */ - class LogicalView extends View - { - /** - * The child views of this logical view. - */ - Vector children; - - /** - * Creates a new LogicalView instance. - */ - LogicalView(Element el) - { - super(el); - children = new Vector(); - } - - /** - * Returns the container that holds this view. The logical view returns - * the enclosing FlowView's container here. - * - * @return the container that holds this view - */ - public Container getContainer() - { - return FlowView.this.getContainer(); - } - - /** - * Returns the number of child views of this logical view. - * - * @return the number of child views of this logical view - */ - public int getViewCount() - { - return children.size(); - } - - /** - * Returns the child view at the specified index. - * - * @param index the index - * - * @return the child view at the specified index - */ - public View getView(int index) - { - return (View) children.get(index); - } - - /** - * Replaces some child views with other child views. - * - * @param offset the offset at which to replace child views - * @param length the number of children to remove - * @param views the views to be inserted - */ - public void replace(int offset, int length, View[] views) - { - if (length > 0) - { - for (int count = 0; count < length; ++count) - children.remove(offset); - } - - int endOffset = offset + views.length; - for (int i = offset; i < endOffset; ++i) - { - children.add(i, views[i - offset]); - // Set the parent of the child views to the flow view itself so - // it has something to resolve. - views[i - offset].setParent(FlowView.this); - } + View logicalView = getLogicalView(fv); + // FIXME: Handle the bias thing correctly. + int index = logicalView.getViewIndex(startOffset, Position.Bias.Forward); + View retVal = null; + if (index >= 0) + { + retVal = logicalView.getView(index); + if (retVal.getStartOffset() != startOffset) + retVal = retVal.createFragment(startOffset, retVal.getEndOffset()); + } + return retVal; } /** - * Returns the index of the child view that contains the specified - * position in the document model. + * Tries to adjust the specified row to fit within the desired span. The + * default implementation iterates through the children of the specified + * row to find the view that has the highest break weight and - if there + * is more than one view with such a break weight - which is nearest to + * the end of the row. If there is such a view that has a break weight > + * {@link View#BadBreakWeight}, this view is broken using the + * {@link View#breakView(int, int, float, float)} method and this view and + * all views after the now broken view are replaced by the broken view. * - * @param pos the position for which we are searching the child view - * @param b the bias - * - * @return the index of the child view that contains the specified - * position in the document model + * @param fv the flow view + * @param rowIndex the index of the row to be adjusted + * @param desiredSpan the layout span + * @param x the X location at which the row starts */ - public int getViewIndex(int pos, Position.Bias b) - { - int index = -1; - int i = 0; - for (Iterator it = children.iterator(); it.hasNext(); i++) + protected void adjustRow(FlowView fv, int rowIndex, int desiredSpan, int x) { + // Determine the last view that has the highest break weight. + int axis = fv.getFlowAxis(); + View row = fv.getView(rowIndex); + int count = row.getViewCount(); + int breakIndex = -1; + int maxBreakWeight = View.BadBreakWeight; + int breakX = x; + int breakSpan = desiredSpan; + int currentX = x; + int currentSpan = desiredSpan; + for (int i = 0; i < count; ++i) { - View child = (View) it.next(); - if (child.getStartOffset() >= pos - && child.getEndOffset() < pos) + View view = row.getView(i); + int weight = view.getBreakWeight(axis, currentX, currentSpan); + if (weight >= maxBreakWeight) { - index = i; - break; + breakIndex = i; + breakX = currentX; + breakSpan = currentSpan; + maxBreakWeight = weight; } + int size = (int) view.getPreferredSpan(axis); + currentX += size; + currentSpan -= size; } - return index; - } - /** - * Throws an AssertionError because it must never be called. LogicalView - * only serves as a holder for child views and has no visual - * representation. - */ - public float getPreferredSpan(int axis) - { - throw new AssertionError("This method must not be called in " - + "LogicalView."); - } - - /** - * Throws an AssertionError because it must never be called. LogicalView - * only serves as a holder for child views and has no visual - * representation. - */ - public Shape modelToView(int pos, Shape a, Position.Bias b) - throws BadLocationException - { - throw new AssertionError("This method must not be called in " - + "LogicalView."); - } - - /** - * Throws an AssertionError because it must never be called. LogicalView - * only serves as a holder for child views and has no visual - * representation. - */ - public void paint(Graphics g, Shape s) - { - throw new AssertionError("This method must not be called in " - + "LogicalView."); + // If there is a potential break location found, break the row at + // this location. + if (breakIndex > -1) + { + View toBeBroken = row.getView(breakIndex); + View brokenView = toBeBroken.breakView(axis, + toBeBroken.getStartOffset(), + breakX, breakSpan); + row.replace(breakIndex, count - breakIndex, + new View[]{brokenView}); + } } + } + /** + * This special subclass of <code>View</code> is used to represent + * the logical representation of this view. It does not support any + * visual representation, this is handled by the physical view implemented + * in the <code>FlowView</code>. + */ + class LogicalView extends BoxView + { /** - * Throws an AssertionError because it must never be called. LogicalView - * only serves as a holder for child views and has no visual - * representation. + * Creates a new LogicalView instance. */ - public int viewToModel(float x, float y, Shape a, Position.Bias[] b) + LogicalView(Element el, int axis) { - throw new AssertionError("This method must not be called in " - + "LogicalView."); + super(el, axis); } } @@ -424,6 +354,11 @@ public abstract class FlowView extends BoxView protected FlowStrategy strategy; /** + * Indicates if the flow should be rebuild during the next layout. + */ + private boolean layoutDirty; + + /** * Creates a new <code>FlowView</code> for the given * <code>Element</code> and <code>axis</code>. * @@ -436,6 +371,7 @@ public abstract class FlowView extends BoxView { super(element, axis); strategy = sharedStrategy; + layoutDirty = true; } /** @@ -510,16 +446,8 @@ public abstract class FlowView extends BoxView { if (layoutPool == null) { - layoutPool = new LogicalView(getElement()); - - Element el = getElement(); - int count = el.getElementCount(); - for (int i = 0; i < count; ++i) - { - Element childEl = el.getElement(i); - View childView = vf.create(childEl); - layoutPool.append(childView); - } + layoutPool = new LogicalView(getElement(), getAxis()); + layoutPool.setParent(this); } } @@ -534,27 +462,32 @@ public abstract class FlowView extends BoxView */ protected void layout(int width, int height) { - boolean rebuild = false; - int flowAxis = getFlowAxis(); if (flowAxis == X_AXIS) { - rebuild = !(width == layoutSpan); - layoutSpan = width; + if (layoutSpan != width) + { + layoutChanged(Y_AXIS); + layoutSpan = width; + } } else { - rebuild = !(height == layoutSpan); - layoutSpan = height; + if (layoutSpan != height) + { + layoutChanged(X_AXIS); + layoutSpan = height; + } } - if (rebuild) - strategy.layout(this); + if (layoutDirty) + { + strategy.layout(this); + layoutDirty = false; + } - // TODO: If the span along the box axis has changed in the process of - // relayouting the rows (that is, if rows have been added or removed), - // call preferenceChanged in order to throw away cached layout information - // of the surrounding BoxView. + if (getPreferredSpan(getAxis()) != height) + preferenceChanged(this, false, true); super.layout(width, height); } @@ -574,6 +507,7 @@ public abstract class FlowView extends BoxView // be updated accordingly. layoutPool.insertUpdate(changes, a, vf); strategy.insertUpdate(this, changes, getInsideAllocation(a)); + layoutDirty = true; } /** @@ -588,6 +522,7 @@ public abstract class FlowView extends BoxView public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory vf) { strategy.removeUpdate(this, changes, getInsideAllocation(a)); + layoutDirty = true; } /** @@ -602,6 +537,7 @@ public abstract class FlowView extends BoxView public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory vf) { strategy.changedUpdate(this, changes, getInsideAllocation(a)); + layoutDirty = true; } /** @@ -640,4 +576,30 @@ public abstract class FlowView extends BoxView } return result; } + + /** + * Calculates the size requirements of this <code>BoxView</code> along + * its minor axis, that is the axis opposite to the axis specified in the + * constructor. + * + * This is overridden and forwards the request to the logical view. + * + * @param axis the axis that is examined + * @param r the <code>SizeRequirements</code> object to hold the result, + * if <code>null</code>, a new one is created + * + * @return the size requirements for this <code>BoxView</code> along + * the specified axis + */ + protected SizeRequirements calculateMinorAxisRequirements(int axis, + SizeRequirements r) + { + // We need to call super here so that the alignment is properly + // calculated. + SizeRequirements res = super.calculateMinorAxisRequirements(axis, r); + res.minimum = (int) layoutPool.getMinimumSpan(axis); + res.preferred = (int) layoutPool.getPreferredSpan(axis); + res.maximum = (int) layoutPool.getMaximumSpan(axis); + return res; + } } diff --git a/libjava/classpath/javax/swing/text/GapContent.java b/libjava/classpath/javax/swing/text/GapContent.java index 80dcfa56e06..28d1d6ee01f 100644 --- a/libjava/classpath/javax/swing/text/GapContent.java +++ b/libjava/classpath/javax/swing/text/GapContent.java @@ -1,5 +1,5 @@ /* GapContent.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,8 +39,10 @@ exception statement from your version. */ package javax.swing.text; import java.io.Serializable; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.ListIterator; import java.util.Vector; @@ -68,8 +70,8 @@ public class GapContent /** * A {@link Position} implementation for <code>GapContent</code>. */ - class GapContentPosition - implements Position, Comparable + private class GapContentPosition + implements Position, Comparable { /** The index within the buffer array. */ @@ -130,7 +132,7 @@ public class GapContent } } - class InsertUndo extends AbstractUndoableEdit + private class InsertUndo extends AbstractUndoableEdit { public int where, length; String text; @@ -169,7 +171,7 @@ public class GapContent } - class UndoRemove extends AbstractUndoableEdit + private class UndoRemove extends AbstractUndoableEdit { public int where; String text; @@ -206,7 +208,41 @@ public class GapContent } } - + + /** + * Compares WeakReference objects in a List by comparing the referenced + * objects instead. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class WeakPositionComparator + implements Comparator + { + + /** + * Compares two objects of type WeakReference. The objects are compared + * using the referenced objects compareTo() method. + */ + public int compare(Object o1, Object o2) + { + // Unwrap references. + if (o1 instanceof WeakReference) + o1 = ((WeakReference) o1).get(); + if (o2 instanceof WeakReference) + o2 = ((WeakReference) o2).get(); + + GapContentPosition p1 = (GapContentPosition) o1; + GapContentPosition p2 = (GapContentPosition) o2; + + int retVal; + if (p1 == null || p2 == null) + retVal = -1; + else + retVal = p1.compareTo(p2); + return retVal; + } + } + /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = -6226052713477823730L; @@ -233,9 +269,10 @@ public class GapContent /** * The positions generated by this GapContent. They are kept in an ordered - * fashion, so they can be looked up easily. + * fashion, so they can be looked up easily. The value objects will be + * WeakReference objects that in turn hold GapContentPosition objects. */ - ArrayList positions; + private ArrayList positions; /** * Creates a new GapContent object. @@ -310,8 +347,12 @@ public class GapContent int length = length(); int strLen = str.length(); + if (where < 0) + throw new BadLocationException("The where argument cannot be smaller" + + " than the zero", where); + if (where >= length) - throw new BadLocationException("the where argument cannot be greater" + throw new BadLocationException("The where argument cannot be greater" + " than the content length", where); replace(where, 0, str.toCharArray(), strLen); @@ -446,18 +487,22 @@ public class GapContent throw new BadLocationException("The offset was out of the bounds of this" + " buffer", offset); + clearPositionReferences(); + // We store the actual array index in the GapContentPosition. The real // offset is then calculated in the GapContentPosition. int mark = offset; if (offset >= gapStart) mark += gapEnd - gapStart; GapContentPosition pos = new GapContentPosition(mark); + WeakReference r = new WeakReference(pos); // Add this into our list in a sorted fashion. - int index = Collections.binarySearch(positions, pos); + int index = Collections.binarySearch(positions, r, + new WeakPositionComparator()); if (index < 0) index = -(index + 1); - positions.add(index, pos); + positions.add(index, r); return pos; } @@ -557,7 +602,7 @@ public class GapContent assert newGapEnd > gapEnd : "The new gap end must be greater than the " + "old gap end."; - setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd + 1); + setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd); gapEnd = newGapEnd; } @@ -566,7 +611,7 @@ public class GapContent * * @return the allocated buffer array */ - protected Object getArray() + protected final Object getArray() { return buffer; } @@ -642,19 +687,30 @@ public class GapContent int endOffset = offset + length; int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset)); + new GapContentPosition(offset), + new WeakPositionComparator()); if (index1 < 0) index1 = -(index1 + 1); // Search the first index with the specified offset. The binarySearch does // not necessarily find the first one. - while (index1 > 0 - && ((GapContentPosition) positions.get(index1 - 1)).mark == offset) - index1--; + while (index1 > 0) + { + WeakReference r = (WeakReference) positions.get(index1 - 1); + GapContentPosition p = (GapContentPosition) r.get(); + if (p != null && p.mark == offset || p == null) + index1--; + else + break; + } for (ListIterator i = positions.listIterator(index1); i.hasNext();) { - GapContentPosition p = (GapContentPosition) i.next(); + WeakReference r = (WeakReference) i.next(); + GapContentPosition p = (GapContentPosition) r.get(); + if (p == null) + continue; + if (p.mark > endOffset) break; if (p.mark >= offset && p.mark <= endOffset) @@ -672,24 +728,35 @@ public class GapContent * @param length the length of the range to search * @param value the new value for each mark */ - void setPositionsInRange(int offset, int length, int value) + private void setPositionsInRange(int offset, int length, int value) { int endOffset = offset + length; int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset)); + new GapContentPosition(offset), + new WeakPositionComparator()); if (index1 < 0) index1 = -(index1 + 1); // Search the first index with the specified offset. The binarySearch does // not necessarily find the first one. - while (index1 > 0 - && ((GapContentPosition) positions.get(index1 - 1)).mark == offset) - index1--; + while (index1 > 0) + { + WeakReference r = (WeakReference) positions.get(index1 - 1); + GapContentPosition p = (GapContentPosition) r.get(); + if (p != null && p.mark == offset || p == null) + index1--; + else + break; + } for (ListIterator i = positions.listIterator(index1); i.hasNext();) { - GapContentPosition p = (GapContentPosition) i.next(); + WeakReference r = (WeakReference) i.next(); + GapContentPosition p = (GapContentPosition) r.get(); + if (p == null) + continue; + if (p.mark > endOffset) break; @@ -707,23 +774,35 @@ public class GapContent * @param length the length of the range to search * @param incr the increment */ - void adjustPositionsInRange(int offset, int length, int incr) + private void adjustPositionsInRange(int offset, int length, int incr) { int endOffset = offset + length; int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset)); + new GapContentPosition(offset), + new WeakPositionComparator()); if (index1 < 0) index1 = -(index1 + 1); // Search the first index with the specified offset. The binarySearch does // not necessarily find the first one. - while (index1 > 0 - && ((GapContentPosition) positions.get(index1 - 1)).mark == offset) - index1--; + while (index1 > 0) + { + WeakReference r = (WeakReference) positions.get(index1 - 1); + GapContentPosition p = (GapContentPosition) r.get(); + if (p != null && p.mark == offset || p == null) + index1--; + else + break; + } + for (ListIterator i = positions.listIterator(index1); i.hasNext();) { - GapContentPosition p = (GapContentPosition) i.next(); + WeakReference r = (WeakReference) i.next(); + GapContentPosition p = (GapContentPosition) r.get(); + if (p == null) + continue; + if (p.mark > endOffset) break; @@ -747,6 +826,17 @@ public class GapContent } /** + * @specnote This method is not very well specified and the positions vector + * is implementation specific. The undo positions are managed + * differently in this implementation, this method is only here + * for binary compatibility. + */ + protected void updateUndoPositions(Vector positions, int offset, int length) + { + // We do nothing here. + } + + /** * Outputs debugging info to System.err. It prints out the buffer array, * the gapStart is marked by a < sign, the gapEnd is marked by a > * sign and each position is marked by a # sign. @@ -776,8 +866,23 @@ public class GapContent { for (Iterator i = positions.iterator(); i.hasNext();) { - GapContentPosition pos = (GapContentPosition) i.next(); + WeakReference r = (WeakReference) i.next(); + GapContentPosition pos = (GapContentPosition) r.get(); System.err.println("position at: " + pos.mark); } } + + /** + * Clears all GC'ed references in the positions array. + */ + private void clearPositionReferences() + { + Iterator i = positions.iterator(); + while (i.hasNext()) + { + WeakReference r = (WeakReference) i.next(); + if (r.get() == null) + i.remove(); + } + } } diff --git a/libjava/classpath/javax/swing/text/GlyphView.java b/libjava/classpath/javax/swing/text/GlyphView.java index 47deb50d03a..d505274c91f 100644 --- a/libjava/classpath/javax/swing/text/GlyphView.java +++ b/libjava/classpath/javax/swing/text/GlyphView.java @@ -277,38 +277,41 @@ public class GlyphView extends View implements TabableView, Cloneable public void paint(GlyphView view, Graphics g, Shape a, int p0, int p1) { + Color oldColor = g.getColor(); int height = (int) getHeight(view); Segment txt = view.getText(p0, p1); Rectangle bounds = a.getBounds(); - TabExpander tabEx = null; View parent = view.getParent(); if (parent instanceof TabExpander) tabEx = (TabExpander) parent; - // Fill the background of the text run. - Color background = view.getBackground(); - g.setColor(background); int width = Utilities.getTabbedTextWidth(txt, g.getFontMetrics(), bounds.x, tabEx, txt.offset); - g.fillRect(bounds.x, bounds.y, width, height); - + // Fill the background of the text run. + Color background = view.getBackground(); + if (background != null) + { + g.setColor(background); + g.fillRect(bounds.x, bounds.y, width, height); + } // Draw the actual text. g.setColor(view.getForeground()); g.setFont(view.getFont()); + int ascent = g.getFontMetrics().getAscent(); if (view.isSuperscript()) // TODO: Adjust font for superscripting. - Utilities.drawTabbedText(txt, bounds.x, bounds.y - height / 2, g, tabEx, - txt.offset); + Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent - height / 2, + g, tabEx, txt.offset); else if (view.isSubscript()) // TODO: Adjust font for subscripting. - Utilities.drawTabbedText(txt, bounds.x, bounds.y + height / 2, g, tabEx, - txt.offset); + Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent + height / 2, + g, tabEx, txt.offset); else - Utilities.drawTabbedText(txt, bounds.x, bounds.y, g, tabEx, + Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent, g, tabEx, txt.offset); - if (view.isStikeThrough()) + if (view.isStrikeThrough()) { int strikeHeight = (int) (getAscent(view) / 2); g.drawLine(bounds.x, bounds.y + strikeHeight, bounds.height + width, @@ -320,6 +323,7 @@ public class GlyphView extends View implements TabableView, Cloneable g.drawLine(bounds.x, bounds.y + lineHeight, bounds.height + width, bounds.y + lineHeight); } + g.setColor(oldColor); } /** @@ -470,12 +474,12 @@ public class GlyphView extends View implements TabableView, Cloneable /** * The start offset within the document for this view. */ - int startOffset; + private int startOffset; /** * The end offset within the document for this view. */ - int endOffset; + private int endOffset; /** * Creates a new <code>GlyphView</code> for the given <code>Element</code>. @@ -485,8 +489,8 @@ public class GlyphView extends View implements TabableView, Cloneable public GlyphView(Element element) { super(element); - startOffset = element.getStartOffset(); - endOffset = element.getEndOffset(); + startOffset = -1; + endOffset = -1; } /** @@ -534,8 +538,7 @@ public class GlyphView extends View implements TabableView, Cloneable { Element el = getElement(); checkPainter(); - getGlyphPainter().paint(this, g, a, el.getStartOffset(), - el.getEndOffset()); + getGlyphPainter().paint(this, g, a, getStartOffset(), getEndOffset()); } @@ -563,7 +566,8 @@ public class GlyphView extends View implements TabableView, Cloneable tabEx, 0.F); } else - span = painter.getHeight(this); + span = painter.getHeight(this); + return span; } @@ -682,7 +686,10 @@ public class GlyphView extends View implements TabableView, Cloneable */ public int getStartOffset() { - return startOffset; + int start = startOffset; + if (start < 0) + start = super.getStartOffset(); + return start; } /** @@ -694,7 +701,10 @@ public class GlyphView extends View implements TabableView, Cloneable */ public int getEndOffset() { - return endOffset; + int end = endOffset; + if (end < 0) + end = super.getEndOffset(); + return end; } /** @@ -771,7 +781,11 @@ public class GlyphView extends View implements TabableView, Cloneable { Element el = getElement(); AttributeSet atts = el.getAttributes(); - return StyleConstants.getBackground(atts); + // We cannot use StyleConstants.getBackground() here, because that returns + // BLACK as default (when background == null). What we need is the + // background setting of the text component instead, which is what we get + // when background == null anyway. + return (Color) atts.getAttribute(StyleConstants.Background); } /** @@ -782,7 +796,7 @@ public class GlyphView extends View implements TabableView, Cloneable * * @return whether the text should be rendered strike-through or not */ - public boolean isStikeThrough() + public boolean isStrikeThrough() { Element el = getElement(); AttributeSet atts = el.getAttributes(); @@ -876,13 +890,15 @@ public class GlyphView extends View implements TabableView, Cloneable checkPainter(); GlyphPainter painter = getGlyphPainter(); - int breakLocation = painter.getBoundedPosition(this, p0, pos, len); + // Try to find a suitable line break. BreakIterator lineBreaker = BreakIterator.getLineInstance(); Segment txt = new Segment(); try { - getDocument().getText(getStartOffset(), getEndOffset(), txt); + int start = getStartOffset(); + int length = getEndOffset() - start; + getDocument().getText(start, length, txt); } catch (BadLocationException ex) { @@ -891,11 +907,10 @@ public class GlyphView extends View implements TabableView, Cloneable err.initCause(ex); throw err; } - lineBreaker.setText(txt); - int goodBreakLocation = lineBreaker.previous(); - if (goodBreakLocation != BreakIterator.DONE) - breakLocation = goodBreakLocation; - + int breakLocation = + Utilities.getBreakLocation(txt, getContainer().getFontMetrics(getFont()), + (int) pos, (int) (pos + len), + getTabExpander(), p0); View brokenView = createFragment(p0, breakLocation); return brokenView; } @@ -922,23 +937,24 @@ public class GlyphView extends View implements TabableView, Cloneable weight = super.getBreakWeight(axis, pos, len); else { - // Determine the model locations at pos and pos + len. - int spanX = (int) getPreferredSpan(X_AXIS); - int spanY = (int) getPreferredSpan(Y_AXIS); - Rectangle dummyAlloc = new Rectangle(0, 0, spanX, spanY); - Position.Bias[] biasRet = new Position.Bias[1]; - int offset1 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet); - int offset2 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet); - Segment txt = getText(offset1, offset2); - BreakIterator lineBreaker = BreakIterator.getLineInstance(); - lineBreaker.setText(txt); - int breakLoc = lineBreaker.previous(); - if (breakLoc == offset1) - weight = View.BadBreakWeight; - else if(breakLoc == BreakIterator.DONE) - weight = View.GoodBreakWeight; - else - weight = View.ExcellentBreakWeight; + // FIXME: Commented out because the Utilities.getBreakLocation method + // is still buggy. The GoodBreakWeight is a reasonable workaround for + // now. +// int startOffset = getStartOffset(); +// int endOffset = getEndOffset() - 1; +// Segment s = getText(startOffset, endOffset); +// Container c = getContainer(); +// FontMetrics fm = c.getFontMetrics(c.getFont()); +// int x0 = (int) pos; +// int x = (int) (pos + len); +// int breakLoc = Utilities.getBreakLocation(s, fm, x0, x, +// getTabExpander(), +// startOffset); +// if (breakLoc == startOffset || breakLoc == endOffset) +// weight = GoodBreakWeight; +// else +// weight = ExcellentBreakWeight; + weight = GoodBreakWeight; } return weight; } @@ -955,14 +971,14 @@ public class GlyphView extends View implements TabableView, Cloneable */ public void changedUpdate(DocumentEvent e, Shape a, ViewFactory vf) { - getParent().preferenceChanged(this, true, true); + preferenceChanged(this, true, true); } /** * Receives notification that some text has been inserted within the * text fragment that this view is responsible for. This calls - * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for - * width. + * {@link View#preferenceChanged(View, boolean, boolean)} for the + * direction in which the glyphs are rendered. * * @param e the document event describing the change; not used here * @param a the view allocation on screen; not used here @@ -970,7 +986,7 @@ public class GlyphView extends View implements TabableView, Cloneable */ public void insertUpdate(DocumentEvent e, Shape a, ViewFactory vf) { - getParent().preferenceChanged(this, true, false); + preferenceChanged(this, true, false); } /** @@ -985,7 +1001,7 @@ public class GlyphView extends View implements TabableView, Cloneable */ public void removeUpdate(DocumentEvent e, Shape a, ViewFactory vf) { - getParent().preferenceChanged(this, true, false); + preferenceChanged(this, true, false); } /** @@ -1000,8 +1016,10 @@ public class GlyphView extends View implements TabableView, Cloneable public View createFragment(int p0, int p1) { GlyphView fragment = (GlyphView) clone(); - fragment.startOffset = p0; - fragment.endOffset = p1; + if (p0 != getStartOffset()) + fragment.startOffset = p0; + if (p1 != getEndOffset()) + fragment.endOffset = p1; return fragment; } diff --git a/libjava/classpath/javax/swing/text/IconView.java b/libjava/classpath/javax/swing/text/IconView.java index af2581a8831..699cda90eba 100644 --- a/libjava/classpath/javax/swing/text/IconView.java +++ b/libjava/classpath/javax/swing/text/IconView.java @@ -130,8 +130,6 @@ public class IconView throws BadLocationException { Element el = getElement(); - if (pos < el.getStartOffset() || pos >= el.getEndOffset()) - throw new BadLocationException("Illegal offset for this view", pos); Rectangle r = a.getBounds(); Icon icon = StyleConstants.getIcon(el.getAttributes()); return new Rectangle(r.x, r.y, icon.getIconWidth(), icon.getIconHeight()); diff --git a/libjava/classpath/javax/swing/text/JTextComponent.java b/libjava/classpath/javax/swing/text/JTextComponent.java index afa1f24a6a4..6b8348ceaf5 100644 --- a/libjava/classpath/javax/swing/text/JTextComponent.java +++ b/libjava/classpath/javax/swing/text/JTextComponent.java @@ -60,7 +60,9 @@ import java.util.Enumeration; import java.util.Hashtable; import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleEditableText; import javax.accessibility.AccessibleRole; import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleText; @@ -86,200 +88,415 @@ public abstract class JTextComponent extends JComponent implements Scrollable, Accessible { /** - * AccessibleJTextComponent + * This class implements accessibility support for the JTextComponent class. + * It provides an implementation of the Java Accessibility API appropriate + * to menu user-interface elements. */ - // FIXME: This inner class is a complete stub and needs to be implemented. - public class AccessibleJTextComponent extends AccessibleJComponent - implements AccessibleText, CaretListener, DocumentListener + public class AccessibleJTextComponent extends AccessibleJComponent implements + AccessibleText, CaretListener, DocumentListener, AccessibleAction, + AccessibleEditableText { private static final long serialVersionUID = 7664188944091413696L; + /** The caret's offset. */ + int dot = 0; + + /** The current JTextComponent. */ + JTextComponent textComp = JTextComponent.this; + /** - * Constructor AccessibleJTextComponent + * Constructs an AccessibleJTextComponent. + * Adds a listener to track caret change. */ public AccessibleJTextComponent() { - // Nothing to do here. + super(); + textComp.addCaretListener(this); } /** - * getCaretPosition - * @return int + * Returns the zero-based offset of the caret. Note: The character + * to the right of the caret will have the same index value as the + * offset (the caret is between two characters). + * + * @return offset of caret */ public int getCaretPosition() { - return 0; // TODO + dot = textComp.getCaretPosition(); + return dot; } /** - * getSelectedText - * @return String + * Returns the portion of the text that is selected. + * + * @return null if no text is selected. */ public String getSelectedText() { - return null; // TODO + return textComp.getSelectedText(); } /** - * getSelectionStart - * @return int + * Returns the start offset within the selected text. If there is no + * selection, but there is a caret, the start and end offsets will be + * the same. Return 0 if the text is empty, or the caret position if no selection. + * + * @return index of the start of the text >= 0. */ public int getSelectionStart() { - return 0; // TODO + if (getSelectedText() == null || (textComp.getText().equals(""))) + return 0; + return textComp.getSelectionStart(); } /** - * getSelectionEnd - * @return int + * Returns the end offset within the selected text. If there is no + * selection, but there is a caret, the start and end offsets will + * be the same. Return 0 if the text is empty, or the caret position + * if no selection. + * + * @return index of the end of the text >= 0. */ public int getSelectionEnd() { - return 0; // TODO + if (getSelectedText() == null || (textComp.getText().equals(""))) + return 0; + return textComp.getSelectionEnd(); } /** - * caretUpdate - * @param value0 TODO + * Handles caret updates (fire appropriate property change event, which are + * AccessibleContext.ACCESSIBLE_CARET_PROPERTY and + * AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY). This keeps track of + * the dot position internally. When the caret moves, the internal position + * is updated after firing the event. + * + * @param e - caret event */ - public void caretUpdate(CaretEvent value0) + public void caretUpdate(CaretEvent e) { - // TODO + // TODO: fire appropriate event. + dot = e.getDot(); } /** - * getAccessibleStateSet - * @return AccessibleStateSet + * Returns the accessible state set of this component. + * + * @return the accessible state set of this component */ public AccessibleStateSet getAccessibleStateSet() { - return null; // TODO + AccessibleStateSet state = super.getAccessibleStateSet(); + // TODO: Figure out what state must be added here to the super's state. + return state; } /** - * getAccessibleRole - * @return AccessibleRole + * Returns the accessible role of this component. + * + * @return the accessible role of this component + * + * @see AccessibleRole */ public AccessibleRole getAccessibleRole() { - return null; // TODO + return AccessibleRole.TEXT; } /** - * getAccessibleText - * @return AccessibleText + * Returns the AccessibleEditableText interface for this text component. + * + * @return this + */ + public AccessibleEditableText getAccessibleEditableText() + { + return this; + } + + /** + * Get the AccessibleText associated with this object. In the implementation + * of the Java Accessibility API for this class, return this object, + * which is responsible for implementing the AccessibleText interface on + * behalf of itself. + * + * @return this + * + * @see AccessibleText */ public AccessibleText getAccessibleText() { - return null; // TODO + return this; } - + /** - * insertUpdate - * @param value0 TODO + * Insert update. Fire appropriate property change event which + * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY. + * + * @param e - document event */ - public void insertUpdate(DocumentEvent value0) + public void insertUpdate(DocumentEvent e) { // TODO } /** - * removeUpdate - * @param value0 TODO + * Remove update. Fire appropriate property change event which + * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY. + * + * @param e - document event */ - public void removeUpdate(DocumentEvent value0) + public void removeUpdate(DocumentEvent e) { // TODO } /** - * changedUpdate - * @param value0 TODO + * Changed update. Fire appropriate property change event which + * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY. + * + * @param e - document event */ - public void changedUpdate(DocumentEvent value0) + public void changedUpdate(DocumentEvent e) { // TODO } /** - * getIndexAtPoint - * @param value0 TODO - * @return int + * 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 + * @return the character index, or -1 */ - public int getIndexAtPoint(Point value0) + public int getIndexAtPoint(Point p) { return 0; // TODO } /** - * getRootEditorRect - * @return Rectangle + * Determines the bounding box of the indexed character. Returns an empty + * rectangle if the index is out of bounds. The bounds are returned in local coordinates. + * If the index is invalid a null rectangle is returned. The screen coordinates returned are + * "unscrolled coordinates" if the JTextComponent is contained in a JScrollPane in which + * case the resulting rectangle should be composed with the parent coordinates. + * Note: the JTextComponent must have a valid size (e.g. have been added to a parent + * container whose ancestor container is a valid top-level window) for this method to + * be able to return a meaningful (non-null) value. + * + * @param index the 0-based character index + * @return the bounding box, may be empty or null. */ - Rectangle getRootEditorRect() + public Rectangle getCharacterBounds(int index) { - return null; + return null; // TODO } /** - * getCharacterBounds - * @param value0 TODO - * @return Rectangle + * Return the number of characters. + * + * @return the character count */ - public Rectangle getCharacterBounds(int value0) + public int getCharCount() + { + return textComp.getText().length(); + } + + /** + * Returns the attributes of a character at an index, or null if the index + * is out of bounds. + * + * @param index the 0-based character index + * @return the character's attributes + */ + public AttributeSet getCharacterAttribute(int index) { return null; // TODO } /** - * getCharCount - * @return int + * Returns the section of text at the index, or null if the index or part + * is invalid. + * + * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE} + * @param index the 0-based character index + * @return the selection of text at that index, or null */ - public int getCharCount() + public String getAtIndex(int part, int index) { - return 0; // TODO + return null; // TODO } /** - * getCharacterAttribute - * @param value0 TODO - * @return AttributeSet + * Returns the section of text after the index, or null if the index or part + * is invalid. + * + * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE} + * @param index the 0-based character index + * @return the selection of text after that index, or null */ - public AttributeSet getCharacterAttribute(int value0) + public String getAfterIndex(int part, int index) { return null; // TODO } /** - * getAtIndex - * @param value0 TODO - * @param value1 TODO - * @return String + * Returns the section of text before the index, or null if the index or part + * is invalid. + * + * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE} + * @param index the 0-based character index + * @return the selection of text before that index, or null */ - public String getAtIndex(int value0, int value1) + public String getBeforeIndex(int part, int index) { return null; // TODO } + + /** + * Get the number possible actions for this object, with the zeroth + * representing the default action. + * + * @return the 0-based number of actions + */ + public int getAccessibleActionCount() + { + return 0; // TODO + } + + /** + * Get a description for the specified action. Returns null if out of + * bounds. + * + * @param i + * the action to describe, 0-based + * @return description of the action + */ + public String getAccessibleActionDescription(int i) + { + // TODO: Not implemented fully + return super.getAccessibleDescription(); + } + + /** + * Perform the specified action. Does nothing if out of bounds. + * + * @param i the action to perform, 0-based + * @return true if the action was performed + */ + public boolean doAccessibleAction(int i) + { + return false; // TODO + } + + /** + * Set the text contents to the given string. + * + * @param s the new text + */ + public void setTextContents(String s) + { + // TODO + } /** - * getAfterIndex - * @param value0 TODO - * @param value1 TODO - * @return String + * Inserts the given string at the specified location. + * + * @param index the index for insertion + * @param s the new text */ - public String getAfterIndex(int value0, int value1) + public void insertTextAtIndex(int index, String s) { - return null; // TODO + replaceText(index, index, s); } /** - * getBeforeIndex - * @param value0 TODO - * @param value1 TODO - * @return String + * Return the text between two points. + * + * @param start the start position, inclusive + * @param end the end position, exclusive */ - public String getBeforeIndex(int value0, int value1) + public String getTextRange(int start, int end) { - return null; // TODO + try + { + return textComp.getText(start, end - start); + } + catch (BadLocationException ble) + { + return ""; + } + } + + /** + * Delete the text between two points. + * + * @param start the start position, inclusive + * @param end the end position, exclusive + */ + public void delete(int start, int end) + { + replaceText(start, end, ""); + } + + /** + * Cut the text between two points to the system clipboard. + * + * @param start the start position, inclusive + * @param end the end position, exclusive + */ + public void cut(int start, int end) + { + textComp.select(start, end); + textComp.cut(); + } + + /** + * Paste the text from the system clipboard at the given index. + * + * @param start the start position + */ + public void paste(int start) + { + textComp.setCaretPosition(start); + textComp.paste(); + } + + /** + * Replace the text between two points with the given string. + * + * @param start the start position, inclusive + * @param end the end position, exclusive + * @param s the string to paste + */ + public void replaceText(int start, int end, String s) + { + textComp.select(start, end); + textComp.replaceSelection(s); + } + + /** + * Select the text between two points. + * + * @param start the start position, inclusive + * @param end the end position, exclusive + */ + public void selectText(int start, int end) + { + textComp.select(start, end); + } + + /** + * Set the attributes of text between two points. + * + * @param start the start position, inclusive + * @param end the end position, exclusive + * @param s the new attribute set for the range + */ + public void setAttributes(int start, int end, AttributeSet s) + { + // TODO } } @@ -945,7 +1162,7 @@ public abstract class JTextComponent extends JComponent */ public AccessibleContext getAccessibleContext() { - return null; + return new AccessibleJTextComponent(); } public void setMargin(Insets m) @@ -1024,9 +1241,15 @@ public abstract class JTextComponent extends JComponent */ public String getSelectedText() { + int start = getSelectionStart(); + int offset = getSelectionEnd() - start; + + if (offset <= 0) + return null; + try { - return doc.getText(getSelectionStart(), getSelectionEnd()); + return doc.getText(start, offset); } catch (BadLocationException e) { @@ -1375,8 +1598,12 @@ public abstract class JTextComponent extends JComponent // Insert new text. doc.insertString(start, content, null); - // Set dot to new position. - setCaretPosition(start + content.length()); + // Set dot to new position, + dot = start + content.length(); + setCaretPosition(dot); + + // and update it's magic position. + caret.setMagicCaretPosition(modelToView(dot).getLocation()); } catch (BadLocationException e) { @@ -1387,7 +1614,7 @@ public abstract class JTextComponent extends JComponent public boolean getScrollableTracksViewportHeight() { if (getParent() instanceof JViewport) - return ((JViewport) getParent()).getHeight() > getPreferredSize().height; + return getParent().getHeight() > getPreferredSize().height; return false; } @@ -1395,7 +1622,7 @@ public abstract class JTextComponent extends JComponent public boolean getScrollableTracksViewportWidth() { if (getParent() instanceof JViewport) - return ((JViewport) getParent()).getWidth() > getPreferredSize().width; + return getParent().getWidth() > getPreferredSize().width; return false; } diff --git a/libjava/classpath/javax/swing/text/LabelView.java b/libjava/classpath/javax/swing/text/LabelView.java index 4890735b925..03279c4b2b5 100644 --- a/libjava/classpath/javax/swing/text/LabelView.java +++ b/libjava/classpath/javax/swing/text/LabelView.java @@ -109,7 +109,11 @@ public class LabelView extends GlyphView { Element el = getElement(); AttributeSet atts = el.getAttributes(); - background = StyleConstants.getBackground(atts); + // We cannot use StyleConstants.getBackground() here, because that returns + // BLACK as default (when background == null). What we need is the + // background setting of the text component instead, which is what we get + // when background == null anyway. + background = (Color) atts.getAttribute(StyleConstants.Background); foreground = StyleConstants.getForeground(atts); strikeThrough = StyleConstants.isStrikeThrough(atts); subscript = StyleConstants.isSubscript(atts); diff --git a/libjava/classpath/javax/swing/text/MutableAttributeSet.java b/libjava/classpath/javax/swing/text/MutableAttributeSet.java index 2fe9ad50f67..3728b9ce126 100644 --- a/libjava/classpath/javax/swing/text/MutableAttributeSet.java +++ b/libjava/classpath/javax/swing/text/MutableAttributeSet.java @@ -1,5 +1,5 @@ /* MutableAttributeSet.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,46 +40,78 @@ package javax.swing.text; import java.util.Enumeration; /** - * MutableAttributeSet + * An {@link AttributeSet} that supports modification of the stored + * attributes. + * * @author Andrew Selkirk - * @version 1.0 + * @since 1.2 */ public interface MutableAttributeSet extends AttributeSet { /** - * addAttribute - * @param name TODO - * @param value TODO + * Adds an attribute with the given <code>name</code> and <code>value</code> + * to the set. If the set already contains an attribute with the given + * <code>name</code>, the attribute value is updated. + * + * @param name the attribute name (<code>null</code> not permitted). + * @param value the value (<code>null</code> not permitted). + * + * @throws NullPointerException if either argument is <code>null</code>. */ void addAttribute(Object name, Object value); /** - * addAttributes - * @param attributes TODO + * Adds all the attributes from <code>attributes</code> to this set. + * + * @param attributes the set of attributes to add (<code>null</code> not + * permitted). + * + * @throws NullPointerException if <code>attributes</code> is + * <code>null</code>. */ void addAttributes(AttributeSet attributes); /** - * removeAttribute - * @param name TODO + * Removes the attribute with the specified <code>name</code>, if this + * attribute is defined. This method will only remove an attribute from + * this set, not from the resolving parent. + * + * @param name the attribute name (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>name</code> is <code>null</code>. */ void removeAttribute(Object name); /** - * removeAttributes - * @param names TODO + * Removes the attributes listed in <code>names</code>. + * + * @param names the attribute names (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>names</code> is <code>null</code> + * or contains any <code>null</code> values. */ void removeAttributes(Enumeration names); /** - * removeAttributes - * @param attributes TODO + * Removes attributes from this set if they are found in the + * given set. Only attributes whose key AND value are removed. + * Removes attributes only from this set, not from the resolving parent. + * Since the resolving parent is stored as an attribute, if + * <code>attributes</code> has the same resolving parent as this set, the + * parent will be removed from this set. + * + * @param attributes the attributes (<code>null</code> not permitted). */ void removeAttributes(AttributeSet attributes); /** - * setResolveParent - * @param parent TODO + * Sets the reolving parent for this set. When looking up an attribute, if + * it is not found in this set, then the resolving parent is also used for + * the lookup. + * + * @param parent the parent attribute set (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>parent</code> is <code>null</code>. */ void setResolveParent(AttributeSet parent); } diff --git a/libjava/classpath/javax/swing/text/NavigationFilter.java b/libjava/classpath/javax/swing/text/NavigationFilter.java index 45f58f9e229..ea9b29db837 100644 --- a/libjava/classpath/javax/swing/text/NavigationFilter.java +++ b/libjava/classpath/javax/swing/text/NavigationFilter.java @@ -68,4 +68,31 @@ public class NavigationFilter { fb.setDot(dot, bias); } + + /** + * Returns the next visual position in the specified direction at which one + * would place a caret. The default implementation forwards to the text + * component's root view. Subclasses may wish to restrict that more. + * + * @param c the text component + * @param pos the current model position + * @param bias the bias of <code>pos</code> + * @param dir the direction, one of {@link javax.swing.SwingConstants#NORTH}, + * {@link javax.swing.SwingConstants#SOUTH}, + * {@link javax.swing.SwingConstants#WEST} or + * {@link javax.swing.SwingConstants#EAST} + * @param retBias the bias of the returned position + * + * @return the next model location to place the caret + * + * @throws BadLocationException when <code>pos</code> is not a valid model + * position + */ + public int getNextVisualPositionFrom(JTextComponent c, int pos, + Position.Bias bias, int dir, + Position.Bias[] retBias) + throws BadLocationException + { + return c.getUI().getNextVisualPositionFrom(c, pos, bias, dir, retBias); + } } diff --git a/libjava/classpath/javax/swing/text/ParagraphView.java b/libjava/classpath/javax/swing/text/ParagraphView.java index c4864503187..15bed781825 100644 --- a/libjava/classpath/javax/swing/text/ParagraphView.java +++ b/libjava/classpath/javax/swing/text/ParagraphView.java @@ -63,10 +63,20 @@ public class ParagraphView extends FlowView implements TabExpander { super(el, X_AXIS); } + public float getAlignment(int axis) { - // FIXME: This is very likely not 100% correct. Work this out. - return 0.0F; + float align; + if (axis == X_AXIS) + align = 0.0F; // TODO: Implement according to justification + else + align = super.getAlignment(axis); + return align; + } + + protected void loadChildren(ViewFactory vf) + { + // Do nothing here. The children are added while layouting. } } @@ -128,17 +138,18 @@ public class ParagraphView extends FlowView implements TabExpander */ public float getAlignment(int axis) { + float align; if (axis == X_AXIS) - return 0.0F; + align = super.getAlignment(axis); else if (getViewCount() > 0) { - float prefHeight = getPreferredSpan(Y_AXIS); float firstRowHeight = getView(0).getPreferredSpan(Y_AXIS); - return (firstRowHeight / 2.F) / prefHeight; + align = (firstRowHeight / 2.F) / prefHeight; } else - return 0.0F; + align = 0.0F; + return align; } /** @@ -229,4 +240,184 @@ public class ParagraphView extends FlowView implements TabExpander { return tabSet; } + + /** + * Finds the next offset in the document that has one of the characters + * specified in <code>string</code>. If there is no such character found, + * this returns -1. + * + * @param string the characters to search for + * @param start the start offset + * + * @return the next offset in the document that has one of the characters + * specified in <code>string</code> + */ + protected int findOffsetToCharactersInString(char[] string, int start) + { + int offset = -1; + Document doc = getDocument(); + Segment text = new Segment(); + try + { + doc.getText(start, doc.getLength() - start, text); + int index = start; + + searchLoop: + while (true) + { + char ch = text.next(); + if (ch == Segment.DONE) + break; + + for (int j = 0; j < string.length; ++j) + { + if (string[j] == ch) + { + offset = index; + break searchLoop; + } + } + index++; + } + } + catch (BadLocationException ex) + { + // Ignore this and return -1. + } + return offset; + } + + protected int getClosestPositionTo(int pos, Position.Bias bias, Shape a, + int direction, Position.Bias[] biasRet, + int rowIndex, int x) + throws BadLocationException + { + // FIXME: Implement this properly. However, this looks like it might + // have been replaced by viewToModel. + return pos; + } + + /** + * Returns the size that is used by this view (or it's child views) between + * <code>startOffset</code> and <code>endOffset</code>. If the child views + * implement the {@link TabableView} interface, then this is used to + * determine the span, otherwise we use the preferred span of the child + * views. + * + * @param startOffset the start offset + * @param endOffset the end offset + * + * @return the span used by the view between <code>startOffset</code> and + * <code>endOffset</cod> + */ + protected float getPartialSize(int startOffset, int endOffset) + { + int startIndex = getViewIndex(startOffset, Position.Bias.Backward); + int endIndex = getViewIndex(endOffset, Position.Bias.Forward); + float span; + if (startIndex == endIndex) + { + View child = getView(startIndex); + if (child instanceof TabableView) + { + TabableView tabable = (TabableView) child; + span = tabable.getPartialSpan(startOffset, endOffset); + } + else + span = child.getPreferredSpan(X_AXIS); + } + else if (endIndex - startIndex == 1) + { + View child1 = getView(startIndex); + if (child1 instanceof TabableView) + { + TabableView tabable = (TabableView) child1; + span = tabable.getPartialSpan(startOffset, child1.getEndOffset()); + } + else + span = child1.getPreferredSpan(X_AXIS); + View child2 = getView(endIndex); + if (child2 instanceof TabableView) + { + TabableView tabable = (TabableView) child2; + span += tabable.getPartialSpan(child2.getStartOffset(), endOffset); + } + else + span += child2.getPreferredSpan(X_AXIS); + } + else + { + // Start with the first view. + View child1 = getView(startIndex); + if (child1 instanceof TabableView) + { + TabableView tabable = (TabableView) child1; + span = tabable.getPartialSpan(startOffset, child1.getEndOffset()); + } + else + span = child1.getPreferredSpan(X_AXIS); + + // Add up the view spans between the start and the end view. + for (int i = startIndex + 1; i < endIndex; i++) + { + View child = getView(i); + span += child.getPreferredSpan(X_AXIS); + } + + // Add the span of the last view. + View child2 = getView(endIndex); + if (child2 instanceof TabableView) + { + TabableView tabable = (TabableView) child2; + span += tabable.getPartialSpan(child2.getStartOffset(), endOffset); + } + else + span += child2.getPreferredSpan(X_AXIS); + } + return span; + } + + /** + * Returns the location where the tabs are calculated from. This returns + * <code>0.0F</code> by default. + * + * @return the location where the tabs are calculated from + */ + protected float getTabBase() + { + return 0.0F; + } + + /** + * @specnote This method is specified to take a Row parameter, which is a + * private inner class of that class, which makes it unusable from + * application code. Also, this method seems to be replaced by + * {@link FlowStrategy#adjustRow(FlowView, int, int, int)}. + * + */ + protected void adjustRow(Row r, int desiredSpan, int x) + { + } + + /** + * @specnote This method's signature differs from the one defined in + * {@link View} and is therefore never called. It is probably there + * for historical reasons. + */ + public View breakView(int axis, float len, Shape a) + { + // This method is not used. + return null; + } + + /** + * @specnote This method's signature differs from the one defined in + * {@link View} and is therefore never called. It is probably there + * for historical reasons. + */ + public int getBreakWeight(int axis, float len) + { + // This method is not used. + return 0; + } } diff --git a/libjava/classpath/javax/swing/text/PasswordView.java b/libjava/classpath/javax/swing/text/PasswordView.java index e54331c5a8e..9d4c86a8388 100644 --- a/libjava/classpath/javax/swing/text/PasswordView.java +++ b/libjava/classpath/javax/swing/text/PasswordView.java @@ -107,8 +107,6 @@ public class PasswordView protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException { - // FIXME: Throw BadLocationException somehow. - // Update font metrics. updateMetrics(); @@ -119,25 +117,18 @@ public class PasswordView g.setColor(selectedColor); g.setColor(Color.BLACK); - // Initialize buffer for faster drawing of all characters. - int len = p1 - p0; - char[] buffer = new char[len]; - for (int index = 0; index < len; ++index) - buffer[index] = ch; - - // Draw echo charaters. - g.drawChars(buffer, 0, len, x, y); - - // Return new x position right of all drawn characters. - return x + len * metrics.charWidth(ch); + // Draw echo character using drawEchoCharacter() method. + for (int index = p0; index < p1; ++index) + x = drawEchoCharacter(g, x, y, ch); + return x; } /** * Draws unselected text at a given position. * * @param g the <code>Graphics</code> object to draw to - * @param x the x-position - * @param y the y-position + * @param x the x-position of the start of the baseline + * @param y the y-position of the start of the baseline * @param p0 the position of the first character to draw * @param p1 the position of the first character not to draw * @@ -146,35 +137,20 @@ public class PasswordView protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException { - // FIXME: Throw BadLocationException somehow. - // Update font metrics. updateMetrics(); // Get echo character. char ch = getEchoChar(); - Segment segment = new Segment(); // Set color for unselected text. g.setColor(unselectedColor); g.setColor(Color.BLACK); - // Initialize buffer for faster drawing of all characters. - p1--; - getDocument().getText(p0, p1 - p0, segment); - int len = segment.toString().length(); - - char[] buffer = new char[len]; - for (int index = 0; index < len; ++index) - buffer[index] = ch; - - y += getPreferredSpan(Y_AXIS)/2; - - // Draw echo charaters. - g.drawChars(buffer, 0, len, x, y); - - // Return new x position right of all drawn characters. - return x + (len * metrics.charWidth(ch)); + // Draw echo character using drawEchoCharacter() method. + for (int index = p0; index < p1; ++index) + x = drawEchoCharacter(g, x, y, ch); + return x; } /** diff --git a/libjava/classpath/javax/swing/text/PlainDocument.java b/libjava/classpath/javax/swing/text/PlainDocument.java index 2200cae80a0..c699dcad2aa 100644 --- a/libjava/classpath/javax/swing/text/PlainDocument.java +++ b/libjava/classpath/javax/swing/text/PlainDocument.java @@ -1,5 +1,5 @@ /* PlainDocument.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,6 +40,15 @@ package javax.swing.text; import java.util.ArrayList; +/** + * A simple document class which maps lines to {@link Element}s. + * + * @author Anthony Balkissoon (abalkiss@redhat.com) + * @author Graydon Hoare (graydon@redhat.com) + * @author Roman Kennke (roman@kennke.org) + * @author Michael Koch (konqueror@gmx.de) + * @author Robert Schuster (robertschuster@fsfe.org) + */ public class PlainDocument extends AbstractDocument { private static final long serialVersionUID = 4758290289196893664L; @@ -109,18 +118,21 @@ public class PlainDocument extends AbstractDocument AttributeSet attributes) { int offset = event.getOffset(); + int eventLength = event.getLength(); int end = offset + event.getLength(); - int elementIndex = rootElement.getElementIndex(offset); + int oldElementIndex, elementIndex = rootElement.getElementIndex(offset); Element firstElement = rootElement.getElement(elementIndex); - + oldElementIndex = elementIndex; + // If we're inserting immediately after a newline we have to fix the - // Element structure. - if (offset > 0) + // Element structure (but only if we are dealing with a line which + // has not existed as Element before). + if (offset > 0 && firstElement.getStartOffset() != offset) { try { String s = getText(offset - 1, 1); - if (s.equals("\n")) + if (s.equals("\n") ) { int newEl2EndOffset = end; boolean replaceNext = false; @@ -159,33 +171,43 @@ public class PlainDocument extends AbstractDocument Element[] added; try { - String str = content.getString(0, content.length()); + String str = content.getString(offset, eventLength); ArrayList elts = new ArrayList(); // Determine how many NEW lines were added by finding the newline // characters within the newly inserted text int j = firstElement.getStartOffset(); - int i = str.indexOf('\n', offset); - while (i != -1 && i <= end) + int i = str.indexOf('\n', 0); + int contentLength = content.length(); + + while (i != -1 && i <= eventLength) { // For each new line, create a new element elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY, - j, i + 1)); - j = i + 1; - if (j >= str.length()) - break; - i = str.indexOf('\n', j); + j, offset + i + 1)); + + j = offset + i + 1; + if (j >= contentLength) + break; + i = str.indexOf('\n', i + 1); } + // If there were new lines added we have to add an ElementEdit to // the DocumentEvent and we have to call rootElement.replace to // insert the new lines if (elts.size() != 0) { + // If we have created new lines test whether there are remaining + // characters in firstElement after the inserted text and if so + // create a new element for them. + if (j < firstElement.getEndOffset()) + elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY, j, firstElement.getEndOffset())); + // Set up the ElementEdit by filling the added and removed // arrays with the proper Elements added = new Element[elts.size()]; - for (int k = 0; k < elts.size(); ++k) - added[k] = (Element) elts.get(k); + elts.toArray(added); + removed[0] = firstElement; // Now create and add the ElementEdit @@ -204,6 +226,7 @@ public class PlainDocument extends AbstractDocument ae.initCause(e); throw ae; } + super.insertUpdate(event, attributes); } diff --git a/libjava/classpath/javax/swing/text/PlainView.java b/libjava/classpath/javax/swing/text/PlainView.java index a318ee71ae0..4bb3a8eda33 100644 --- a/libjava/classpath/javax/swing/text/PlainView.java +++ b/libjava/classpath/javax/swing/text/PlainView.java @@ -1,5 +1,5 @@ /* PlainView.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. @@ -46,7 +46,7 @@ import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; -import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentEvent.ElementChange; @@ -137,22 +137,32 @@ public class PlainView extends View implements TabExpander return rect; } + /** + * Draws a line of text. The X and Y coordinates specify the start of + * the <em>baseline</em> of the line. + * + * @param lineIndex the index of the line + * @param g the graphics to use for drawing the text + * @param x the X coordinate of the baseline + * @param y the Y coordinate of the baseline + */ protected void drawLine(int lineIndex, Graphics g, int x, int y) { try { - metrics = g.getFontMetrics(); - // FIXME: Selected text are not drawn yet. - Element line = getElement().getElement(lineIndex); - drawUnselectedText(g, x, y, line.getStartOffset(), line.getEndOffset()); - //drawSelectedText(g, , , , ); + 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, , , , ); } catch (BadLocationException e) - { - AssertionError ae = new AssertionError("Unexpected bad location"); - ae.initCause(e); - throw ae; - } + { + AssertionError ae = new AssertionError("Unexpected bad location"); + ae.initCause(e); + throw ae; + } } protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1) @@ -164,6 +174,20 @@ public class PlainView extends View implements TabExpander return Utilities.drawTabbedText(segment, x, y, g, this, 0); } + /** + * Draws a chunk of unselected text. + * + * @param g the graphics to use for drawing the text + * @param x the X coordinate of the baseline + * @param y the Y coordinate of the baseline + * @param p0 the start position in the text model + * @param p1 the end position in the text model + * + * @return the X location of the end of the range + * + * @throws BadLocationException if <code>p0</code> or <code>p1</code> are + * invalid + */ protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException { @@ -194,12 +218,12 @@ public class PlainView extends View implements TabExpander // FIXME: Text may be scrolled. Document document = textComponent.getDocument(); Element root = document.getDefaultRootElement(); - int y = rect.y; + int y = rect.y + metrics.getAscent(); for (int i = 0; i < root.getElementCount(); i++) { - drawLine(i, g, rect.x, y); - y += metrics.getHeight(); + drawLine(i, g, rect.x, y); + y += metrics.getHeight(); } } @@ -284,18 +308,20 @@ public class PlainView extends View implements TabExpander // make sure we have the metrics updateMetrics(); - float span = 0; Element el = getElement(); + float span; switch (axis) { case X_AXIS: span = determineMaxLineLength(); + break; case Y_AXIS: default: span = metrics.getHeight() * el.getElementCount(); break; } + return span; } @@ -318,12 +344,19 @@ public class PlainView extends View implements TabExpander Element root = doc.getDefaultRootElement(); // PlainView doesn't support line-wrapping so we can find out which - // Element was clicked on just by the y-position - int lineClicked = (int) (y - rec.y) / metrics.getHeight(); - if (lineClicked >= root.getElementCount()) - return getEndOffset() - 1; + // Element was clicked on just by the y-position. + // Since the coordinates may be outside of the coordinate space + // of the allocation area (e.g. user dragged mouse outside + // the component) we have to limit the values. + // This has the nice effect that the user can drag the + // mouse above or below the component and it will still + // react to the x values (e.g. when selecting). + int lineClicked + = Math.min(Math.max((int) (y - rec.y) / metrics.getHeight(), 0), + root.getElementCount() - 1); Element line = root.getElement(lineClicked); + Segment s = getLineBuffer(); int start = line.getStartOffset(); // We don't want the \n at the end of the line. @@ -353,6 +386,8 @@ public class PlainView extends View implements TabExpander */ protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f) { + float oldMaxLineLength = maxLineLength; + Rectangle alloc = a.getBounds(); Element el = getElement(); ElementChange ec = changes.getChange(el); @@ -360,7 +395,19 @@ public class PlainView extends View implements TabExpander // repaint the changed line if (ec == null) { - int line = getElement().getElementIndex(changes.getOffset()); + int line = el.getElementIndex(changes.getOffset()); + + // If characters have been removed from the current longest line + // we have to find out which one is the longest now otherwise + // the preferred x-axis span will not shrink. + if (changes.getType() == DocumentEvent.EventType.REMOVE + && el.getElement(line) == longestLine) + { + maxLineLength = -1; + if (determineMaxLineLength() != alloc.width) + preferenceChanged(this, true, false); + } + damageLineRange(line, line, a, getContainer()); return; } @@ -373,12 +420,13 @@ public class PlainView extends View implements TabExpander if (removed == null && newElements == null) { int line = getElement().getElementIndex(changes.getOffset()); + damageLineRange(line, line, a, getContainer()); return; } // Check to see if we removed the longest line, if so we have to - // search through all lines and find the longest one again + // search through all lines and find the longest one again. if (removed != null) { for (int i = 0; i < removed.length; i++) @@ -386,8 +434,11 @@ public class PlainView extends View implements TabExpander { // reset maxLineLength and search through all lines for longest one maxLineLength = -1; - determineMaxLineLength(); + if (determineMaxLineLength() != alloc.width) + preferenceChanged(this, true, removed.length != newElements.length); + ((JTextComponent)getContainer()).repaint(); + return; } } @@ -397,6 +448,7 @@ public class PlainView extends View implements TabExpander { // No lines were added, just repaint the container and exit ((JTextComponent)getContainer()).repaint(); + return; } @@ -445,6 +497,14 @@ public class PlainView extends View implements TabExpander maxLineLength = longestNewLength; longestLine = longestNewLine; } + + // Report any changes to the preferred sizes of the view + // which may cause the underlying component to be revalidated. + boolean widthChanged = oldMaxLineLength != maxLineLength; + boolean heightChanged = removed.length != newElements.length; + if (widthChanged || heightChanged) + preferenceChanged(this, widthChanged, heightChanged); + // Repaint the container ((JTextComponent)getContainer()).repaint(); } @@ -511,7 +571,9 @@ public class PlainView extends View implements TabExpander host.repaint(); else { - Rectangle repaintRec = rec0.union(rec1); + Rectangle repaintRec = SwingUtilities.computeUnion(rec0.x, rec0.y, + rec0.width, + rec0.height, rec1); host.repaint(repaintRec.x, repaintRec.y, repaintRec.width, repaintRec.height); } diff --git a/libjava/classpath/javax/swing/text/Segment.java b/libjava/classpath/javax/swing/text/Segment.java index 84e0e700f2e..875d9966c1f 100644 --- a/libjava/classpath/javax/swing/text/Segment.java +++ b/libjava/classpath/javax/swing/text/Segment.java @@ -1,5 +1,5 @@ /* Segment.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. @@ -39,20 +39,40 @@ package javax.swing.text; import java.text.CharacterIterator; +/** + * A text fragment represented by a sequence of characters stored in an array. + */ public class Segment implements Cloneable, CharacterIterator { private boolean partialReturn; + + /** The current index. */ private int current; + /** Storage for the characters (may contain additional characters). */ public char[] array; + + /** The number of characters in the segment. */ public int count; + + /** The offset of the first character in the segment. */ public int offset; + /** + * Creates a new <code>Segment</code>. + */ public Segment() { // Nothing to do here. } + /** + * Creates a new <code>Segment</code>. + * + * @param array the underlying character data. + * @param offset the offset of the first character in the segment. + * @param count the number of characters in the segment. + */ public Segment(char[] array, int offset, int count) { this.array = array; @@ -60,6 +80,12 @@ public class Segment implements Cloneable, CharacterIterator this.count = count; } + /** + * Clones the segment (note that the underlying character array is not cloned, + * just the reference to it). + * + * @return A clone of the segment. + */ public Object clone() { try @@ -72,6 +98,13 @@ public class Segment implements Cloneable, CharacterIterator } } + /** + * Returns the character at the current index. If the segment consists of + * zero characters, or the current index has passed the end of the + * characters in the segment, this method returns {@link #DONE}. + * + * @return The character at the current index. + */ public char current() { if (count == 0 @@ -81,6 +114,14 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Sets the current index to the first character in the segment and returns + * that character. If the segment contains zero characters, this method + * returns {@link #DONE}. + * + * @return The first character in the segment, or {@link #DONE} if the + * segment contains zero characters. + */ public char first() { if (count == 0) @@ -90,21 +131,46 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Returns the index of the first character in the segment. + * + * @return The index of the first character. + */ public int getBeginIndex() { return offset; } + /** + * Returns the end index for the segment (one position beyond the last + * character in the segment - note that this can be outside the range of the + * underlying character array). + * + * @return The end index for the segment. + */ public int getEndIndex() { return offset + count; } + /** + * Returns the index of the current character in the segment. + * + * @return The index of the current character. + */ public int getIndex() { return current; } + /** + * Sets the current index to point to the last character in the segment and + * returns that character. If the segment contains zero characters, this + * method returns {@link #DONE}. + * + * @return The last character in the segment, or {@link #DONE} if the + * segment contains zero characters. + */ public char last() { if (count == 0) @@ -114,6 +180,17 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Sets the current index to point to the next character in the segment and + * returns that character. If the next character position is past the end of + * the segment, the index is set to {@link #getEndIndex()} and the method + * returns {@link #DONE}. If the segment contains zero characters, this + * method returns {@link #DONE}. + * + * @return The next character in the segment or {@link #DONE} (if the next + * character position is past the end of the segment or if the + * segment contains zero characters). + */ public char next() { if (count == 0) @@ -129,6 +206,16 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Sets the current index to point to the previous character in the segment + * and returns that character. If the current index is equal to + * {@link #getBeginIndex()}, or if the segment contains zero characters, this + * method returns {@link #DONE}. + * + * @return The previous character in the segment or {@link #DONE} (if the + * current character position is at the beginning of the segment or + * if the segment contains zero characters). + */ public char previous() { if (count == 0 @@ -139,11 +226,26 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Sets the current index and returns the character at that position (or + * {@link #DONE} if the index is equal to {@link #getEndIndex()}. + * + * @param position the current position. + * + * @return The character at the specified <code>position</code>, or + * {@link #DONE} if <code>position</code> is equal to + * {@link #getEndIndex()}. + * + * @throws IllegalArgumentException if <code>position</code> is not in the + * range {@link #getBeginIndex()} to {@link #getEndIndex()}. + */ public char setIndex(int position) { if (position < getBeginIndex() || position > getEndIndex()) - throw new IllegalArgumentException(); + throw new IllegalArgumentException("position: " + position + + ", beginIndex: " + getBeginIndex() + + ", endIndex: " + getEndIndex()); current = position; @@ -153,12 +255,23 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Returns a <code>String</code> containing the same characters as this + * <code>Segment</code>. + * + * @return A <code>String</code> containing the same characters as this + * <code>Segment</code>. + */ public String toString() { return new String(array, offset, count); } /** + * Sets the partial return flag. + * + * @param p the new value of the flag. + * * @since 1.4 */ public void setPartialReturn(boolean p) @@ -167,6 +280,9 @@ public class Segment implements Cloneable, CharacterIterator } /** + * Returns the partial return flag. + * + * @return The partial return flag. * @since 1.4 */ public boolean isPartialReturn() diff --git a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java index 0c9f607b196..8dbcb0c6a14 100644 --- a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java +++ b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java @@ -1,5 +1,5 @@ /* SimpleAttributeSet.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,33 +42,67 @@ import java.io.Serializable; import java.util.Enumeration; import java.util.Hashtable; +/** + * A set of attributes. + */ public class SimpleAttributeSet implements MutableAttributeSet, Serializable, Cloneable { /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = 8267656273837665219L; + /** An empty attribute set. */ public static final AttributeSet EMPTY = new SimpleAttributeSet(); + /** Storage for the attributes. */ Hashtable tab; + /** + * Creates a new attribute set that is initially empty. + */ public SimpleAttributeSet() { - this(null); + tab = new Hashtable(); } + /** + * Creates a new <code>SimpleAttributeSet</code> with the same attributes + * and resolve parent as the specified set. + * + * @param a the attributes (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + */ public SimpleAttributeSet(AttributeSet a) { tab = new Hashtable(); - if (a != null) - addAttributes(a); + addAttributes(a); } + /** + * Adds an attribute with the given <code>name</code> and <code>value</code> + * to the set. If the set already contains an attribute with the given + * <code>name</code>, the attribute value is updated. + * + * @param name the attribute name (<code>null</code> not permitted). + * @param value the value (<code>null</code> not permitted). + * + * @throws NullPointerException if either argument is <code>null</code>. + */ public void addAttribute(Object name, Object value) { tab.put(name, value); } + /** + * Adds all the attributes from <code>attributes</code> to this set. + * + * @param attributes the set of attributes to add (<code>null</code> not + * permitted). + * + * @throws NullPointerException if <code>attributes</code> is + * <code>null</code>. + */ public void addAttributes(AttributeSet attributes) { Enumeration e = attributes.getAttributeNames(); @@ -80,6 +114,11 @@ public class SimpleAttributeSet } } + /** + * Returns a clone of the attribute set. + * + * @return A clone of the attribute set. + */ public Object clone() { SimpleAttributeSet s = new SimpleAttributeSet(); @@ -97,9 +136,18 @@ public class SimpleAttributeSet */ public boolean containsAttribute(Object name, Object value) { - return (tab.containsKey(name) && tab.get(name).equals(value)) || - (getResolveParent() != null && getResolveParent(). - containsAttribute(name, value)); + if (value == null) + throw new NullPointerException("Null 'value' argument."); + if (tab.containsKey(name)) + return tab.get(name).equals(value); + else + { + AttributeSet p = getResolveParent(); + if (p != null) + return p.containsAttribute(name, value); + else + return false; + } } /** @@ -115,6 +163,15 @@ public class SimpleAttributeSet && tab.get(name).equals(value); } + /** + * Returns <code>true</code> of this <code>AttributeSet</code> contains all + * of the specified <code>attributes</code>. + * + * @param attributes the requested attributes + * + * @return <code>true</code> of this <code>AttributeSet</code> contains all + * of the specified <code>attributes</code> + */ public boolean containsAttributes(AttributeSet attributes) { Enumeration e = attributes.getAttributeNames(); @@ -128,11 +185,24 @@ public class SimpleAttributeSet return true; } + /** + * Creates and returns a copy of this <code>AttributeSet</code>. + * + * @return a copy of this <code>AttributeSet</code> + */ public AttributeSet copyAttributes() { return (AttributeSet) clone(); } + /** + * Checks this set for equality with an arbitrary object. + * + * @param obj the object (<code>null</code> permitted). + * + * @return <code>true</code> if this set is equal to <code>obj</code>, and + * <code>false</code> otherwise. + */ public boolean equals(Object obj) { return @@ -140,44 +210,95 @@ public class SimpleAttributeSet && this.isEqual((AttributeSet) obj); } + /** + * Returns the value of the specified attribute, or <code>null</code> if + * there is no attribute with that name. If the attribute is not defined + * directly in this set, the parent hierarchy (if there is one) will be + * used. + * + * @param name the attribute (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>name</code> is <code>null</code>. + */ public Object getAttribute(Object name) { Object val = tab.get(name); if (val != null) return val; - Object p = getResolveParent(); - if (p != null && p instanceof AttributeSet) - return (((AttributeSet)p).getAttribute(name)); + AttributeSet p = getResolveParent(); + if (p != null) + return p.getAttribute(name); return null; } + /** + * Returns the number of attributes stored in this set, plus 1 if a parent + * has been specified (the reference to the parent is stored as a special + * attribute). The attributes stored in the parent do NOT contribute + * to the count. + * + * @return The attribute count. + */ public int getAttributeCount() { return tab.size(); } + /** + * Returns an enumeration of the attribute names. + * + * @return An enumeration of the attribute names. + */ public Enumeration getAttributeNames() { return tab.keys(); } + /** + * Returns the resolving parent. + * + * @return The resolving parent (possibly <code>null</code>). + * + * @see #setResolveParent(AttributeSet) + */ public AttributeSet getResolveParent() { return (AttributeSet) tab.get(ResolveAttribute); } + /** + * Returns a hash code for this instance. + * + * @return A hash code. + */ public int hashCode() { return tab.hashCode(); } + /** + * Returns <code>true</code> if the given attribute is defined in this set, + * and <code>false</code> otherwise. The parent attribute set is not + * checked. + * + * @param attrName the attribute name (<code>null</code> not permitted). + */ public boolean isDefined(Object attrName) { return tab.containsKey(attrName); } + /** + * Returns <code>true</code> if the set contains no attributes, and + * <code>false</code> otherwise. Note that the resolving parent is + * stored as an attribute, so this method will return <code>false</code> if + * a resolving parent is set. + * + * @return <code>true</code> if the set contains no attributes, and + * <code>false</code> otherwise. + */ public boolean isEmpty() { return tab.isEmpty(); @@ -186,7 +307,13 @@ public class SimpleAttributeSet /** * Returns true if the given set has the same number of attributes * as this set and <code>containsAttributes(attr)</code> returns - * true. + * <code>true</code>. + * + * @param attr the attribute set (<code>null</code> not permitted). + * + * @return A boolean. + * + * @throws NullPointerException if <code>attr</code> is <code>null</code>. */ public boolean isEqual(AttributeSet attr) { @@ -194,6 +321,15 @@ public class SimpleAttributeSet && this.containsAttributes(attr); } + /** + * Removes the attribute with the specified <code>name</code>, if this + * attribute is defined. This method will only remove an attribute from + * this set, not from the resolving parent. + * + * @param name the attribute name (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>name</code> is <code>null</code>. + */ public void removeAttribute(Object name) { tab.remove(name); @@ -202,7 +338,12 @@ public class SimpleAttributeSet /** * Removes attributes from this set if they are found in the * given set. Only attributes whose key AND value are removed. - * Removes attributes only from this set, not from the resolving parent. + * Removes attributes only from this set, not from the resolving parent. + * Since the resolving parent is stored as an attribute, if + * <code>attributes</code> has the same resolving parent as this set, the + * parent will be removed from this set. + * + * @param attributes the attributes (<code>null</code> not permitted). */ public void removeAttributes(AttributeSet attributes) { @@ -216,6 +357,14 @@ public class SimpleAttributeSet } } + /** + * Removes the attributes listed in <code>names</code>. + * + * @param names the attribute names (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>names</code> is <code>null</code> + * or contains any <code>null</code> values. + */ public void removeAttributes(Enumeration names) { while (names.hasMoreElements()) @@ -224,11 +373,31 @@ public class SimpleAttributeSet } } + /** + * Sets the reolving parent for this set. When looking up an attribute, if + * it is not found in this set, then the resolving parent is also used for + * the lookup. + * <p> + * Note that the parent is stored as an attribute, and will contribute 1 to + * the count returned by {@link #getAttributeCount()}. + * + * @param parent the parent attribute set (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>parent</code> is <code>null</code>. + * + * @see #setResolveParent(AttributeSet) + */ public void setResolveParent(AttributeSet parent) { addAttribute(ResolveAttribute, parent); } - + + /** + * Returns a string representation of this instance, typically used for + * debugging purposes. + * + * @return A string representation of this instance. + */ public String toString() { return tab.toString(); diff --git a/libjava/classpath/javax/swing/text/StringContent.java b/libjava/classpath/javax/swing/text/StringContent.java index 7db377a1c9b..0a31505f3a6 100644 --- a/libjava/classpath/javax/swing/text/StringContent.java +++ b/libjava/classpath/javax/swing/text/StringContent.java @@ -1,5 +1,5 @@ /* StringContent.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -54,7 +54,8 @@ import javax.swing.undo.UndoableEdit; * * <p>Do not use this class for large size.</p> */ -public final class StringContent implements AbstractDocument.Content, Serializable +public final class StringContent + implements AbstractDocument.Content, Serializable { /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = 4755994433709540381L; @@ -87,7 +88,8 @@ public final class StringContent implements AbstractDocument.Content, Serializab try { StringContent.this.checkLocation(this.start, this.length); - this.redoContent = new String(StringContent.this.content, this.start, this.length); + this.redoContent = new String(StringContent.this.content, this.start, + this.length); StringContent.this.remove(this.start, this.length); } catch (BadLocationException b) @@ -175,11 +177,20 @@ public final class StringContent implements AbstractDocument.Content, Serializab } } + /** + * Creates a new instance containing the string "\n". + */ public StringContent() { this(1); } + /** + * Creates a new instance containing the string "\n". + * + * @param initialLength the initial length of the underlying character + * array used to store the content. + */ public StringContent(int initialLength) { super(); @@ -198,7 +209,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab Iterator iter = this.positions.iterator(); while(iter.hasNext()) { - Position p = (Position)iter.next(); + Position p = (Position) iter.next(); if ((offset <= p.getOffset()) && (p.getOffset() <= (offset + length))) refPos.add(p); @@ -206,6 +217,16 @@ public final class StringContent implements AbstractDocument.Content, Serializab return refPos; } + /** + * Creates a position reference for the character at the given offset. The + * position offset will be automatically updated when new characters are + * inserted into or removed from the content. + * + * @param offset the character offset. + * + * @throws BadLocationException if offset is outside the bounds of the + * content. + */ public Position createPosition(int offset) throws BadLocationException { if (offset < this.count || offset > this.count) @@ -215,11 +236,27 @@ public final class StringContent implements AbstractDocument.Content, Serializab return sp; } + /** + * Returns the length of the string content, including the '\n' character at + * the end. + * + * @return The length of the string content. + */ public int length() { return this.count; } + /** + * Inserts <code>str</code> at the given position and returns an + * {@link UndoableEdit} that enables undo/redo support. + * + * @param where the insertion point (must be less than + * <code>length()</code>). + * @param str the string to insert (<code>null</code> not permitted). + * + * @return An object that can undo the insertion. + */ public UndoableEdit insertString(int where, String str) throws BadLocationException { @@ -235,13 +272,15 @@ public final class StringContent implements AbstractDocument.Content, Serializab if (where > 0) System.arraycopy(this.content, 0, temp, 0, where); System.arraycopy(insert, 0, temp, where, insert.length); - System.arraycopy(this.content, where, temp, (where + insert.length), (temp.length - where - insert.length)); + System.arraycopy(this.content, where, temp, (where + insert.length), + (temp.length - where - insert.length)); if (this.content.length < temp.length) this.content = new char[temp.length]; // Copy the result in the original char array. System.arraycopy(temp, 0, this.content, 0, temp.length); // Move all the positions. - Vector refPos = getPositionsInRange(this.positions, where, temp.length - where); + Vector refPos = getPositionsInRange(this.positions, where, + temp.length - where); Iterator iter = refPos.iterator(); while (iter.hasNext()) { @@ -252,20 +291,35 @@ public final class StringContent implements AbstractDocument.Content, Serializab return iundo; } + /** + * Removes the specified range of characters and returns an + * {@link UndoableEdit} that enables undo/redo support. + * + * @param where the starting index. + * @param nitems the number of characters. + * + * @return An object that can undo the removal. + * + * @throws BadLocationException if the character range extends outside the + * bounds of the content OR includes the last character. + */ public UndoableEdit remove(int where, int nitems) throws BadLocationException { - checkLocation(where, nitems); + checkLocation(where, nitems + 1); char[] temp = new char[(this.content.length - nitems)]; this.count = this.count - nitems; - RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where, nitems)); + RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where, + nitems)); // Copy array. System.arraycopy(this.content, 0, temp, 0, where); - System.arraycopy(this.content, where + nitems, temp, where, this.content.length - where - nitems); + System.arraycopy(this.content, where + nitems, temp, where, + this.content.length - where - nitems); this.content = new char[temp.length]; // Then copy the result in the original char array. System.arraycopy(temp, 0, this.content, 0, this.content.length); // Move all the positions. - Vector refPos = getPositionsInRange(this.positions, where, this.content.length + nitems - where); + Vector refPos = getPositionsInRange(this.positions, where, + this.content.length + nitems - where); Iterator iter = refPos.iterator(); while (iter.hasNext()) { @@ -278,31 +332,75 @@ public final class StringContent implements AbstractDocument.Content, Serializab return rundo; } + /** + * Returns a new <code>String</code> containing the characters in the + * specified range. + * + * @param where the start index. + * @param len the number of characters. + * + * @return A string. + * + * @throws BadLocationException if the requested range of characters extends + * outside the bounds of the content. + */ public String getString(int where, int len) throws BadLocationException { checkLocation(where, len); - return new String (this.content, where, len); + return new String(this.content, where, len); } - public void getChars(int where, int len, Segment txt) throws BadLocationException + /** + * Updates <code>txt</code> to contain a direct reference to the underlying + * character array. + * + * @param where the index of the first character. + * @param len the number of characters. + * @param txt a carrier for the return result (<code>null</code> not + * permitted). + * + * @throws BadLocationException if the requested character range is not + * within the bounds of the content. + * @throws NullPointerException if <code>txt</code> is <code>null</code>. + */ + public void getChars(int where, int len, Segment txt) + throws BadLocationException { checkLocation(where, len); - if (txt != null) - { - txt.array = this.content; - txt.offset = where; - txt.count = len; - } + txt.array = this.content; + txt.offset = where; + txt.count = len; } - // This is package-private to avoid an accessor method. + + /** + * @specnote This method is not very well specified and the positions vector + * is implementation specific. The undo positions are managed + * differently in this implementation, this method is only here + * for binary compatibility. + */ + protected void updateUndoPositions(Vector positions) + { + // We do nothing here. + } + + /** + * A utility method that checks the validity of the specified character + * range. + * + * @param where the first character in the range. + * @param len the number of characters in the range. + * + * @throws BadLocationException if the specified range is not within the + * bounds of the content. + */ void checkLocation(int where, int len) throws BadLocationException { if (where < 0) throw new BadLocationException("Invalid location", 1); else if (where > this.count) throw new BadLocationException("Invalid location", this.count); - else if ((where + len)>this.count) + else if ((where + len) > this.count) throw new BadLocationException("Invalid range", this.count); } diff --git a/libjava/classpath/javax/swing/text/StyleConstants.java b/libjava/classpath/javax/swing/text/StyleConstants.java index 598eaf621bc..c7906b8ad32 100644 --- a/libjava/classpath/javax/swing/text/StyleConstants.java +++ b/libjava/classpath/javax/swing/text/StyleConstants.java @@ -1,5 +1,5 @@ /* StyleConstants.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,45 +43,124 @@ import java.awt.Component; import javax.swing.Icon; +/** + * Represents standard attribute keys. This class also contains a set of + * useful static utility methods for querying and populating an + * {@link AttributeSet}. + * + * @since 1.2 + */ public class StyleConstants { + /** + * A value representing left alignment for the + * {@link ParagraphConstants#Alignment} attribute. + */ public static final int ALIGN_LEFT = 0; + + /** + * A value representing center alignment for the + * {@link ParagraphConstants#Alignment} attribute. + */ public static final int ALIGN_CENTER = 1; + + /** + * A value representing right alignment for the + * {@link ParagraphConstants#Alignment} attribute. + */ public static final int ALIGN_RIGHT = 2; + + /** + * A value representing ful justification for the + * {@link ParagraphConstants#Alignment} attribute. + */ public static final int ALIGN_JUSTIFIED = 3; + /** An alias for {@link CharacterConstants#Background}. */ public static final Object Background = CharacterConstants.Background; + + /** An alias for {@link CharacterConstants#BidiLevel}. */ public static final Object BidiLevel = CharacterConstants.BidiLevel; + + /** An alias for {@link CharacterConstants#Bold}. */ public static final Object Bold = CharacterConstants.Bold; - public static final Object ComponentAttribute = CharacterConstants.ComponentAttribute; + + /** An alias for {@link CharacterConstants#ComponentAttribute}. */ + public static final Object ComponentAttribute + = CharacterConstants.ComponentAttribute; + + /** An alias for {@link CharacterConstants#Family}. */ public static final Object Family = CharacterConstants.Family; + + /** An alias for {@link CharacterConstants#Family}. */ public static final Object FontFamily = CharacterConstants.Family; + + /** An alias for {@link CharacterConstants#Size}. */ public static final Object FontSize = CharacterConstants.Size; + + /** An alias for {@link CharacterConstants#Foreground}. */ public static final Object Foreground = CharacterConstants.Foreground; + + /** An alias for {@link CharacterConstants#IconAttribute}. */ public static final Object IconAttribute = CharacterConstants.IconAttribute; + + /** An alias for {@link CharacterConstants#Italic}. */ public static final Object Italic = CharacterConstants.Italic; + + /** An alias for {@link CharacterConstants#Size}. */ public static final Object Size = CharacterConstants.Size; + + /** An alias for {@link CharacterConstants#StrikeThrough}. */ public static final Object StrikeThrough = CharacterConstants.StrikeThrough; + + /** An alias for {@link CharacterConstants#Subscript}. */ public static final Object Subscript = CharacterConstants.Subscript; + + /** An alias for {@link CharacterConstants#Superscript}. */ public static final Object Superscript = CharacterConstants.Superscript; + + /** An alias for {@link CharacterConstants#Underline}. */ public static final Object Underline = CharacterConstants.Underline; + /** An alias for {@link ParagraphConstants#Alignment}. */ public static final Object Alignment = ParagraphConstants.Alignment; - public static final Object FirstLineIndent = ParagraphConstants.FirstLineIndent; + + /** An alias for {@link ParagraphConstants#FirstLineIndent}. */ + public static final Object FirstLineIndent + = ParagraphConstants.FirstLineIndent; + + /** An alias for {@link ParagraphConstants#LeftIndent}. */ public static final Object LeftIndent = ParagraphConstants.LeftIndent; + + /** An alias for {@link ParagraphConstants#LineSpacing}. */ public static final Object LineSpacing = ParagraphConstants.LineSpacing; + + /** An alias for {@link ParagraphConstants#Orientation}. */ public static final Object Orientation = ParagraphConstants.Orientation; + + /** An alias for {@link ParagraphConstants#RightIndent}. */ public static final Object RightIndent = ParagraphConstants.RightIndent; + + /** An alias for {@link ParagraphConstants#SpaceAbove}. */ public static final Object SpaceAbove = ParagraphConstants.SpaceAbove; + + /** An alias for {@link ParagraphConstants#SpaceBelow}. */ public static final Object SpaceBelow = ParagraphConstants.SpaceBelow; + + /** An alias for {@link ParagraphConstants#TabSet}. */ public static final Object TabSet = ParagraphConstants.TabSet; public static final String ComponentElementName = "component"; + public static final String IconElementName = "icon"; - public static final Object ComposedTextAttribute = new StyleConstants("composed text"); + public static final Object ComposedTextAttribute + = new StyleConstants("composed text"); + public static final Object ModelAttribute = new StyleConstants("model"); + public static final Object NameAttribute = new StyleConstants("name"); + public static final Object ResolveAttribute = new StyleConstants("resolver"); String keyname; @@ -93,279 +172,727 @@ public class StyleConstants keyname = k; } + /** + * Returns a string representation of the attribute key. + * + * @return A string representation of the attribute key. + */ public String toString() { return keyname; } + /** + * Returns the alignment specified in the given attributes, or + * {@link #ALIGN_LEFT} if no alignment is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The alignment (typically one of {@link #ALIGN_LEFT}, + * {@link #ALIGN_RIGHT}, {@link #ALIGN_CENTER} or + * {@link #ALIGN_JUSTIFIED}). + * + * @see #setAlignment(MutableAttributeSet, int) + */ public static int getAlignment(AttributeSet a) { - if (a.isDefined(Alignment)) - return ((Integer)a.getAttribute(Alignment)).intValue(); + Integer i = (Integer) a.getAttribute(Alignment); + if (i != null) + return i.intValue(); else return ALIGN_LEFT; } + /** + * Returns the background color specified in the given attributes, or + * {@link Color#BLACK} if no background color is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The background color. + * + * @see #setBackground(MutableAttributeSet, Color) + */ public static Color getBackground(AttributeSet a) { - if (a.isDefined(Background)) - return (Color) a.getAttribute(Background); + Color c = (Color) a.getAttribute(Background); + if (c != null) + return c; else - return Color.WHITE; + return Color.BLACK; } - + + /** + * Returns the bidi level specified in the given attributes, or + * <code>0</code> if no bidi level is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The bidi level. + * + * @see #setBidiLevel(MutableAttributeSet, int) + */ public static int getBidiLevel(AttributeSet a) { - if (a.isDefined(BidiLevel)) - return ((Integer)a.getAttribute(BidiLevel)).intValue(); + Integer i = (Integer) a.getAttribute(BidiLevel); + if (i != null) + return i.intValue(); else return 0; } + /** + * Returns the component specified in the given attributes, or + * <code>null</code> if no component is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The component (possibly <code>null</code>). + * + * @see #setComponent(MutableAttributeSet, Component) + */ public static Component getComponent(AttributeSet a) { - if (a.isDefined(ComponentAttribute)) - return (Component) a.getAttribute(ComponentAttribute); + Component c = (Component) a.getAttribute(ComponentAttribute); + if (c != null) + return c; else - return (Component) null; + return null; } + /** + * Returns the indentation specified in the given attributes, or + * <code>0.0f</code> if no indentation is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The indentation. + * + * @see #setFirstLineIndent(MutableAttributeSet, float) + */ public static float getFirstLineIndent(AttributeSet a) { - if (a.isDefined(FirstLineIndent)) - return ((Float)a.getAttribute(FirstLineIndent)).floatValue(); + Float f = (Float) a.getAttribute(FirstLineIndent); + if (f != null) + return f.floatValue(); else - return 0.f; + return 0.0f; } + /** + * Returns the font family specified in the given attributes, or + * <code>Monospaced</code> if no font family is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The font family. + * + * @see #setFontFamily(MutableAttributeSet, String) + */ public static String getFontFamily(AttributeSet a) { - if (a.isDefined(FontFamily)) - return (String) a.getAttribute(FontFamily); + String ff = (String) a.getAttribute(FontFamily); + if (ff != null) + return ff; else return "Monospaced"; } + /** + * Returns the font size specified in the given attributes, or + * <code>12</code> if no font size is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The font size. + * + * @see #setFontSize(MutableAttributeSet, int) + */ public static int getFontSize(AttributeSet a) { - if (a.isDefined(FontSize)) - return ((Integer)a.getAttribute(FontSize)).intValue(); + Integer i = (Integer) a.getAttribute(FontSize); + if (i != null) + return i.intValue(); else return 12; } + /** + * Returns the foreground color specified in the given attributes, or + * {@link Color#BLACK} if no foreground color is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The foreground color. + * + * @see #setForeground(MutableAttributeSet, Color) + */ public static Color getForeground(AttributeSet a) { - if (a.isDefined(Foreground)) - return (Color) a.getAttribute(Foreground); + Color c = (Color) a.getAttribute(Foreground); + if (c != null) + return c; else return Color.BLACK; } + /** + * Returns the icon specified in the given attributes, or + * <code>null</code> if no icon is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The icon (possibly <code>null</code>). + * + * @see #setIcon(MutableAttributeSet, Icon) + */ public static Icon getIcon(AttributeSet a) { - if (a.isDefined(IconAttribute)) - return (Icon) a.getAttribute(IconAttribute); - else - return (Icon) null; + return (Icon) a.getAttribute(IconAttribute); } + /** + * Returns the left indentation specified in the given attributes, or + * <code>0.0f</code> if no left indentation is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The left indentation. + * + * @see #setLeftIndent(MutableAttributeSet, float) + */ public static float getLeftIndent(AttributeSet a) { - if (a.isDefined(LeftIndent)) - return ((Float)a.getAttribute(LeftIndent)).floatValue(); + Float f = (Float) a.getAttribute(LeftIndent); + if (f != null) + return f.floatValue(); else - return 0.f; + return 0.0f; } + /** + * Returns the line spacing specified in the given attributes, or + * <code>0.0f</code> if no line spacing is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The line spacing. + * + * @see #setLineSpacing(MutableAttributeSet, float) + */ public static float getLineSpacing(AttributeSet a) { - if (a.isDefined(LineSpacing)) - return ((Float)a.getAttribute(LineSpacing)).floatValue(); + Float f = (Float) a.getAttribute(LineSpacing); + if (f != null) + return f.floatValue(); else - return 0.f; + return 0.0f; } + /** + * Returns the right indentation specified in the given attributes, or + * <code>0.0f</code> if no right indentation is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The right indentation. + * + * @see #setRightIndent(MutableAttributeSet, float) + */ public static float getRightIndent(AttributeSet a) { - if (a.isDefined(RightIndent)) - return ((Float)a.getAttribute(RightIndent)).floatValue(); + Float f = (Float) a.getAttribute(RightIndent); + if (f != null) + return f.floatValue(); else - return 0.f; + return 0.0f; } + /** + * Returns the 'space above' specified in the given attributes, or + * <code>0.0f</code> if no 'space above' is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The 'space above'. + * + * @see #setSpaceAbove(MutableAttributeSet, float) + */ public static float getSpaceAbove(AttributeSet a) { - if (a.isDefined(SpaceAbove)) - return ((Float)a.getAttribute(SpaceAbove)).floatValue(); - else - return 0.f; + Float f = (Float) a.getAttribute(SpaceAbove); + if (f != null) + return f.floatValue(); + else + return 0.0f; } + /** + * Returns the 'space below' specified in the given attributes, or + * <code>0.0f</code> if no 'space below' is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The 'space below'. + * + * @see #setSpaceBelow(MutableAttributeSet, float) + */ public static float getSpaceBelow(AttributeSet a) { - if (a.isDefined(SpaceBelow)) - return ((Float)a.getAttribute(SpaceBelow)).floatValue(); + Float f = (Float) a.getAttribute(SpaceBelow); + if (f != null) + return f.floatValue(); else - return 0.f; + return 0.0f; } + /** + * Returns the tab set specified in the given attributes, or + * <code>null</code> if no tab set is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The tab set. + * + * @see #setTabSet(MutableAttributeSet, javax.swing.text.TabSet) + */ public static javax.swing.text.TabSet getTabSet(AttributeSet a) { - if (a.isDefined(StyleConstants.TabSet)) - return (javax.swing.text.TabSet) a.getAttribute(StyleConstants.TabSet); - else - return (javax.swing.text.TabSet) null; + // I'm guessing that the fully qualified class name is to differentiate + // between the TabSet class and the TabSet (attribute) instance on some + // compiler... + return (javax.swing.text.TabSet) a.getAttribute(StyleConstants.TabSet); } + /** + * Returns the value of the bold flag in the given attributes, or + * <code>false</code> if no bold flag is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The bold flag. + * + * @see #setBold(MutableAttributeSet, boolean) + */ public static boolean isBold(AttributeSet a) { - if (a.isDefined(Bold)) - return ((Boolean) a.getAttribute(Bold)).booleanValue(); + Boolean b = (Boolean) a.getAttribute(Bold); + if (b != null) + return b.booleanValue(); else - return false; + return false; } + /** + * Returns the value of the italic flag in the given attributes, or + * <code>false</code> if no italic flag is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The italic flag. + * + * @see #setItalic(MutableAttributeSet, boolean) + */ public static boolean isItalic(AttributeSet a) { - if (a.isDefined(Italic)) - return ((Boolean) a.getAttribute(Italic)).booleanValue(); + Boolean b = (Boolean) a.getAttribute(Italic); + if (b != null) + return b.booleanValue(); else - return false; + return false; } + /** + * Returns the value of the strike-through flag in the given attributes, or + * <code>false</code> if no strike-through flag is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The strike-through flag. + * + * @see #setStrikeThrough(MutableAttributeSet, boolean) + */ public static boolean isStrikeThrough(AttributeSet a) { - if (a.isDefined(StrikeThrough)) - return ((Boolean) a.getAttribute(StrikeThrough)).booleanValue(); + Boolean b = (Boolean) a.getAttribute(StrikeThrough); + if (b != null) + return b.booleanValue(); else - return false; + return false; } + /** + * Returns the value of the subscript flag in the given attributes, or + * <code>false</code> if no subscript flag is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The subscript flag. + * + * @see #setSubscript(MutableAttributeSet, boolean) + */ public static boolean isSubscript(AttributeSet a) { - if (a.isDefined(Subscript)) - return ((Boolean) a.getAttribute(Subscript)).booleanValue(); + Boolean b = (Boolean) a.getAttribute(Subscript); + if (b != null) + return b.booleanValue(); else - return false; + return false; } + /** + * Returns the value of the superscript flag in the given attributes, or + * <code>false</code> if no superscript flag is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The superscript flag. + * + * @see #setSuperscript(MutableAttributeSet, boolean) + */ public static boolean isSuperscript(AttributeSet a) { - if (a.isDefined(Superscript)) - return ((Boolean) a.getAttribute(Superscript)).booleanValue(); - else - return false; + Boolean b = (Boolean) a.getAttribute(Superscript); + if (b != null) + return b.booleanValue(); + else + return false; } + /** + * Returns the value of the underline flag in the given attributes, or + * <code>false</code> if no underline flag is specified. + * + * @param a the attribute set (<code>null</code> not permitted). + * + * @return The underline flag. + * + * @see #setUnderline(MutableAttributeSet, boolean) + */ public static boolean isUnderline(AttributeSet a) { - if (a.isDefined(Underline)) - return ((Boolean) a.getAttribute(Underline)).booleanValue(); + Boolean b = (Boolean) a.getAttribute(Underline); + if (b != null) + return b.booleanValue(); else - return false; + return false; } + /** + * Adds an alignment attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param align the alignment (typically one of + * {@link StyleConstants#ALIGN_LEFT}, + * {@link StyleConstants#ALIGN_RIGHT}, + * {@link StyleConstants#ALIGN_CENTER} or + * {@link StyleConstants#ALIGN_JUSTIFIED}). + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #getAlignment(AttributeSet) + */ public static void setAlignment(MutableAttributeSet a, int align) { a.addAttribute(Alignment, new Integer(align)); } - public static void setBackground(MutableAttributeSet a, Color fg) + /** + * Adds a background attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param bg the background (<code>null</code> not permitted). + * + * @throws NullPointerException if either argument is <code>null</code>. + * + * @see #getBackground(AttributeSet) + */ + public static void setBackground(MutableAttributeSet a, Color bg) { - a.addAttribute(Background, fg); + a.addAttribute(Background, bg); } + /** + * Adds a bidi-level attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param lev the level. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #getBidiLevel(AttributeSet) + */ public static void setBidiLevel(MutableAttributeSet a, int lev) { a.addAttribute(BidiLevel, new Integer(lev)); } + /** + * Adds a bold attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param b the new value of the bold attribute. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #isBold(AttributeSet) + */ public static void setBold(MutableAttributeSet a, boolean b) { a.addAttribute(Bold, Boolean.valueOf(b)); } + /** + * Adds a component attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param c the component (<code>null</code> not permitted). + * + * @throws NullPointerException if either argument is <code>null</code>. + * + * @see #getComponent(AttributeSet) + */ public static void setComponent(MutableAttributeSet a, Component c) { a.addAttribute(ComponentAttribute, c); } + /** + * Adds a first line indentation attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param i the indentation. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #getFirstLineIndent(AttributeSet) + */ public static void setFirstLineIndent(MutableAttributeSet a, float i) { a.addAttribute(FirstLineIndent, new Float(i)); } + /** + * Adds a font family attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param fam the font family name (<code>null</code> not permitted). + * + * @throws NullPointerException if either argument is <code>null</code>. + * + * @see #getFontFamily(AttributeSet) + */ public static void setFontFamily(MutableAttributeSet a, String fam) { a.addAttribute(FontFamily, fam); } + /** + * Adds a font size attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param s the font size (in points). + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #getFontSize(AttributeSet) + */ public static void setFontSize(MutableAttributeSet a, int s) { a.addAttribute(FontSize, new Integer(s)); } + /** + * Adds a foreground color attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param fg the foreground color (<code>null</code> not permitted). + * + * @throws NullPointerException if either argument is <code>null</code>. + * + * @see #getForeground(AttributeSet) + */ public static void setForeground(MutableAttributeSet a, Color fg) { a.addAttribute(Foreground, fg); } + /** + * Adds an icon attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param c the icon (<code>null</code> not permitted). + * + * @throws NullPointerException if either argument is <code>null</code>. + * + * @see #getIcon(AttributeSet) + */ public static void setIcon(MutableAttributeSet a, Icon c) { a.addAttribute(IconAttribute, c); } + /** + * Adds an italic attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param b the new value of the italic attribute. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #isItalic(AttributeSet) + */ public static void setItalic(MutableAttributeSet a, boolean b) { a.addAttribute(Italic, Boolean.valueOf(b)); } + /** + * Adds a left indentation attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param i the indentation. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #getLeftIndent(AttributeSet) + */ public static void setLeftIndent(MutableAttributeSet a, float i) { a.addAttribute(LeftIndent, new Float(i)); } + /** + * Adds a line spacing attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param i the line spacing. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #getLineSpacing(AttributeSet) + */ public static void setLineSpacing(MutableAttributeSet a, float i) { a.addAttribute(LineSpacing, new Float(i)); } + /** + * Adds a right indentation attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param i the right indentation. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #getRightIndent(AttributeSet) + */ public static void setRightIndent(MutableAttributeSet a, float i) { a.addAttribute(RightIndent, new Float(i)); } + /** + * Adds a 'space above' attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param i the space above attribute value. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #getSpaceAbove(AttributeSet) + */ public static void setSpaceAbove(MutableAttributeSet a, float i) { a.addAttribute(SpaceAbove, new Float(i)); } + /** + * Adds a 'space below' attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param i the space below attribute value. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #getSpaceBelow(AttributeSet) + */ public static void setSpaceBelow(MutableAttributeSet a, float i) { a.addAttribute(SpaceBelow, new Float(i)); } + /** + * Adds a strike-through attribue to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param b the strike-through attribute value. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #isStrikeThrough(AttributeSet) + */ public static void setStrikeThrough(MutableAttributeSet a, boolean b) { a.addAttribute(StrikeThrough, Boolean.valueOf(b)); } + /** + * Adds a subscript attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param b the subscript attribute value. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #isSubscript(AttributeSet) + */ public static void setSubscript(MutableAttributeSet a, boolean b) { a.addAttribute(Subscript, Boolean.valueOf(b)); } + /** + * Adds a superscript attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param b the superscript attribute value. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #isSuperscript(AttributeSet) + */ public static void setSuperscript(MutableAttributeSet a, boolean b) { a.addAttribute(Superscript, Boolean.valueOf(b)); } - public static void setTabSet(MutableAttributeSet a, javax.swing.text.TabSet tabs) + /** + * Adds a {@link TabSet} attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param tabs the tab set (<code>null</code> not permitted). + * + * @throws NullPointerException if either argument is <code>null</code>. + * + * @see #getTabSet(AttributeSet) + */ + public static void setTabSet(MutableAttributeSet a, + javax.swing.text.TabSet tabs) { a.addAttribute(StyleConstants.TabSet, tabs); } + /** + * Adds an underline attribute to the specified set. + * + * @param a the attribute set (<code>null</code> not permitted). + * @param b the underline attribute value. + * + * @throws NullPointerException if <code>a</code> is <code>null</code>. + * + * @see #isUnderline(AttributeSet) + */ public static void setUnderline(MutableAttributeSet a, boolean b) { a.addAttribute(Underline, Boolean.valueOf(b)); @@ -373,73 +900,173 @@ public class StyleConstants // The remainder are so-called "typesafe enumerations" which // alias subsets of the above constants. + + /** + * A set of keys for attributes that apply to characters. + */ public static class CharacterConstants extends StyleConstants implements AttributeSet.CharacterAttribute { + /** + * Private constructor prevents new instances being created. + * + * @param k the key name. + */ private CharacterConstants(String k) { super(k); } - public static Object Background = ColorConstants.Background; - public static Object BidiLevel = new CharacterConstants("bidiLevel"); - public static Object Bold = FontConstants.Bold; - public static Object ComponentAttribute = new CharacterConstants("component"); - public static Object Family = FontConstants.Family; - public static Object Size = FontConstants.Size; - public static Object Foreground = ColorConstants.Foreground; - public static Object IconAttribute = new CharacterConstants("icon"); - public static Object Italic = FontConstants.Italic; - public static Object StrikeThrough = new CharacterConstants("strikethrough"); - public static Object Subscript = new CharacterConstants("subscript"); - public static Object Superscript = new CharacterConstants("superscript"); - public static Object Underline = new CharacterConstants("underline"); + /** An alias for {@link ColorConstants#Background}. */ + public static final Object Background = ColorConstants.Background; + + /** A key for the bidi level character attribute. */ + public static final Object BidiLevel = new CharacterConstants("bidiLevel"); + + /** An alias for {@link FontConstants#Bold}. */ + public static final Object Bold = FontConstants.Bold; + + /** A key for the component character attribute. */ + public static final Object ComponentAttribute + = new CharacterConstants("component"); + + /** An alias for {@link FontConstants#Family}. */ + public static final Object Family = FontConstants.Family; + + /** An alias for {@link FontConstants#Size}. */ + public static final Object Size = FontConstants.Size; + + /** An alias for {@link ColorConstants#Foreground}. */ + public static final Object Foreground = ColorConstants.Foreground; + + /** A key for the icon character attribute. */ + public static final Object IconAttribute = new CharacterConstants("icon"); + + /** A key for the italic character attribute. */ + public static final Object Italic = FontConstants.Italic; + + /** A key for the strike through character attribute. */ + public static final Object StrikeThrough + = new CharacterConstants("strikethrough"); + + /** A key for the subscript character attribute. */ + public static final Object Subscript = new CharacterConstants("subscript"); + + /** A key for the superscript character attribute. */ + public static final Object Superscript + = new CharacterConstants("superscript"); + + /** A key for the underline character attribute. */ + public static final Object Underline = new CharacterConstants("underline"); + } + /** + * A set of keys for attributes that relate to colors. + */ public static class ColorConstants extends StyleConstants implements AttributeSet.ColorAttribute, AttributeSet.CharacterAttribute { + /** + * Private constructor prevents new instances being created. + * + * @param k the key name. + */ private ColorConstants(String k) { super(k); } - public static Object Foreground = new ColorConstants("foreground"); - public static Object Background = new ColorConstants("background"); + + /** A key for the foreground color attribute. */ + public static final Object Foreground = new ColorConstants("foreground"); + + /** A key for the background color attribute. */ + public static final Object Background = new ColorConstants("background"); } + /** + * A set of keys for attributes that apply to fonts. + */ public static class FontConstants extends StyleConstants implements AttributeSet.FontAttribute, AttributeSet.CharacterAttribute { + /** + * Private constructor prevents new instances being created. + * + * @param k the key name. + */ private FontConstants(String k) { super(k); } - public static Object Bold = new FontConstants("bold"); - public static Object Family = new FontConstants("family"); - public static Object Italic = new FontConstants("italic"); - public static Object Size = new FontConstants("size"); + + /** A key for the bold font attribute. */ + public static final Object Bold = new FontConstants("bold"); + + /** A key for the family font attribute. */ + public static final Object Family = new FontConstants("family"); + + /** A key for the italic font attribute. */ + public static final Object Italic = new FontConstants("italic"); + + /** A key for the size font attribute. */ + public static final Object Size = new FontConstants("size"); } + /** + * A set of keys for attributes that apply to paragraphs. + */ public static class ParagraphConstants extends StyleConstants implements AttributeSet.ParagraphAttribute { + /** + * Private constructor prevents new instances being created. + * + * @param k the key name. + */ private ParagraphConstants(String k) { super(k); } - public static Object Alignment = new ParagraphConstants("Alignment"); - public static Object FirstLineIndent = new ParagraphConstants("FirstLineIndent"); - public static Object LeftIndent = new ParagraphConstants("LeftIndent"); - public static Object LineSpacing = new ParagraphConstants("LineSpacing"); - public static Object Orientation = new ParagraphConstants("Orientation"); - public static Object RightIndent = new ParagraphConstants("RightIndent"); - public static Object SpaceAbove = new ParagraphConstants("SpaceAbove"); - public static Object SpaceBelow = new ParagraphConstants("SpaceBelow"); - public static Object TabSet = new ParagraphConstants("TabSet"); + + /** A key for the alignment paragraph attribute. */ + public static final Object Alignment = new ParagraphConstants("Alignment"); + + /** A key for the first line indentation paragraph attribute. */ + public static final Object FirstLineIndent + = new ParagraphConstants("FirstLineIndent"); + + /** A key for the left indentation paragraph attribute. */ + public static final Object LeftIndent + = new ParagraphConstants("LeftIndent"); + + /** A key for the line spacing paragraph attribute. */ + public static final Object LineSpacing + = new ParagraphConstants("LineSpacing"); + + /** A key for the orientation paragraph attribute. */ + public static final Object Orientation + = new ParagraphConstants("Orientation"); + + /** A key for the right indentation paragraph attribute. */ + public static final Object RightIndent + = new ParagraphConstants("RightIndent"); + + /** A key for the 'space above' paragraph attribute. */ + public static final Object SpaceAbove + = new ParagraphConstants("SpaceAbove"); + + /** A key for the 'space below' paragraph attribute. */ + public static final Object SpaceBelow + = new ParagraphConstants("SpaceBelow"); + + /** A key for the tabset paragraph attribute. */ + public static final Object TabSet = new ParagraphConstants("TabSet"); + } } diff --git a/libjava/classpath/javax/swing/text/StyleContext.java b/libjava/classpath/javax/swing/text/StyleContext.java index dabc0ba9cd0..e2643a2aacd 100644 --- a/libjava/classpath/javax/swing/text/StyleContext.java +++ b/libjava/classpath/javax/swing/text/StyleContext.java @@ -48,6 +48,7 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Enumeration; import java.util.EventListener; +import java.util.HashSet; import java.util.Hashtable; import javax.swing.event.ChangeEvent; @@ -370,7 +371,7 @@ public class StyleContext { StringBuffer sb = new StringBuffer(); sb.append("[StyleContext.SmallattributeSet:"); - for (int i = 0; i < attrs.length; ++i) + for (int i = 0; i < attrs.length - 1; ++i) { sb.append(" ("); sb.append(attrs[i].toString()); @@ -406,7 +407,12 @@ public class StyleContext static StyleContext defaultStyleContext = new StyleContext(); static final int compressionThreshold = 9; - + + /** + * These attribute keys are handled specially in serialization. + */ + private static HashSet staticAttributeKeys = new HashSet(); + EventListenerList listenerList; Hashtable styleTable; @@ -737,4 +743,19 @@ public class StyleContext { throw new InternalError("not implemented"); } + + /** + * Registers an attribute key as a well-known keys. When an attribute with + * such a key is written to a stream,, a special syntax is used so that it + * can be recognized when it is read back in. All attribute keys defined + * in <code>StyleContext</code> are registered as static keys. If you define + * additional attribute keys that you want to exist as nonreplicated objects, + * then you should register them using this method. + * + * @param key the key to register as static attribute key + */ + public static void registerStaticAttributeKey(Object key) + { + staticAttributeKeys.add(key); + } } diff --git a/libjava/classpath/javax/swing/text/TableView.java b/libjava/classpath/javax/swing/text/TableView.java index d3113b82be2..2dcb9ebf7b3 100644 --- a/libjava/classpath/javax/swing/text/TableView.java +++ b/libjava/classpath/javax/swing/text/TableView.java @@ -54,7 +54,7 @@ import javax.swing.event.DocumentEvent; * * @author Roman Kennke (kennke@aicas.com) */ -public class TableView +public abstract class TableView extends BoxView { @@ -90,6 +90,18 @@ public class TableView public void replace(int offset, int length, View[] views) { super.replace(offset, length, views); + int viewCount = getViewCount(); + if (columnRequirements == null + || viewCount > columnRequirements.length) + { + columnRequirements = new SizeRequirements[viewCount]; + for (int i = 0; i < columnRequirements.length; i++) + columnRequirements[i] = new SizeRequirements(); + } + if (columnOffsets == null || columnOffsets.length < viewCount) + columnOffsets = new int[viewCount]; + if (columnSpans == null || columnSpans.length < viewCount) + columnSpans = new int[viewCount]; layoutChanged(X_AXIS); } @@ -108,8 +120,6 @@ public class TableView protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { - // TODO: Maybe prepare columnSpans and columnOffsets. - // Some sanity checks. If these preconditions are not met, then the // following code will not work. Also, there must be something // seriously wrong then. @@ -140,7 +150,7 @@ public class TableView { // FIXME: Figure out how to fetch the row heights from the TableView's // element. - super.layoutMajorAxis(targetSpan, axis, offsets, spans); + super.layoutMinorAxis(targetSpan, axis, offsets, spans); } /** @@ -303,7 +313,7 @@ public class TableView /** * The size requirements of the columns. */ - private SizeRequirements[] columnRequirements; + SizeRequirements[] columnRequirements = new SizeRequirements[0]; /** * Creates a new instance of <code>TableView</code>. @@ -313,15 +323,6 @@ public class TableView public TableView(Element el) { super(el, Y_AXIS); - int numChildren = el.getElementCount(); - View[] rows = new View[numChildren]; - for (int i = 0; i < numChildren; ++i) - { - Element rowEl = el.getElement(i); - TableRow rowView = createTableRow(rowEl); - rows[i] = rowView; - } - replace(0, 0, rows); } /** @@ -385,7 +386,10 @@ public class TableView protected void layoutColumns(int targetSpan, int[] offsets, int spans[], SizeRequirements[] reqs) { - // TODO: Figure out what exactly to do here. + updateColumnRequirements(); + SizeRequirements r = calculateMinorAxisRequirements(X_AXIS, null); + SizeRequirements.calculateTiledPositions(targetSpan, r, columnRequirements, + offsets, spans); } /** @@ -462,4 +466,26 @@ public class TableView // and look for a range that contains the given position. return super.getViewAtPosition(pos, a); } + + /** + * Updates the column requirements. + */ + private void updateColumnRequirements() + { + int rowCount = getViewCount(); + for (int r = 0; r < rowCount; ++r) + { + TableRow row = (TableRow) getView(r); + int columnCount = row.getViewCount(); + for (int c = 0; c < columnCount; ++c) + { + View cell = row.getView(c); + SizeRequirements cr = columnRequirements[c]; + cr.minimum = Math.max(cr.minimum, (int) cell.getMinimumSpan(X_AXIS)); + cr.preferred = Math.max(cr.preferred, + (int) cell.getPreferredSpan(X_AXIS)); + cr.maximum = Math.max(cr.maximum, (int) cell.getMaximumSpan(X_AXIS)); + } + } + } } diff --git a/libjava/classpath/javax/swing/text/Utilities.java b/libjava/classpath/javax/swing/text/Utilities.java index 1adc8ff87e9..d109a4a950f 100644 --- a/libjava/classpath/javax/swing/text/Utilities.java +++ b/libjava/classpath/javax/swing/text/Utilities.java @@ -41,12 +41,8 @@ package javax.swing.text; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Point; -import java.awt.Rectangle; import java.text.BreakIterator; -import javax.swing.SwingConstants; -import javax.swing.SwingUtilities; - /** * A set of utilities to deal with text. This is used by several other classes * inside this package. @@ -73,6 +69,10 @@ public class Utilities * are taken into account. Tabs are expanded using the * specified {@link TabExpander}. * + * + * The X and Y coordinates denote the start of the <em>baseline</em> where + * the text should be drawn. + * * @param s the text fragment to be drawn. * @param x the x position for drawing. * @param y the y position for drawing. @@ -88,15 +88,14 @@ public class Utilities // This buffers the chars to be drawn. char[] buffer = s.array; - - // The current x and y pixel coordinates. - int pixelX = x; - int pixelY = y; - // The font metrics of the current selected font. FontMetrics metrics = g.getFontMetrics(); int ascent = metrics.getAscent(); + // The current x and y pixel coordinates. + int pixelX = x; + int pixelY = y - ascent; + int pixelWidth = 0; int pos = s.offset; int len = 0; @@ -238,9 +237,10 @@ public class Utilities int pos; int currentX = x0; - for (pos = p0; pos < s.count; pos++) + for (pos = 0; pos < s.count; pos++) { char nextChar = s.array[s.offset+pos]; + if (nextChar == 0) { if (! round) @@ -256,6 +256,7 @@ public class Utilities else currentX = (int) te.nextTabStop(currentX, pos); } + if (currentX > x) { if (! round) @@ -263,7 +264,8 @@ public class Utilities break; } } - return pos; + + return pos + p0; } /** @@ -510,10 +512,10 @@ public class Utilities { int mark = Utilities.getTabbedTextOffset(s, metrics, x0, x, e, startOffset); BreakIterator breaker = BreakIterator.getWordInstance(); - breaker.setText(s.toString()); - + breaker.setText(s); + // If mark is equal to the end of the string, just use that position - if (mark == s.count) + if (mark == s.count + s.offset) return mark; // Try to find a word boundary previous to the mark at which we @@ -571,15 +573,29 @@ public class Utilities public static final int getPositionAbove(JTextComponent c, int offset, int x) throws BadLocationException { - View rootView = c.getUI().getRootView(c); - Rectangle r = c.modelToView(offset); - int offs = c.viewToModel(new Point(x, r.y)); - int pos = rootView.getNextVisualPositionFrom(offs, - Position.Bias.Forward, - SwingUtilities.calculateInnerArea(c, null), - SwingConstants.NORTH, - new Position.Bias[1]); - return pos; + int offs = getRowStart(c, offset); + + if(offs == -1) + return -1; + + // Effectively calculates the y value of the previous line. + Point pt = c.modelToView(offs-1).getLocation(); + + pt.x = x; + + // Calculate a simple fitting offset. + offs = c.viewToModel(pt); + + // Find out the real x positions of the calculated character and its + // neighbour. + int offsX = c.modelToView(offs).getLocation().x; + int offsXNext = c.modelToView(offs+1).getLocation().x; + + // Chose the one which is nearer to us and return its offset. + if (Math.abs(offsX-x) <= Math.abs(offsXNext-x)) + return offs; + else + return offs+1; } /** @@ -598,14 +614,31 @@ public class Utilities public static final int getPositionBelow(JTextComponent c, int offset, int x) throws BadLocationException { - View rootView = c.getUI().getRootView(c); - Rectangle r = c.modelToView(offset); - int offs = c.viewToModel(new Point(x, r.y)); - int pos = rootView.getNextVisualPositionFrom(offs, - Position.Bias.Forward, - SwingUtilities.calculateInnerArea(c, null), - SwingConstants.SOUTH, - new Position.Bias[1]); - return pos; - } + int offs = getRowEnd(c, offset); + + if(offs == -1) + return -1; + + // Effectively calculates the y value of the previous line. + Point pt = c.modelToView(offs+1).getLocation(); + + pt.x = x; + + // Calculate a simple fitting offset. + offs = c.viewToModel(pt); + + if (offs == c.getDocument().getLength()) + return offs; + + // Find out the real x positions of the calculated character and its + // neighbour. + int offsX = c.modelToView(offs).getLocation().x; + int offsXNext = c.modelToView(offs+1).getLocation().x; + + // Chose the one which is nearer to us and return its offset. + if (Math.abs(offsX-x) <= Math.abs(offsXNext-x)) + return offs; + else + return offs+1; + } } diff --git a/libjava/classpath/javax/swing/text/View.java b/libjava/classpath/javax/swing/text/View.java index b835842bc0e..2feaf29a4f9 100644 --- a/libjava/classpath/javax/swing/text/View.java +++ b/libjava/classpath/javax/swing/text/View.java @@ -44,6 +44,7 @@ import java.awt.Rectangle; import java.awt.Shape; import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; public abstract class View implements SwingConstants @@ -72,8 +73,29 @@ public abstract class View implements SwingConstants public abstract void paint(Graphics g, Shape s); + /** + * Sets the parent for this view. This is the first method that is beeing + * called on a view to setup the view hierarchy. This is also the last method + * beeing called when the view is disconnected from the view hierarchy, in + * this case <code>parent</code> is null. + * + * If <code>parent</code> is <code>null</code>, a call to this method also + * calls <code>setParent</code> on the children, thus disconnecting them from + * the view hierarchy. That means that super must be called when this method + * is overridden. + * + * @param parent the parent to set, <code>null</code> when this view is + * beeing disconnected from the view hierarchy + */ public void setParent(View parent) { + if (parent == null) + { + int numChildren = getViewCount(); + for (int i = 0; i < numChildren; i++) + getView(i).setParent(null); + } + this.parent = parent; } @@ -101,27 +123,65 @@ public abstract class View implements SwingConstants return elt; } + /** + * Returns the preferred span along the specified axis. Normally the view is + * rendered with the span returned here if that is possible. + * + * @param axis the axis + * + * @return the preferred span along the specified axis + */ public abstract float getPreferredSpan(int axis); + /** + * Returns the resize weight of this view. A value of <code>0</code> or less + * means this view is not resizeable. Positive values make the view + * resizeable. The default implementation returns <code>0</code> + * unconditionally. + * + * @param axis the axis + * + * @return the resizability of this view along the specified axis + */ public int getResizeWeight(int axis) { return 0; } + /** + * Returns the maximum span along the specified axis. The default + * implementation will forward to + * {@link #getPreferredSpan(int)} unless {@link #getResizeWeight(int)} + * returns a value > 0, in which case this returns {@link Integer#MIN_VALUE}. + * + * @param axis the axis + * + * @return the maximum span along the specified axis + */ public float getMaximumSpan(int axis) { + float max = Integer.MAX_VALUE; if (getResizeWeight(axis) <= 0) - return getPreferredSpan(axis); - - return Integer.MAX_VALUE; + max = getPreferredSpan(axis); + return max; } + /** + * Returns the minimum span along the specified axis. The default + * implementation will forward to + * {@link #getPreferredSpan(int)} unless {@link #getResizeWeight(int)} + * returns a value > 0, in which case this returns <code>0</code>. + * + * @param axis the axis + * + * @return the minimum span along the specified axis + */ public float getMinimumSpan(int axis) { + float min = 0; if (getResizeWeight(axis) <= 0) - return getPreferredSpan(axis); - - return Integer.MAX_VALUE; + min = getPreferredSpan(axis); + return min; } public void setSize(float width, float height) @@ -129,6 +189,20 @@ public abstract class View implements SwingConstants // The default implementation does nothing. } + /** + * Returns the alignment of this view along the baseline of the parent view. + * An alignment of <code>0.0</code> will align this view with the left edge + * along the baseline, an alignment of <code>0.5</code> will align it + * centered to the baseline, an alignment of <code>1.0</code> will align + * the right edge along the baseline. + * + * The default implementation returns 0.5 unconditionally. + * + * @param axis the axis + * + * @return the alignment of this view along the parents baseline for the + * specified axis + */ public float getAlignment(int axis) { return 0.5f; @@ -160,6 +234,15 @@ public abstract class View implements SwingConstants return parent != null ? parent.getViewFactory() : null; } + /** + * Replaces a couple of child views with new child views. If + * <code>length == 0</code> then this is a simple insertion, if + * <code>views == null</code> this only removes some child views. + * + * @param offset the offset at which to replace + * @param length the number of child views to be removed + * @param views the new views to be inserted, may be <code>null</code> + */ public void replace(int offset, int length, View[] views) { // Default implementation does nothing. @@ -392,6 +475,10 @@ public abstract class View implements SwingConstants * of the change to the model. This calles {@link #forwardUpdateToView} * for each View that must be forwarded to. * + * If <code>ec</code> is not <code>null</code> (this means there have been + * structural changes to the element that this view is responsible for) this + * method should recognize this and don't notify newly added child views. + * * @param ec the ElementChange describing the element changes (may be * <code>null</code> if there were no changes) * @param ev the DocumentEvent describing the changes to the model @@ -404,10 +491,31 @@ public abstract class View implements SwingConstants DocumentEvent ev, Shape shape, ViewFactory vf) { int count = getViewCount(); - for (int i = 0; i < count; i++) + if (count > 0) { - View child = getView(i); - forwardUpdateToView(child, ev, shape, vf); + int startOffset = ev.getOffset(); + int endOffset = startOffset + ev.getLength(); + int startIndex = getViewIndex(startOffset, Position.Bias.Backward); + int endIndex = getViewIndex(endOffset, Position.Bias.Forward); + int index = -1; + int addLength = -1; + if (ec != null) + { + index = ec.getIndex(); + addLength = ec.getChildrenAdded().length; + } + + if (startIndex >= 0 && endIndex >= 0) + { + for (int i = startIndex; i <= endIndex; i++) + { + // Skip newly added child views. + if (index >= 0 && i >= index && i < (index+addLength)) + continue; + View child = getView(i); + forwardUpdateToView(child, ev, shape, vf); + } + } } } @@ -503,9 +611,9 @@ public abstract class View implements SwingConstants if (b2 != Position.Bias.Forward && b2 != Position.Bias.Backward) throw new IllegalArgumentException ("b2 must be either Position.Bias.Forward or Position.Bias.Backward"); - Shape s1 = modelToView(p1, a, b1); - Shape s2 = modelToView(p2, a, b2); - return s1.getBounds().union(s2.getBounds()); + Rectangle s1 = (Rectangle) modelToView(p1, a, b1); + Rectangle s2 = (Rectangle) modelToView(p2, a, b2); + return SwingUtilities.computeUnion(s1.x, s1.y, s1.width, s1.height, s2); } /** @@ -570,7 +678,7 @@ public abstract class View implements SwingConstants * Dumps the complete View hierarchy. This method can be used for debugging * purposes. */ - void dump() + protected void dump() { // Climb up the hierarchy to the parent. View parent = getParent(); @@ -590,7 +698,7 @@ public abstract class View implements SwingConstants { for (int i = 0; i < indent; ++i) System.out.print('.'); - System.out.println(this); + System.out.println(this + "(" + getStartOffset() + "," + getEndOffset() + ": " + getElement()); int count = getViewCount(); for (int i = 0; i < count; ++i) diff --git a/libjava/classpath/javax/swing/text/WrappedPlainView.java b/libjava/classpath/javax/swing/text/WrappedPlainView.java index baba343c5bf..e2790a05ca0 100644 --- a/libjava/classpath/javax/swing/text/WrappedPlainView.java +++ b/libjava/classpath/javax/swing/text/WrappedPlainView.java @@ -270,8 +270,7 @@ public class WrappedPlainView extends BoxView implements TabExpander protected int calculateBreakPosition(int p0, int p1) { Container c = getContainer(); - Rectangle alloc = c.isValid() ? c.getBounds() - : new Rectangle(c.getPreferredSize()); + Rectangle alloc = new Rectangle(0, 0, getWidth(), getHeight()); updateMetrics(); try { diff --git a/libjava/classpath/javax/swing/text/html/FormView.java b/libjava/classpath/javax/swing/text/html/FormView.java new file mode 100644 index 00000000000..b85c6943404 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/FormView.java @@ -0,0 +1,230 @@ +/* FormView.java -- A view for a variety of HTML form elements + 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.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JPasswordField; +import javax.swing.JRadioButton; +import javax.swing.JTextField; +import javax.swing.UIManager; +import javax.swing.text.AttributeSet; +import javax.swing.text.ComponentView; +import javax.swing.text.Element; +import javax.swing.text.StyleConstants; + +/** + * A View that renders HTML form elements like buttons and input fields. + * This is implemented as a {@link ComponentView} that creates different Swing + * component depending on the type and setting of the different form elements. + * + * Namely, this view creates the following components: + * <table> + * <tr><th>Element type</th><th>Swing component</th></tr> + * <tr><td>input, button</td><td>JButton</td></tr> + * <tr><td>input, checkbox</td><td>JButton</td></tr> + * <tr><td>input, image</td><td>JButton</td></tr> + * <tr><td>input, password</td><td>JButton</td></tr> + * <tr><td>input, radio</td><td>JButton</td></tr> + * <tr><td>input, reset</td><td>JButton</td></tr> + * <tr><td>input, submit</td><td>JButton</td></tr> + * <tr><td>input, text</td><td>JButton</td></tr> + * <tr><td>select, size > 1 or with multiple attribute</td> + * <td>JList in JScrollPane</td></tr> + * <tr><td>select, size unspecified or == 1</td><td>JComboBox</td></tr> + * <tr><td>textarea, text</td><td>JTextArea in JScrollPane</td></tr> + * <tr><td>input, file</td><td>JTextField</td></tr> + * </table> + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FormView + extends ComponentView + implements ActionListener +{ + + /** + * If the value attribute of an <code><input type="submit">> + * tag is not specified, then this string is used. + * + * @deprecated As of JDK1.3 the value is fetched from the UIManager property + * <code>FormView.submitButtonText</code>. + */ + public static final String SUBMIT = + UIManager.getString("FormView.submitButtonText"); + + /** + * If the value attribute of an <code><input type="reset">> + * tag is not specified, then this string is used. + * + * @deprecated As of JDK1.3 the value is fetched from the UIManager property + * <code>FormView.resetButtonText</code>. + */ + public static final String RESET = + UIManager.getString("FormView.resetButtonText"); + + /** + * Creates a new <code>FormView</code>. + * + * @param el the element that is displayed by this view. + */ + public FormView(Element el) + { + super(el); + } + + /** + * Creates the correct AWT component for rendering the form element. + */ + protected Component createComponent() + { + Component comp = null; + Element el = getElement(); + Object tag = el.getAttributes().getAttribute(StyleConstants.NameAttribute); + if (tag.equals(HTML.Tag.INPUT)) + { + AttributeSet atts = el.getAttributes(); + String type = (String) atts.getAttribute(HTML.Attribute.TYPE); + String value = (String) atts.getAttribute(HTML.Attribute.VALUE); + if (type.equals("button")) + comp = new JButton(value); + else if (type.equals("checkbox")) + comp = new JCheckBox(value); + else if (type.equals("image")) + comp = new JButton(value); // FIXME: Find out how to fetch the image. + else if (type.equals("password")) + comp = new JPasswordField(value); + else if (type.equals("radio")) + comp = new JRadioButton(value); + else if (type.equals("reset")) + { + if (value == null || value.equals("")) + value = RESET; + comp = new JButton(value); + } + else if (type.equals("submit")) + { + if (value == null || value.equals("")) + value = SUBMIT; + comp = new JButton(value); + } + else if (type.equals("text")) + comp = new JTextField(value); + + } + // FIXME: Implement the remaining components. + return comp; + } + + /** + * Determines the maximum span for this view on the specified axis. + * + * @param axis the axis along which to determine the span + * + * @return the maximum span for this view on the specified axis + * + * @throws IllegalArgumentException if the axis is invalid + */ + public float getMaximumSpan(int axis) + { + // FIXME: The specs say that for some components the maximum span == the + // preferred span of the component. This should be figured out and + // implemented accordingly. + float span; + if (axis == X_AXIS) + span = getComponent().getMaximumSize().width; + else if (axis == Y_AXIS) + span = getComponent().getMaximumSize().height; + else + throw new IllegalArgumentException("Invalid axis parameter"); + return span; + } + + /** + * Processes an action from the Swing component. + * + * If the action comes from a submit button, the form is submitted by calling + * {@link #submitData}. In the case of a reset button, the form is reset to + * the original state. If the action comes from a password or text field, + * then the input focus is transferred to the next input element in the form, + * unless this text/password field is the last one, in which case the form + * is submitted. + * + * @param ev the action event + */ + public void actionPerformed(ActionEvent ev) + { + Element el = getElement(); + Object tag = el.getAttributes().getAttribute(StyleConstants.NameAttribute); + if (tag.equals(HTML.Tag.INPUT)) + { + AttributeSet atts = el.getAttributes(); + String type = (String) atts.getAttribute(HTML.Attribute.TYPE); + if (type.equals("submit")) + submitData(""); // FIXME: How to fetch the actual form data? + } + // FIXME: Implement the remaining actions. + } + + /** + * Submits the form data. A separate thread is created to do the + * transmission. + * + * @param data the form data + */ + protected void submitData(String data) + { + // FIXME: Implement this. + } + + /** + * Submits the form data in response to a click on a + * <code><input type="image"></code> element. + * + * @param imageData the mouse click coordinates + */ + protected void imageSubmit(String imageData) + { + // FIXME: Implement this. + } +} diff --git a/libjava/classpath/javax/swing/text/html/HTML.java b/libjava/classpath/javax/swing/text/html/HTML.java index 0b758d2b873..2b521cd22b4 100644 --- a/libjava/classpath/javax/swing/text/html/HTML.java +++ b/libjava/classpath/javax/swing/text/html/HTML.java @@ -57,8 +57,7 @@ public class HTML /** * Represents a HTML attribute. */ - public static class Attribute - implements Serializable + public static final class Attribute { /** * The action attribute @@ -464,47 +463,18 @@ public class HTML * The width attribute */ public static final Attribute WIDTH = new Attribute("width"); - private final String name; - - /** - * Creates the attribute with the given name. - */ - protected Attribute(String a_name) - { - name = a_name; - } - - /** - * Calls compareTo on the tag names (Strings) - */ - public int compareTo(Object other) - { - return name.compareTo(((Attribute) other).name); - } /** - * The attributes are equal if the names are equal - * (ignoring case) + * The attribute name. */ - public boolean equals(Object other) - { - if (other == this) - return true; - - if (!(other instanceof Attribute)) - return false; - - Attribute that = (Attribute) other; - - return that.name.equalsIgnoreCase(name); - } + private final String name; /** - * Returns the hash code which corresponds to the string for this tag. + * Creates the attribute with the given name. */ - public int hashCode() + private Attribute(String a_name) { - return name == null ? 0 : name.hashCode(); + name = a_name; } /** @@ -559,7 +529,6 @@ public class HTML * Represents a HTML tag. */ public static class Tag - implements Comparable, Serializable { /** * The <a> tag @@ -1047,42 +1016,6 @@ public class HTML } /** - * Calls compareTo on the tag names (Strings) - */ - public int compareTo(Object other) - { - return name.compareTo(((Tag) other).name); - } - - /** - * The tags are equal if the names are equal (ignoring case). - */ - public boolean equals(Object other) - { - if (other == this) - { - return true; - } - - if (!(other instanceof Tag)) - { - return false; - } - - Tag that = (Tag) other; - - return that.name.equalsIgnoreCase(name); - } - - /** - * Returns the hash code which corresponds to the string for this tag. - */ - public int hashCode() - { - return name == null ? 0 : name.hashCode(); - } - - /** * Returns the tag name. The names of the built-in tags are always * returned in lowercase. */ diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java index 5b2452b32f6..2a96953ee91 100644 --- a/libjava/classpath/javax/swing/text/html/HTMLDocument.java +++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java @@ -38,10 +38,8 @@ exception statement from your version. */ package javax.swing.text.html; -import java.net.URL; - import java.io.IOException; - +import java.net.URL; import java.util.HashMap; import java.util.Stack; import java.util.Vector; @@ -131,16 +129,17 @@ public class HTMLDocument extends DefaultStyledDocument } /** - * Replaces the contents of the document with the given element specifications. - * This is called before insert if the loading is done in bursts. This is the - * only method called if loading the document entirely in one burst. + * Replaces the contents of the document with the given element + * specifications. This is called before insert if the loading is done + * in bursts. This is the only method called if loading the document + * entirely in one burst. * * @param data - the date that replaces the content of the document */ protected void create(DefaultStyledDocument.ElementSpec[] data) { - // FIXME: Not implemented - System.out.println("create not implemented"); + // Once the super behaviour is properly implemented it should be sufficient + // to simply call super.create(data). super.create(data); } @@ -149,11 +148,35 @@ public class HTMLDocument extends DefaultStyledDocument * * @return the new default root */ - protected AbstractDocument.AbstractElement createDefaultRoot() + protected AbstractElement createDefaultRoot() { - // FIXME: Not implemented - System.out.println("createDefaultRoot not implemented"); - return super.createDefaultRoot(); + AbstractDocument.AttributeContext ctx = getAttributeContext(); + + // Create html element. + AttributeSet atts = ctx.getEmptySet(); + atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.HTML); + BranchElement html = (BranchElement) createBranchElement(null, atts); + + // Create body element. + atts = ctx.getEmptySet(); + atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.BODY); + BranchElement body = (BranchElement) createBranchElement(html, atts); + html.replace(0, 0, new Element[] { body }); + + // Create p element. + atts = ctx.getEmptySet(); + atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.P); + BranchElement p = (BranchElement) createBranchElement(body, atts); + body.replace(0, 0, new Element[] { p }); + + // Create an empty leaf element. + atts = ctx.getEmptySet(); + atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, + HTML.Tag.CONTENT); + Element leaf = createLeafElement(p, atts, 0, 1); + p.replace(0, 0, new Element[]{ leaf }); + + return html; } /** @@ -165,28 +188,29 @@ public class HTMLDocument extends DefaultStyledDocument * @param a - the attributes for the element * @param p0 - the beginning of the range >= 0 * @param p1 - the end of the range >= p0 + * * @return the new element */ protected Element createLeafElement(Element parent, AttributeSet a, int p0, int p1) { - // FIXME: Not implemented - System.out.println("createLeafElement not implemented"); - return super.createLeafElement(parent, a, p0, p1); + RunElement el = new RunElement(parent, a, p0, p1); + el.addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT); + return new RunElement(parent, a, p0, p1); } - /** This method returns an HTMLDocument.BlockElement object representing the + /** + * This method returns an HTMLDocument.BlockElement object representing the * attribute set a and attached to parent. * * @param parent - the parent element * @param a - the attributes for the element + * * @return the new element */ protected Element createBranchElement(Element parent, AttributeSet a) { - // FIXME: Not implemented - System.out.println("createBranchElement not implemented"); - return super.createBranchElement(parent, a); + return new BlockElement(parent, a); } /** @@ -204,9 +228,9 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void insert(int offset, DefaultStyledDocument.ElementSpec[] data) throws BadLocationException - { - super.insert(offset, data); - } + { + super.insert(offset, data); + } /** * Updates document structure as a result of text insertion. This will happen @@ -451,7 +475,7 @@ public class HTMLDocument extends DefaultStyledDocument { public BlockElement (Element parent, AttributeSet a) { - super (parent, a); + super(parent, a); } /** @@ -470,10 +494,14 @@ public class HTMLDocument extends DefaultStyledDocument */ public String getName() { - return (String) getAttribute(StyleConstants.NameAttribute); + Object tag = getAttribute(StyleConstants.NameAttribute); + String name = null; + if (tag != null) + name = tag.toString(); + return name; } } - + /** * RunElement represents a section of text that has a set of * HTML character level attributes assigned to it. @@ -502,7 +530,11 @@ public class HTMLDocument extends DefaultStyledDocument */ public String getName() { - return (String) getAttribute(StyleConstants.NameAttribute); + Object tag = getAttribute(StyleConstants.NameAttribute); + String name = null; + if (tag != null) + name = tag.toString(); + return name; } /** @@ -531,7 +563,13 @@ public class HTMLDocument extends DefaultStyledDocument /** A stack for character attribute sets **/ Stack charAttrStack = new Stack(); - + + /** + * The parse stack. This stack holds HTML.Tag objects that reflect the + * current position in the parsing process. + */ + private Stack parseStack = new Stack(); + /** A mapping between HTML.Tag objects and the actions that handle them **/ HashMap tagToAction; @@ -699,8 +737,8 @@ public class HTMLDocument extends DefaultStyledDocument */ public void start(HTML.Tag t, MutableAttributeSet a) { - // FIXME: Implement. - print ("ParagraphAction.start not implemented"); + // FIXME: What else must be done here? + blockOpen(t, a); } /** @@ -709,8 +747,8 @@ public class HTMLDocument extends DefaultStyledDocument */ public void end(HTML.Tag t) { - // FIXME: Implement. - print ("ParagraphAction.end not implemented"); + // FIXME: What else must be done here? + blockClose(t); } } @@ -1102,7 +1140,11 @@ public class HTMLDocument extends DefaultStyledDocument elements = new DefaultStyledDocument.ElementSpec[parseBuffer.size()]; parseBuffer.copyInto(elements); parseBuffer.removeAllElements(); - insert(offset, elements); + if (offset == 0) + create(elements); + else + insert(offset, elements); + offset += HTMLDocument.this.getLength() - offset; } @@ -1250,12 +1292,27 @@ public class HTMLDocument extends DefaultStyledDocument { printBuffer(); DefaultStyledDocument.ElementSpec element; - element = new DefaultStyledDocument.ElementSpec(attr.copyAttributes(), - DefaultStyledDocument.ElementSpec.StartTagType); + + // If the previous tag is content and the parent is p-implied, then + // we must also close the p-implied. + if (parseStack.size() > 0 && parseStack.peek() == HTML.Tag.IMPLIED) + { + element = new DefaultStyledDocument.ElementSpec(null, + DefaultStyledDocument.ElementSpec.EndTagType); + parseBuffer.addElement(element); + parseStack.pop(); + } + + parseStack.push(t); + AbstractDocument.AttributeContext ctx = getAttributeContext(); + AttributeSet copy = attr.copyAttributes(); + copy = ctx.addAttribute(copy, StyleConstants.NameAttribute, t); + element = new DefaultStyledDocument.ElementSpec(copy, + DefaultStyledDocument.ElementSpec.StartTagType); parseBuffer.addElement(element); printBuffer(); } - + /** * Instructs the parse buffer to close the block element associated with * the given HTML.Tag @@ -1266,10 +1323,40 @@ public class HTMLDocument extends DefaultStyledDocument { printBuffer(); DefaultStyledDocument.ElementSpec element; + + // If the previous tag is a start tag then we insert a synthetic + // content tag. + DefaultStyledDocument.ElementSpec prev; + prev = (DefaultStyledDocument.ElementSpec) + parseBuffer.get(parseBuffer.size() - 1); + if (prev.getType() == DefaultStyledDocument.ElementSpec.StartTagType) + { + AbstractDocument.AttributeContext ctx = getAttributeContext(); + AttributeSet attributes = ctx.getEmptySet(); + attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute, + HTML.Tag.CONTENT); + element = new DefaultStyledDocument.ElementSpec(attributes, + DefaultStyledDocument.ElementSpec.ContentType, + new char[0], 0, 0); + parseBuffer.add(element); + } + // If the previous tag is content and the parent is p-implied, then + // we must also close the p-implied. + else if (parseStack.peek() == HTML.Tag.IMPLIED) + { + element = new DefaultStyledDocument.ElementSpec(null, + DefaultStyledDocument.ElementSpec.EndTagType); + parseBuffer.addElement(element); + if (parseStack.size() > 0) + parseStack.pop(); + } + element = new DefaultStyledDocument.ElementSpec(null, DefaultStyledDocument.ElementSpec.EndTagType); parseBuffer.addElement(element); printBuffer(); + if (parseStack.size() > 0) + parseStack.pop(); } /** @@ -1298,16 +1385,42 @@ public class HTMLDocument extends DefaultStyledDocument protected void addContent(char[] data, int offs, int length, boolean generateImpliedPIfNecessary) { + AbstractDocument.AttributeContext ctx = getAttributeContext(); + DefaultStyledDocument.ElementSpec element; + AttributeSet attributes = null; + + // Content must always be embedded inside a paragraph element, + // so we create this if the previous element is not one of + // <p>, <h1> .. <h6>. + boolean createImpliedParagraph = false; + HTML.Tag parent = (HTML.Tag) parseStack.peek(); + if (parent != HTML.Tag.P && parent != HTML.Tag.H1 + && parent != HTML.Tag.H2 + && parent != HTML.Tag.H3 && parent != HTML.Tag.H4 + && parent != HTML.Tag.H5 && parent != HTML.Tag.H6 + && parent != HTML.Tag.TD) + { + attributes = ctx.getEmptySet(); + attributes = ctx.addAttribute(attributes, + StyleConstants.NameAttribute, + HTML.Tag.IMPLIED); + element = new DefaultStyledDocument.ElementSpec(attributes, + DefaultStyledDocument.ElementSpec.StartTagType); + parseBuffer.add(element); + parseStack.push(HTML.Tag.IMPLIED); + } + // Copy the attribute set, don't use the same object because // it may change - AttributeSet attributes = null; if (charAttr != null) attributes = charAttr.copyAttributes(); - - DefaultStyledDocument.ElementSpec element; + else + attributes = ctx.getEmptySet(); + attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute, + HTML.Tag.CONTENT); element = new DefaultStyledDocument.ElementSpec(attributes, - DefaultStyledDocument.ElementSpec.ContentType, - data, offs, length); + DefaultStyledDocument.ElementSpec.ContentType, + data, offs, length); printBuffer(); // Add the element to the buffer diff --git a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java index 1ef9768c923..2d5d1eb79da 100644 --- a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java +++ b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java @@ -56,17 +56,11 @@ import javax.accessibility.AccessibleContext; import javax.swing.Action; import javax.swing.JEditorPane; -import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; -import javax.swing.text.BoxView; -import javax.swing.text.ComponentView; import javax.swing.text.Document; import javax.swing.text.EditorKit; import javax.swing.text.Element; -import javax.swing.text.IconView; -import javax.swing.text.LabelView; import javax.swing.text.MutableAttributeSet; -import javax.swing.text.ParagraphView; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; import javax.swing.text.StyledEditorKit; @@ -532,8 +526,8 @@ public class HTMLEditorKit public View create(Element element) { View view = null; - Object attr = element.getAttributes().getAttribute( - StyleConstants.NameAttribute); + Object attr = + element.getAttributes().getAttribute(StyleConstants.NameAttribute); if (attr instanceof HTML.Tag) { HTML.Tag tag = (HTML.Tag) attr; @@ -553,8 +547,16 @@ public class HTMLEditorKit view = new BlockView(element, View.Y_AXIS); // FIXME: Uncomment when the views have been implemented - /* else if (tag.equals(HTML.Tag.CONTENT)) - view = new InlineView(element); + else if (tag.equals(HTML.Tag.CONTENT)) + view = new InlineView(element); + else if (tag == HTML.Tag.HEAD) + view = new NullView(element); + else if (tag.equals(HTML.Tag.TABLE)) + view = new HTMLTableView(element); + else if (tag.equals(HTML.Tag.TD)) + view = new ParagraphView(element); + + /* else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR) || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL)) view = new ListView(element); @@ -564,8 +566,6 @@ public class HTMLEditorKit view = new HRuleView(element); else if (tag.equals(HTML.Tag.BR)) view = new BRView(element); - else if (tag.equals(HTML.Tag.TABLE)) - view = new TableView(element); else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT) || tag.equals(HTML.Tag.TEXTAREA)) view = new FormView(element); @@ -575,21 +575,11 @@ public class HTMLEditorKit view = new FrameSetView(element); else if (tag.equals(HTML.Tag.FRAME)) view = new FrameView(element); */ - } - + } if (view == null) { - String name = element.getName(); - if (name.equals(AbstractDocument.ContentElementName)) - view = new LabelView(element); - else if (name.equals(AbstractDocument.ParagraphElementName)) - view = new ParagraphView(element); - else if (name.equals(AbstractDocument.SectionElementName)) - view = new BoxView(element, View.Y_AXIS); - else if (name.equals(StyleConstants.ComponentElementName)) - view = new ComponentView(element); - else if (name.equals(StyleConstants.IconElementName)) - view = new IconView(element); + System.err.println("missing tag->view mapping for: " + element); + view = new NullView(element); } return view; } @@ -958,7 +948,8 @@ public class HTMLEditorKit throw new IOException("Parser is null."); HTMLDocument hd = ((HTMLDocument) doc); - hd.setBase(editorPane.getPage()); + if (editorPane != null) + hd.setBase(editorPane.getPage()); ParserCallback pc = hd.getReader(pos); // FIXME: What should ignoreCharSet be set to? diff --git a/libjava/classpath/javax/xml/stream/events/StartEntity.java b/libjava/classpath/javax/swing/text/html/HTMLTableView.java index d41e0db7a72..cac44d8dc27 100644 --- a/libjava/classpath/javax/xml/stream/events/StartEntity.java +++ b/libjava/classpath/javax/swing/text/html/HTMLTableView.java @@ -1,5 +1,5 @@ -/* StartEntity.java -- - Copyright (C) 2005 Free Software Foundation, Inc. +/* HTMLTableView.java -- A table view for HTML tables + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,19 +35,48 @@ 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.stream.events; + +package javax.swing.text.html; + +import javax.swing.text.Element; +import javax.swing.text.TableView; +import javax.swing.text.View; +import javax.swing.text.ViewFactory; /** - * An start-entity event. + * A conrete implementation of TableView that renders HTML tables. + * + * @author Roman Kennke (kennke@aicas.com) */ -public interface StartEntity - extends XMLEvent +class HTMLTableView + extends TableView { /** - * Returns the entity name. + * Creates a new HTMLTableView for the specified element. + * + * @param el the element for the table view */ - String getName(); + public HTMLTableView(Element el) + { + super(el); + } + /** + * Loads the children of the Table. This completely bypasses the ViewFactory + * and creates instances of TableRow instead. + * + * @param vf ignored + */ + protected void loadChildren(ViewFactory vf) + { + Element el = getElement(); + int numChildren = el.getElementCount(); + View[] rows = new View[numChildren]; + for (int i = 0; i < numChildren; ++i) + { + rows[i] = createTableRow(el.getElement(i)); + } + replace(0, getViewCount(), rows); + } } - diff --git a/libjava/classpath/javax/swing/text/html/InlineView.java b/libjava/classpath/javax/swing/text/html/InlineView.java new file mode 100644 index 00000000000..77ec86e8263 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/InlineView.java @@ -0,0 +1,166 @@ +/* InlineView.java -- Renders HTML content + 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.Shape; + +import javax.swing.event.DocumentEvent; +import javax.swing.text.AttributeSet; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.LabelView; +import javax.swing.text.View; +import javax.swing.text.ViewFactory; + +/** + * Renders HTML content (identified by {@link HTML.Tag#CONTENT}). This is + * basically a {@link LabelView} that is adjusted to understand styles defined + * by stylesheets. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class InlineView + extends LabelView +{ + + /** + * Creates a new <code>InlineView</code> that renders the specified element. + * + * @param element the element for this view + */ + public InlineView(Element element) + { + super(element); + } + + /** + * Receives notification that something was inserted into the document in + * a location that this view is responsible for. + * + * @param e the document event + * @param a the current allocation of this view + * @param f the view factory for creating new views + * + * @since 1.5 + */ + public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) + { + // FIXME: What to do here? + super.insertUpdate(e, a, f); + } + + /** + * Receives notification that something was removed from the document in + * a location that this view is responsible for. + * + * @param e the document event + * @param a the current allocation of this view + * @param f the view factory for creating new views + * + * @since 1.5 + */ + public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) + { + // FIXME: What to do here? + super.removeUpdate(e, a, f); + } + + /** + * Receives notification that attributes have changed in the document in + * a location that this view is responsible for. This calls + * {@link #setPropertiesFromAttributes}. + * + * @param e the document event + * @param a the current allocation of this view + * @param f the view factory for creating new views + * + * @since 1.5 + */ + public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) + { + super.changedUpdate(e, a, f); + setPropertiesFromAttributes(); + } + + /** + * Returns the attributes that are used for rendering. This is implemented + * to multiplex the attributes specified in the model with a stylesheet. + * + * @return the attributes that are used for rendering + */ + public AttributeSet getAttributes() + { + // FIXME: Implement this. + return super.getAttributes(); + } + + + public int getBreakWeight(int axis, float pos, float len) + { + // FIXME: Implement this. + return super.getBreakWeight(axis, pos, len); + } + + public View breakView(int axis, int offset, float pos, float len) + { + // FIXME: Implement this. + return super.breakView(axis, offset, pos, len); + } + + protected void setPropertiesFromAttributes() + { + // FIXME: Implement this. + super.setPropertiesFromAttributes(); + } + + /** + * Returns the stylesheet used by this view. This returns the stylesheet + * of the <code>HTMLDocument</code> that is rendered by this view. + * + * @return the stylesheet used by this view + */ + protected StyleSheet getStyleSheet() + { + Document doc = getDocument(); + StyleSheet styleSheet = null; + if (doc instanceof HTMLDocument) + styleSheet = ((HTMLDocument) doc).getStyleSheet(); + return styleSheet; + } +} diff --git a/libjava/classpath/javax/swing/text/html/NullView.java b/libjava/classpath/javax/swing/text/html/NullView.java new file mode 100644 index 00000000000..4b66c5ad87e --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/NullView.java @@ -0,0 +1,102 @@ +/* NullView.java -- A dummy view that renders nothing + 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.Shape; + +import javax.swing.text.BadLocationException; +import javax.swing.text.Element; +import javax.swing.text.View; +import javax.swing.text.Position.Bias; + +/** + * A dummy view that renders nothing. This is used for invisible HTML elements + * like <head>. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class NullView + extends View +{ + + /** + * Creates a new NullView. + * + * @param elem the element + */ + public NullView(Element elem) + { + super(elem); + } + + /** + * Does nothing. + */ + public void paint(Graphics g, Shape s) + { + // Nothing to do here. + } + + /** + * Returns zero for both directions. + */ + public float getPreferredSpan(int axis) + { + return 0; + } + + /** + * Returns the allocation of this view, which should be empty anyway. + */ + public Shape modelToView(int pos, Shape a, Bias b) + throws BadLocationException + { + return a; + } + + /** + * Returns the start offset of the element. + */ + public int viewToModel(float x, float y, Shape a, Bias[] b) + { + return getElement().getStartOffset(); + } + +} diff --git a/libjava/classpath/javax/swing/text/html/ObjectView.java b/libjava/classpath/javax/swing/text/html/ObjectView.java new file mode 100644 index 00000000000..d6a77c06aad --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/ObjectView.java @@ -0,0 +1,110 @@ +/* ObjectView.java -- A view for HTML object tags + 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.Component; + +import javax.swing.text.AttributeSet; +import javax.swing.text.ComponentView; +import javax.swing.text.Element; + +/** + * A view for HTML <code><object></code> tags. + * + * This is a {@link ComponentView} that creates special components depending + * on the object specification. If the object tag has a classid attribute, then + * this view will try to load the class specified by this attribute using the + * classloader that loaded the associated document. If the class could be + * loaded, an instance is created and the type narrowed to {@link Component}. + * + * It is also possible to set bean properties on the created component using + * nested <code><param></code> tags. For example: + * <pre> + * <object classid="javax.swing.JLabel"> + * <param name="text" value="sample text"> + * </object> + * </pre> + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class ObjectView extends ComponentView +{ + + /** + * Creates a new <code>ObjectView</code>. + * + * @param el the element for which to create a view + */ + public ObjectView(Element el) + { + super(el); + } + + /** + * Creates a component based on the specification in the element of this + * view. See the class description for details. + */ + protected Component createComponent() + { + Component comp = null; + Element el = getElement(); + AttributeSet atts = el.getAttributes(); + String classId = (String) atts.getAttribute("classid"); + try + { + Class objectClass = Class.forName(classId); + Object instance = objectClass.newInstance(); + comp = (Component) instance; + } + catch (ClassNotFoundException ex) + { + // Ignored. + } + catch (IllegalAccessException ex) + { + // Ignored. + } + catch (InstantiationException ex) + { + // Ignored. + } + // FIXME: Handle param tags and set bean properties accordingly. + return comp; + } +} diff --git a/libjava/classpath/javax/swing/text/html/Option.java b/libjava/classpath/javax/swing/text/html/Option.java new file mode 100644 index 00000000000..1def51b2f59 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/Option.java @@ -0,0 +1,157 @@ +/* Option.java -- Value class for <option> list model elements + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import javax.swing.text.AttributeSet; + +/** + * Value class for the combobox model that renders <code><option></code> + * elements. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class Option +{ + + /** + * The attributes of the <option> tag. + */ + private AttributeSet attributes; + + /** + * The label. + */ + private String label; + + /** + * The selected state of this label. + */ + private boolean selected; + + /** + * Creates a new <code>Option</code> instance that uses the specified + * tag attributes. + * + * @param attr the attributes to use + */ + public Option(AttributeSet attr) + { + attributes = attr; + label = null; + selected = false; + // FIXME: Probably initialize something using the attributes. + } + + /** + * Sets the label to use for this <code><option></code> tag. + * + * @param l the label to set + */ + public void setLabel(String l) + { + label = l; + } + + /** + * Returns the label of this <code><option></code> tag. + * + * @return the label of this <code><option></code> tag + */ + public String getLabel() + { + return label; + } + + /** + * Returns the attributes used to render this <code><option></code> + * tag. + * + * @return the attributes used to render this <code><option></code> tag + */ + public AttributeSet getAttributes() + { + return attributes; + } + + /** + * Returns a string representation of this <code><option></code> tag. + * This returns the <code>label</code> property. + * + * @return a string representation of this <code><option></code> tag + */ + public String toString() + { + return label; + } + + /** + * Sets the selected state of this <code><option></code> tag. + * + * @param s the selected state to set + */ + protected void setSelection(boolean s) + { + selected = s; + } + + /** + * Returns <code>true</code> when this option is selected, <code>false</code> + * otherwise. + * + * @return <code>true</code> when this option is selected, <code>false</code> + * otherwise + */ + public boolean isSelected() + { + return selected; + } + + /** + * Returns the string associated with the <code>value</code> attribute or + * the label, if no such attribute is specified. + * + * @return the string associated with the <code>value</code> attribute or + * the label, if no such attribute is specified + */ + public String getValue() + { + // FIXME: Return some attribute here if specified. + return label; + } +} diff --git a/libjava/classpath/javax/swing/text/html/ParagraphView.java b/libjava/classpath/javax/swing/text/html/ParagraphView.java new file mode 100644 index 00000000000..2339f4e661d --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/ParagraphView.java @@ -0,0 +1,209 @@ +/* ParagraphView.java -- Renders a paragraph in HTML + 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.Shape; + +import javax.swing.SizeRequirements; +import javax.swing.text.AttributeSet; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.View; + +/** + * Renders a paragraph in HTML. This is a subclass of + * {@link javax.swing.text.ParagraphView} with some adjustments for + * understanding stylesheets. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class ParagraphView + extends javax.swing.text.ParagraphView +{ + + /** + * Creates a new ParagraphView for the specified element. + * + * @param element the element + */ + public ParagraphView(Element element) + { + super(element); + } + + /** + * Sets the parent of this view. This is implemented to call the parent + * functionality and then trigger {@link #setPropertiesFromAttributes} in + * order to load the stylesheet attributes. + * + * @param parent the parent view to set + */ + public void setParent(View parent) + { + super.setParent(parent); + if (parent != null) + setPropertiesFromAttributes(); + } + + /** + * Returns the attributes used by this view. This is implemented to multiplex + * the attributes of the model with the attributes of the stylesheet. + */ + public AttributeSet getAttributes() + { + // FIXME: Implement this multiplexing thing. + return super.getAttributes(); + } + + /** + * Loads the visual properties of the ParagraphView from the element's + * attributes and the stylesheet of the HTML document. + */ + protected void setPropertiesFromAttributes() + { + // FIXME: Implement this. + } + + /** + * Returns the stylesheet used by this view. + * + * @return the stylesheet used by this view + */ + protected StyleSheet getStyleSheet() + { + Document doc = getDocument(); + StyleSheet styleSheet = null; + if (doc instanceof HTMLDocument) + styleSheet = ((HTMLDocument) doc).getStyleSheet(); + return styleSheet; + } + + /** + * Calculates the minor axis requirements of this view. This is implemented + * to return the super class'es requirements and modifies the minimumSpan + * slightly so that it is not smaller than the length of the longest word. + * + * @param axis the axis + * @param r the SizeRequirements object to be used as return parameter; + * if <code>null</code> a new one will be created + * + * @return the requirements along the minor layout axis + */ + protected SizeRequirements calculateMinorAxisRequirements(int axis, + SizeRequirements r) + { + // FIXME: Implement the above specified behaviour. + return super.calculateMinorAxisRequirements(axis, r); + } + + /** + * Determines if this view is visible or not. If none of the children is + * visible and the only visible child is the break that ends the paragraph, + * this paragraph is not considered to be visible. + * + * @return the visibility of this paragraph + */ + public boolean isVisible() + { + // FIXME: Implement the above specified behaviour. + return super.isVisible(); + } + + /** + * Paints this view. This delegates to the superclass after the coordinates + * have been updated for tab calculations. + * + * @param g the graphics object + * @param a the current allocation of this view + */ + public void paint(Graphics g, Shape a) + { + // FIXME: Implement the above specified behaviour. + super.paint(g, a); + } + + /** + * Returns the preferred span of this view. If this view is not visible, + * we return <code>0</code>, otherwise the super class is called. + * + * @param axis the axis + * + * @return the preferred span of this view + */ + public float getPreferredSpan(int axis) + { + float span = 0; + if (isVisible()) + span = super.getPreferredSpan(axis); + return span; + } + + /** + * Returns the minimum span of this view. If this view is not visible, + * we return <code>0</code>, otherwise the super class is called. + * + * @param axis the axis + * + * @return the minimum span of this view + */ + public float getMinimumSpan(int axis) + { + float span = 0; + if (isVisible()) + span = super.getMinimumSpan(axis); + return span; + } + + /** + * Returns the maximum span of this view. If this view is not visible, + * we return <code>0</code>, otherwise the super class is called. + * + * @param axis the axis + * + * @return the maximum span of this view + */ + public float getMaximumSpan(int axis) + { + float span = 0; + if (isVisible()) + span = super.getMaximumSpan(axis); + return span; + } +} diff --git a/libjava/classpath/javax/swing/text/package.html b/libjava/classpath/javax/swing/text/package.html index 50043b6c4e8..5db555d8898 100644 --- a/libjava/classpath/javax/swing/text/package.html +++ b/libjava/classpath/javax/swing/text/package.html @@ -40,7 +40,7 @@ exception statement from your version. --> <head><title>GNU Classpath - javax.swing.text</title></head> <body> -<p></p> - +<p>Provides core text classes and interfaces representing models and views +used by the text components for display and editing of text.</p> </body> </html> diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java b/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java index ae8b99c2fe5..e28c9261bab 100644 --- a/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java +++ b/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java @@ -45,7 +45,6 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; -import java.awt.Insets; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -60,26 +59,52 @@ import javax.swing.Icon; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.SwingUtilities; -import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; import javax.swing.event.EventListenerList; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; /** - * DefaultTreeCellEditor + * Participates in the tree cell editing. + * * @author Andrew Selkirk + * @author Audrius Meskauskas */ public class DefaultTreeCellEditor implements ActionListener, TreeCellEditor, TreeSelectionListener { /** - * EditorContainer + * 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. + */ + static int CLICK_COUNT_TO_START = 3; + + /** + * This container that appears on the tree during editing session. + * It contains the editing component displays various other editor - + * specific parts like editing icon. */ public class EditorContainer extends Container { + /** + * Use v 1.5 serial version UID for interoperability. + */ + static final long serialVersionUID = 6470339600449699810L; + /** * Creates an <code>EditorContainer</code> object. */ @@ -96,17 +121,11 @@ public class DefaultTreeCellEditor { // Do nothing here. } - - /** - * Returns the preferred size for the Container. - * - * @return Dimension of EditorContainer - */ - public Dimension getPreferredSize() + + public void setBounds(Rectangle bounds) { - Dimension containerSize = super.getPreferredSize(); - containerSize.width += DefaultTreeCellEditor.this.offset; - return containerSize; + super.setBounds(bounds); + doLayout(); } /** @@ -118,63 +137,68 @@ public class DefaultTreeCellEditor */ public void paint(Graphics g) { - Rectangle tr = tree.getPathBounds(lastPath); - if (tr != null) + if (editingIcon != null) { - Insets i = ((DefaultTextField) editingComponent).getBorder() - .getBorderInsets(this); - int textIconGap = 3; - tr.x -= i.left; - - // paints icon - if (editingIcon != null) - { - editingIcon.paintIcon(this, g, tr.x - editingIcon. - getIconWidth()/2, tr.y + i.top + i.bottom); - tr.x += editingIcon.getIconWidth()/2 + textIconGap; - } - - tr.width += offset; - - // paint background - g.translate(tr.x, tr.y); - editingComponent.setSize(new Dimension(tr.width, tr.height)); - editingComponent.paint(g); - g.translate(-tr.x, -tr.y); + // From the previous version, the left margin is taken as half + // of the icon width. + editingIcon.paintIcon(this, g, TREE_ICON_GAP, 0); } super.paint(g); } /** - * Lays out this Container. If editing, the editor will be placed at offset - * in the x direction and 0 for y. + * Lays out this Container, moving the editor component to the left + * (leaving place for the icon). */ public void doLayout() { - if (DefaultTreeCellEditor.this.tree.isEditing()) - setLocation(offset, 0); - super.doLayout(); + // The offset of the editing component. + int eOffset; + + // Move the component to the left, leaving room for the editing icon: + if (editingIcon != null) + eOffset = TREE_ICON_GAP + editingIcon.getIconWidth() + ICON_TEXT_GAP; + else + eOffset = 0; + + Rectangle bounds = getBounds(); + Component c = getComponent(0); + c.setLocation(eOffset, 0); + + // Span the editing component near over all window width. + c.setSize(bounds.width - eOffset - TREE_ICON_GAP, 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 + * still not able to auto - scroll horizontally, replicating such strategy + * would prevent adding extra characters to the text being edited. + */ } } /** - * DefaultTextField + * The default text field, used in the editing sessions. */ public class DefaultTextField extends JTextField { + /** + * Use v 1.5 serial version UID for interoperability. + */ + static final long serialVersionUID = -6629304544265300143L; + /** - * border + * The border of the text field. */ protected Border border; /** * Creates a <code>DefaultTextField</code> object. * - * @param border the border to use + * @param aBorder the border to use */ - public DefaultTextField(Border border) + public DefaultTextField(Border aBorder) { - this.border = border; + border = aBorder; } /** @@ -228,6 +252,31 @@ public class DefaultTreeCellEditor return renderer.getPreferredSize(); } } + + /** + * Listens for the events from the realEditor. + */ + class RealEditorListener implements CellEditorListener + { + /** + * The method is called when the editing has been cancelled. + * @param event unused + */ + public void editingCanceled(ChangeEvent event) + { + cancelCellEditing(); + } + + /** + * The method is called after completing the editing session. + * + * @param event unused + */ + public void editingStopped(ChangeEvent event) + { + stopCellEditing(); + } + } private EventListenerList listenerList = new EventListenerList(); @@ -334,6 +383,9 @@ public class DefaultTreeCellEditor if (editor == null) editor = createTreeCellEditor(); + else + editor.addCellEditorListener(new RealEditorListener()); + realEditor = editor; lastPath = tree.getLeadSelectionPath(); @@ -342,7 +394,6 @@ public class DefaultTreeCellEditor setFont(UIManager.getFont("Tree.font")); setBorderSelectionColor(UIManager.getColor("Tree.selectionBorderColor")); editingIcon = renderer.getIcon(); - timer = new javax.swing.Timer(1200, this); } /** @@ -371,7 +422,7 @@ public class DefaultTreeCellEditor else renderer.setIcon(renderer.getClosedIcon()); editingIcon = renderer.getIcon(); - + editingComponent = getTreeCellEditorComponent(tree, val, true, expanded, isLeaf, lastRow); } @@ -470,20 +521,21 @@ public class DefaultTreeCellEditor boolean leaf, int row) { if (realEditor == null) - createTreeCellEditor(); + realEditor = createTreeCellEditor(); return realEditor.getTreeCellEditorComponent(tree, value, isSelected, expanded, leaf, row); } /** - * Returns the value currently being edited. + * Returns the value currently being edited (requests it from the + * {@link realEditor}. * * @return the value currently being edited */ public Object getCellEditorValue() { - return editingComponent; + return realEditor.getCellEditorValue(); } /** @@ -503,12 +555,6 @@ public class DefaultTreeCellEditor prepareForEditing(); return true; } - - // Cell may not be currently editable, but may need to start timer. - if (shouldStartEditingTimer(event)) - startEditingTimer(); - else if (timer.isRunning()) - timer.stop(); return false; } @@ -532,9 +578,11 @@ public class DefaultTreeCellEditor */ public boolean stopCellEditing() { - if (editingComponent != null && realEditor.stopCellEditing()) + if (editingComponent != null) { - timer.stop(); + stopEditingTimer(); + tree.stopEditing(); + editingComponent = null; return true; } return false; @@ -548,15 +596,26 @@ public class DefaultTreeCellEditor { if (editingComponent != null) { - timer.stop(); - realEditor.cancelCellEditing(); + tree.cancelEditing(); + editingComponent = null; } + stopEditingTimer(); + } + + /** + * Stop the editing timer, if it is installed and running. + */ + private void stopEditingTimer() + { + if (timer != null && timer.isRunning()) + timer.stop(); } /** * Adds a <code>CellEditorListener</code> object to this editor. - * - * @param listener the listener to add + * + * @param listener + * the listener to add */ public void addCellEditorListener(CellEditorListener listener) { @@ -595,21 +654,16 @@ public class DefaultTreeCellEditor tPath = lastPath; lastPath = e.getNewLeadSelectionPath(); lastRow = tree.getRowForPath(lastPath); - configureEditingComponent(tree, renderer, realEditor); + stopCellEditing(); } /** - * Messaged when the timer fires, this will start the editing session. + * Messaged when the timer fires. * * @param e the event that characterizes the action. */ public void actionPerformed(ActionEvent e) { - if (lastPath != null && tPath != null && tPath.equals(lastPath)) - { - tree.startEditingAtPath(lastPath); - timer.stop(); - } } /** @@ -639,13 +693,11 @@ public class DefaultTreeCellEditor } /** - * Starts the editing timer. + * Starts the editing timer (if one installed). */ protected void startEditingTimer() { - if (timer == null) - timer = new javax.swing.Timer(1200, this); - if (!timer.isRunning()) + if (timer != null) timer.start(); } @@ -713,6 +765,7 @@ public class DefaultTreeCellEditor */ protected void prepareForEditing() { + editingContainer.removeAll(); editingContainer.add(editingComponent); } @@ -734,8 +787,11 @@ public class DefaultTreeCellEditor */ protected TreeCellEditor createTreeCellEditor() { - realEditor = new DefaultCellEditor(new DefaultTreeCellEditor.DefaultTextField( + DefaultCellEditor editor = new DefaultCellEditor(new DefaultTreeCellEditor.DefaultTextField( UIManager.getBorder("Tree.selectionBorder"))); - return realEditor; + editor.addCellEditorListener(new RealEditorListener()); + editor.setClickCountToStart(CLICK_COUNT_TO_START); + realEditor = editor; + return editor; } } diff --git a/libjava/classpath/javax/swing/undo/StateEdit.java b/libjava/classpath/javax/swing/undo/StateEdit.java index 80e4e33ec29..326abea1f4e 100644 --- a/libjava/classpath/javax/swing/undo/StateEdit.java +++ b/libjava/classpath/javax/swing/undo/StateEdit.java @@ -104,9 +104,11 @@ public class StateEdit * System (RCS). This certainly should not be part of the API * specification. But in order to be API-compatible with * Sun’s reference implementation, GNU Classpath also has to - * provide this field. However, we do not try to match its value. + * provide this field and match its value. The value used here has + * been in every JDK release at least from 1.2 to 1.5. */ - protected static final String RCSID = ""; + protected static final String RCSID = "$" + + "Id: StateEdit.java,v 1.6 1997/10/01 20:05:51 sandipc Exp $"; /** diff --git a/libjava/classpath/javax/swing/undo/StateEditable.java b/libjava/classpath/javax/swing/undo/StateEditable.java index 9a7fb09545d..bec396e1e20 100644 --- a/libjava/classpath/javax/swing/undo/StateEditable.java +++ b/libjava/classpath/javax/swing/undo/StateEditable.java @@ -78,9 +78,11 @@ public interface StateEditable * System (RCS). This certainly should not be part of the API * specification. But in order to be API-compatible with * Sun’s reference implementation, GNU Classpath also has to - * provide this field. However, we do not try to match its value. + * provide this field and match its value. The value used here has + * been in every JDK release at least from 1.2 to 1.5. */ - String RCSID = ""; + String RCSID = "$" + + "Id: StateEditable.java,v 1.2 1997/09/08 19:39:08 marklin Exp $"; /** diff --git a/libjava/classpath/javax/xml/parsers/DocumentBuilderFactory.java b/libjava/classpath/javax/xml/parsers/DocumentBuilderFactory.java index 1cbb9a79f08..0dc574e656b 100644 --- a/libjava/classpath/javax/xml/parsers/DocumentBuilderFactory.java +++ b/libjava/classpath/javax/xml/parsers/DocumentBuilderFactory.java @@ -309,6 +309,7 @@ public abstract class DocumentBuilderFactory /** * Returns the schema. * @see #setSchema + * @since 1.5 */ public Schema getSchema() { @@ -318,6 +319,7 @@ public abstract class DocumentBuilderFactory /** * Sets the schema. * @see #getSchema + * @since 1.5 */ public void setSchema(Schema schema) { @@ -327,7 +329,7 @@ public abstract class DocumentBuilderFactory /** * Indicates whether parsers obtained from this factory will be XInclude * aware. - * @since 1.3 + * @since 1.5 */ public boolean isXIncludeAware() { @@ -336,11 +338,32 @@ public abstract class DocumentBuilderFactory /** * Sets whether parsers obtained from this factory will be XInclude aware. - * @since 1.3 + * @since 1.5 */ public void setXIncludeAware(boolean state) { xIncludeAware = state; } + + /** + * Sets the value of the specified feature. + * @param name the feature name (URI) + * @param value whether to enable the feature or not + * @exception ParserConfigurationException if the feature is not + * supported. + * @since 1.5 + */ + public abstract void setFeature(String name, boolean value) + throws ParserConfigurationException; + + /** + * Returns the value of the specified feature. + * @param name the feature name (URI) + * @exception ParserConfigurationException if the feature is not + * supported. + * @since 1.5 + */ + public abstract boolean getFeature(String name) + throws ParserConfigurationException; } diff --git a/libjava/classpath/javax/xml/stream/EventFilter.java b/libjava/classpath/javax/xml/stream/EventFilter.java index 288c7411dea..6d0cb65521e 100644 --- a/libjava/classpath/javax/xml/stream/EventFilter.java +++ b/libjava/classpath/javax/xml/stream/EventFilter.java @@ -1,5 +1,5 @@ /* EventFilter.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,7 +43,6 @@ import javax.xml.stream.events.XMLEvent; * Simple filter interface for XML events. */ public interface EventFilter - extends XMLFilter { /** diff --git a/libjava/classpath/javax/xml/stream/Location.java b/libjava/classpath/javax/xml/stream/Location.java index d043ba254e9..8f9f807e0f2 100644 --- a/libjava/classpath/javax/xml/stream/Location.java +++ b/libjava/classpath/javax/xml/stream/Location.java @@ -63,9 +63,14 @@ public interface Location int getCharacterOffset(); /** + * Returns the public identifier for this location, if any. + */ + String getPublicId(); + + /** * Returns the system identifier for the underlying source. */ - String getLocationURI(); + String getSystemId(); } diff --git a/libjava/classpath/javax/xml/stream/StreamFilter.java b/libjava/classpath/javax/xml/stream/StreamFilter.java index 77fbfc7f533..376bd940a89 100644 --- a/libjava/classpath/javax/xml/stream/StreamFilter.java +++ b/libjava/classpath/javax/xml/stream/StreamFilter.java @@ -1,5 +1,5 @@ /* StreamFilter.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,7 +41,6 @@ package javax.xml.stream; * Simple filter interface for XMLStreamReaders. */ public interface StreamFilter - extends XMLFilter { /** diff --git a/libjava/classpath/javax/xml/stream/XMLEventFactory.java b/libjava/classpath/javax/xml/stream/XMLEventFactory.java index 456414d6101..ee47af2a90d 100644 --- a/libjava/classpath/javax/xml/stream/XMLEventFactory.java +++ b/libjava/classpath/javax/xml/stream/XMLEventFactory.java @@ -1,5 +1,5 @@ /* XMLEventFactory.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -320,10 +320,8 @@ public abstract class XMLEventFactory /** * Create an entity reference event. */ - //public abstract EntityReference createEntityReference(String name, - // EntityDeclaration declaration); public abstract EntityReference createEntityReference(String name, - String replacementText); + EntityDeclaration declaration); /** * Create a comment event. diff --git a/libjava/classpath/javax/xml/stream/XMLEventReader.java b/libjava/classpath/javax/xml/stream/XMLEventReader.java index 5d4c1700065..35ad5696eda 100644 --- a/libjava/classpath/javax/xml/stream/XMLEventReader.java +++ b/libjava/classpath/javax/xml/stream/XMLEventReader.java @@ -1,5 +1,5 @@ /* XMLEventReader.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,10 +44,21 @@ import javax.xml.stream.events.XMLEvent; * An XML parser. */ public interface XMLEventReader - extends XMLIterator + extends Iterator { /** + * Returns the next XML event. + */ + XMLEvent nextEvent() + throws XMLStreamException; + + /** + * Indicates whether there are more XML events to be read. + */ + boolean hasNext(); + + /** * Looks at the next XML event without advancing the cursor in the stream. * Returns <code>null</code> if there are no more events to read. */ @@ -80,5 +91,12 @@ public interface XMLEventReader Object getProperty(String name) throws IllegalArgumentException; + /** + * Free any resources associated with this parser. + * This method will not close the underlying input source. + */ + void close() + throws XMLStreamException; + } diff --git a/libjava/classpath/javax/xml/stream/XMLEventWriter.java b/libjava/classpath/javax/xml/stream/XMLEventWriter.java index 60b18f977ca..fe85f236ebb 100644 --- a/libjava/classpath/javax/xml/stream/XMLEventWriter.java +++ b/libjava/classpath/javax/xml/stream/XMLEventWriter.java @@ -1,5 +1,5 @@ /* XMLEventWriter.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. diff --git a/libjava/classpath/javax/xml/stream/XMLInputFactory.java b/libjava/classpath/javax/xml/stream/XMLInputFactory.java index 4c904a62fde..4dfd1203a70 100644 --- a/libjava/classpath/javax/xml/stream/XMLInputFactory.java +++ b/libjava/classpath/javax/xml/stream/XMLInputFactory.java @@ -1,5 +1,5 @@ /* XMLInputFactory.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -324,17 +324,17 @@ public abstract class XMLInputFactory /** * Creates a new stream reader. - * + */ public abstract XMLStreamReader createXMLStreamReader(String systemId, InputStream stream) - throws XMLStreamException;*/ + throws XMLStreamException; /** * Creates a new stream reader. - * + */ public abstract XMLStreamReader createXMLStreamReader(String systemId, Reader reader) - throws XMLStreamException;*/ + throws XMLStreamException; /** * Creates a new event reader. @@ -344,10 +344,10 @@ public abstract class XMLInputFactory /** * Creates a new event reader. - * + */ public abstract XMLEventReader createXMLEventReader(String systemId, Reader reader) - throws XMLStreamException;*/ + throws XMLStreamException; /** * Creates a new event reader. @@ -376,10 +376,10 @@ public abstract class XMLInputFactory /** * Creates a new event reader. - * + */ public abstract XMLEventReader createXMLEventReader(String systemId, InputStream stream) - throws XMLStreamException;*/ + throws XMLStreamException; /** * Create a new filtered reader. @@ -444,15 +444,5 @@ public abstract class XMLInputFactory */ public abstract XMLEventAllocator getEventAllocator(); - /** - * Sets whether text will be coalesced. - */ - public abstract void setCoalescing(boolean coalescing); - - /** - * Indicates whether text will be coalesced. - */ - public abstract boolean isCoalescing(); - } diff --git a/libjava/classpath/javax/xml/stream/XMLOutputFactory.java b/libjava/classpath/javax/xml/stream/XMLOutputFactory.java index cf31f02a591..e4c9dd40d46 100644 --- a/libjava/classpath/javax/xml/stream/XMLOutputFactory.java +++ b/libjava/classpath/javax/xml/stream/XMLOutputFactory.java @@ -1,5 +1,5 @@ /* XMLOutputFactory.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -46,7 +46,7 @@ import java.io.IOException; import java.io.OutputStream; import java.io.Writer; import java.util.Properties; -//import javax.xml.transform.Result; +import javax.xml.transform.Result; /** * Factory for obtaining XML stream and event writers for various kinds of @@ -77,8 +77,8 @@ public abstract class XMLOutputFactory * If true, the writer will create a namespace declaration for any * attribute that doesn't have a namespace declaration in scope. */ - public static final java.lang.String IS_PREFIX_DEFAULTING = - "javax.xml.stream.isPrefixDefaulting"; + public static final java.lang.String IS_REPAIRING_NAMESPACES = + "javax.xml.stream.isRepairingNamespaces"; protected XMLOutputFactory() { @@ -219,16 +219,16 @@ public abstract class XMLOutputFactory * @exception UnsupportedOperationException if this method is not * supported */ - //public abstract XMLStreamWriter createXMLStreamWriter(Result result) - // throws XMLStreamException; + public abstract XMLStreamWriter createXMLStreamWriter(Result result) + throws XMLStreamException; /** * Creates a new event writer. * @exception UnsupportedOperationException if this method is not * supported */ - //public abstract XMLEventWriter createXMLEventWriter(Result result) - // throws XMLStreamException; + public abstract XMLEventWriter createXMLEventWriter(Result result) + throws XMLStreamException; /** * Creates a new event writer. @@ -264,23 +264,9 @@ public abstract class XMLOutputFactory throws IllegalArgumentException; /** - * Indicates whether writers created by this factory will perform prefix - * defaulting. - * @see #IS_PREFIX_DEFAULTING - */ - public abstract boolean isPrefixDefaulting(); - - /** * Indicates whether the specified property is supported. */ public abstract boolean isPropertySupported(String name); - /** - * Sets whether writers created by this factory will perform prefix - * defaulting. - * @see #IS_PREFIX_DEFAULTING - */ - public abstract void setPrefixDefaulting(boolean value); - } diff --git a/libjava/classpath/javax/xml/stream/XMLReporter.java b/libjava/classpath/javax/xml/stream/XMLReporter.java index bdf0b8accc4..d545656813c 100644 --- a/libjava/classpath/javax/xml/stream/XMLReporter.java +++ b/libjava/classpath/javax/xml/stream/XMLReporter.java @@ -1,5 +1,5 @@ /* XMLReporter.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. diff --git a/libjava/classpath/javax/xml/stream/XMLResolver.java b/libjava/classpath/javax/xml/stream/XMLResolver.java index 148afc6f1a5..2dabaeea407 100644 --- a/libjava/classpath/javax/xml/stream/XMLResolver.java +++ b/libjava/classpath/javax/xml/stream/XMLResolver.java @@ -1,5 +1,5 @@ /* XMLResolver.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,8 +37,6 @@ exception statement from your version. */ package javax.xml.stream; -import java.io.InputStream; - /** * Interface used to resolve XML external entities during parsing. */ @@ -59,28 +57,10 @@ public interface XMLResolver * @param systemID the system ID of the external entity * @param baseURI the absolute base URI of the referring entity * @param namespace the namespace of the external entity - * + */ Object resolveEntity(String publicID, String systemID, String baseURI, String namespace) - throws XMLStreamException;*/ - - /** - * Retrieves a resource from the specified URI. - */ - XMLEventReader resolveAsXMLEventReader(String uri) throws XMLStreamException; - /** - * Retrieves a resource from the specified URI. - */ - XMLStreamReader resolveAsXMLStreamReader(String uri) - throws XMLStreamException; - - /** - * Retrieves a resource from the specified URI. - */ - InputStream resolve(String uri) - throws XMLStreamException; - } diff --git a/libjava/classpath/javax/xml/stream/XMLStreamConstants.java b/libjava/classpath/javax/xml/stream/XMLStreamConstants.java index 1f0d2ef33cd..e41627dd601 100644 --- a/libjava/classpath/javax/xml/stream/XMLStreamConstants.java +++ b/libjava/classpath/javax/xml/stream/XMLStreamConstants.java @@ -1,5 +1,5 @@ /* XMLStreamConstants.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -109,24 +109,14 @@ public interface XMLStreamConstants static final int NAMESPACE = 13; /** - * A start-entity event. - */ - static final int START_ENTITY = 14; - - /** - * An end-entity event. - */ - static final int END_ENTITY = 15; - - /** * A notation declaration event. */ - static final int NOTATION_DECLARATION = 16; + static final int NOTATION_DECLARATION = 14; /** * An entity declaration event. */ - static final int ENTITY_DECLARATION = 17; + static final int ENTITY_DECLARATION = 15; } diff --git a/libjava/classpath/javax/xml/stream/XMLStreamReader.java b/libjava/classpath/javax/xml/stream/XMLStreamReader.java index e598fabb6b6..f8648b1adce 100644 --- a/libjava/classpath/javax/xml/stream/XMLStreamReader.java +++ b/libjava/classpath/javax/xml/stream/XMLStreamReader.java @@ -1,5 +1,5 @@ /* XMLStreamReader.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -136,7 +136,7 @@ public interface XMLStreamReader /** * Returns the QName of the attribute at the given index. */ - QName getAttributeQName(int index); + QName getAttributeName(int index); /** * Returns the namespace URI of the attribute at the given index. @@ -146,7 +146,7 @@ public interface XMLStreamReader /** * Returns the local-name of the attribute at the given index. */ - String getAttributeName(int index); + String getAttributeLocalName(int index); /** * Returns the namespace prefix of the attribute at the given index. diff --git a/libjava/classpath/javax/xml/stream/events/EntityDeclaration.java b/libjava/classpath/javax/xml/stream/events/EntityDeclaration.java index a319f098cc4..a0120ddb0de 100644 --- a/libjava/classpath/javax/xml/stream/events/EntityDeclaration.java +++ b/libjava/classpath/javax/xml/stream/events/EntityDeclaration.java @@ -1,5 +1,5 @@ /* EntityDeclaration.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -67,12 +67,12 @@ public interface EntityDeclaration /** * Returns the replacement text for the entity. */ - //String getReplacementText(); + String getReplacementText(); /** * Returns the base URI for the entity. */ - //String getBaseURI(); + String getBaseURI(); } diff --git a/libjava/classpath/javax/xml/stream/events/EntityReference.java b/libjava/classpath/javax/xml/stream/events/EntityReference.java index 72447096b68..460433c1690 100644 --- a/libjava/classpath/javax/xml/stream/events/EntityReference.java +++ b/libjava/classpath/javax/xml/stream/events/EntityReference.java @@ -1,5 +1,5 @@ /* EntityReference.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,34 +45,14 @@ public interface EntityReference { /** - * Returns the base URI for the entity. - */ - String getBaseUri(); - - /** - * Returns the public identifier for the entity. - */ - String getPublicId(); - - /** - * Returns the system identifierfor the entity. - */ - String getSystemId(); - - /** * Returns the declaration of this reference. */ - //EntityDeclaration getDeclaration(); + EntityDeclaration getDeclaration(); /** * Returns the entity name. */ String getName(); - /** - * Returns the replacement text for the entity. - */ - String getReplacementText(); - } diff --git a/libjava/classpath/javax/xml/stream/events/XMLEvent.java b/libjava/classpath/javax/xml/stream/events/XMLEvent.java index 54e9516f62b..7c427da87d2 100644 --- a/libjava/classpath/javax/xml/stream/events/XMLEvent.java +++ b/libjava/classpath/javax/xml/stream/events/XMLEvent.java @@ -1,5 +1,5 @@ /* XMLEvent.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -106,16 +106,6 @@ public interface XMLEvent boolean isEndDocument(); /** - * Indicates whether this event is a start-entity event. - */ - boolean isStartEntity(); - - /** - * Indicates whether this event is an end-entity event. - */ - boolean isEndEntity(); - - /** * Returns this event as a start-element event. */ StartElement asStartElement(); diff --git a/libjava/classpath/javax/xml/stream/util/EventReaderDelegate.java b/libjava/classpath/javax/xml/stream/util/EventReaderDelegate.java index f6d1585b790..be943e465e1 100644 --- a/libjava/classpath/javax/xml/stream/util/EventReaderDelegate.java +++ b/libjava/classpath/javax/xml/stream/util/EventReaderDelegate.java @@ -1,5 +1,5 @@ /* EventReaderDelegate.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -82,16 +82,22 @@ public class EventReaderDelegate return parent; } - public XMLEvent next() + public XMLEvent nextEvent() throws XMLStreamException { if (parent != null) + return parent.nextEvent(); + throw new NoSuchElementException(); + } + + public Object next() + { + if (parent != null) return parent.next(); throw new NoSuchElementException(); } public boolean hasNext() - throws XMLStreamException { if (parent != null) return parent.hasNext(); @@ -130,5 +136,17 @@ public class EventReaderDelegate throw new IllegalArgumentException(name); } + public void close() + throws XMLStreamException + { + if (parent != null) + parent.close(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } diff --git a/libjava/classpath/javax/xml/stream/util/ReaderDelegate.java b/libjava/classpath/javax/xml/stream/util/ReaderDelegate.java index ef701756316..d502866fbcc 100644 --- a/libjava/classpath/javax/xml/stream/util/ReaderDelegate.java +++ b/libjava/classpath/javax/xml/stream/util/ReaderDelegate.java @@ -1,5 +1,5 @@ /* ReaderDelegate.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -186,10 +186,10 @@ public class ReaderDelegate return 0; } - public QName getAttributeQName(int index) + public QName getAttributeName(int index) { if (parent != null) - return parent.getAttributeQName(index); + return parent.getAttributeName(index); return null; } @@ -207,10 +207,10 @@ public class ReaderDelegate return null; } - public String getAttributeName(int index) + public String getAttributeLocalName(int index) { if (parent != null) - return parent.getAttributeName(index); + return parent.getAttributeLocalName(index); return null; } diff --git a/libjava/classpath/javax/xml/validation/SchemaFactory.java b/libjava/classpath/javax/xml/validation/SchemaFactory.java index 35bf205642b..f33c1c6297e 100644 --- a/libjava/classpath/javax/xml/validation/SchemaFactory.java +++ b/libjava/classpath/javax/xml/validation/SchemaFactory.java @@ -39,6 +39,7 @@ package javax.xml.validation; import java.io.File; import java.net.URL; +import javax.xml.XMLConstants; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import org.w3c.dom.ls.LSResourceResolver; @@ -50,7 +51,7 @@ import org.xml.sax.SAXNotSupportedException; /** * Factory for obtaining schemata. * - * @author (a href='mailto:dog@gnu.org'>Chris Burdess</a) + * @author Chris Burdess (dog@gnu.org) * @since 1.3 */ public abstract class SchemaFactory @@ -70,7 +71,10 @@ public abstract class SchemaFactory */ public static final SchemaFactory newInstance(String schemaLanguage) { - // TODO + if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(schemaLanguage)) + return new gnu.xml.validation.xmlschema.XMLSchemaSchemaFactory(); + if (XMLConstants.RELAXNG_NS_URI.equals(schemaLanguage)) + return new gnu.xml.validation.relaxng.RELAXNGSchemaFactory(); throw new IllegalArgumentException(schemaLanguage); } |