summaryrefslogtreecommitdiff
path: root/javax
diff options
context:
space:
mode:
Diffstat (limited to 'javax')
-rw-r--r--javax/management/BadAttributeValueExpException.java91
-rw-r--r--javax/management/BadStringOperationException.java92
-rw-r--r--javax/management/InstanceAlreadyExistsException.java76
-rw-r--r--javax/management/InstanceNotFoundException.java76
-rw-r--r--javax/management/InvalidApplicationException.java92
-rw-r--r--javax/management/MBeanConstructorInfo.java10
-rw-r--r--javax/management/MBeanFeatureInfo.java2
-rw-r--r--javax/management/MBeanInfo.java23
-rw-r--r--javax/management/MBeanOperationInfo.java8
-rw-r--r--javax/management/MBeanRegistrationException.java84
-rw-r--r--javax/management/MalformedObjectNameException.java76
-rw-r--r--javax/management/RuntimeErrorException.java115
-rw-r--r--javax/management/RuntimeMBeanException.java114
-rw-r--r--javax/management/ServiceNotFoundException.java75
-rw-r--r--javax/management/StandardMBean.java32
-rw-r--r--javax/management/openmbean/InvalidOpenTypeException.java76
-rw-r--r--javax/management/openmbean/KeyAlreadyExistsException.java77
-rw-r--r--javax/management/openmbean/OpenMBeanAttributeInfo.java120
-rw-r--r--javax/management/openmbean/OpenMBeanAttributeInfoSupport.java546
-rw-r--r--javax/management/openmbean/OpenMBeanConstructorInfo.java112
-rw-r--r--javax/management/openmbean/OpenMBeanConstructorInfoSupport.java174
-rw-r--r--javax/management/openmbean/OpenMBeanInfo.java154
-rw-r--r--javax/management/openmbean/OpenMBeanInfoSupport.java191
-rw-r--r--javax/management/openmbean/OpenMBeanOperationInfo.java154
-rw-r--r--javax/management/openmbean/OpenMBeanOperationInfoSupport.java240
-rw-r--r--javax/management/openmbean/OpenMBeanParameterInfo.java190
-rw-r--r--javax/management/openmbean/OpenMBeanParameterInfoSupport.java511
-rw-r--r--javax/management/openmbean/SimpleType.java2
-rw-r--r--javax/management/openmbean/TabularData.java45
-rw-r--r--javax/management/openmbean/TabularDataSupport.java652
-rw-r--r--javax/naming/Name.java14
-rw-r--r--javax/naming/spi/NamingManager.java32
-rw-r--r--javax/swing/JMenu.java97
-rw-r--r--javax/swing/JPopupMenu.java9
-rw-r--r--javax/swing/JTree.java9
-rw-r--r--javax/swing/Popup.java2
-rw-r--r--javax/swing/SwingUtilities.java112
-rw-r--r--javax/swing/plaf/basic/BasicButtonListener.java6
-rw-r--r--javax/swing/plaf/basic/BasicButtonUI.java75
-rw-r--r--javax/swing/plaf/basic/BasicInternalFrameUI.java57
-rw-r--r--javax/swing/plaf/basic/BasicMenuItemUI.java4
-rw-r--r--javax/swing/plaf/basic/BasicMenuUI.java207
-rw-r--r--javax/swing/plaf/metal/MetalBorders.java16
-rw-r--r--javax/swing/plaf/metal/MetalMenuBarUI.java9
-rw-r--r--javax/swing/text/AbstractDocument.java651
-rw-r--r--javax/swing/text/BoxView.java22
-rw-r--r--javax/swing/text/DefaultHighlighter.java389
-rw-r--r--javax/swing/text/DefaultStyledDocument.java1893
-rw-r--r--javax/swing/text/GapContent.java189
-rw-r--r--javax/swing/text/GlyphView.java29
-rw-r--r--javax/swing/text/JTextComponent.java278
-rw-r--r--javax/swing/text/LabelView.java44
-rw-r--r--javax/swing/text/PlainView.java138
-rw-r--r--javax/swing/text/Utilities.java8
-rw-r--r--javax/swing/text/WrappedPlainView.java24
55 files changed, 6969 insertions, 1555 deletions
diff --git a/javax/management/BadAttributeValueExpException.java b/javax/management/BadAttributeValueExpException.java
new file mode 100644
index 000000000..fbdf1deca
--- /dev/null
+++ b/javax/management/BadAttributeValueExpException.java
@@ -0,0 +1,91 @@
+/* BadAttributeValueExpException.java -- Thrown by invalid query attributes.
+ 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.management;
+
+/**
+ * Thrown when the value of an a attribute passed to a query proves to
+ * be invalid. This exception is only used internally by the Java
+ * management API and is not exposed to user code.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class BadAttributeValueExpException
+ extends Exception
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = -3105272988410493376L;
+
+ /**
+ * The attribute value that caused the exception.
+ */
+ private Object val;
+
+ /**
+ * Constructs a new <code>BadAttributeValueExpException</code>
+ * using the specified object to represent the invalid value.
+ *
+ * @param val the inappropriate value.
+ */
+ public BadAttributeValueExpException(Object val)
+ {
+ super();
+ this.val = val;
+ }
+
+ /**
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.BadAttributeValueExpException</code>)
+ * and the invalid value.
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ public String toString()
+ {
+ return getClass().getName()
+ + "[val=" + val
+ + "]";
+ }
+
+}
+
diff --git a/javax/management/BadStringOperationException.java b/javax/management/BadStringOperationException.java
new file mode 100644
index 000000000..8e5949ef7
--- /dev/null
+++ b/javax/management/BadStringOperationException.java
@@ -0,0 +1,92 @@
+/* BadStringOperationException.java -- Thrown by invalid query attributes.
+ 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.management;
+
+/**
+ * Thrown when a string-based operation passed to a query proves to
+ * be invalid. This exception is only used internally by the Java
+ * management API and is not exposed to user code.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class BadStringOperationException
+ extends Exception
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = 7802201238441662100L;
+
+ /**
+ * The operation that caused the exception.
+ */
+ private String op;
+
+ /**
+ * Constructs a new <code>BadStringOperationException</code>
+ * using the specified object to represent the invalid string
+ * operation.
+ *
+ * @param op the inappropriate string operation.
+ */
+ public BadStringOperationException(String op)
+ {
+ super();
+ this.op = op;
+ }
+
+ /**
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.BadStringOperationException</code>)
+ * and the invalid string operation.
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ public String toString()
+ {
+ return getClass().getName()
+ + "[op=" + op
+ + "]";
+ }
+
+}
+
diff --git a/javax/management/InstanceAlreadyExistsException.java b/javax/management/InstanceAlreadyExistsException.java
new file mode 100644
index 000000000..c783208cb
--- /dev/null
+++ b/javax/management/InstanceAlreadyExistsException.java
@@ -0,0 +1,76 @@
+/* InstanceAlreadyExistsException.java -- Thrown by invalid values.
+ 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.management;
+
+/**
+ * Thrown when an attempt to register a bean is made, and
+ * the bean is already registered.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class InstanceAlreadyExistsException
+ extends OperationsException
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = 8893743928912733931L;
+
+ /**
+ * Constructs a new <code>InstanceAlreadyExistsException</code>.
+ */
+ public InstanceAlreadyExistsException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new <code>InstanceAlreadyExistsException</code>
+ * with the specified message.
+ *
+ * @param message the error message to give to the user.
+ */
+ public InstanceAlreadyExistsException(String message)
+ {
+ super(message);
+ }
+
+}
+
diff --git a/javax/management/InstanceNotFoundException.java b/javax/management/InstanceNotFoundException.java
new file mode 100644
index 000000000..4d209fc47
--- /dev/null
+++ b/javax/management/InstanceNotFoundException.java
@@ -0,0 +1,76 @@
+/* InstanceNotFoundException.java -- Thrown by invalid values.
+ 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.management;
+
+/**
+ * Thrown when an attempt to locate a bean is made, and
+ * the bean does not exist in the repository.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class InstanceNotFoundException
+ extends OperationsException
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = -882579438394773049L;
+
+ /**
+ * Constructs a new <code>InstanceNotFoundException</code>.
+ */
+ public InstanceNotFoundException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new <code>InstanceNotFoundException</code>
+ * with the specified message.
+ *
+ * @param message the error message to give to the user.
+ */
+ public InstanceNotFoundException(String message)
+ {
+ super(message);
+ }
+
+}
+
diff --git a/javax/management/InvalidApplicationException.java b/javax/management/InvalidApplicationException.java
new file mode 100644
index 000000000..0bcf2d6cb
--- /dev/null
+++ b/javax/management/InvalidApplicationException.java
@@ -0,0 +1,92 @@
+/* InvalidApplicationException.java -- Thrown by invalid query attributes.
+ 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.management;
+
+/**
+ * Thrown when a query or attribute is applied to a management bean
+ * which is of the wrong class. This exception is only used
+ * internally by the Java management API and is not exposed to user
+ * code.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class InvalidApplicationException
+ extends Exception
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = -3048022274675537269L;
+
+ /**
+ * The attribute value that caused the exception.
+ */
+ private Object val;
+
+ /**
+ * Constructs a new <code>InvalidApplicationException</code>
+ * using the specified object to represent the invalid value.
+ *
+ * @param val the inappropriate expression.
+ */
+ public InvalidApplicationException(Object val)
+ {
+ super();
+ this.val = val;
+ }
+
+ /**
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.InvalidApplicationException</code>)
+ * and the invalid expression.
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ public String toString()
+ {
+ return getClass().getName()
+ + "[val=" + val
+ + "]";
+ }
+
+}
+
diff --git a/javax/management/MBeanConstructorInfo.java b/javax/management/MBeanConstructorInfo.java
index 832a3296d..9ddd432a8 100644
--- a/javax/management/MBeanConstructorInfo.java
+++ b/javax/management/MBeanConstructorInfo.java
@@ -89,10 +89,11 @@ public class MBeanConstructorInfo
* Constructs a @link{MBeanConstructorInfo} with the specified
* name, description and parameter information. A <code>null</code>
* value for the parameter information is the same as passing in
- * an empty array.
+ * an empty array. A copy of the parameter array is taken, so
+ * later changes have no effect.
*
* @param name the name of the constructor.
- * @param desc a description of the attribute.
+ * @param desc a description of the constructor.
* @param sig the signature of the constructor, as a series
* of {@link MBeanParameterInfo} objects, one for
* each parameter.
@@ -104,7 +105,10 @@ public class MBeanConstructorInfo
if (sig == null)
signature = new MBeanParameterInfo[0];
else
- signature = sig;
+ {
+ signature = new MBeanParameterInfo[sig.length];
+ System.arraycopy(sig, 0, signature, 0, sig.length);
+ }
}
/**
diff --git a/javax/management/MBeanFeatureInfo.java b/javax/management/MBeanFeatureInfo.java
index 4f0243e18..74a030387 100644
--- a/javax/management/MBeanFeatureInfo.java
+++ b/javax/management/MBeanFeatureInfo.java
@@ -79,7 +79,7 @@ public class MBeanFeatureInfo
/**
* The <code>toString()</code> result of this instance.
*/
- protected transient String string;
+ transient String string;
/**
* Constructs a new {@link MBeanFeatureInfo} with the specified
diff --git a/javax/management/MBeanInfo.java b/javax/management/MBeanInfo.java
index e6f03f065..d30de0499 100644
--- a/javax/management/MBeanInfo.java
+++ b/javax/management/MBeanInfo.java
@@ -140,7 +140,8 @@ public class MBeanInfo
* can be loaded by the MBean server or class loader; it merely
* has to be a syntactically correct class name. Any of the
* arrays may be <code>null</code>; this will be treated as if
- * an empty array was supplied.
+ * an empty array was supplied. A copy of the arrays is
+ * taken, so later changes have no effect.
*
* @param name the name of the class this instance describes.
* @param desc a description of the bean.
@@ -162,19 +163,31 @@ public class MBeanInfo
if (attribs == null)
attributes = new MBeanAttributeInfo[0];
else
- attributes = attribs;
+ {
+ attributes = new MBeanAttributeInfo[attribs.length];
+ System.arraycopy(attribs, 0, attributes, 0, attribs.length);
+ }
if (cons == null)
constructors = new MBeanConstructorInfo[0];
else
- constructors = cons;
+ {
+ constructors = new MBeanConstructorInfo[cons.length];
+ System.arraycopy(cons, 0, constructors, 0, cons.length);
+ }
if (ops == null)
operations = new MBeanOperationInfo[0];
else
- operations = ops;
+ {
+ operations = new MBeanOperationInfo[ops.length];
+ System.arraycopy(ops, 0, operations, 0, ops.length);
+ }
if (notifs == null)
notifications = new MBeanNotificationInfo[0];
else
- notifications = notifs;
+ {
+ notifications = new MBeanNotificationInfo[notifs.length];
+ System.arraycopy(notifs, 0, notifications, 0, notifs.length);
+ }
}
/**
diff --git a/javax/management/MBeanOperationInfo.java b/javax/management/MBeanOperationInfo.java
index a2db8d1b0..2a78d19d9 100644
--- a/javax/management/MBeanOperationInfo.java
+++ b/javax/management/MBeanOperationInfo.java
@@ -140,7 +140,8 @@ public class MBeanOperationInfo
* Constructs a @link{MBeanOperationInfo} with the specified name,
* description, parameter information, return type and impact. A
* <code>null</code> value for the parameter information is the same
- * as passing in an empty array.
+ * as passing in an empty array. A copy of the parameter array is
+ * taken, so later changes have no effect.
*
* @param name the name of the constructor.
* @param desc a description of the attribute.
@@ -158,7 +159,10 @@ public class MBeanOperationInfo
if (sig == null)
signature = new MBeanParameterInfo[0];
else
- signature = sig;
+ {
+ signature = new MBeanParameterInfo[sig.length];
+ System.arraycopy(sig, 0, signature, 0, sig.length);
+ }
this.type = type;
this.impact = impact;
}
diff --git a/javax/management/MBeanRegistrationException.java b/javax/management/MBeanRegistrationException.java
new file mode 100644
index 000000000..9f62b9aa0
--- /dev/null
+++ b/javax/management/MBeanRegistrationException.java
@@ -0,0 +1,84 @@
+/* MBeanRegistrationException.java -- A bean registration exception.
+ 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.management;
+
+/**
+ * Represents an arbitrary exception thrown during registration of a
+ * management bean. When registering a bean causes an exception to be
+ * thrown, the resulting exception is wrapped inside an {@link
+ * MBeanRegistrationException}. Calling {@link getTargetException()}
+ * will return the wrapped exception.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class MBeanRegistrationException
+ extends MBeanException
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = 4482382455277067805L;
+
+ /**
+ * Constructs a new <code>MBeanRegistrationException</code> wrapping
+ * the specified exception.
+ *
+ * @param e the exception to be wrapped.
+ */
+ public MBeanRegistrationException(Exception e)
+ {
+ super(e);
+ }
+
+ /**
+ * Constructs a new <code>MBeanRegistrationException</code> wrapping
+ * the specified exception and using the supplied message.
+ *
+ * @param e the exception to be wrapped.
+ * @param message the error message to give to the user.
+ */
+ public MBeanRegistrationException(Exception e, String message)
+ {
+ super(e, message);
+ }
+
+
+}
+
diff --git a/javax/management/MalformedObjectNameException.java b/javax/management/MalformedObjectNameException.java
new file mode 100644
index 000000000..e2f577490
--- /dev/null
+++ b/javax/management/MalformedObjectNameException.java
@@ -0,0 +1,76 @@
+/* MalformedObjectNameException.java -- Thrown by invalid values.
+ 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.management;
+
+/**
+ * Thrown when a string used as an {@link ObjectName}
+ * is invalid.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class MalformedObjectNameException
+ extends OperationsException
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = -572689714442915824L;
+
+ /**
+ * Constructs a new <code>MalformedObjectNameException</code>.
+ */
+ public MalformedObjectNameException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new <code>MalformedObjectNameException</code>
+ * with the specified message.
+ *
+ * @param message the error message to give to the user.
+ */
+ public MalformedObjectNameException(String message)
+ {
+ super(message);
+ }
+
+}
+
diff --git a/javax/management/RuntimeErrorException.java b/javax/management/RuntimeErrorException.java
new file mode 100644
index 000000000..811dc40f2
--- /dev/null
+++ b/javax/management/RuntimeErrorException.java
@@ -0,0 +1,115 @@
+/* RuntimeErrorException.java -- A user-defined management error.
+ 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.management;
+
+/**
+ * Represents an arbitrary error thrown by a management
+ * bean. When a management bean executes code that causes
+ * an error to be thrown, the resulting error is
+ * wrapped inside an {@link RuntimeErrorException}. Calling
+ * {@link getTargetError()} will return the wrapped
+ * exception.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class RuntimeErrorException
+ extends JMRuntimeException
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = 704338937753949796L;
+
+ /**
+ * The target error.
+ *
+ * @serial the target error.
+ */
+ private Error error;
+
+ /**
+ * Constructs a new <code>RuntimeErrorException</code> wrapping
+ * the specified error.
+ *
+ * @param e the error to be wrapped.
+ */
+ public RuntimeErrorException(Error e)
+ {
+ super();
+ error = e;
+ }
+
+ /**
+ * Constructs a new <code>RuntimeErrorException</code> wrapping
+ * the specified error and using the supplied message.
+ *
+ * @param e the error to be wrapped.
+ * @param message the error message to give to the user.
+ */
+ public RuntimeErrorException(Error e, String message)
+ {
+ super(message);
+ error = e;
+ }
+
+ /**
+ * Returns the true cause of this error, the wrapped
+ * error.
+ *
+ * @return the wrapped error.
+ */
+ public Throwable getCause()
+ {
+ return error;
+ }
+
+ /**
+ * Returns the true cause of this error, the wrapped
+ * error.
+ *
+ * @return the wrapped error.
+ */
+ public Error getTargetError()
+ {
+ return error;
+ }
+
+}
+
diff --git a/javax/management/RuntimeMBeanException.java b/javax/management/RuntimeMBeanException.java
new file mode 100644
index 000000000..95225a80a
--- /dev/null
+++ b/javax/management/RuntimeMBeanException.java
@@ -0,0 +1,114 @@
+/* RuntimeMBeanException.java -- A user-defined management exception.
+ 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.management;
+
+/**
+ * Represents an arbitrary runtime exception thrown by a management
+ * bean. When a management bean executes code that causes a runtime
+ * exception to be thrown, the resulting exception is wrapped inside a
+ * {@link RuntimeMBeanException}. Calling {@link
+ * getTargetException()} will return the wrapped exception.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class RuntimeMBeanException
+ extends JMRuntimeException
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = 5274912751982730171L;
+
+ /**
+ * The target exception.
+ *
+ * @serial the target exception.
+ */
+ private RuntimeException runtimeException;
+
+ /**
+ * Constructs a new <code>RuntimeMBeanException</code> wrapping
+ * the specified exception.
+ *
+ * @param e the exception to be wrapped.
+ */
+ public RuntimeMBeanException(RuntimeException e)
+ {
+ super();
+ runtimeException = e;
+ }
+
+ /**
+ * Constructs a new <code>RuntimeMBeanException</code> wrapping
+ * the specified exception and using the supplied message.
+ *
+ * @param e the exception to be wrapped.
+ * @param message the error message to give to the user.
+ */
+ public RuntimeMBeanException(RuntimeException e, String message)
+ {
+ super(message);
+ runtimeException = e;
+ }
+
+ /**
+ * Returns the true cause of this exception, the wrapped runtime
+ * exception.
+ *
+ * @return the wrapped exception.
+ */
+ public Throwable getCause()
+ {
+ return runtimeException;
+ }
+
+ /**
+ * Returns the true cause of this exception, the wrapped runtime
+ * exception.
+ *
+ * @return the wrapped exception.
+ */
+ public RuntimeException getTargetException()
+ {
+ return runtimeException;
+ }
+
+}
+
diff --git a/javax/management/ServiceNotFoundException.java b/javax/management/ServiceNotFoundException.java
new file mode 100644
index 000000000..602e1490d
--- /dev/null
+++ b/javax/management/ServiceNotFoundException.java
@@ -0,0 +1,75 @@
+/* ServiceNotFoundException.java -- Thrown by invalid values.
+ 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.management;
+
+/**
+ * Thrown when a requested service is unsupported.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class ServiceNotFoundException
+ extends OperationsException
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = -3990675661956646827L;
+
+ /**
+ * Constructs a new <code>ServiceNotFoundException</code>.
+ */
+ public ServiceNotFoundException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new <code>ServiceNotFoundException</code>
+ * with the specified message.
+ *
+ * @param message the error message to give to the user.
+ */
+ public ServiceNotFoundException(String message)
+ {
+ super(message);
+ }
+
+}
+
diff --git a/javax/management/StandardMBean.java b/javax/management/StandardMBean.java
index 736192ee2..16b6f0b66 100644
--- a/javax/management/StandardMBean.java
+++ b/javax/management/StandardMBean.java
@@ -205,17 +205,13 @@ public class StandardMBean
Method getter;
try
{
- getter = iface.getMethod("get" +
- name.substring(0, 1).toUpperCase() +
- name.substring(1), null);
+ getter = iface.getMethod("get" + name, null);
}
catch (NoSuchMethodException e)
{
try
{
- getter = iface.getMethod("is" +
- name.substring(0, 1).toUpperCase() +
- name.substring(1), null);
+ getter = iface.getMethod("is" + name, null);
}
catch (NoSuchMethodException ex)
{
@@ -564,11 +560,9 @@ public class StandardMBean
Method[] amethods;
String attrib;
if (name.startsWith("is"))
- attrib = name.substring(2,3).toLowerCase()
- + name.substring(3);
+ attrib = name.substring(2);
else
- attrib = name.substring(3,4).toLowerCase()
- + name.substring(4);
+ attrib = name.substring(3);
if (attributes.containsKey(attrib))
amethods = (Method[]) attributes.get(attrib);
else
@@ -583,8 +577,7 @@ public class StandardMBean
methods[a].getParameterTypes().length == 1)
{
Method[] amethods;
- String attrib = name.substring(3,4).toLowerCase()
- + name.substring(4);
+ String attrib = name.substring(3);
if (attributes.containsKey(attrib))
amethods = (Method[]) attributes.get(attrib);
else
@@ -595,7 +588,8 @@ public class StandardMBean
amethods[1] = methods[a];
}
else
- operations.add(new MBeanOperationInfo("", methods[a]));
+ operations.add(new MBeanOperationInfo(methods[a].getName(),
+ methods[a]));
}
List attribs = new ArrayList(attributes.size());
Iterator it = attributes.entrySet().iterator();
@@ -605,7 +599,8 @@ public class StandardMBean
Method[] amethods = (Method[]) entry.getValue();
try
{
- attribs.add(new MBeanAttributeInfo((String) entry.getKey(), "",
+ attribs.add(new MBeanAttributeInfo((String) entry.getKey(),
+ (String) entry.getKey(),
amethods[0], amethods[1]));
}
catch (IntrospectionException e)
@@ -632,7 +627,8 @@ public class StandardMBean
MBeanConstructorInfo[] cinfo = new MBeanConstructorInfo[cons.length];
for (int a = 0; a < cinfo.length; ++a)
{
- MBeanConstructorInfo oldInfo = new MBeanConstructorInfo("", cons[a]);
+ MBeanConstructorInfo oldInfo = new MBeanConstructorInfo(cons[a].getName(),
+ cons[a]);
String desc = getDescription(oldInfo);
MBeanParameterInfo[] params = oldInfo.getSignature();
MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length];
@@ -665,8 +661,8 @@ public class StandardMBean
oinfo[a] = new MBeanOperationInfo(oldInfo.getName(), desc, pinfo,
oldInfo.getReturnType(), impact);
}
- info = new MBeanInfo(impl.getClass().getName(), "", ainfo, cinfo,
- oinfo, null);
+ info = new MBeanInfo(impl.getClass().getName(), impl.getClass().getName(),
+ ainfo, cinfo, oinfo, null);
String cname = getClassName(info);
String desc = getDescription(info);
info = new MBeanInfo(cname, desc, ainfo, cinfo, oinfo, null);
@@ -679,7 +675,7 @@ public class StandardMBean
*
* @return the management interface.
*/
- public Class getMBeanInterface()
+ public final Class getMBeanInterface()
{
return iface;
}
diff --git a/javax/management/openmbean/InvalidOpenTypeException.java b/javax/management/openmbean/InvalidOpenTypeException.java
new file mode 100644
index 000000000..9c9ff8cfa
--- /dev/null
+++ b/javax/management/openmbean/InvalidOpenTypeException.java
@@ -0,0 +1,76 @@
+/* InvalidOpenTypeException.java -- Thrown by an invalid open type.
+ 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.management.openmbean;
+
+/**
+ * Thrown when a open data value has an erroneous open
+ * type.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class InvalidOpenTypeException
+ extends IllegalArgumentException
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = -2837312755412327534L;
+
+ /**
+ * Constructs a new <code>InvalidOpenTypeException</code>.
+ */
+ public InvalidOpenTypeException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new <code>InvalidOpenTypeException</code>
+ * with the specified message.
+ *
+ * @param message the error message to give to the user.
+ */
+ public InvalidOpenTypeException(String message)
+ {
+ super(message);
+ }
+
+}
+
diff --git a/javax/management/openmbean/KeyAlreadyExistsException.java b/javax/management/openmbean/KeyAlreadyExistsException.java
new file mode 100644
index 000000000..cc6bba636
--- /dev/null
+++ b/javax/management/openmbean/KeyAlreadyExistsException.java
@@ -0,0 +1,77 @@
+/* KeyAlreadyExistsException.java -- Thrown when a key clashes with another.
+ 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.management.openmbean;
+
+/**
+ * Thrown when a key (a field name or row index) is passed to a method
+ * of the {@link CompositeData} or {@link TabularData} classes and it
+ * is found to already be in use.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class KeyAlreadyExistsException
+ extends IllegalArgumentException
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = 1845183636745282866L;
+
+ /**
+ * Constructs a new <code>KeyAlreadyExistsException</code>.
+ */
+ public KeyAlreadyExistsException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new <code>KeyAlreadyExistsException</code>
+ * with the specified message.
+ *
+ * @param message the error message to give to the user.
+ */
+ public KeyAlreadyExistsException(String message)
+ {
+ super(message);
+ }
+
+}
+
diff --git a/javax/management/openmbean/OpenMBeanAttributeInfo.java b/javax/management/openmbean/OpenMBeanAttributeInfo.java
new file mode 100644
index 000000000..1b276fd19
--- /dev/null
+++ b/javax/management/openmbean/OpenMBeanAttributeInfo.java
@@ -0,0 +1,120 @@
+/* OpenMBeanAttributeInfo.java -- Open typed info about an attribute.
+ 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.management.openmbean;
+
+/**
+ * Describes an attribute associated with an open management bean.
+ * This interface includes those methods specified by {@link
+ * javax.management.MBeanAttributeInfo}, so implementations should
+ * extend this class.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public interface OpenMBeanAttributeInfo
+ extends OpenMBeanParameterInfo
+{
+
+ /**
+ * Compares this attribute with the supplied object. This returns
+ * true iff the object is an instance of {@link OpenMBeanAttributeInfo}
+ * with an equal name and open type, the same default, minimum,
+ * maximum and legal values and the same access properties
+ * ({@link #isIs()}, {@link #isReadable()}, {@link #isWritable()}).
+ *
+ * @param obj the object to compare.
+ * @return true if the object is a {@link OpenMBeanParameterInfo}
+ * instance,
+ * <code>name.equals(object.getName())</code>,
+ * <code>openType.equals(object.getOpenType())</code>,
+ * <code>defaultValue.equals(object.getDefaultValue())</code>,
+ * <code>minValue.equals(object.getMinValue())</code>,
+ * <code>maxValue.equals(object.getMaxValue())</code>,
+ * <code>legalValues.equals(object.getLegalValues())</code>,
+ * <code>is == object.isIs()</code>,
+ * <code>isRead == object.isReadable()</code>,
+ * and <code>isWrite == object.isWritable()</code>.
+ */
+ boolean equals(Object obj);
+
+ /**
+ * Returns the hashcode of the attribute information as the sum of
+ * the hashcodes of the name, open type, default value, maximum
+ * value, minimum value, the set of legal values and the access
+ * properties.
+ *
+ * @return the hashcode of the attribute information.
+ */
+ int hashCode();
+
+ /**
+ * Returns true if the accessor method of this attribute
+ * is of the form <code>isXXX</code>.
+ *
+ * @return true if the accessor takes the form <code>isXXX</code>.
+ */
+ boolean isIs();
+
+ /**
+ * Returns true if value of this attribute can be read.
+ *
+ * @return true if the value of the attribute can be read.
+ */
+ boolean isReadable();
+
+ /**
+ * Returns true if the value of this attribute can be changed.
+ *
+ * @return true if the value of the attribute can be changed.
+ */
+ boolean isWritable();
+
+ /**
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.OpenMBeanAttributeInfo</code>)
+ * along with the name, open type, default, minimum, maximum
+ * and legal values of the parameter and the access permissions
+ * ({@link #isIs()}, {@link #isReadable()}, {@link #isWritable()}).
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ String toString();
+
+}
diff --git a/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java b/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java
new file mode 100644
index 000000000..83e043640
--- /dev/null
+++ b/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java
@@ -0,0 +1,546 @@
+/* OpenMBeanAttributeInfoSupport.java -- Open typed info about an attribute.
+ 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.management.openmbean;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.management.MBeanAttributeInfo;
+
+/**
+ * Describes an attribute of an open management bean.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class OpenMBeanAttributeInfoSupport
+ extends MBeanAttributeInfo
+ implements OpenMBeanAttributeInfo
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = -4867215622149721849L;
+
+ /**
+ * The open type of the attribute.
+ */
+ private OpenType openType;
+
+ /**
+ * The default value of the attribute (may be <code>null</code>).
+ */
+ private Object defaultValue;
+
+ /**
+ * The possible legal values of the attribute (may be <code>null</code>).
+ */
+ private Set legalValues;
+
+ /**
+ * The minimum value of the attribute (may be <code>null</code>).
+ */
+ private Comparable minValue;
+
+ /**
+ * The maximum value of the attribute (may be <code>null</code>).
+ */
+ private Comparable maxValue;
+
+ /**
+ * The hash code of this instance.
+ */
+ private transient Integer hashCode;
+
+ /**
+ * The <code>toString()</code> result of this instance.
+ */
+ private transient String string;
+
+ /**
+ * Constructs a new {@link OpenMBeanAttributeInfo} using the
+ * specified name, description, open type and access properties.
+ * The name, description and open type may not be <code>null</code>
+ * and the name and description may not be equal to the empty
+ * string.
+ *
+ * @param name the name of the attribute.
+ * @param desc a description of the attribute.
+ * @param type the open type of the attribute.
+ * @param isReadable true if the attribute's value can be read.
+ * @param isWritable true if the attribute's value can be changed.
+ * @param isIs true if the attribute uses an accessor of the form isXXX.
+ * @throws IllegalArgumentException if the name, description or
+ * open type are <code>null</code>
+ * or the name or description are
+ * the empty string.
+ */
+ public OpenMBeanAttributeInfoSupport(String name, String desc, OpenType type,
+ boolean isReadable, boolean isWritable,
+ boolean isIs)
+ {
+ super(name, type == null ? null : type.getClassName(), desc, isReadable,
+ isWritable, isIs);
+ if (name == null)
+ throw new IllegalArgumentException("The name may not be null.");
+ if (desc == null)
+ throw new IllegalArgumentException("The description may not be null.");
+ if (type == null)
+ throw new IllegalArgumentException("The type may not be null.");
+ if (name.length() == 0)
+ throw new IllegalArgumentException("The name may not be the empty string.");
+ if (desc.length() == 0)
+ throw new IllegalArgumentException("The description may not be the " +
+ "empty string.");
+ }
+
+ /**
+ * Constructs a new {@link OpenMBeanAttributeInfo} using the
+ * specified name, description, open type and default value. The
+ * name, description and open type cannot be <code>null</code> and
+ * the name and description may not be equal to the empty string.
+ * The default value may be <code>null</code>. If non-null, it must
+ * be a valid value of the given open type. Default values are not
+ * applicable to the open types, {@link ArrayType} and {@link
+ * TabularType}.
+ *
+ * @param name the name of the attribute.
+ * @param desc a description of the attribute.
+ * @param type the open type of the attribute.
+ * @param isReadable true if the attribute's value can be read.
+ * @param isWritable true if the attribute's value can be changed.
+ * @param isIs true if the attribute uses an accessor of the form isXXX.
+ * @param defaultValue the default value of the attribute.
+ * @throws IllegalArgumentException if the name, description or
+ * open type are <code>null</code>
+ * or the name or description are
+ * the empty string.
+ * @throws OpenDataException if <code>defaultValue<code> is non-null
+ * and is either not a value of the given
+ * open type or the open type is an instance
+ * of {@link ArrayType} or {@link TabularType}.
+ */
+ public OpenMBeanAttributeInfoSupport(String name, String desc, OpenType type,
+ boolean isReadable, boolean isWritable,
+ boolean isIs, Object defaultValue)
+ throws OpenDataException
+ {
+ this(name, desc, type, isReadable, isWritable, isIs, defaultValue, null);
+ }
+
+ /**
+ * <p>
+ * Constructs a new {@link OpenMBeanAttributeInfo} using the
+ * specified name, description, open type, access properties,
+ * default, maximum and minimum values. The name, description
+ * and open type cannot be <code>null</code> and the name and
+ * description may not be equal to the empty string. The
+ * default, maximum and minimum values may be <code>null</code>.
+ * The following conditions apply when the attributes mentioned
+ * are non-null:
+ * </p>
+ * <ul>
+ * <li>The values must be valid values for the given open type.</li>
+ * <li>Default values are not applicable to the open types, {@link
+ * ArrayType} and {@link TabularType}.</li>
+ * <li>The minimum value must be smaller than or equal to the maximum value
+ * (literally, <code>minValue.compareTo(maxValue) <= 0</code>.</li>
+ * <li>The minimum value must be smaller than or equal to the default value
+ * (literally, <code>minValue.compareTo(defaultValue) <= 0</code>.</li>
+ * <li>The default value must be smaller than or equal to the maximum value
+ * (literally, <code>defaultValue.compareTo(maxValue) <= 0</code>.</li>
+ * </ul>
+ *
+ * @param name the name of the attribute.
+ * @param desc a description of the attribute.
+ * @param type the open type of the attribute.
+ * @param isReadable true if the attribute's value can be read.
+ * @param isWritable true if the attribute's value can be changed.
+ * @param isIs true if the attribute uses an accessor of the form isXXX.
+ * @param defaultValue the default value of the attribute, or <code>null</code>.
+ * @param minimumValue the minimum value of the attribute, or <code>null</code>.
+ * @param maximumValue the maximum value of the attribute, or <code>null</code>.
+ * @throws IllegalArgumentException if the name, description or
+ * open type are <code>null</code>
+ * or the name or description are
+ * the empty string.
+ * @throws OpenDataException if any condition in the list above is broken.
+ */
+ public OpenMBeanAttributeInfoSupport(String name, String desc, OpenType type,
+ boolean isReadable, boolean isWritable,
+ boolean isIs, Object defaultValue,
+ Comparable minimumValue,
+ Comparable maximumValue)
+ throws OpenDataException
+ {
+ this(name, desc, type, isReadable, isWritable, isIs);
+ if (defaultValue != null && !(type.isValue(defaultValue)))
+ throw new OpenDataException("The default value is not a member of the " +
+ "open type given.");
+ if (minimumValue != null && !(type.isValue(minimumValue)))
+ throw new OpenDataException("The minimum value is not a member of the " +
+ "open type given.");
+ if (maximumValue != null && !(type.isValue(maximumValue)))
+ throw new OpenDataException("The maximum value is not a member of the " +
+ "open type given.");
+ if (defaultValue != null && (type instanceof ArrayType ||
+ type instanceof TabularType))
+ throw new OpenDataException("Default values are not applicable for " +
+ "array or tabular types.");
+ if (minValue != null && maxValue != null
+ && minValue.compareTo(maxValue) > 0)
+ throw new OpenDataException("The minimum value is greater than the " +
+ "maximum.");
+ if (minValue != null && defaultValue != null
+ && minValue.compareTo(defaultValue) > 0)
+ throw new OpenDataException("The minimum value is greater than the " +
+ "default.");
+ if (defaultValue != null && maxValue != null
+ && maxValue.compareTo(defaultValue) < 0)
+ throw new OpenDataException("The default value is greater than the " +
+ "maximum.");
+
+ openType = type;
+ this.defaultValue = defaultValue;
+ minValue = minimumValue;
+ maxValue = maximumValue;
+ }
+
+ /**
+ * <p>
+ * Constructs a new {@link OpenMBeanAttributeInfo} using the
+ * specified name, description, open type, access properties, default
+ * value and set of legal values. The name, description and open type
+ * cannot be <code>null</code> and the name and description may not be
+ * equal to the empty string. The default, maximum and minimum values
+ * may be <code>null</code>. The following conditions apply when the
+ * attributes mentioned are non-null:
+ * </p>
+ * <ul>
+ * <li>The default value and each of the legal values must be a valid
+ * value for the given open type.</li>
+ * <li>Default and legal values are not applicable to the open types, {@link
+ * ArrayType} and {@link TabularType}.</li>
+ * <li>The default value is not in the set of legal values.</li>
+ * </ul>
+ * <p>
+ * The legal values are copied from the array into a unmodifiable set,
+ * so future modifications to the array have no effect.
+ * </p>
+ *
+ * @param name the name of the attribute.
+ * @param desc a description of the attribute.
+ * @param type the open type of the attribute.
+ * @param isReadable true if the attribute's value can be read.
+ * @param isWritable true if the attribute's value can be changed.
+ * @param isIs true if the attribute uses an accessor of the form isXXX.
+ * @param defaultValue the default value of the attribute, or <code>null</code>.
+ * @param legalValues the legal values of the attribute. May be
+ * <code>null</code> or an empty array.
+ * @throws IllegalArgumentException if the name, description or
+ * open type are <code>null</code>
+ * or the name or description are
+ * the empty string.
+ * @throws OpenDataException if any condition in the list above is broken.
+ */
+ public OpenMBeanAttributeInfoSupport(String name, String desc, OpenType type,
+ boolean isReadable, boolean isWritable,
+ boolean isIs, Object defaultValue,
+ Object[] legalValues)
+ throws OpenDataException
+ {
+ this(name, desc, type, isReadable, isWritable, isIs);
+ if (defaultValue != null && !(type.isValue(defaultValue)))
+ throw new OpenDataException("The default value is not a member of the " +
+ "open type given.");
+ if (defaultValue != null && (type instanceof ArrayType ||
+ type instanceof TabularType))
+ throw new OpenDataException("Default values are not applicable for " +
+ "array or tabular types.");
+ if (legalValues != null && (type instanceof ArrayType ||
+ type instanceof TabularType))
+ throw new OpenDataException("Legal values are not applicable for " +
+ "array or tabular types.");
+ if (legalValues != null && legalValues.length > 0)
+ {
+ Set lv = new HashSet(legalValues.length);
+ for (int a = 0; a < legalValues.length; ++a)
+ {
+ if (legalValues[a] != null &&
+ !(type.isValue(legalValues[a])))
+ throw new OpenDataException("The legal value, "
+ + legalValues[a] +
+ "is not a member of the " +
+ "open type given.");
+ lv.add(legalValues[a]);
+ }
+ if (defaultValue != null && !(lv.contains(defaultValue)))
+ throw new OpenDataException("The default value is not in the set " +
+ "of legal values.");
+ this.legalValues = Collections.unmodifiableSet(lv);
+ }
+ openType = type;
+ this.defaultValue = defaultValue;
+ }
+
+ /**
+ * Compares this attribute with the supplied object. This returns
+ * true iff the object is an instance of {@link OpenMBeanAttributeInfo}
+ * with an equal name and open type and the same default, minimum,
+ * maximum and legal values and the same access properties.
+ *
+ * @param obj the object to compare.
+ * @return true if the object is a {@link OpenMBeanAttributeInfo}
+ * instance,
+ * <code>name.equals(object.getName())</code>,
+ * <code>openType.equals(object.getOpenType())</code>,
+ * <code>isRead == object.isReadable()</code>,
+ * <code>isWrite == object.isWritable()</code>,
+ * <code>isIs == object.isIs()</code>,
+ * <code>defaultValue.equals(object.getDefaultValue())</code>,
+ * <code>minValue.equals(object.getMinValue())</code>,
+ * <code>maxValue.equals(object.getMaxValue())</code>,
+ * and <code>legalValues.equals(object.getLegalValues())</code>.
+ */
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof OpenMBeanAttributeInfo))
+ return false;
+ OpenMBeanAttributeInfo o = (OpenMBeanAttributeInfo) obj;
+ return getName().equals(o.getName()) &&
+ openType.equals(o.getOpenType()) &&
+ isReadable() == o.isReadable() &&
+ isWritable() == o.isWritable() &&
+ isIs() == o.isIs() &&
+ (defaultValue == null ? o.getDefaultValue() == null :
+ defaultValue.equals(o.getDefaultValue())) &&
+ (minValue == null ? o.getMinValue() == null :
+ minValue.equals(o.getMinValue())) &&
+ (maxValue == null ? o.getMaxValue() == null :
+ maxValue.equals(o.getMaxValue())) &&
+ (legalValues == null ? o.getLegalValues() == null :
+ legalValues.equals(o.getLegalValues()));
+ }
+
+ /**
+ * Returns the default value of this attribute, or <code>null</code>
+ * if there is no default value.
+ *
+ * @return the default value of the attribute, or <code>null</code>
+ * if there is no default.
+ */
+ public Object getDefaultValue()
+ {
+ return defaultValue;
+ }
+
+ /**
+ * Returns a {@link java.util.Set} enumerating the legal values
+ * of this attribute, or <code>null</code> if no such limited
+ * set exists for this attribute.
+ *
+ * @return a set of legal values, or <code>null</code> if no such
+ * set exists.
+ */
+ public Set getLegalValues()
+ {
+ return legalValues;
+ }
+
+ /**
+ * Returns the maximum value of this attribute, or <code>null</code>
+ * if there is no maximum.
+ *
+ * @return the maximum value, or <code>null</code> if none exists.
+ */
+ public Comparable getMaxValue()
+ {
+ return maxValue;
+ }
+
+ /**
+ * Returns the minimum value of this attribute, or <code>null</code>
+ * if there is no minimum.
+ *
+ * @return the minimum value, or <code>null</code> if none exists.
+ */
+ public Comparable getMinValue()
+ {
+ return minValue;
+ }
+
+ /**
+ * Returns the open type instance which represents the type of this
+ * attribute.
+ *
+ * @return the open type of this attribute.
+ */
+ public OpenType getOpenType()
+ {
+ return openType;
+ }
+
+ /**
+ * Returns true if this attribute has a default value
+ * (i.e. the value is non-null).
+ *
+ * @return true if this attribute has a default.
+ */
+ public boolean hasDefaultValue()
+ {
+ return defaultValue != null;
+ }
+
+ /**
+ * <p>
+ * Returns the hashcode of the attribute information as the sum of
+ * the hashcodes of the name, open type, default value, maximum
+ * value, minimum value and the set of legal values.
+ * </p>
+ * <p>
+ * As instances of this class are immutable, the hash code
+ * is computed just once for each instance and reused
+ * throughout its life.
+ * </p>
+ *
+ * @return the hashcode of the attribute information.
+ */
+ public int hashCode()
+ {
+ if (hashCode == null)
+ hashCode = Integer.valueOf(getName().hashCode() +
+ openType.hashCode() +
+ Boolean.valueOf(isReadable()).hashCode() +
+ (2 *
+ Boolean.valueOf(isWritable()).hashCode()) +
+ (4 * Boolean.valueOf(isIs()).hashCode()) +
+ (defaultValue == null ? 0 :
+ defaultValue.hashCode()) +
+ (minValue == null ? 0 :
+ minValue.hashCode()) +
+ (maxValue == null ? 0 :
+ maxValue.hashCode()) +
+ (legalValues == null ? 0 :
+ legalValues.hashCode()));
+ return hashCode.intValue();
+ }
+
+ /**
+ * Returns true if there is a set of legal values for this
+ * attribute (i.e. the value is non-null).
+ *
+ * @return true if a set of legal values exists for this
+ * attribute.
+ */
+ public boolean hasLegalValues()
+ {
+ return legalValues != null;
+ }
+
+ /**
+ * Returns true if there is a maximum value for this attribute
+ * (i.e. the value is non-null).
+ *
+ * @return true if a maximum value exists for this attribute.
+ */
+ public boolean hasMaxValue()
+ {
+ return maxValue != null;
+ }
+
+ /**
+ * Returns true if there is a minimum value for this attribute.
+ * (i.e. the value is non-null).
+ *
+ * @return true if a minimum value exists for this attribute.
+ */
+ public boolean hasMinValue()
+ {
+ return minValue != null;
+ }
+
+ /**
+ * Returns true if the specified object is a valid value for
+ * this attribute.
+ *
+ * @param obj the object to test.
+ * @return true if <code>obj</code> is a valid value for this
+ * attribute.
+ */
+ public boolean isValue(Object obj)
+ {
+ return openType.isValue(obj);
+ }
+
+ /**
+ * <p>
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.OpenMBeanAttributeInfo</code>)
+ * along with the name, open type, access properties, default,
+ * minimum, maximum and legal values of the attribute.
+ * </p>
+ * <p>
+ * As instances of this class are immutable, the return value
+ * is computed just once for each instance and reused
+ * throughout its life.
+ * </p>
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ public String toString()
+ {
+ if (string == null)
+ string = getClass().getName()
+ + "[name=" + getName()
+ + ",openType=" + openType
+ + ",isReadable=" + isReadable()
+ + ",isWritable=" + isWritable()
+ + ",isIs=" + isIs()
+ + ",defaultValue=" + defaultValue
+ + ",minValue=" + minValue
+ + ",maxValue=" + maxValue
+ + ",legalValues=" + legalValues
+ + "]";
+ return string;
+ }
+
+}
diff --git a/javax/management/openmbean/OpenMBeanConstructorInfo.java b/javax/management/openmbean/OpenMBeanConstructorInfo.java
new file mode 100644
index 000000000..34cef131f
--- /dev/null
+++ b/javax/management/openmbean/OpenMBeanConstructorInfo.java
@@ -0,0 +1,112 @@
+/* OpenMBeanConstructorInfo.java -- Open typed info about a constructor.
+ 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.management.openmbean;
+
+import javax.management.MBeanParameterInfo;
+
+/**
+ * Describes a constructor for an open management bean.
+ * This interface includes those methods specified by {@link
+ * javax.management.MBeanConstructorInfo}, so implementations should
+ * extend this class. The {@link #getSignature()} method should
+ * return an array containing instances of {@link OpenMBeanParameterInfo}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public interface OpenMBeanConstructorInfo
+{
+
+ /**
+ * Compares this attribute with the supplied object. This returns
+ * true iff the object is an instance of {@link OpenMBeanConstructorInfo}
+ * with an equal name and signature.
+ *
+ * @param obj the object to compare.
+ * @return true if the object is a {@link OpenMBeanParameterInfo}
+ * instance,
+ * <code>name.equals(object.getName())</code>,
+ * and <code>signature.equals(object.getSignature())</code>.
+ */
+ boolean equals(Object obj);
+
+ /**
+ * Returns a description of this constructor.
+ *
+ * @return a human-readable description.
+ */
+ String getDescription();
+
+ /**
+ * Returns the name of this constructor.
+ *
+ * @return the name of the constructor.
+ */
+ String getName();
+
+ /**
+ * Returns the constructor's signature, in the form of
+ * information on each parameter. Each parameter is
+ * described by an instance of {@link OpenMBeanParameterInfo}.
+ *
+ * @return an array of {@link OpenMBeanParameterInfo} objects,
+ * describing the constructor parameters.
+ */
+ MBeanParameterInfo[] getSignature();
+
+ /**
+ * Returns the hashcode of the constructor information as the sum of
+ * the hashcodes of the name and signature (calculated by
+ * <code>java.util.Arrays.asList(signature).hashCode()</code>).
+ *
+ * @return the hashcode of the constructor information.
+ */
+ int hashCode();
+
+ /**
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.OpenMBeanConstructorInfo</code>)
+ * along with the name and signature.
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ String toString();
+
+}
diff --git a/javax/management/openmbean/OpenMBeanConstructorInfoSupport.java b/javax/management/openmbean/OpenMBeanConstructorInfoSupport.java
new file mode 100644
index 000000000..9dac01a59
--- /dev/null
+++ b/javax/management/openmbean/OpenMBeanConstructorInfoSupport.java
@@ -0,0 +1,174 @@
+/* OpenMBeanConstructorInfoSupport.java -- Open typed info about an constructor.
+ 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.management.openmbean;
+
+import java.util.Arrays;
+
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanParameterInfo;
+
+/**
+ * Describes a constructor for an open management bean.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class OpenMBeanConstructorInfoSupport
+ extends MBeanConstructorInfo
+ implements OpenMBeanConstructorInfo
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = -4400441579007477003L;
+
+ /**
+ * The hash code of this instance.
+ */
+ private transient Integer hashCode;
+
+ /**
+ * The <code>toString()</code> result of this instance.
+ */
+ private transient String string;
+
+ /**
+ * Constructs a @link{OpenMBeanConstructorInfo} with the specified
+ * name, description and parameter information. A <code>null</code>
+ * value for the parameter information is the same as passing in
+ * an empty array. Neither the name nor the description may be
+ * null or equal to the empty string. A copy of the parameter array
+ * is taken, so later changes have no effect.
+ *
+ * @param name the name of the constructor.
+ * @param desc a description of the constructor.
+ * @param sig the signature of the constructor, as a series
+ * of {@link MBeanParameterInfo} objects, one for
+ * each parameter.
+ * @throws IllegalArgumentException if the name or description is
+ * either <code>null</code>
+ * or the empty string.
+ * @throws ArrayStoreException if the members of the signature array
+ * are not assignable to
+ * {@link javax.management.MBeanParameterInfo}
+ */
+ public OpenMBeanConstructorInfoSupport(String name, String desc,
+ OpenMBeanParameterInfo[] sig)
+ {
+ super(name, desc, (MBeanParameterInfo[]) sig);
+ if (name == null)
+ throw new IllegalArgumentException("The name may not be null.");
+ if (desc == null)
+ throw new IllegalArgumentException("The description may not be null.");
+ if (name.length() == 0)
+ throw new IllegalArgumentException("The name may not be the empty string.");
+ if (desc.length() == 0)
+ throw new IllegalArgumentException("The description may not be the " +
+ "empty string.");
+ }
+
+ /**
+ * Compares this attribute with the supplied object. This returns
+ * true iff the object is an instance of {@link OpenMBeanConstructorInfo}
+ * with an equal name and signature.
+ *
+ * @param obj the object to compare.
+ * @return true if the object is a {@link OpenMBeanParameterInfo}
+ * instance,
+ * <code>name.equals(object.getName())</code>,
+ * and <code>signature.equals(object.getSignature())</code>.
+ */
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof OpenMBeanConstructorInfo))
+ return false;
+ OpenMBeanConstructorInfo o = (OpenMBeanConstructorInfo) obj;
+ return getName().equals(o.getName()) &&
+ getSignature().equals(o.getSignature());
+ }
+
+ /**
+ * <p>
+ * Returns the hashcode of the constructor information as the sum of
+ * the hashcodes of the name and signature (calculated by
+ * <code>java.util.Arrays.asList(signature).hashCode()</code>).
+ * </p>
+ * <p>
+ * As instances of this class are immutable, the return value
+ * is computed just once for each instance and reused
+ * throughout its life.
+ * </p>
+ *
+ * @return the hashcode of the constructor information.
+ */
+ public int hashCode()
+ {
+ if (hashCode == null)
+ hashCode = Integer.valueOf(getName().hashCode() +
+ Arrays.asList(getSignature()).hashCode());
+ return hashCode.intValue();
+ }
+
+ /**
+ * <p>
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.OpenMBeanConstructorInfo</code>)
+ * along with the name and signature.
+ * </p>
+ * <p>
+ * As instances of this class are immutable, the return value
+ * is computed just once for each instance and reused
+ * throughout its life.
+ * </p>
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ public String toString()
+ {
+ if (string == null)
+ string = getClass().getName()
+ + "[name=" + getName()
+ + ",signature=" + Arrays.toString(getSignature())
+ + "]";
+ return string;
+ }
+
+}
diff --git a/javax/management/openmbean/OpenMBeanInfo.java b/javax/management/openmbean/OpenMBeanInfo.java
new file mode 100644
index 000000000..5aa4df451
--- /dev/null
+++ b/javax/management/openmbean/OpenMBeanInfo.java
@@ -0,0 +1,154 @@
+/* OpenMBeanInfo.java -- Open typed info about a management bean.
+ 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.management.openmbean;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+
+/**
+ * Describes an open management bean. Open management beans are
+ * management beans where {@link
+ * javax.management.DynamicMBean#getMBeanInfo()} returns an
+ * implementation of this interface. This interface includes those
+ * methods specified by {@link javax.management.MBeanInfo},
+ * so implementations should extend this class. Each method
+ * which returns an array of one of the <code>MBeanXXXInfo</code>
+ * classes should return an array containing instances
+ * of the equivalent open version (<code>OpenMBeanXXXInfo</code>).
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public interface OpenMBeanInfo
+{
+
+ /**
+ * Compares this attribute with the supplied object. This returns
+ * true iff the object is an instance of {@link OpenMBeanInfo}
+ * with the same class name and equal instances of the info classes.
+ *
+ * @param obj the object to compare.
+ * @return true if the object is a {@link OpenMBeanInfo}
+ * instance,
+ * <code>className.equals(object.getClassName())</code>
+ * and each info class has an equal in the other object.
+ */
+ boolean equals(Object obj);
+
+ /**
+ * Returns descriptions of each of the attributes provided by this
+ * management bean. The elements should be implementations of the
+ * {@link OpenMBeanAttributeInfo} class.
+ *
+ * @return an array of {@link OpenMBeanAttributeInfo} objects,
+ * representing the attributes emitted by this
+ * management bean.
+ */
+ MBeanAttributeInfo[] getAttributes();
+
+ /**
+ * Returns the class name of the management bean.
+ *
+ * @return the bean's class name.
+ */
+ String getClassName();
+
+ /**
+ * Returns descriptions of each of the constructors provided by this
+ * management bean. The elements should be implementations of the
+ * {@link OpenMBeanConstructorInfo} class.
+ *
+ * @return an array of {@link OpenMBeanConstructorInfo} objects,
+ * representing the constructors emitted by this
+ * management bean.
+ */
+ MBeanConstructorInfo[] getConstructors();
+
+ /**
+ * Returns a description of this operation.
+ *
+ * @return a human-readable description.
+ */
+ String getDescription();
+
+ /**
+ * Returns descriptions of each of the notifications provided by this
+ * management bean. The elements should be implementations of the
+ * {@link OpenMBeanNotificationInfo} class.
+ *
+ * @return an array of {@link OpenMBeanNotificationInfo} objects,
+ * representing the notifications emitted by this
+ * management bean.
+ */
+ MBeanNotificationInfo[] getNotifications();
+
+ /**
+ * Returns descriptions of each of the operations provided by this
+ * management bean. The elements should be implementations of the
+ * {@link OpenMBeanOperationInfo} class.
+ *
+ * @return an array of {@link OpenMBeanOperationInfo} objects,
+ * representing the operations emitted by this
+ * management bean.
+ */
+ MBeanOperationInfo[] getOperations();
+
+ /**
+ * Returns the hashcode of the bean information as the sum of the
+ * hashcodes of the class name and each array (calculated using
+ * java.util.HashSet(<code>java.util.Arrays.asList(signature)).hashCode()</code>).
+ *
+ * @return the hashcode of the bean information.
+ */
+ int hashCode();
+
+ /**
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.OpenMBeanInfo</code>)
+ * along with the class name and textual representations
+ * of each array.
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ String toString();
+
+}
diff --git a/javax/management/openmbean/OpenMBeanInfoSupport.java b/javax/management/openmbean/OpenMBeanInfoSupport.java
new file mode 100644
index 000000000..5f8d55b83
--- /dev/null
+++ b/javax/management/openmbean/OpenMBeanInfoSupport.java
@@ -0,0 +1,191 @@
+/* OpenMBeanInfoSupport.java -- Open typed info about a bean.
+ 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.management.openmbean;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+import javax.management.MBeanInfo;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+
+/**
+ * Describes an open management bean.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class OpenMBeanInfoSupport
+ extends MBeanInfo
+ implements OpenMBeanInfo
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = 4349395935420511492L;
+
+ /**
+ * The hash code of this instance.
+ */
+ private transient Integer hashCode;
+
+ /**
+ * The <code>toString()</code> result of this instance.
+ */
+ private transient String string;
+
+ /**
+ * Constructs a new {@link OpenMBeanInfo} using the supplied
+ * class name and description with the given attributes,
+ * operations, constructors and notifications. The class
+ * name does not have to actually specify a valid class that
+ * can be loaded by the MBean server or class loader; it merely
+ * has to be a syntactically correct class name. Any of the
+ * arrays may be <code>null</code>; this will be treated as if
+ * an empty array was supplied. A copy of the arrays is
+ * taken, so later changes have no effect.
+ *
+ * @param name the name of the class this instance describes.
+ * @param desc a description of the bean.
+ * @param attribs the attribute descriptions for the bean,
+ * or <code>null</code>.
+ * @param cons the constructor descriptions for the bean,
+ * or <code>null</code>.
+ * @param ops the operation descriptions for the bean,
+ * or <code>null</code>.
+ * @param notifs the notification descriptions for the bean,
+ * or <code>null</code>.
+ * @throws ArrayStoreException if a members of an array
+ * is not assignable to the equivalent
+ * <code>MBeanXXXInfo</code> class.
+ */
+ public OpenMBeanInfoSupport(String name, String desc,
+ OpenMBeanAttributeInfo[] attribs,
+ OpenMBeanConstructorInfo[] cons,
+ OpenMBeanOperationInfo[] ops,
+ MBeanNotificationInfo[] notifs)
+ {
+ super(name, desc, (MBeanAttributeInfo[]) attribs,
+ (MBeanConstructorInfo[]) cons,
+ (MBeanOperationInfo[]) ops,
+ notifs);
+ }
+
+ /**
+ * Compares this attribute with the supplied object. This returns
+ * true iff the object is an instance of {@link OpenMBeanInfo}
+ * with the same class name and equal instances of the info classes.
+ *
+ * @param obj the object to compare.
+ * @return true if the object is a {@link OpenMBeanInfo}
+ * instance,
+ * <code>className.equals(object.getClassName())</code>
+ * and each info class has an equal in the other object.
+ */
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof OpenMBeanInfo))
+ return false;
+ OpenMBeanInfo o = (OpenMBeanInfo) obj;
+ return getClassName().equals(o.getClassName()) &&
+ getAttributes().equals(o.getAttributes()) &&
+ getConstructors().equals(o.getConstructors()) &&
+ getNotifications().equals(o.getNotifications()) &&
+ getOperations().equals(o.getOperations());
+ }
+
+ /**
+ * <p>
+ * Returns the hashcode of the bean information as the sum of the
+ * hashcodes of the class name and each array (calculated using
+ * java.util.HashSet(<code>java.util.Arrays.asList(signature)).hashCode()</code>).
+ * </p>
+ * <p>
+ * As instances of this class are immutable, the return value
+ * is computed just once for each instance and reused
+ * throughout its life.
+ * </p>
+ *
+ * @return the hashcode of the bean information.
+ */
+ public int hashCode()
+ {
+ if (hashCode == null)
+ hashCode =
+ Integer.valueOf(getClassName().hashCode() +
+ new HashSet(Arrays.asList(getAttributes())).hashCode() +
+ new HashSet(Arrays.asList(getConstructors())).hashCode() +
+ new HashSet(Arrays.asList(getNotifications())).hashCode() +
+ new HashSet(Arrays.asList(getOperations())).hashCode());
+ return hashCode.intValue();
+ }
+
+ /**
+ * <p>
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.OpenMBeanInfo</code>)
+ * along with the class name and textual representations
+ * of each array.
+ * </p>
+ * <p>
+ * As instances of this class are immutable, the return value
+ * is computed just once for each instance and reused
+ * throughout its life.
+ * </p>
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ public String toString()
+ {
+ if (string == null)
+ string = getClass().getName()
+ + "[className=" + getClassName()
+ + ",attributes=" + Arrays.toString(getAttributes())
+ + ",constructors=" + Arrays.toString(getConstructors())
+ + ",notifications=" + Arrays.toString(getNotifications())
+ + ",operations=" + Arrays.toString(getOperations())
+ + "]";
+ return string;
+ }
+
+}
diff --git a/javax/management/openmbean/OpenMBeanOperationInfo.java b/javax/management/openmbean/OpenMBeanOperationInfo.java
new file mode 100644
index 000000000..8b61329d9
--- /dev/null
+++ b/javax/management/openmbean/OpenMBeanOperationInfo.java
@@ -0,0 +1,154 @@
+/* OpenMBeanOperationInfo.java -- Open typed info about a operation.
+ 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.management.openmbean;
+
+import javax.management.MBeanParameterInfo;
+
+/**
+ * Describes a operation for an open management bean.
+ * This interface includes those methods specified by {@link
+ * javax.management.MBeanOperationInfo}, so implementations should
+ * extend this class. The {@link #getSignature()} method should
+ * return an array containing instances of {@link OpenMBeanParameterInfo}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public interface OpenMBeanOperationInfo
+{
+
+ /**
+ * Compares this attribute with the supplied object. This returns
+ * true iff the object is an instance of {@link OpenMBeanOperationInfo}
+ * with an equal name, signature, open return type and impact.
+ *
+ * @param obj the object to compare.
+ * @return true if the object is a {@link OpenMBeanParameterInfo}
+ * instance,
+ * <code>name.equals(object.getName())</code>,
+ * <code>signature.equals(object.getSignature())</code>,
+ * <code>returnOpenType.equals(object.getReturnOpenType())</code>,
+ * and <code>impact == object.getImpact()</code>.
+ */
+ boolean equals(Object obj);
+
+ /**
+ * Returns a description of this operation.
+ *
+ * @return a human-readable description.
+ */
+ String getDescription();
+
+ /**
+ * <p>
+ * Returns the impact of performing this operation.
+ * The value is equal to one of the following:
+ * </p>
+ * <ol>
+ * <li>{@link javax.management.MBeanOperationInfo#INFO}
+ * &mdash; the method just returns
+ * information (akin to an accessor).</li>
+ * <li>{@link javax.management.MBeanOperationInfo#ACTION}
+ * the method just alters the state of the bean, without
+ * returning a value (akin to a mutator).</li>
+ * <li>{@link javax.management.MBeanOperationInfo#ACTION_INFO}
+ * the method both makes state changes and returns a value.</li>
+ * <li>{@link javax.management.MBeanOperationInfo#UNKNOWN}
+ * the behaviour of the operation is unknown.</li>
+ * </ol>
+ *
+ * @return the impact of performing the operation.
+ */
+ int getImpact();
+
+ /**
+ * Returns the name of this operation.
+ *
+ * @return the name of the operation.
+ */
+ String getName();
+
+ /**
+ * Returns the open type instance which represents the type of the
+ * return value.
+ *
+ * @return the open type of the return value.
+ */
+ OpenType getReturnOpenType();
+
+ /**
+ * Returns the return type of the operation, as the class
+ * name. This should be identical to
+ * <code>getReturnOpenType.getClassName()</code>.
+ *
+ * @return the return type.
+ */
+ String getReturnType();
+
+ /**
+ * Returns the operation's signature, in the form of
+ * information on each parameter. Each parameter is
+ * described by an instance of {@link OpenMBeanParameterInfo}.
+ *
+ * @return an array of {@link OpenMBeanParameterInfo} objects,
+ * describing the operation parameters.
+ */
+ MBeanParameterInfo[] getSignature();
+
+ /**
+ * Returns the hashcode of the operation information as the sum of
+ * the hashcodes of the name, open return type, impact and signature
+ * (calculated by
+ * <code>java.util.Arrays.asList(signature).hashCode()</code>).
+ *
+ * @return the hashcode of the operation information.
+ */
+ int hashCode();
+
+ /**
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.OpenMBeanOperationInfo</code>)
+ * along with the name, signature, open return type and impact.
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ String toString();
+
+}
diff --git a/javax/management/openmbean/OpenMBeanOperationInfoSupport.java b/javax/management/openmbean/OpenMBeanOperationInfoSupport.java
new file mode 100644
index 000000000..07564897c
--- /dev/null
+++ b/javax/management/openmbean/OpenMBeanOperationInfoSupport.java
@@ -0,0 +1,240 @@
+/* OpenMBeanOperationInfoSupport.java -- Open typed info about an operation.
+ 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.management.openmbean;
+
+import java.util.Arrays;
+
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+
+/**
+ * Describes a operation for an open management bean.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class OpenMBeanOperationInfoSupport
+ extends MBeanOperationInfo
+ implements OpenMBeanOperationInfo
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = 4996859732565369366L;
+
+ /**
+ * The open type representing the return value.
+ */
+ private OpenType returnOpenType;
+
+ /**
+ * The hash code of this instance.
+ */
+ private transient Integer hashCode;
+
+ /**
+ * The <code>toString()</code> result of this instance.
+ */
+ private transient String string;
+
+ /**
+ * Constructs a @link{OpenMBeanOperationInfo} with the specified name,
+ * description, parameter information, open return type and impact. A
+ * <code>null</code> value for the parameter information is the same
+ * as passing in an empty array. A copy of the parameter array is
+ * taken, so later changes have no effect. The name and the
+ * description may not be equal to the empty string, and neither
+ * the name, description nor the open return type may be
+ * <code>null</code>. The value of <code>impact</code> must be
+ * one of the four valid values
+ * ({@link javax.management.MBeanOperationInfo#INFO},
+ * {@link javax.management.MBeanOperationInfo#ACTION},
+ * {@link javax.management.MBeanOperationInfo#ACTION_INFO} and
+ * {@link javax.management.MBeanOperationInfo#UNKNOWN}).
+ *
+ *
+ * @param name the name of the constructor.
+ * @param desc a description of the attribute.
+ * @param sig the signature of the method, as a series
+ * of {@link MBeanParameterInfo} objects, one for
+ * each parameter.
+ * @param type the open return type of the method.
+ * @param impact the impact of performing the operation.
+ * @throws IllegalArgumentException if the name, description or
+ * open return type is <code>null</code>,
+ * the name or description are equal to
+ * the empty string, or the impact factor
+ * is not one of the values enumerated
+ * above.
+ * @throws ArrayStoreException if the members of the signature array
+ * are not assignable to
+ * {@link javax.management.MBeanParameterInfo}
+ */
+ public OpenMBeanOperationInfoSupport(String name, String desc,
+ OpenMBeanParameterInfo[] sig,
+ OpenType type, int impact)
+ {
+ super(name, desc, (MBeanParameterInfo[]) sig,
+ type == null ? null : type.getClassName(), impact);
+ if (name == null)
+ throw new IllegalArgumentException("The name may not be null.");
+ if (desc == null)
+ throw new IllegalArgumentException("The description may not be null.");
+ if (type == null)
+ throw new IllegalArgumentException("The type may not be null.");
+ if (name.length() == 0)
+ throw new IllegalArgumentException("The name may not be the empty string.");
+ if (desc.length() == 0)
+ throw new IllegalArgumentException("The description may not be the " +
+ "empty string.");
+ if (impact != ACTION && impact != INFO &&
+ impact != ACTION_INFO && impact != UNKNOWN)
+ throw new IllegalArgumentException("The impact factor is an invalid value.");
+ returnOpenType = type;
+ }
+
+ /**
+ * Compares this attribute with the supplied object. This returns
+ * true iff the object is an instance of {@link OpenMBeanOperationInfo}
+ * with an equal name, signature, open return type and impact.
+ *
+ * @param obj the object to compare.
+ * @return true if the object is a {@link OpenMBeanParameterInfo}
+ * instance,
+ * <code>name.equals(object.getName())</code>,
+ * <code>signature.equals(object.getSignature())</code>,
+ * <code>returnOpenType.equals(object.getReturnOpenType())</code>,
+ * and <code>impact == object.getImpact()</code>.
+ */
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof OpenMBeanOperationInfo))
+ return false;
+ OpenMBeanOperationInfo o = (OpenMBeanOperationInfo) obj;
+ return getName().equals(o.getName()) &&
+ getSignature().equals(o.getSignature()) &&
+ returnOpenType.equals(o.getReturnOpenType()) &&
+ getImpact() == o.getImpact();
+ }
+
+ /**
+ * Returns the open type instance which represents the type of the
+ * return value.
+ *
+ * @return the open type of the return value.
+ */
+ public OpenType getReturnOpenType()
+ {
+ return returnOpenType;
+ }
+
+ /**
+ * <p>
+ * Returns the hashcode of the operation information as the sum of
+ * the hashcodes of the name, open return type, impact and signature
+ * (calculated by
+ * <code>java.util.Arrays.asList(signature).hashCode()</code>).
+ * </p>
+ * <p>
+ * As instances of this class are immutable, the return value
+ * is computed just once for each instance and reused
+ * throughout its life.
+ * </p>
+ *
+ * @return the hashcode of the operation information.
+ */
+ public int hashCode()
+ {
+ if (hashCode == null)
+ hashCode = Integer.valueOf(getName().hashCode() +
+ returnOpenType.hashCode() +
+ Integer.valueOf(getImpact()).hashCode() +
+ Arrays.asList(getSignature()).hashCode());
+ return hashCode.intValue();
+ }
+
+ /**
+ * <p>
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.OpenMBeanOperationInfo</code>)
+ * along with the name, signature, open return type and impact.
+ * </p>
+ * <p>
+ * As instances of this class are immutable, the return value
+ * is computed just once for each instance and reused
+ * throughout its life.
+ * </p>
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ public String toString()
+ {
+ if (string == null)
+ {
+ String impactString;
+ switch (getImpact())
+ {
+ case INFO:
+ impactString = "INFO";
+ break;
+ case ACTION:
+ impactString = "ACTION";
+ break;
+ case ACTION_INFO:
+ impactString = "ACTION_INFO";
+ break;
+ case UNKNOWN:
+ impactString = "UNKNOWN";
+ break;
+ default:
+ impactString = "ERRONEOUS VALUE";
+ }
+ string = getClass().getName()
+ + "[name=" + getName()
+ + ",signature=" + Arrays.toString(getSignature())
+ + ",returnOpenType=" + returnOpenType
+ + ",impact=" + impactString
+ + "]";
+ }
+ return string;
+ }
+
+}
diff --git a/javax/management/openmbean/OpenMBeanParameterInfo.java b/javax/management/openmbean/OpenMBeanParameterInfo.java
new file mode 100644
index 000000000..780e8ba11
--- /dev/null
+++ b/javax/management/openmbean/OpenMBeanParameterInfo.java
@@ -0,0 +1,190 @@
+/* OpenMBeanParameterInfo.java -- Open typed info about a parameter.
+ 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.management.openmbean;
+
+import java.util.Set;
+
+/**
+ * Describes the parameters of a constructor or operation associated
+ * with an open management bean. This interface includes those methods
+ * specified by {@link javax.management.MBeanParameterInfo}, so
+ * implementations should extend this class.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public interface OpenMBeanParameterInfo
+{
+
+ /**
+ * Compares this parameter with the supplied object. This returns
+ * true iff the object is an instance of {@link OpenMBeanParameterInfo}
+ * with an equal name and open type and the same default, minimum,
+ * maximum and legal values.
+ *
+ * @param obj the object to compare.
+ * @return true if the object is a {@link OpenMBeanParameterInfo}
+ * instance,
+ * <code>name.equals(object.getName())</code>,
+ * <code>openType.equals(object.getOpenType())</code>,
+ * <code>defaultValue.equals(object.getDefaultValue())</code>,
+ * <code>minValue.equals(object.getMinValue())</code>,
+ * <code>maxValue.equals(object.getMaxValue())</code>,
+ * and <code>legalValues.equals(object.getLegalValues())</code>.
+ */
+ boolean equals(Object obj);
+
+ /**
+ * Returns the default value of this parameter, or <code>null</code>
+ * if there is no default value.
+ *
+ * @return the default value of the parameter, or <code>null</code>
+ * if there is no default.
+ */
+ Object getDefaultValue();
+
+ /**
+ * Returns a description of this parameter.
+ *
+ * @return a human-readable description.
+ */
+ String getDescription();
+
+ /**
+ * Returns a {@link java.util.Set} enumerating the legal values
+ * of this parameter, or <code>null</code> if no such limited
+ * set exists for this parameter.
+ *
+ * @return a set of legal values, or <code>null</code> if no such
+ * set exists.
+ */
+ Set getLegalValues();
+
+ /**
+ * Returns the maximum value of this parameter, or <code>null</code>
+ * if there is no maximum.
+ *
+ * @return the maximum value, or <code>null</code> if none exists.
+ */
+ Comparable getMaxValue();
+
+ /**
+ * Returns the minimum value of this parameter, or <code>null</code>
+ * if there is no minimum.
+ *
+ * @return the minimum value, or <code>null</code> if none exists.
+ */
+ Comparable getMinValue();
+
+ /**
+ * Returns the name of this parameter.
+ *
+ * @return the name of the parameter.
+ */
+ String getName();
+
+ /**
+ * Returns the open type instance which represents the type of this
+ * parameter.
+ *
+ * @return the open type of this parameter.
+ */
+ OpenType getOpenType();
+
+ /**
+ * Returns true if this parameter has a default value.
+ *
+ * @return true if this parameter has a default.
+ */
+ boolean hasDefaultValue();
+
+ /**
+ * Returns the hashcode of the parameter information as the sum of
+ * the hashcodes of the name, open type, default value, maximum
+ * value, minimum value and the set of legal values.
+ *
+ * @return the hashcode of the parameter information.
+ */
+ int hashCode();
+
+ /**
+ * Returns true if there is a set of legal values for this
+ * parameter.
+ *
+ * @return true if a set of legal values exists for this
+ * parameter.
+ */
+ boolean hasLegalValues();
+
+ /**
+ * Returns true if there is a maximum value for this parameter.
+ *
+ * @return true if a maximum value exists for this parameter.
+ */
+ boolean hasMaxValue();
+
+ /**
+ * Returns true if there is a minimum value for this parameter.
+ *
+ * @return true if a minimum value exists for this parameter.
+ */
+ boolean hasMinValue();
+
+ /**
+ * Returns true if the specified object is a valid value for
+ * this parameter.
+ *
+ * @param obj the object to test.
+ * @return true if <code>obj</code> is a valid value for this
+ * parameter.
+ */
+ boolean isValue(Object obj);
+
+ /**
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.OpenMBeanParameterInfo</code>)
+ * along with the name, open type, default, minimum, maximum
+ * and legal values of the parameter.
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ String toString();
+
+}
diff --git a/javax/management/openmbean/OpenMBeanParameterInfoSupport.java b/javax/management/openmbean/OpenMBeanParameterInfoSupport.java
new file mode 100644
index 000000000..af3bda6c7
--- /dev/null
+++ b/javax/management/openmbean/OpenMBeanParameterInfoSupport.java
@@ -0,0 +1,511 @@
+/* OpenMBeanParameterInfoSupport.java -- Open typed info about a parameter.
+ 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.management.openmbean;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.management.MBeanParameterInfo;
+
+/**
+ * Describes the parameters of a constructor or operation associated
+ * with an open management bean.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class OpenMBeanParameterInfoSupport
+ extends MBeanParameterInfo
+ implements OpenMBeanParameterInfo
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = -7235016873758443122L;
+
+ /**
+ * The open type of the parameter.
+ */
+ private OpenType openType;
+
+ /**
+ * The default value of the parameter (may be <code>null</code>).
+ */
+ private Object defaultValue;
+
+ /**
+ * The possible legal values of the parameter (may be <code>null</code>).
+ */
+ private Set legalValues;
+
+ /**
+ * The minimum value of the parameter (may be <code>null</code>).
+ */
+ private Comparable minValue;
+
+ /**
+ * The maximum value of the parameter (may be <code>null</code>).
+ */
+ private Comparable maxValue;
+
+ /**
+ * The hash code of this instance.
+ */
+ private transient Integer hashCode;
+
+ /**
+ * The <code>toString()</code> result of this instance.
+ */
+ private transient String string;
+
+ /**
+ * Constructs a new {@link OpenMBeanParameterInfo} using the specified
+ * name, description and open type. None of these values may be
+ * <code>null</code> and the name and description may not be equal
+ * to the empty string.
+ *
+ * @param name the name of the parameter.
+ * @param desc a description of the parameter.
+ * @param type the open type of the parameter.
+ * @throws IllegalArgumentException if the name, description or
+ * open type are <code>null</code>
+ * or the name or description are
+ * the empty string.
+ */
+ public OpenMBeanParameterInfoSupport(String name, String desc, OpenType type)
+ {
+ super(name, type == null ? null : type.getClassName(), desc);
+ if (name == null)
+ throw new IllegalArgumentException("The name may not be null.");
+ if (desc == null)
+ throw new IllegalArgumentException("The description may not be null.");
+ if (type == null)
+ throw new IllegalArgumentException("The type may not be null.");
+ if (name.length() == 0)
+ throw new IllegalArgumentException("The name may not be the empty string.");
+ if (desc.length() == 0)
+ throw new IllegalArgumentException("The description may not be the " +
+ "empty string.");
+ openType = type;
+ }
+
+ /**
+ * Constructs a new {@link OpenMBeanParameterInfo} using the
+ * specified name, description, open type and default value. The
+ * name, description and open type cannot be <code>null</code> and
+ * the name and description may not be equal to the empty string.
+ * The default value may be <code>null</code>. If non-null, it must
+ * be a valid value of the given open type. Default values are not
+ * applicable to the open types, {@link ArrayType} and {@link
+ * TabularType}.
+ *
+ * @param name the name of the parameter.
+ * @param desc a description of the parameter.
+ * @param type the open type of the parameter.
+ * @param defaultValue the default value of the parameter.
+ * @throws IllegalArgumentException if the name, description or
+ * open type are <code>null</code>
+ * or the name or description are
+ * the empty string.
+ * @throws OpenDataException if <code>defaultValue<code> is non-null
+ * and is either not a value of the given
+ * open type or the open type is an instance
+ * of {@link ArrayType} or {@link TabularType}.
+ */
+ public OpenMBeanParameterInfoSupport(String name, String desc, OpenType type,
+ Object defaultValue)
+ throws OpenDataException
+ {
+ this(name, desc, type, defaultValue, null);
+ }
+
+ /**
+ * <p>
+ * Constructs a new {@link OpenMBeanParameterInfo} using the
+ * specified name, description, open type, default, maximum and
+ * minimum values. The name, description and open type cannot be
+ * <code>null</code> and the name and description may not be equal
+ * to the empty string. The default, maximum and minimum values may
+ * be <code>null</code>. The following conditions apply when the
+ * parameters mentioned are non-null:
+ * </p>
+ * <ul>
+ * <li>The values must be valid values for the given open type.</li>
+ * <li>Default values are not applicable to the open types, {@link
+ * ArrayType} and {@link TabularType}.</li>
+ * <li>The minimum value must be smaller than or equal to the maximum value
+ * (literally, <code>minValue.compareTo(maxValue) <= 0</code>.</li>
+ * <li>The minimum value must be smaller than or equal to the default value
+ * (literally, <code>minValue.compareTo(defaultValue) <= 0</code>.</li>
+ * <li>The default value must be smaller than or equal to the maximum value
+ * (literally, <code>defaultValue.compareTo(maxValue) <= 0</code>.</li>
+ * </ul>
+ *
+ * @param name the name of the parameter.
+ * @param desc a description of the parameter.
+ * @param type the open type of the parameter.
+ * @param defaultValue the default value of the parameter, or <code>null</code>.
+ * @param minimumValue the minimum value of the parameter, or <code>null</code>.
+ * @param maximumValue the maximum value of the parameter, or <code>null</code>.
+ * @throws IllegalArgumentException if the name, description or
+ * open type are <code>null</code>
+ * or the name or description are
+ * the empty string.
+ * @throws OpenDataException if any condition in the list above is broken.
+ */
+ public OpenMBeanParameterInfoSupport(String name, String desc, OpenType type,
+ Object defaultValue, Comparable minimumValue,
+ Comparable maximumValue)
+ throws OpenDataException
+ {
+ this(name, desc, type);
+ if (defaultValue != null && !(type.isValue(defaultValue)))
+ throw new OpenDataException("The default value is not a member of the " +
+ "open type given.");
+ if (minimumValue != null && !(type.isValue(minimumValue)))
+ throw new OpenDataException("The minimum value is not a member of the " +
+ "open type given.");
+ if (maximumValue != null && !(type.isValue(maximumValue)))
+ throw new OpenDataException("The maximum value is not a member of the " +
+ "open type given.");
+ if (defaultValue != null && (type instanceof ArrayType ||
+ type instanceof TabularType))
+ throw new OpenDataException("Default values are not applicable for " +
+ "array or tabular types.");
+ if (minValue != null && maxValue != null
+ && minValue.compareTo(maxValue) > 0)
+ throw new OpenDataException("The minimum value is greater than the " +
+ "maximum.");
+ if (minValue != null && defaultValue != null
+ && minValue.compareTo(defaultValue) > 0)
+ throw new OpenDataException("The minimum value is greater than the " +
+ "default.");
+ if (defaultValue != null && maxValue != null
+ && maxValue.compareTo(defaultValue) < 0)
+ throw new OpenDataException("The default value is greater than the " +
+ "maximum.");
+
+ this.defaultValue = defaultValue;
+ minValue = minimumValue;
+ maxValue = maximumValue;
+ }
+
+ /**
+ * <p>
+ * Constructs a new {@link OpenMBeanParameterInfo} using the
+ * specified name, description, open type, default value and
+ * set of legal values. The name, description and open type cannot be
+ * <code>null</code> and the name and description may not be equal
+ * to the empty string. The default, maximum and minimum values may
+ * be <code>null</code>. The following conditions apply when the
+ * parameters mentioned are non-null:
+ * </p>
+ * <ul>
+ * <li>The default value and each of the legal values must be a valid
+ * value for the given open type.</li>
+ * <li>Default and legal values are not applicable to the open types, {@link
+ * ArrayType} and {@link TabularType}.</li>
+ * <li>The default value is not in the set of legal values.</li>
+ * </ul>
+ * <p>
+ * The legal values are copied from the array into a unmodifiable set,
+ * so future modifications to the array have no effect.
+ * </p>
+ *
+ * @param name the name of the parameter.
+ * @param desc a description of the parameter.
+ * @param type the open type of the parameter.
+ * @param defaultValue the default value of the parameter, or <code>null</code>.
+ * @param legalValues the legal values of the parameter. May be
+ * <code>null</code> or an empty array.
+ * @throws IllegalArgumentException if the name, description or
+ * open type are <code>null</code>
+ * or the name or description are
+ * the empty string.
+ * @throws OpenDataException if any condition in the list above is broken.
+ */
+ public OpenMBeanParameterInfoSupport(String name, String desc, OpenType type,
+ Object defaultValue, Object[] legalValues)
+ throws OpenDataException
+ {
+ this(name, desc, type);
+ if (defaultValue != null && !(type.isValue(defaultValue)))
+ throw new OpenDataException("The default value is not a member of the " +
+ "open type given.");
+ if (defaultValue != null && (type instanceof ArrayType ||
+ type instanceof TabularType))
+ throw new OpenDataException("Default values are not applicable for " +
+ "array or tabular types.");
+ if (legalValues != null && (type instanceof ArrayType ||
+ type instanceof TabularType))
+ throw new OpenDataException("Legal values are not applicable for " +
+ "array or tabular types.");
+ if (legalValues != null && legalValues.length > 0)
+ {
+ Set lv = new HashSet(legalValues.length);
+ for (int a = 0; a < legalValues.length; ++a)
+ {
+ if (legalValues[a] != null &&
+ !(type.isValue(legalValues[a])))
+ throw new OpenDataException("The legal value, "
+ + legalValues[a] +
+ "is not a member of the " +
+ "open type given.");
+ lv.add(legalValues[a]);
+ }
+ if (defaultValue != null && !(lv.contains(defaultValue)))
+ throw new OpenDataException("The default value is not in the set " +
+ "of legal values.");
+ this.legalValues = Collections.unmodifiableSet(lv);
+ }
+ this.defaultValue = defaultValue;
+ }
+
+ /**
+ * Compares this parameter with the supplied object. This returns
+ * true iff the object is an instance of {@link OpenMBeanParameterInfo}
+ * with an equal name and open type and the same default, minimum,
+ * maximum and legal values.
+ *
+ * @param obj the object to compare.
+ * @return true if the object is a {@link OpenMBeanParameterInfo}
+ * instance,
+ * <code>name.equals(object.getName())</code>,
+ * <code>openType.equals(object.getOpenType())</code>,
+ * <code>defaultValue.equals(object.getDefaultValue())</code>,
+ * <code>minValue.equals(object.getMinValue())</code>,
+ * <code>maxValue.equals(object.getMaxValue())</code>,
+ * and <code>legalValues.equals(object.getLegalValues())</code>.
+ */
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof OpenMBeanParameterInfo))
+ return false;
+ OpenMBeanParameterInfo o = (OpenMBeanParameterInfo) obj;
+ return getName().equals(o.getName()) &&
+ openType.equals(o.getOpenType()) &&
+ (defaultValue == null ? o.getDefaultValue() == null :
+ defaultValue.equals(o.getDefaultValue())) &&
+ (minValue == null ? o.getMinValue() == null :
+ minValue.equals(o.getMinValue())) &&
+ (maxValue == null ? o.getMaxValue() == null :
+ maxValue.equals(o.getMaxValue())) &&
+ (legalValues == null ? o.getLegalValues() == null :
+ legalValues.equals(o.getLegalValues()));
+ }
+
+ /**
+ * Returns the default value of this parameter, or <code>null</code>
+ * if there is no default value.
+ *
+ * @return the default value of the parameter, or <code>null</code>
+ * if there is no default.
+ */
+ public Object getDefaultValue()
+ {
+ return defaultValue;
+ }
+
+ /**
+ * Returns a {@link java.util.Set} enumerating the legal values
+ * of this parameter, or <code>null</code> if no such limited
+ * set exists for this parameter.
+ *
+ * @return a set of legal values, or <code>null</code> if no such
+ * set exists.
+ */
+ public Set getLegalValues()
+ {
+ return legalValues;
+ }
+
+ /**
+ * Returns the maximum value of this parameter, or <code>null</code>
+ * if there is no maximum.
+ *
+ * @return the maximum value, or <code>null</code> if none exists.
+ */
+ public Comparable getMaxValue()
+ {
+ return maxValue;
+ }
+
+ /**
+ * Returns the minimum value of this parameter, or <code>null</code>
+ * if there is no minimum.
+ *
+ * @return the minimum value, or <code>null</code> if none exists.
+ */
+ public Comparable getMinValue()
+ {
+ return minValue;
+ }
+
+ /**
+ * Returns the open type instance which represents the type of this
+ * parameter.
+ *
+ * @return the open type of this parameter.
+ */
+ public OpenType getOpenType()
+ {
+ return openType;
+ }
+
+ /**
+ * Returns true if this parameter has a default value
+ * (i.e. the value is non-null).
+ *
+ * @return true if this parameter has a default.
+ */
+ public boolean hasDefaultValue()
+ {
+ return defaultValue != null;
+ }
+
+ /**
+ * <p>
+ * Returns the hashcode of the parameter information as the sum of
+ * the hashcodes of the name, open type, default value, maximum
+ * value, minimum value and the set of legal values.
+ * </p>
+ * <p>
+ * As instances of this class are immutable, the hash code
+ * is computed just once for each instance and reused
+ * throughout its life.
+ * </p>
+ *
+ * @return the hashcode of the parameter information.
+ */
+ public int hashCode()
+ {
+ if (hashCode == null)
+ hashCode = Integer.valueOf(getName().hashCode() +
+ openType.hashCode() +
+ (defaultValue == null ? 0 :
+ defaultValue.hashCode()) +
+ (minValue == null ? 0 :
+ minValue.hashCode()) +
+ (maxValue == null ? 0 :
+ maxValue.hashCode()) +
+ (legalValues == null ? 0 :
+ legalValues.hashCode()));
+ return hashCode.intValue();
+ }
+
+ /**
+ * Returns true if there is a set of legal values for this
+ * parameter (i.e. the value is non-null).
+ *
+ * @return true if a set of legal values exists for this
+ * parameter.
+ */
+ public boolean hasLegalValues()
+ {
+ return legalValues != null;
+ }
+
+ /**
+ * Returns true if there is a maximum value for this parameter
+ * (i.e. the value is non-null).
+ *
+ * @return true if a maximum value exists for this parameter.
+ */
+ public boolean hasMaxValue()
+ {
+ return maxValue != null;
+ }
+
+ /**
+ * Returns true if there is a minimum value for this parameter.
+ * (i.e. the value is non-null).
+ *
+ * @return true if a minimum value exists for this parameter.
+ */
+ public boolean hasMinValue()
+ {
+ return minValue != null;
+ }
+
+ /**
+ * Returns true if the specified object is a valid value for
+ * this parameter.
+ *
+ * @param obj the object to test.
+ * @return true if <code>obj</code> is a valid value for this
+ * parameter.
+ */
+ public boolean isValue(Object obj)
+ {
+ return openType.isValue(obj);
+ }
+
+ /**
+ * <p>
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.OpenMBeanParameterInfo</code>)
+ * along with the name, open type, default, minimum, maximum
+ * and legal values of the parameter.
+ * </p>
+ * <p>
+ * As instances of this class are immutable, the return value
+ * is computed just once for each instance and reused
+ * throughout its life.
+ * </p>
+ *
+ * @return a @link{java.lang.String} instance representing
+ * the instance in textual form.
+ */
+ public String toString()
+ {
+ if (string == null)
+ string = getClass().getName()
+ + "[name=" + getName()
+ + ",openType=" + openType
+ + ",defaultValue=" + defaultValue
+ + ",minValue=" + minValue
+ + ",maxValue=" + maxValue
+ + ",legalValues=" + legalValues
+ + "]";
+ return string;
+ }
+
+}
diff --git a/javax/management/openmbean/SimpleType.java b/javax/management/openmbean/SimpleType.java
index 3962909d4..39753f1c6 100644
--- a/javax/management/openmbean/SimpleType.java
+++ b/javax/management/openmbean/SimpleType.java
@@ -53,7 +53,7 @@ import java.io.ObjectStreamException;
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
* @since 1.5
*/
-public class SimpleType
+public final class SimpleType
extends OpenType
{
diff --git a/javax/management/openmbean/TabularData.java b/javax/management/openmbean/TabularData.java
index 17c8de981..7e57e0fd8 100644
--- a/javax/management/openmbean/TabularData.java
+++ b/javax/management/openmbean/TabularData.java
@@ -55,12 +55,14 @@ public interface TabularData
/**
* Calculates the index the specified {@link CompositeData} value
* would have, if it was to be added to this {@link TabularData}
- * instance. This method includes a check that the type of
- * the given value is the same as the row type of this instance,
- * but not a check for existing instances of the given value.
- * The value must also not be <code>null</code>. Possible indices
- * are returned by the {@link TabularType#getIndexNames()} method
- * of this instance's tabular type.
+ * instance. This method includes a check that the type of the
+ * given value is the same as the row type of this instance, but not
+ * a check for existing instances of the given value. The value
+ * must also not be <code>null</code>. Possible indices are
+ * returned by the {@link TabularType#getIndexNames()} method of
+ * this instance's tabular type. The returned indices are the
+ * values of the fields in the supplied {@link CompositeData}
+ * instance that match the names given in the {@link TabularType}.
*
* @param val the {@link CompositeData} value whose index should
* be calculated.
@@ -106,7 +108,7 @@ public interface TabularData
* Compares the specified object with this object for equality.
* The object is judged equivalent if it is non-null, and also
* an instance of {@link TabularData} with the same row type,
- * and index to value mappings. The two compared instances may
+ * and {@link CompositeData} values. The two compared instances may
* be equivalent even if they represent different implementations
* of {@link TabularData}.
*
@@ -123,9 +125,9 @@ public interface TabularData
* @return the matching {@link CompositeData} value, or
* <code>null</code> if one does not exist.
* @throws NullPointerException if the key is <code>null</code>.
- * @throws InvalidOpenTypeException if the key does not match
- * the {@link TabularType} of this
- * instance.
+ * @throws InvalidKeyException if the key does not match
+ * the {@link TabularType} of this
+ * instance.
*/
CompositeData get(Object[] key);
@@ -138,14 +140,12 @@ public interface TabularData
TabularType getTabularType();
/**
- * Returns the hash code of the composite data type.
- * This is computed as the sum of the hash codes of the
- * each index and its value, together with the hash
- * code of the tabular type. These are the same elements
- * of the type that are compared as part of the
- * {@link #equals(java.lang.Object)} method, thus ensuring
- * that the hashcode is compatible with the equality
- * test.
+ * Returns the hash code of the composite data type. This is
+ * computed as the sum of the hash codes of each value, together
+ * with the hash code of the tabular type. These are the same
+ * elements of the type that are compared as part of the {@link
+ * #equals(java.lang.Object)} method, thus ensuring that the
+ * hashcode is compatible with the equality test.
*
* @return the hash code of this instance.
*/
@@ -196,15 +196,16 @@ public interface TabularData
* values in the array, as well as from the existing values
* in the table. The operation should be atomic; if one
* value can not be added, then none of the values should
- * be.
+ * be. If the array is <code>null</code> or empty, the
+ * method simply returns.
*
* @param vals the {@link CompositeData} values to add.
- * @throws NullPointerException if <code>val</code> is
+ * @throws NullPointerException if a value from the array is
* <code>null</code>.
- * @throws InvalidOpenTypeException if the type of the
+ * @throws InvalidOpenTypeException if the type of a
* given value does not
* match the row type.
- * @throws KeyAlreadyExistsException if the value has the
+ * @throws KeyAlreadyExistsException if a value has the
* same calculated index
* as an existing value or
* of one of the other
diff --git a/javax/management/openmbean/TabularDataSupport.java b/javax/management/openmbean/TabularDataSupport.java
new file mode 100644
index 000000000..9dc8a0e97
--- /dev/null
+++ b/javax/management/openmbean/TabularDataSupport.java
@@ -0,0 +1,652 @@
+/* TabularDataSupport.java -- Tables of composite data structures.
+ 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.management.openmbean;
+
+import java.io.Serializable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Provides an implementation of the {@link TabularData}
+ * interface using a {@link java.util.HashMap}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public class TabularDataSupport
+ implements TabularData, Serializable, Cloneable, Map
+{
+
+ /**
+ * Compatible with JDK 1.5
+ */
+ private static final long serialVersionUID = 5720150593236309827L;
+
+ /**
+ * Mapping of rows to column values.
+ *
+ * @serial the map of rows to column values.
+ */
+ private Map dataMap;
+
+ /**
+ * The tabular type which represents this tabular data instance.
+ *
+ * @serial the type information for this instance.
+ */
+ private TabularType tabularType;
+
+ /**
+ * Constructs a new empty {@link TabularDataSupport} with the
+ * specified type. The type may not be null. This constructor
+ * simply calls the other, with the default initial capacity of
+ * <code>101</code> and default load factor of <code>0.75</code>.
+ *
+ * @param type the tabular type of this tabular data instance.
+ * @throws IllegalArgumentException if <code>type</code> is
+ * <code>null</code>.
+ */
+ public TabularDataSupport(TabularType type)
+ {
+ this(type, 101, 0.75f);
+ }
+
+ /**
+ * Constructs a new empty {@link TabularDataSupport} with the
+ * specified type and the supplied initial capacity and load factor
+ * being used for the underlying {@link java.util.HashMap}. The
+ * type may not be null and the initial capacity and load factor
+ * must be positive.
+ *
+ * @param type the tabular type of this tabular data instance.
+ * @param cap the initial capacity of the underlying map.
+ * @param lf the load factor of the underlying map.
+ * @throws IllegalArgumentException if <code>type</code> is
+ * <code>null</code>, or
+ * <code>cap</code> or
+ * <code>lf</code> are
+ * negative.
+ */
+ public TabularDataSupport(TabularType type, int cap, float lf)
+ {
+ if (type == null)
+ throw new IllegalArgumentException("The type may not be null.");
+ tabularType = type;
+ dataMap = new HashMap(cap, lf);
+ }
+
+ /**
+ * Calculates the index the specified {@link CompositeData} value
+ * would have, if it was to be added to this {@link TabularData}
+ * instance. This method includes a check that the type of the
+ * given value is the same as the row type of this instance, but not
+ * a check for existing instances of the given value. The value
+ * must also not be <code>null</code>. Possible indices are
+ * selected by the {@link TabularType#getIndexNames()} method of
+ * this instance's tabular type. The returned indices are the
+ * values of the fields in the supplied {@link CompositeData}
+ * instance that match the names given in the {@link TabularType}.
+ *
+ * @param val the {@link CompositeData} value whose index should
+ * be calculated.
+ * @return the index the value would take on, if it were to be added.
+ * @throws NullPointerException if the value is <code>null</code>.
+ * @throws InvalidOpenTypeException if the value does not match the
+ * row type of this instance.
+ */
+ public Object[] calculateIndex(CompositeData val)
+ {
+ if (!(val.getCompositeType().equals(tabularType.getRowType())))
+ throw new InvalidOpenTypeException("The type of the given value " +
+ "does not match the row type " +
+ "of this instance.");
+ List indexNames = tabularType.getIndexNames();
+ List matchingIndicies = new ArrayList(indexNames.size());
+ Iterator it = indexNames.iterator();
+ while (it.hasNext())
+ {
+ String name = (String) it.next();
+ matchingIndicies.add(val.get(name));
+ }
+ return matchingIndicies.toArray();
+ }
+
+ /**
+ * Removes all {@link CompositeData} values from the table.
+ */
+ public void clear()
+ {
+ dataMap.clear();
+ }
+
+ /**
+ * Returns a shallow clone of the information, as obtained by the
+ * {@link Object} implementation of {@link Object#clone()}. The map
+ * is also cloned, but it still references the same objects.
+ *
+ * @return a shallow clone of this {@link TabularDataSupport}.
+ */
+ public Object clone()
+ {
+ TabularDataSupport clone = null;
+ try
+ {
+ clone = (TabularDataSupport) super.clone();
+ clone.setMap((HashMap) ((HashMap) dataMap).clone());
+ }
+ catch (CloneNotSupportedException e)
+ {
+ /* This won't happen as we implement Cloneable */
+ }
+ return clone;
+ }
+
+ /**
+ * Returns true iff this instance of the {@link TabularData} class
+ * contains a {@link CompositeData} value at the specified index.
+ * The method returns <code>false</code> if the given key can
+ * not be cast to an {@link java.lang.Object} array; otherwise
+ * it returns the result of {@link #containsKey(java.lang.Object[])}.
+ *
+ *
+ * @param key the key to test for.
+ * @return true if the key maps to a {@link CompositeData} value.
+ */
+ public boolean containsKey(Object key)
+ {
+ if (key instanceof Object[])
+ return containsKey((Object[]) key);
+ else
+ return false;
+ }
+
+ /**
+ * Returns true iff this instance of the {@link TabularData} class
+ * contains a {@link CompositeData} value at the specified index.
+ * In any other circumstance, including if the given key
+ * is <code>null</code> or of the incorrect type, according to
+ * the {@link TabularType} of this instance, this method returns
+ * false.
+ *
+ * @param key the key to test for.
+ * @return true if the key maps to a {@link CompositeData} value.
+ */
+ public boolean containsKey(Object[] key)
+ {
+ if (key == null)
+ return false;
+ if (!(isKeyValid(key)))
+ return false;
+ return dataMap.containsKey(key);
+ }
+
+ /**
+ * Returns true iff this instance of the {@link TabularData} class
+ * contains the specified {@link CompositeData} value. If the given
+ * value is not an instance of {@link CompositeData}, this method
+ * simply returns false.
+ *
+ * @param val the value to test for.
+ * @return true if the value exists.
+ */
+ public boolean containsValue(Object val)
+ {
+ if (val instanceof CompositeData)
+ return containsValue((CompositeData) val);
+ else
+ return false;
+ }
+
+ /**
+ * Returns true iff this instance of the {@link TabularData} class
+ * contains the specified {@link CompositeData} value.
+ * In any other circumstance, including if the given value
+ * is <code>null</code> or of the incorrect type, according to
+ * the {@link TabularType} of this instance, this method returns
+ * false.
+ *
+ * @param val the value to test for.
+ * @return true if the value exists.
+ */
+ public boolean containsValue(CompositeData val)
+ {
+ if (val == null)
+ return false;
+ if (!(val.getCompositeType().equals(tabularType.getRowType())))
+ return false;
+ return dataMap.containsValue(val);
+ }
+
+ /**
+ * <p>
+ * Returns a set view of the mappings in this Map. Each element in the
+ * set is a Map.Entry. The set is backed by the map, so that changes in
+ * one show up in the other. Modifications made while an iterator is
+ * in progress cause undefined behavior. If the set supports removal,
+ * these methods remove the underlying mapping from the map:
+ * <code>Iterator.remove</code>, <code>Set.remove</code>,
+ * <code>removeAll</code>, <code>retainAll</code>, and <code>clear</code>.
+ * Element addition, via <code>add</code> or <code>addAll</code>, is
+ * not supported via this set.
+ * </p>
+ * <p>
+ * <strong>Note</strong>: using the
+ * {@link java.util.Map.Entry#setValue(Object) will cause corruption of
+ * the index to row mappings.
+ * </p>
+ *
+ * @return the set view of all mapping entries
+ * @see java.util.Map.Entry
+ */
+ public Set entrySet()
+ {
+ return dataMap.entrySet();
+ }
+
+ /**
+ * Compares the specified object with this object for equality.
+ * The object is judged equivalent if it is non-null, and also
+ * an instance of {@link TabularData} with the same row type,
+ * and {@link CompositeData} values. The two compared instances may
+ * be equivalent even if they represent different implementations
+ * of {@link TabularData}.
+ *
+ * @param obj the object to compare for equality.
+ * @return true if <code>obj</code> is equal to <code>this</code>.
+ */
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof TabularData))
+ return false;
+ TabularData data = (TabularData) obj;
+ return tabularType.equals(data.getTabularType()) &&
+ dataMap.values().equals(data.values());
+ }
+
+ /**
+ * Retrieves the value for the specified key by simply
+ * calling <code>get((Object[]) key)</code>.
+ *
+ * @param key the key whose value should be returned.
+ * @return the matching {@link CompositeData} value, or
+ * <code>null</code> if one does not exist.
+ * @throws NullPointerException if the key is <code>null</code>.
+ * @throws ClassCastException if the key is not an instance
+ * of <code>Object[]</code>.
+ * @throws InvalidKeyException if the key does not match
+ * the {@link TabularType} of this
+ * instance.
+ */
+ public Object get(Object key)
+ {
+ return get((Object[]) key);
+ }
+
+ /**
+ * Retrieves the {@link CompositeData} value for the specified
+ * key, or <code>null</code> if no such mapping exists.
+ *
+ * @param key the key whose value should be returned.
+ * @return the matching {@link CompositeData} value, or
+ * <code>null</code> if one does not exist.
+ * @throws NullPointerException if the key is <code>null</code>.
+ * @throws InvalidKeyException if the key does not match
+ * the {@link TabularType} of this
+ * instance.
+ */
+ public CompositeData get(Object[] key)
+ {
+ if (!(isKeyValid(key)))
+ throw new InvalidKeyException("The key does not match the " +
+ "tabular type of this instance.");
+ return (CompositeData) dataMap.get(key);
+ }
+
+ /**
+ * Returns the tabular type which corresponds to this instance
+ * of {@link TabularData}.
+ *
+ * @return the tabular type for this instance.
+ */
+ public TabularType getTabularType()
+ {
+ return tabularType;
+ }
+
+ /**
+ * Returns the hash code of the composite data type. This is
+ * computed as the sum of the hash codes of each value, together
+ * with the hash code of the tabular type. These are the same
+ * elements of the type that are compared as part of the {@link
+ * #equals(java.lang.Object)} method, thus ensuring that the
+ * hashcode is compatible with the equality test.
+ *
+ * @return the hash code of this instance.
+ */
+ public int hashCode()
+ {
+ return tabularType.hashCode() + dataMap.values().hashCode();
+ }
+
+ /**
+ * Returns true if this {@link TabularData} instance
+ * contains no {@link CompositeData} values.
+ *
+ * @return true if the instance is devoid of rows.
+ */
+ public boolean isEmpty()
+ {
+ return dataMap.isEmpty();
+ }
+
+ /**
+ * Returns true if the given key is valid for the
+ * @link{TabularType} of this instance.
+ *
+ * @return true if the key is valid.
+ * @throws NullPointerException if <code>key</code>
+ * is null.
+ */
+ private boolean isKeyValid(Object[] key)
+ {
+ Iterator it = tabularType.getIndexNames().iterator();
+ CompositeType rowType = tabularType.getRowType();
+ for (int a = 0; it.hasNext(); ++a)
+ {
+ OpenType type = rowType.getType((String) it.next());
+ if (!(type.isValue(key[a])))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns a set view of the keys in this Map. The set is backed by the
+ * map, so that changes in one show up in the other. Modifications made
+ * while an iterator is in progress cause undefined behavior. If the set
+ * supports removal, these methods remove the underlying mapping from
+ * the map: <code>Iterator.remove</code>, <code>Set.remove</code>,
+ * <code>removeAll</code>, <code>retainAll</code>, and <code>clear</code>.
+ * Element addition, via <code>add</code> or <code>addAll</code>, is
+ * not supported via this set.
+ *
+ * @return the set view of all keys
+ */
+ public Set keySet()
+ {
+ return dataMap.keySet();
+ }
+
+ /**
+ * Adds the specified {@link CompositeData} value to the
+ * table. The value must be non-null, of the same type
+ * as the row type of this instance, and must not have
+ * the same index as an existing value. The index is
+ * calculated using the index names of the
+ * {@link TabularType} for this instance.
+ *
+ * @param val the {@link CompositeData} value to add.
+ * @throws NullPointerException if <code>val</code> is
+ * <code>null</code>.
+ * @throws InvalidOpenTypeException if the type of the
+ * given value does not
+ * match the row type.
+ * @throws KeyAlreadyExistsException if the value has the
+ * same calculated index
+ * as an existing value.
+ */
+ public void put(CompositeData val)
+ {
+ Object[] key = calculateIndex(val);
+ if (dataMap.containsKey(key))
+ throw new KeyAlreadyExistsException("A value with this index " +
+ "already exists.");
+ dataMap.put(key, val);
+ }
+
+ /**
+ * Adds the specified {@link CompositeData} value to the
+ * table, ignoring the supplied key, by simply calling
+ * <code>put((CompositeData) val)</code>.
+ *
+ * @param key ignored.
+ * @param val the {@link CompositeData} value to add.
+ * @return the {@link CompositeData} value.
+ * @throws NullPointerException if <code>val</code> is
+ * <code>null</code>.
+ * @throws InvalidOpenTypeException if the type of the
+ * given value does not
+ * match the row type.
+ * @throws KeyAlreadyExistsException if the value has the
+ * same calculated index
+ * as an existing value.
+ */
+ public Object put(Object key, Object val)
+ {
+ put((CompositeData) val);
+ return val;
+ }
+
+ /**
+ * Adds each of the specified {@link CompositeData} values
+ * to the table. Each element of the array must meet the
+ * conditions given for the {@link #put(CompositeData)}
+ * method. In addition, the index of each value in the
+ * array must be distinct from the index of the other
+ * values in the array, as well as from the existing values
+ * in the table. The operation should be atomic; if one
+ * value can not be added, then none of the values should
+ * be. If the array is <code>null</code> or empty, the
+ * method simply returns.
+ *
+ * @param vals the {@link CompositeData} values to add.
+ * @throws NullPointerException if a value from the array is
+ * <code>null</code>.
+ * @throws InvalidOpenTypeException if the type of a
+ * given value does not
+ * match the row type.
+ * @throws KeyAlreadyExistsException if a value has the
+ * same calculated index
+ * as an existing value or
+ * of one of the other
+ * specified values.
+ */
+ public void putAll(CompositeData[] vals)
+ {
+ if (vals == null || vals.length == 0)
+ return;
+ Map mapToAdd = new HashMap(vals.length);
+ for (int a = 0; a < vals.length; ++a)
+ {
+ Object[] key = calculateIndex(vals[a]);
+ if (dataMap.containsKey(key))
+ throw new KeyAlreadyExistsException("Element " + a + ": A " +
+ "value with this index " +
+ "already exists.");
+ mapToAdd.put(key, vals[a]);
+ }
+ dataMap.putAll(mapToAdd);
+ }
+
+ /**
+ * Converts each value from the specified map to a member of an
+ * array of {@link CompositeData} values and adds them using {@link
+ * #put(CompositeData[])}, if possible. As in {@link
+ * #put(Object,Object)}, the keys are simply ignored. This method
+ * is useful for adding the {@link CompositeData} values from a
+ * different {@link TabularData} instance, which uses the same
+ * {@link TabularType} but a different selection of index names, to
+ * this one. If the map is <code>null</code> or empty, the method
+ * simply returns.
+ *
+ * @param m the map to add. Only the values are used and must
+ * all be instances of {@link CompositeData}.
+ * @throws NullPointerException if a value from the map is
+ * <code>null</code>.
+ * @throws ClassCastException if a value from the map is not
+ * an instance of {@link CompositeData}.
+ * @throws InvalidOpenTypeException if the type of the
+ * given value does not
+ * match the row type.
+ * @throws KeyAlreadyExistsException if the value has the
+ * same calculated index
+ * as an existing value or
+ * of one of the other
+ * specified values.
+ */
+ public void putAll(Map m)
+ {
+ if (m == null || m.size() == 0)
+ return;
+ Collection vals = m.values();
+ CompositeData[] data = new CompositeData[vals.size()];
+ Iterator it = vals.iterator();
+ for (int a = 0; it.hasNext(); ++a)
+ {
+ data[a] = (CompositeData) it.next();
+ }
+ putAll(data);
+ }
+
+ /**
+ * Removes the value for the specified key by simply
+ * calling <code>remove((Object[]) key)</code>.
+ *
+ * @param key the key whose value should be removed.
+ * @return the removed value, or <code>null</code> if
+ * there is no value for the given key.
+ * @throws NullPointerException if the key is <code>null</code>.
+ * @throws ClassCastException if the key is not an instance
+ * of <code>Object[]</code>.
+ * @throws InvalidOpenTypeException if the key does not match
+ * the {@link TabularType} of this
+ * instance.
+ */
+ public Object remove(Object key)
+ {
+ return remove((Object[]) key);
+ }
+
+ /**
+ * Removes the {@link CompositeData} value located at the
+ * specified index. <code>null</code> is returned if the
+ * value does not exist. Otherwise, the removed value is
+ * returned.
+ *
+ * @param key the key of the value to remove.
+ * @return the removed value, or <code>null</code> if
+ * there is no value for the given key.
+ * @throws NullPointerException if the key is <code>null</code>.
+ * @throws InvalidOpenTypeException if the key does not match
+ * the {@link TabularType} of this
+ * instance.
+ */
+ public CompositeData remove(Object[] key)
+ {
+ if (!(isKeyValid(key)))
+ throw new InvalidKeyException("The key does not match the " +
+ "tabular type of this instance.");
+ return (CompositeData) dataMap.remove(key);
+ }
+
+ /**
+ * Package-private method to set the internal {@link java.util.Map}
+ * instance (used in cloning).
+ *
+ * @param map the new map used.
+ */
+ void setMap(Map map)
+ {
+ dataMap = map;
+ }
+
+ /**
+ * Returns the number of {@link CompositeData} values or rows
+ * in the table.
+ *
+ * @return the number of rows in the table.
+ */
+ public int size()
+ {
+ return dataMap.size();
+ }
+
+ /**
+ * Returns a textual representation of this instance. This
+ * is constructed using the class name
+ * (<code>javax.management.openmbean.TabularDataSupport</code>)
+ * and the result of calling <code>toString()</code> on the
+ * tabular type and underlying hash map instance.
+ *
+ * @return a {@link java.lang.String} representation of the
+ * object.
+ */
+ public String toString()
+ {
+ return getClass().getName()
+ + "[tabularType=" + tabularType
+ + ",dataMap=" + dataMap
+ + "]";
+ }
+
+ /**
+ * Returns a collection (or bag) view of the values in this Map. The
+ * collection is backed by the map, so that changes in one show up in
+ * the other. Modifications made while an iterator is in progress cause
+ * undefined behavior. If the collection supports removal, these methods
+ * remove the underlying mapping from the map: <code>Iterator.remove</code>,
+ * <code>Collection.remove</code>, <code>removeAll</code>,
+ * <code>retainAll</code>, and <code>clear</code>. Element addition, via
+ * <code>add</code> or <code>addAll</code>, is not supported via this
+ * collection.
+ *
+ * @return the collection view of all values
+ */
+ public Collection values()
+ {
+ return dataMap.values();
+ }
+
+}
+
diff --git a/javax/naming/Name.java b/javax/naming/Name.java
index 18655c339..687ebd6fb 100644
--- a/javax/naming/Name.java
+++ b/javax/naming/Name.java
@@ -62,6 +62,8 @@ import java.util.Enumeration;
*/
public interface Name extends Cloneable, Serializable, Comparable<Object>
{
+ // This class is implemented as gnu.javax.naming.ictxImpl.trans.GnuName
+
long serialVersionUID = -3617482732056931635L;
/**
@@ -94,22 +96,27 @@ public interface Name extends Cloneable, Serializable, Comparable<Object>
* Returns the components till the given index as a <code>Name</code>.
* The returned <code>Name</code> can be modified without changing the
* original.
+ *
+ * @param posn the ending position, exclusive
*
* @exception ArrayIndexOutOfBoundsException if the given index is smaller
* then zero or greater then or equal to <code>size()</code>.
*/
- Name getPrefix(int i);
+ Name getPrefix(int posn);
/**
* Returns the components from the given index till the end as a
* <code>Name</code>.
* The returned <code>Name</code> can be modified without changing the
* original.
+ *
+ * @param posn the starting position, inclusive. If it is equal to the size
+ * of the name, the empty name is returned.
*
* @exception ArrayIndexOutOfBoundsException if the given index is smaller
* then zero or greater then or equal to <code>size()</code>.
*/
- Name getSuffix(int i);
+ Name getSuffix(int posn);
/**
* Adds the given <code>String</code> component to the end of this
@@ -145,7 +152,8 @@ public interface Name extends Cloneable, Serializable, Comparable<Object>
/**
* Inserts all the components of the given <code>Name</code> to this
- * <code>Name</code> at the given index. The method modifies the current
+ * <code>Name</code> at the given index. Components after this index
+ * (if any) are shifted up. The method modifies the current
* <code>Name</code> and then returns it.
*
* @exception ArrayIndexOutOfBoundsException if the given index is smaller
diff --git a/javax/naming/spi/NamingManager.java b/javax/naming/spi/NamingManager.java
index 04c119edc..3dfba0f66 100644
--- a/javax/naming/spi/NamingManager.java
+++ b/javax/naming/spi/NamingManager.java
@@ -190,9 +190,12 @@ public class NamingManager
String scheme, Hashtable<?,?> environment)
throws NamingException
{
- // Specified as the default in the docs. Unclear if this is
- // right for us.
- String defaultPrefix = "com.sun.jndi.url";
+ // Doc specifies com.sun.jndi.url as the final destination, but we cannot
+ // put our classes into such namespace.
+ String defaultPrefix = "gnu.javax.naming.jndi.url";
+
+ // The final default location, as specified in the documentation.
+ String finalPrefix = "com.sun.jndi.url";
StringBuffer allPrefixes = new StringBuffer();
@@ -215,6 +218,8 @@ public class NamingManager
if (allPrefixes.length() > 0)
allPrefixes.append(':');
allPrefixes.append(defaultPrefix);
+ allPrefixes.append(':');
+ allPrefixes.append(finalPrefix);
scheme = scheme + "." + scheme + "URLContextFactory";
@@ -228,12 +233,21 @@ public class NamingManager
Class factoryClass = forName(tryClass);
if (factoryClass != null)
{
- ObjectFactory factory = (ObjectFactory) factoryClass.newInstance();
- Object obj = factory.getObjectInstance(refInfo, name, nameCtx,
- environment);
- Context ctx = (Context) obj;
- if (ctx != null)
- return ctx;
+ Object obj;
+ try
+ {
+ ObjectFactory factory = (ObjectFactory) factoryClass.newInstance();
+ obj = factory.getObjectInstance(refInfo, name, nameCtx,
+ environment);
+ Context ctx = (Context) obj;
+ if (ctx != null)
+ return ctx;
+ }
+ catch (RuntimeException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
}
}
catch (ClassNotFoundException _1)
diff --git a/javax/swing/JMenu.java b/javax/swing/JMenu.java
index 0840509f9..68f31e335 100644
--- a/javax/swing/JMenu.java
+++ b/javax/swing/JMenu.java
@@ -40,7 +40,6 @@ package javax.swing;
import java.awt.Component;
import java.awt.Point;
-import java.awt.PopupMenu;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
@@ -99,7 +98,6 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
{
super();
setOpaque(false);
- setDelay(200);
}
/**
@@ -113,7 +111,6 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
popupMenu = new JPopupMenu();
popupMenu.setInvoker(this);
setOpaque(false);
- setDelay(200);
}
/**
@@ -129,7 +126,6 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
popupMenu = new JPopupMenu();
popupMenu.setInvoker(this);
setOpaque(false);
- setDelay(200);
}
/**
@@ -143,7 +139,6 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
{
// FIXME: tearoff not implemented
this(text);
- setDelay(200);
}
/**
@@ -342,63 +337,6 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
}
/**
- * A helper method to handle setSelected calls from both mouse events and
- * direct calls to setSelected. Direct calls shouldn't expand the popup
- * menu and should select the JMenu even if it is disabled. Mouse events
- * only select the JMenu if it is enabled and should expand the popup menu
- * associated with this JMenu.
- * @param selected whether or not the JMenu was selected
- * @param menuEnabled whether or not selecting the menu is "enabled". This
- * is always true for direct calls, and is set to isEnabled() for mouse
- * based calls.
- * @param showMenu whether or not to show the popup menu
- */
- private void setSelectedHelper(boolean selected, boolean menuEnabled, boolean showMenu)
- {
- // If menu is selected and enabled, activates the menu and
- // displays associated popup.
- if (selected && menuEnabled)
- {
- super.setArmed(true);
- super.setSelected(true);
-
- // FIXME: The popup menu should be shown on the screen after certain
- // number of seconds pass. The 'delay' property of this menu indicates
- // this amount of seconds. 'delay' property is 0 by default.
- if (isShowing())
- {
- fireMenuSelected();
-
- int x = 0;
- int y = 0;
- if (showMenu)
- if (menuLocation == null)
- {
- // Calculate correct position of the popup. Note that location of the popup
- // passed to show() should be relative to the popup's invoker
- if (isTopLevelMenu())
- y = this.getHeight();
- else
- x = this.getWidth();
- getPopupMenu().show(this, x, y);
- }
- else
- {
- getPopupMenu().show(this, menuLocation.x, menuLocation.y);
- }
- }
- }
-
- else
- {
- super.setSelected(false);
- super.setArmed(false);
- fireMenuDeselected();
- getPopupMenu().setVisible(false);
- }
- }
-
- /**
* Changes this menu selected state if selected is true and false otherwise
* This method fires menuEvents to menu's registered listeners.
*
@@ -406,7 +344,9 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public void setSelected(boolean selected)
{
- setSelectedHelper(selected, true, false);
+ ButtonModel m = getModel();
+ if (selected != m.isSelected())
+ m.setSelected(selected);
}
/**
@@ -427,8 +367,17 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public void setPopupMenuVisible(boolean popup)
{
- if (getModel().isEnabled())
- getPopupMenu().setVisible(popup);
+ if (popup != isPopupMenuVisible() && (isEnabled() || ! popup))
+ {
+ if (popup && isShowing())
+ {
+ // Set location as determined by getPopupLocation().
+ Point loc = getPopupMenuOrigin();
+ getPopupMenu().show(this, loc.x, loc.y);
+ }
+ else
+ getPopupMenu().setVisible(false);
+ }
}
/**
@@ -438,12 +387,22 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
protected Point getPopupMenuOrigin()
{
+ Point point;
+
// if menu in the menu bar
if (isTopLevelMenu())
- return new Point(0, this.getHeight());
+ point = new Point(0, this.getHeight());
- // if submenu
- return new Point(this.getWidth(), 0);
+ // if submenu
+ else
+ {
+ int xOffset = UIManager.getInt("Menu.submenuPopupOffsetX");
+ int yOffset = UIManager.getInt("Menu.submenuPopupOffsetY");
+ int x = getWidth() + xOffset;
+ int y = yOffset;
+ point = new Point(x, y);
+ }
+ return point;
}
/**
@@ -748,7 +707,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
{
// if this menu selection is true, then activate this menu and
// display popup associated with this menu
- setSelectedHelper(changed, isEnabled(), true);
+ setSelected(changed);
}
/**
diff --git a/javax/swing/JPopupMenu.java b/javax/swing/JPopupMenu.java
index d46015afd..2e59d4767 100644
--- a/javax/swing/JPopupMenu.java
+++ b/javax/swing/JPopupMenu.java
@@ -820,7 +820,14 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement
*/
public void menuSelectionChanged(boolean changed)
{
- if (! changed)
+ if (invoker instanceof JMenu)
+ {
+ // We need to special case this since the JMenu calculates the
+ // position etc of the popup.
+ JMenu menu = (JMenu) invoker;
+ menu.setPopupMenuVisible(changed);
+ }
+ else if (! changed)
setVisible(false);
}
diff --git a/javax/swing/JTree.java b/javax/swing/JTree.java
index aaf326b69..32acca643 100644
--- a/javax/swing/JTree.java
+++ b/javax/swing/JTree.java
@@ -1509,8 +1509,7 @@ public class JTree extends JComponent implements Scrollable, Accessible
public JTree(TreeModel model)
{
setRootVisible(true);
- setSelectionModel(new EmptySelectionModel());
- selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+ setSelectionModel( new DefaultTreeSelectionModel() );
// The root node appears expanded by default.
nodeStates = new Hashtable();
@@ -2050,14 +2049,16 @@ public class JTree extends JComponent implements Scrollable, Accessible
if (selectionModel == model)
return;
+ if( model == null )
+ model = EmptySelectionModel.sharedInstance();
+
if (selectionModel != null)
selectionModel.removeTreeSelectionListener(selectionRedirector);
TreeSelectionModel oldValue = selectionModel;
selectionModel = model;
- if (selectionModel != null)
- selectionModel.addTreeSelectionListener(selectionRedirector);
+ selectionModel.addTreeSelectionListener(selectionRedirector);
firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue, model);
revalidate();
diff --git a/javax/swing/Popup.java b/javax/swing/Popup.java
index 308cd662d..5074d6418 100644
--- a/javax/swing/Popup.java
+++ b/javax/swing/Popup.java
@@ -284,7 +284,7 @@ public class Popup
panel.setSize(contents.getSize());
Point layeredPaneLoc = layeredPane.getLocationOnScreen();
panel.setLocation(x - layeredPaneLoc.x, y - layeredPaneLoc.y);
- layeredPane.add(panel, JLayeredPane.POPUP_LAYER);
+ layeredPane.add(panel, JLayeredPane.POPUP_LAYER, 0);
panel.repaint();
}
diff --git a/javax/swing/SwingUtilities.java b/javax/swing/SwingUtilities.java
index 996cc2efc..2823367ce 100644
--- a/javax/swing/SwingUtilities.java
+++ b/javax/swing/SwingUtilities.java
@@ -61,6 +61,8 @@ import javax.accessibility.Accessible;
import javax.accessibility.AccessibleStateSet;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.InputMapUIResource;
+import javax.swing.plaf.basic.BasicHTML;
+import javax.swing.text.View;
/**
* A number of static utility functions which are
@@ -751,12 +753,12 @@ public class SwingUtilities
horizontalAlignment = RIGHT;
}
- return layoutCompoundLabel(fm, text, icon,
- verticalAlignment,
- horizontalAlignment,
- verticalTextPosition,
- horizontalTextPosition,
- viewR, iconR, textR, textIconGap);
+ return layoutCompoundLabelImpl(c, fm, text, icon,
+ verticalAlignment,
+ horizontalAlignment,
+ verticalTextPosition,
+ horizontalTextPosition,
+ viewR, iconR, textR, textIconGap);
}
/**
@@ -829,6 +831,82 @@ public class SwingUtilities
Rectangle textR,
int textIconGap)
{
+ return layoutCompoundLabelImpl(null, fm, text, icon, verticalAlignment,
+ horizontalAlignment, verticalTextPosition,
+ horizontalTextPosition, viewR, iconR, textR,
+ textIconGap);
+ }
+
+ /**
+ * <p>Layout a "compound label" consisting of a text string and an icon
+ * which is to be placed near the rendered text. Once the text and icon
+ * are laid out, the text rectangle and icon rectangle parameters are
+ * altered to store the calculated positions.</p>
+ *
+ * <p>The size of the text is calculated from the provided font metrics
+ * object. This object should be the metrics of the font you intend to
+ * paint the label with.</p>
+ *
+ * <p>The position values control where the text is placed relative to
+ * the icon. The horizontal position value should be one of the constants
+ * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>. The
+ * vertical position value should be one fo the constants
+ * <code>TOP</code>, <code>BOTTOM</code> or <code>CENTER</code>.</p>
+ *
+ * <p>The text-icon gap value controls the number of pixels between the
+ * icon and the text.</p>
+ *
+ * <p>The alignment values control where the text and icon are placed, as
+ * a combined unit, within the view rectangle. The horizontal alignment
+ * value should be one of the constants <code>LEFT</code>, <code>RIGHT</code> or
+ * <code>CENTER</code>. The vertical alignment valus should be one of the
+ * constants <code>TOP</code>, <code>BOTTOM</code> or
+ * <code>CENTER</code>.</p>
+ *
+ * <p>If the text and icon are equal to or larger than the view
+ * rectangle, the horizontal and vertical alignment values have no
+ * affect.</p>
+ *
+ * <p>Note that this method does <em>not</em> know how to deal with
+ * horizontal alignments or positions given as <code>LEADING</code> or
+ * <code>TRAILING</code> values. Use the other overloaded variant of this
+ * method if you wish to use such values.
+ *
+ * @param fm The font metrics used to measure the text
+ * @param text The text to place in the compound label
+ * @param icon The icon to place next to the text
+ * @param verticalAlignment The vertical alignment of the label relative
+ * to its component
+ * @param horizontalAlignment The horizontal alignment of the label
+ * relative to its component
+ * @param verticalTextPosition The vertical position of the label's text
+ * relative to its icon
+ * @param horizontalTextPosition The horizontal position of the label's
+ * text relative to its icon
+ * @param viewR The view rectangle, specifying the area which layout is
+ * constrained to
+ * @param iconR A rectangle which is modified to hold the laid-out
+ * position of the icon
+ * @param textR A rectangle which is modified to hold the laid-out
+ * position of the text
+ * @param textIconGap The distance between text and icon
+ *
+ * @return The string of characters, possibly truncated with an elipsis,
+ * which is laid out in this label
+ */
+ private static String layoutCompoundLabelImpl(JComponent c,
+ FontMetrics fm,
+ String text,
+ Icon icon,
+ int verticalAlignment,
+ int horizontalAlignment,
+ int verticalTextPosition,
+ int horizontalTextPosition,
+ Rectangle viewR,
+ Rectangle iconR,
+ Rectangle textR,
+ int textIconGap)
+ {
// Work out basic height and width.
@@ -851,13 +929,23 @@ public class SwingUtilities
}
else
{
- int fromIndex = 0;
- textR.width = fm.stringWidth(text);
- textR.height = fm.getHeight();
- while (text.indexOf('\n', fromIndex) != -1)
+ View html = c == null ? null
+ : (View) c.getClientProperty(BasicHTML.propertyKey);
+ if (html != null)
+ {
+ textR.width = (int) html.getPreferredSpan(View.X_AXIS);
+ textR.height = (int) html.getPreferredSpan(View.Y_AXIS);
+ }
+ else
{
- textR.height += fm.getHeight();
- fromIndex = text.indexOf('\n', fromIndex) + 1;
+ int fromIndex = 0;
+ textR.width = fm.stringWidth(text);
+ textR.height = fm.getHeight();
+ while (text.indexOf('\n', fromIndex) != -1)
+ {
+ textR.height += fm.getHeight();
+ fromIndex = text.indexOf('\n', fromIndex) + 1;
+ }
}
}
diff --git a/javax/swing/plaf/basic/BasicButtonListener.java b/javax/swing/plaf/basic/BasicButtonListener.java
index 848958215..042192b62 100644
--- a/javax/swing/plaf/basic/BasicButtonListener.java
+++ b/javax/swing/plaf/basic/BasicButtonListener.java
@@ -73,12 +73,12 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener,
// Store the TextLayout for this in a client property for speed-up
// painting of the label.
String property = e.getPropertyName();
+ AbstractButton b = (AbstractButton) e.getSource();
if ((property.equals(AbstractButton.TEXT_CHANGED_PROPERTY)
|| property.equals("font"))
&& SystemProperties.getProperty("gnu.javax.swing.noGraphics2D")
== null)
{
- AbstractButton b = (AbstractButton) e.getSource();
String text = b.getText();
if (text == null)
text = "";
@@ -87,6 +87,10 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener,
TextLayout layout = new TextLayout(text, b.getFont(), frc);
b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout);
}
+ if (property.equals(AbstractButton.TEXT_CHANGED_PROPERTY))
+ {
+ BasicHTML.updateRenderer(b, b.getText());
+ }
}
protected void checkOpacity(AbstractButton b)
diff --git a/javax/swing/plaf/basic/BasicButtonUI.java b/javax/swing/plaf/basic/BasicButtonUI.java
index d531133ba..cdaec2543 100644
--- a/javax/swing/plaf/basic/BasicButtonUI.java
+++ b/javax/swing/plaf/basic/BasicButtonUI.java
@@ -56,6 +56,7 @@ import javax.swing.UIManager;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
+import javax.swing.text.View;
/**
* A UI delegate for the {@link JButton} component.
@@ -255,10 +256,72 @@ public class BasicButtonUI extends ButtonUI
installDefaults(b);
installListeners(b);
installKeyboardActions(b);
+ BasicHTML.updateRenderer(b, b.getText());
}
}
/**
+ * Uninstalls the UI from the component.
+ *
+ * @param c the component from which to uninstall the UI
+ */
+ public void uninstallUI(JComponent c)
+ {
+ if (c instanceof AbstractButton)
+ {
+ AbstractButton b = (AbstractButton) c;
+ uninstallKeyboardActions(b);
+ uninstallListeners(b);
+ uninstallDefaults(b);
+ BasicHTML.updateRenderer(b, "");
+ }
+ }
+
+ /**
+ * Calculates the minimum size for the specified component.
+ *
+ * @param c the component for which to compute the minimum size
+ *
+ * @return the minimum size for the specified component
+ */
+ public Dimension getMinimumSize(JComponent c)
+ {
+ Dimension size = getPreferredSize(c);
+ // When the HTML view has a minimum width different from the preferred
+ // width, then substract this here accordingly. The height is not
+ // affected by that.
+ View html = (View) c.getClientProperty(BasicHTML.propertyKey);
+ if (html != null)
+ {
+ size.width -= html.getPreferredSpan(View.X_AXIS)
+ - html.getPreferredSpan(View.X_AXIS);
+ }
+ return size;
+ }
+
+ /**
+ * Calculates the maximum size for the specified component.
+ *
+ * @param c the component for which to compute the maximum size
+ *
+ * @return the maximum size for the specified component
+ */
+ public Dimension getMaximumSize(JComponent c)
+ {
+ Dimension size = getPreferredSize(c);
+ // When the HTML view has a maximum width different from the preferred
+ // width, then add this here accordingly. The height is not
+ // affected by that.
+ View html = (View) c.getClientProperty(BasicHTML.propertyKey);
+ if (html != null)
+ {
+ size.width += html.getMaximumSpan(View.X_AXIS)
+ - html.getPreferredSpan(View.X_AXIS);
+ }
+ return size;
+ }
+
+ /**
* Calculate the preferred size of this component, by delegating to
* {@link BasicGraphicsUtils#getPreferredButtonSize}.
*
@@ -269,8 +332,8 @@ public class BasicButtonUI extends ButtonUI
public Dimension getPreferredSize(JComponent c)
{
AbstractButton b = (AbstractButton) c;
- Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b,
- defaultTextIconGap + defaultTextShiftOffset);
+ Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b,
+ b.getIconTextGap());
return d;
}
@@ -344,7 +407,13 @@ public class BasicButtonUI extends ButtonUI
paintIcon(g, c, ir);
if (text != null)
- paintText(g, b, tr, text);
+ {
+ View html = (View) b.getClientProperty(BasicHTML.propertyKey);
+ if (html != null)
+ html.paint(g, tr);
+ else
+ paintText(g, b, tr, text);
+ }
if (b.isFocusOwner() && b.isFocusPainted())
paintFocus(g, b, vr, tr, ir);
}
diff --git a/javax/swing/plaf/basic/BasicInternalFrameUI.java b/javax/swing/plaf/basic/BasicInternalFrameUI.java
index 8f2181336..8161df29f 100644
--- a/javax/swing/plaf/basic/BasicInternalFrameUI.java
+++ b/javax/swing/plaf/basic/BasicInternalFrameUI.java
@@ -459,18 +459,12 @@ public class BasicInternalFrameUI extends InternalFrameUI
{
if (frame.isMaximum())
{
- JDesktopPane pane = (JDesktopPane) e.getSource();
- Insets insets = pane.getInsets();
- Rectangle bounds = pane.getBounds();
-
- frame.setBounds(bounds.x + insets.left, bounds.y + insets.top,
- bounds.width - insets.left - insets.right,
- bounds.height - insets.top - insets.bottom);
- frame.revalidate();
- frame.repaint();
+ Container parent = frame.getParent();
+ Insets i = parent.getInsets();
+ int width = parent.getWidth() - i.left - i.right;
+ int height = parent.getHeight() - i.top - i.bottom;
+ frame.setBounds(0, 0, width, height);
}
-
- // Sun also resizes the icons. but it doesn't seem to do anything.
}
/**
@@ -949,17 +943,25 @@ public class BasicInternalFrameUI extends InternalFrameUI
{
if (evt.getNewValue() == Boolean.TRUE)
{
+ Container parent = frame.getParent();
+ if (parent != null)
+ parent.removeComponentListener(componentListener);
closeFrame(frame);
}
}
- /*
- * FIXME: need to add ancestor properties to JComponents. else if
- * (evt.getPropertyName().equals(JComponent.ANCESTOR_PROPERTY)) { if
- * (desktopPane != null)
- * desktopPane.removeComponentListener(componentListener); desktopPane =
- * frame.getDesktopPane(); if (desktopPane != null)
- * desktopPane.addComponentListener(componentListener); }
- */
+ else if (property.equals("ancestor"))
+ {
+ Container newParent = (Container) evt.getNewValue();
+ Container oldParent = (Container) evt.getOldValue();
+ if (newParent != null)
+ {
+ newParent.addComponentListener(componentListener);
+ }
+ else if (oldParent != null)
+ {
+ oldParent.removeComponentListener(componentListener);
+ }
+ }
}
}
@@ -1258,6 +1260,12 @@ public class BasicInternalFrameUI extends InternalFrameUI
frame.addPropertyChangeListener(propertyChangeListener);
frame.getRootPane().getGlassPane().addMouseListener(glassPaneDispatcher);
frame.getRootPane().getGlassPane().addMouseMotionListener(glassPaneDispatcher);
+
+ Container parent = frame.getParent();
+ if (parent != null)
+ {
+ parent.addComponentListener(componentListener);
+ }
}
/**
@@ -1286,8 +1294,13 @@ public class BasicInternalFrameUI extends InternalFrameUI
*/
protected void uninstallListeners()
{
- if (desktopPane != null)
- desktopPane.removeComponentListener(componentListener);
+
+ Container parent = frame.getParent();
+ if (parent != null)
+ {
+ parent.removeComponentListener(componentListener);
+ }
+ componentListener = null;
frame.getRootPane().getGlassPane().removeMouseMotionListener(glassPaneDispatcher);
frame.getRootPane().getGlassPane().removeMouseListener(glassPaneDispatcher);
@@ -1298,7 +1311,7 @@ public class BasicInternalFrameUI extends InternalFrameUI
frame.removeMouseListener(borderListener);
propertyChangeListener = null;
- componentListener = null;
+
borderListener = null;
internalFrameListener = null;
glassPaneDispatcher = null;
diff --git a/javax/swing/plaf/basic/BasicMenuItemUI.java b/javax/swing/plaf/basic/BasicMenuItemUI.java
index bbc08535c..6110aca66 100644
--- a/javax/swing/plaf/basic/BasicMenuItemUI.java
+++ b/javax/swing/plaf/basic/BasicMenuItemUI.java
@@ -411,10 +411,6 @@ public class BasicMenuItemUI extends MenuItemUI
{
ArrayList path = new ArrayList();
- // Path to menu should also include its popup menu.
- if (menuItem instanceof JMenu)
- path.add(((JMenu) menuItem).getPopupMenu());
-
Component c = menuItem;
while (c instanceof MenuElement)
{
diff --git a/javax/swing/plaf/basic/BasicMenuUI.java b/javax/swing/plaf/basic/BasicMenuUI.java
index 7d8784fd1..355e0435e 100644
--- a/javax/swing/plaf/basic/BasicMenuUI.java
+++ b/javax/swing/plaf/basic/BasicMenuUI.java
@@ -41,16 +41,22 @@ package javax.swing.plaf.basic;
import gnu.classpath.NotImplementedException;
import java.awt.Component;
+import java.awt.Container;
import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
+import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPopupMenu;
import javax.swing.LookAndFeel;
+import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
+import javax.swing.Timer;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
@@ -69,6 +75,32 @@ import javax.swing.plaf.ComponentUI;
*/
public class BasicMenuUI extends BasicMenuItemUI
{
+ /**
+ * Selects a menu. This is used to delay menu selection.
+ */
+ class SelectMenuAction
+ extends AbstractAction
+ {
+ /**
+ * Performs the action.
+ */
+ public void actionPerformed(ActionEvent event)
+ {
+ JMenu menu = (JMenu) menuItem;
+ MenuSelectionManager defaultManager =
+ MenuSelectionManager.defaultManager();
+ MenuElement path[] = defaultManager.getSelectedPath();
+ if(path.length > 0 && path[path.length - 1] == menu)
+ {
+ MenuElement newPath[] = new MenuElement[path.length + 1];
+ System.arraycopy(path, 0, newPath, 0, path.length);
+ newPath[path.length] = menu.getPopupMenu();
+ defaultManager.setSelectedPath(newPath);
+ }
+ }
+
+ }
+
protected ChangeListener changeListener;
/* MenuListener listens to MenuEvents fired by JMenu */
@@ -201,6 +233,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
protected void installDefaults()
{
+
LookAndFeel.installBorder(menuItem, "Menu.border");
LookAndFeel.installColorsAndFont(menuItem, "Menu.background",
"Menu.foreground", "Menu.font");
@@ -212,6 +245,7 @@ public class BasicMenuUI extends BasicMenuItemUI
selectionForeground = UIManager.getColor("Menu.selectionForeground");
arrowIcon = UIManager.getIcon("Menu.arrowIcon");
oldBorderPainted = UIManager.getBoolean("Menu.borderPainted");
+ ((JMenu) menuItem).setDelay(200);
}
/**
@@ -234,9 +268,10 @@ public class BasicMenuUI extends BasicMenuItemUI
}
protected void setupPostTimer(JMenu menu)
- throws NotImplementedException
{
- // TODO: Implement this properly.
+ Timer timer = new Timer(menu.getDelay(), new SelectMenuAction());
+ timer.setRepeats(false);
+ timer.start();
}
/**
@@ -285,8 +320,7 @@ public class BasicMenuUI extends BasicMenuItemUI
{
public void mouseClicked(MouseEvent e)
{
- MenuSelectionManager manager = MenuSelectionManager.defaultManager();
- manager.processMouseEvent(e);
+ // Nothing to do here.
}
public void mouseDragged(MouseEvent e)
@@ -313,29 +347,46 @@ public class BasicMenuUI extends BasicMenuItemUI
public void mouseEntered(MouseEvent e)
{
- /* When mouse enters menu item, it should be considered selected
-
- if (i) if this menu is a submenu in some other menu
- (ii) or if this menu is in a menu bar and some other menu in a
- menu bar was just selected and has its popup menu visible.
- (If nothing was selected, menu should be pressed before
- it will be selected)
- */
JMenu menu = (JMenu) menuItem;
-
- // NOTE: the following if used to require !menu.isArmed but I could find
- // no reason for this and it was preventing some JDK-compatible behaviour.
- // Specifically, if a menu is selected but its popup menu not visible,
- // and then another menu is selected whose popup menu IS visible, when
- // the mouse is moved over the first menu, its popup menu should become
- // visible.
-
- if (! menu.isTopLevelMenu() || popupVisible())
+ if (menu.isEnabled())
{
- // set new selection and forward this event to MenuSelectionManager
- MenuSelectionManager manager = MenuSelectionManager.defaultManager();
- manager.setSelectedPath(getPath());
- manager.processMouseEvent(e);
+ MenuSelectionManager manager =
+ MenuSelectionManager.defaultManager();
+ MenuElement[] selectedPath = manager.getSelectedPath();
+ if (! menu.isTopLevelMenu())
+ {
+ // Open the menu immediately or delayed, depending on the
+ // delay value.
+ if(! (selectedPath.length > 0
+ && selectedPath[selectedPath.length - 1] == menu.getPopupMenu()))
+ {
+ if(menu.getDelay() == 0)
+ {
+ MenuElement[] path = getPath();
+ MenuElement[] newPath = new MenuElement[path.length + 1];
+ System.arraycopy(path, 0, newPath, 0, path.length);
+ newPath[path.length] = menu.getPopupMenu();
+ manager.setSelectedPath(newPath);
+ }
+ else
+ {
+ manager.setSelectedPath(getPath());
+ setupPostTimer(menu);
+ }
+ }
+ }
+ else
+ {
+ if(selectedPath.length > 0
+ && selectedPath[0] == menu.getParent())
+ {
+ MenuElement[] newPath = new MenuElement[3];
+ newPath[0] = (MenuElement) menu.getParent();
+ newPath[1] = menu;
+ newPath[2] = menu.getPopupMenu();
+ manager.setSelectedPath(newPath);
+ }
+ }
}
}
@@ -354,29 +405,48 @@ public class BasicMenuUI extends BasicMenuItemUI
{
MenuSelectionManager manager = MenuSelectionManager.defaultManager();
JMenu menu = (JMenu) menuItem;
- manager.processMouseEvent(e);
-
- // Menu should be displayed when the menu is pressed only if
- // it is top-level menu
- if (menu.isTopLevelMenu())
+ if (menu.isEnabled())
{
- if (menu.getPopupMenu().isVisible())
- // If menu is visible and menu button was pressed..
- // then need to cancel the menu
- manager.clearSelectedPath();
- else
- {
- // Display the menu
- int x = 0;
- int y = menu.getHeight();
-
- manager.setSelectedPath(getPath());
-
- JMenuBar mb = (JMenuBar) menu.getParent();
-
- // set selectedIndex of the selectionModel of a menuBar
- mb.getSelectionModel().setSelectedIndex(mb.getComponentIndex(menu));
- }
+ // Open up the menu immediately if it's a toplevel menu.
+ // But not yet the popup, which might be opened delayed, see below.
+ if (menu.isTopLevelMenu())
+ {
+ if (menu.isSelected())
+ manager.clearSelectedPath();
+ else
+ {
+ Container cnt = menu.getParent();
+ if (cnt != null && cnt instanceof JMenuBar)
+ {
+ MenuElement[] me = new MenuElement[2];
+ me[0] = (MenuElement) cnt;
+ me[1] = menu;
+ manager.setSelectedPath(me);
+ }
+ }
+ }
+
+ // Open the menu's popup. Either do that immediately if delay == 0,
+ // or delayed when delay > 0.
+ MenuElement[] selectedPath = manager.getSelectedPath();
+ if (selectedPath.length > 0
+ && selectedPath[selectedPath.length - 1] != menu.getPopupMenu())
+ {
+ if(menu.isTopLevelMenu() || menu.getDelay() == 0)
+ {
+ MenuElement[] newPath =
+ new MenuElement[selectedPath.length + 1];
+ System.arraycopy(selectedPath, 0, newPath, 0,
+ selectedPath.length);
+ newPath[selectedPath.length] = menu.getPopupMenu();
+ manager.setSelectedPath(newPath);
+ }
+ else
+ {
+ setupPostTimer(menu);
+ }
+ }
+
}
}
@@ -493,8 +563,44 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public void menuDragMouseDragged(MenuDragMouseEvent e)
{
- MenuSelectionManager manager = MenuSelectionManager.defaultManager();
- manager.setSelectedPath(e.getPath());
+ if (menuItem.isEnabled())
+ {
+ MenuSelectionManager manager = e.getMenuSelectionManager();
+ MenuElement path[] = e.getPath();
+
+ Point p = e.getPoint();
+ if(p.x >= 0 && p.x < menuItem.getWidth()
+ && p.y >= 0 && p.y < menuItem.getHeight())
+ {
+ JMenu menu = (JMenu) menuItem;
+ MenuElement[] selectedPath = manager.getSelectedPath();
+ if(! (selectedPath.length > 0
+ && selectedPath[selectedPath.length-1]
+ == menu.getPopupMenu()))
+ {
+ if(menu.isTopLevelMenu() || menu.getDelay() == 0
+ || e.getID() == MouseEvent.MOUSE_DRAGGED)
+ {
+ MenuElement[] newPath = new MenuElement[path.length + 1];
+ System.arraycopy(path, 0, newPath, 0, path.length);
+ newPath[path.length] = menu.getPopupMenu();
+ manager.setSelectedPath(newPath);
+ }
+ else
+ {
+ manager.setSelectedPath(path);
+ setupPostTimer(menu);
+ }
+ }
+ }
+ else if (e.getID() == MouseEvent.MOUSE_RELEASED)
+ {
+ Component comp = manager.componentForPoint(e.getComponent(),
+ e.getPoint());
+ if (comp == null)
+ manager.clearSelectedPath();
+ }
+ }
}
/**
@@ -505,8 +611,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public void menuDragMouseEntered(MenuDragMouseEvent e)
{
- MenuSelectionManager manager = MenuSelectionManager.defaultManager();
- manager.setSelectedPath(e.getPath());
+ // Nothing to do here.
}
/**
diff --git a/javax/swing/plaf/metal/MetalBorders.java b/javax/swing/plaf/metal/MetalBorders.java
index 7c41180ae..d4e3a8497 100644
--- a/javax/swing/plaf/metal/MetalBorders.java
+++ b/javax/swing/plaf/metal/MetalBorders.java
@@ -926,15 +926,11 @@ public class MetalBorders
/** The border insets. */
protected static Insets borderInsets = new Insets(1, 0, 1, 0);
- // TODO: find where this color really comes from
- private static Color borderColor = new Color(153, 153, 153);
-
/**
* Creates a new border instance.
*/
public MenuBarBorder()
{
- // Nothing to do here.
}
/**
@@ -951,7 +947,17 @@ public class MetalBorders
public void paintBorder(Component c, Graphics g, int x, int y, int w,
int h)
{
- g.setColor(borderColor);
+ // Although it is not correct to decide on the static property
+ // currentTheme which color to use the RI does it like that.
+ // The trouble is that by simply changing the current theme to
+ // e.g. DefaultMetalLookAndFeel this method will use another color
+ // although a change in painting behavior should be expected only
+ // after setting a new look and feel and updating all components.
+ if(MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)
+ g.setColor(UIManager.getColor("MenuBar.borderColor"));
+ else
+ g.setColor(MetalLookAndFeel.getControlShadow());
+
g.drawLine(x, y + h - 1, x + w, y + h - 1);
}
diff --git a/javax/swing/plaf/metal/MetalMenuBarUI.java b/javax/swing/plaf/metal/MetalMenuBarUI.java
index ff763ea9d..40661946b 100644
--- a/javax/swing/plaf/metal/MetalMenuBarUI.java
+++ b/javax/swing/plaf/metal/MetalMenuBarUI.java
@@ -1,5 +1,5 @@
/* MetalMenuBarUI.java -- MenuBar UI for the Metal L&F
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -76,12 +76,15 @@ public class MetalMenuBarUI extends BasicMenuBarUI
*/
public void update(Graphics g, JComponent c)
{
+ int height = c.getHeight();
if (c.isOpaque()
&& UIManager.get("MenuBar.gradient") != null
- && c.getBackground() instanceof UIResource)
+ && c.getBackground() instanceof UIResource
+ && height > 2)
{
- MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(),
+ MetalUtils.paintGradient(g, 0, 0, c.getWidth(), height - 2,
SwingConstants.VERTICAL, "MenuBar.gradient");
+
paint(g, c);
}
else
diff --git a/javax/swing/text/AbstractDocument.java b/javax/swing/text/AbstractDocument.java
index 200ea6742..54797fdb0 100644
--- a/javax/swing/text/AbstractDocument.java
+++ b/javax/swing/text/AbstractDocument.java
@@ -38,8 +38,11 @@ exception statement from your version. */
package javax.swing.text;
+import java.awt.font.TextAttribute;
import java.io.PrintStream;
import java.io.Serializable;
+import java.text.Bidi;
+import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.EventListener;
@@ -105,6 +108,21 @@ public abstract class AbstractDocument implements Document, Serializable
public static final String ElementNameAttribute = "$ename";
/**
+ * Standard name for the bidi root element.
+ */
+ private static final String BidiRootName = "bidi root";
+
+ /**
+ * Key for storing the asynchronous load priority.
+ */
+ private static final String AsyncLoadPriority = "load priority";
+
+ /**
+ * Key for storing the I18N state.
+ */
+ private static final String I18N = "i18n";
+
+ /**
* The actual content model of this <code>Document</code>.
*/
Content content;
@@ -158,7 +176,7 @@ public abstract class AbstractDocument implements Document, Serializable
/**
* The bidi root element.
*/
- private Element bidiRoot;
+ private BidiRootElement bidiRoot;
/**
* Creates a new <code>AbstractDocument</code> with the specified
@@ -191,12 +209,25 @@ public abstract class AbstractDocument implements Document, Serializable
content = doc;
context = ctx;
+ // FIXME: Fully implement bidi.
+ bidiRoot = new BidiRootElement();
+
// FIXME: This is determined using a Mauve test. Make the document
// actually use this.
- putProperty("i18n", Boolean.FALSE);
+ putProperty(I18N, Boolean.FALSE);
- // FIXME: Fully implement bidi.
- bidiRoot = new BranchElement(null, null);
+ // Add one child to the bidi root.
+ writeLock();
+ try
+ {
+ Element[] children = new Element[1];
+ children[0] = new BidiElement(bidiRoot, 0, 1, 0);
+ bidiRoot.replace(0, 0, children);
+ }
+ finally
+ {
+ writeUnlock();
+ }
}
/** Returns the DocumentFilter.FilterBypass instance for this
@@ -352,7 +383,11 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getAsynchronousLoadPriority()
{
- return 0;
+ Object val = getProperty(AsyncLoadPriority);
+ int prio = -1;
+ if (val != null)
+ prio = ((Integer) val).intValue();
+ return prio;
}
/**
@@ -425,14 +460,17 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public final Position getEndPosition()
{
- // FIXME: Properly implement this by calling Content.createPosition().
- return new Position()
- {
- public int getOffset()
- {
- return getLength();
- }
- };
+ Position p;
+ try
+ {
+ p = createPosition(content.length());
+ }
+ catch (BadLocationException ex)
+ {
+ // Shouldn't really happen.
+ p = null;
+ }
+ return p;
}
/**
@@ -504,14 +542,17 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public final Position getStartPosition()
{
- // FIXME: Properly implement this using Content.createPosition().
- return new Position()
- {
- public int getOffset()
- {
- return 0;
- }
- };
+ Position p;
+ try
+ {
+ p = createPosition(0);
+ }
+ catch (BadLocationException ex)
+ {
+ // Shouldn't really happen.
+ p = null;
+ }
+ return p;
}
/**
@@ -574,11 +615,19 @@ public abstract class AbstractDocument implements Document, Serializable
// Bail out if we have a bogus insertion (Behavior observed in RI).
if (text == null || text.length() == 0)
return;
-
- if (documentFilter == null)
- insertStringImpl(offset, text, attributes);
- else
- documentFilter.insertString(getBypass(), offset, text, attributes);
+
+ writeLock();
+ try
+ {
+ if (documentFilter == null)
+ insertStringImpl(offset, text, attributes);
+ else
+ documentFilter.insertString(getBypass(), offset, text, attributes);
+ }
+ finally
+ {
+ writeUnlock();
+ }
}
void insertStringImpl(int offset, String text, AttributeSet attributes)
@@ -591,23 +640,30 @@ public abstract class AbstractDocument implements Document, Serializable
new DefaultDocumentEvent(offset, text.length(),
DocumentEvent.EventType.INSERT);
- try
- {
- writeLock();
- UndoableEdit undo = content.insertString(offset, text);
- if (undo != null)
- event.addEdit(undo);
-
- insertUpdate(event, attributes);
+ UndoableEdit undo = content.insertString(offset, text);
+ if (undo != null)
+ event.addEdit(undo);
- fireInsertUpdate(event);
- if (undo != null)
- fireUndoableEditUpdate(new UndoableEditEvent(this, undo));
- }
- finally
+ // Check if we need bidi layout.
+ if (getProperty(I18N).equals(Boolean.FALSE))
{
- writeUnlock();
+ Object dir = getProperty(TextAttribute.RUN_DIRECTION);
+ if (TextAttribute.RUN_DIRECTION_RTL.equals(dir))
+ putProperty(I18N, Boolean.TRUE);
+ else
+ {
+ char[] chars = text.toCharArray();
+ if (Bidi.requiresBidi(chars, 0, chars.length))
+ putProperty(I18N, Boolean.TRUE);
+ }
}
+
+ insertUpdate(event, attributes);
+
+ fireInsertUpdate(event);
+
+ if (undo != null)
+ fireUndoableEditUpdate(new UndoableEditEvent(this, undo));
}
/**
@@ -620,7 +676,8 @@ public abstract class AbstractDocument implements Document, Serializable
*/
protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr)
{
- // Do nothing here. Subclasses may want to override this.
+ if (Boolean.TRUE.equals(getProperty(I18N)))
+ updateBidi(chng);
}
/**
@@ -632,7 +689,8 @@ public abstract class AbstractDocument implements Document, Serializable
*/
protected void postRemoveUpdate(DefaultDocumentEvent chng)
{
- // Do nothing here. Subclasses may want to override this.
+ if (Boolean.TRUE.equals(getProperty(I18N)))
+ updateBidi(chng);
}
/**
@@ -647,7 +705,317 @@ public abstract class AbstractDocument implements Document, Serializable
if (properties == null)
properties = new Hashtable();
- properties.put(key, value);
+ if (value == null)
+ properties.remove(key);
+ else
+ properties.put(key, value);
+
+ // Update bidi structure if the RUN_DIRECTION is set.
+ if (TextAttribute.RUN_DIRECTION.equals(key))
+ {
+ if (TextAttribute.RUN_DIRECTION_RTL.equals(value)
+ && Boolean.FALSE.equals(getProperty(I18N)))
+ putProperty(I18N, Boolean.TRUE);
+
+ if (Boolean.TRUE.equals(getProperty(I18N)))
+ {
+ writeLock();
+ try
+ {
+ DefaultDocumentEvent ev =
+ new DefaultDocumentEvent(0, getLength(),
+ DocumentEvent.EventType.INSERT);
+ updateBidi(ev);
+ }
+ finally
+ {
+ writeUnlock();
+ }
+ }
+ }
+ }
+
+ /**
+ * Updates the bidi element structure.
+ *
+ * @param ev the document event for the change
+ */
+ private void updateBidi(DefaultDocumentEvent ev)
+ {
+ // Determine start and end offset of the paragraphs to be scanned.
+ int start = 0;
+ int end = 0;
+ DocumentEvent.EventType type = ev.getType();
+ if (type == DocumentEvent.EventType.INSERT
+ || type == DocumentEvent.EventType.CHANGE)
+ {
+ int offs = ev.getOffset();
+ int endOffs = offs + ev.getLength();
+ start = getParagraphElement(offs).getStartOffset();
+ end = getParagraphElement(endOffs).getEndOffset();
+ }
+ else if (type == DocumentEvent.EventType.REMOVE)
+ {
+ Element par = getParagraphElement(ev.getOffset());
+ start = par.getStartOffset();
+ end = par.getEndOffset();
+ }
+ else
+ assert false : "Unknown event type";
+
+ // Determine the bidi levels for the affected range.
+ Bidi[] bidis = getBidis(start, end);
+
+ int removeFrom = 0;
+ int removeTo = 0;
+
+ int offs = 0;
+ int lastRunStart = 0;
+ int lastRunEnd = 0;
+ int lastRunLevel = 0;
+ ArrayList newEls = new ArrayList();
+ for (int i = 0; i < bidis.length; i++)
+ {
+ Bidi bidi = bidis[i];
+ int numRuns = bidi.getRunCount();
+ for (int r = 0; r < numRuns; r++)
+ {
+ if (r == 0 && i == 0)
+ {
+ if (start > 0)
+ {
+ // Try to merge with the previous element if it has the
+ // same bidi level as the first run.
+ int prevElIndex = bidiRoot.getElementIndex(start - 1);
+ removeFrom = prevElIndex;
+ Element prevEl = bidiRoot.getElement(prevElIndex);
+ AttributeSet atts = prevEl.getAttributes();
+ int prevElLevel = StyleConstants.getBidiLevel(atts);
+ if (prevElLevel == bidi.getRunLevel(r))
+ {
+ // Merge previous element with current run.
+ lastRunStart = prevEl.getStartOffset() - start;
+ lastRunEnd = bidi.getRunLimit(r);
+ lastRunLevel = bidi.getRunLevel(r);
+ }
+ else if (prevEl.getEndOffset() > start)
+ {
+ // Split previous element and replace by 2 new elements.
+ lastRunStart = 0;
+ lastRunEnd = bidi.getRunLimit(r);
+ lastRunLevel = bidi.getRunLevel(r);
+ newEls.add(new BidiElement(bidiRoot,
+ prevEl.getStartOffset(),
+ start, prevElLevel));
+ }
+ else
+ {
+ // Simply start new run at start location.
+ lastRunStart = 0;
+ lastRunEnd = bidi.getRunLimit(r);
+ lastRunLevel = bidi.getRunLevel(r);
+ removeFrom++;
+ }
+ }
+ else
+ {
+ // Simply start new run at start location.
+ lastRunStart = 0;
+ lastRunEnd = bidi.getRunLimit(r);
+ lastRunLevel = bidi.getRunLevel(r);
+ removeFrom = 0;
+ }
+ }
+ if (i == bidis.length - 1 && r == numRuns - 1)
+ {
+ if (end <= getLength())
+ {
+ // Try to merge last element with next element.
+ int nextIndex = bidiRoot.getElementIndex(end);
+ Element nextEl = bidiRoot.getElement(nextIndex);
+ AttributeSet atts = nextEl.getAttributes();
+ int nextLevel = StyleConstants.getBidiLevel(atts);
+ int level = bidi.getRunLevel(r);
+ if (lastRunLevel == level && level == nextLevel)
+ {
+ // Merge runs together.
+ if (lastRunStart + start == nextEl.getStartOffset())
+ removeTo = nextIndex - 1;
+ else
+ {
+ newEls.add(new BidiElement(bidiRoot, start + lastRunStart,
+ nextEl.getEndOffset(), level));
+ removeTo = nextIndex;
+ }
+ }
+ else if (lastRunLevel == level)
+ {
+ // Merge current and last run.
+ int endOffs = offs + bidi.getRunLimit(r);
+ newEls.add(new BidiElement(bidiRoot, start + lastRunStart,
+ start + endOffs, level));
+ if (start + endOffs == nextEl.getStartOffset())
+ removeTo = nextIndex - 1;
+ else
+ {
+ newEls.add(new BidiElement(bidiRoot, start + endOffs,
+ nextEl.getEndOffset(),
+ nextLevel));
+ removeTo = nextIndex;
+ }
+ }
+ else if (level == nextLevel)
+ {
+ // Merge current and next run.
+ newEls.add(new BidiElement(bidiRoot, start + lastRunStart,
+ start + lastRunEnd,
+ lastRunLevel));
+ newEls.add(new BidiElement(bidiRoot, start + lastRunEnd,
+ nextEl.getEndOffset(), level));
+ removeTo = nextIndex;
+ }
+ else
+ {
+ // Split next element.
+ int endOffs = offs + bidi.getRunLimit(r);
+ newEls.add(new BidiElement(bidiRoot, start + lastRunStart,
+ start + lastRunEnd,
+ lastRunLevel));
+ newEls.add(new BidiElement(bidiRoot, start + lastRunEnd,
+ start + endOffs, level));
+ newEls.add(new BidiElement(bidiRoot, start + endOffs,
+ nextEl.getEndOffset(),
+ nextLevel));
+ removeTo = nextIndex;
+ }
+ }
+ else
+ {
+ removeTo = bidiRoot.getElementIndex(end);
+ int level = bidi.getRunLevel(r);
+ int runEnd = offs + bidi.getRunLimit(r);
+
+ if (level == lastRunLevel)
+ {
+ // Merge with previous.
+ lastRunEnd = offs + runEnd;
+ newEls.add(new BidiElement(bidiRoot,
+ start + lastRunStart,
+ start + runEnd, level));
+ }
+ else
+ {
+ // Create element for last run and current run.
+ newEls.add(new BidiElement(bidiRoot, start + lastRunStart,
+ start + lastRunEnd,
+ lastRunLevel));
+ newEls.add(new BidiElement(bidiRoot,
+ start + lastRunEnd,
+ start + runEnd,
+ level));
+ }
+ }
+ }
+ else
+ {
+ int level = bidi.getRunLevel(r);
+ int runEnd = bidi.getRunLimit(r);
+
+ if (level == lastRunLevel)
+ {
+ // Merge with previous.
+ lastRunEnd = offs + runEnd;
+ }
+ else
+ {
+ // Create element for last run and update values for
+ // current run.
+ newEls.add(new BidiElement(bidiRoot, start + lastRunStart,
+ start + lastRunEnd,
+ lastRunLevel));
+ lastRunStart = lastRunEnd;
+ lastRunEnd = offs + runEnd;
+ lastRunLevel = level;
+ }
+ }
+ }
+ offs += bidi.getLength();
+ }
+
+ // Determine the bidi elements which are to be removed.
+ int numRemoved = 0;
+ if (bidiRoot.getElementCount() > 0)
+ numRemoved = removeTo - removeFrom + 1;
+ Element[] removed = new Element[numRemoved];
+ for (int i = 0; i < numRemoved; i++)
+ removed[i] = bidiRoot.getElement(removeFrom + i);
+
+ Element[] added = new Element[newEls.size()];
+ added = (Element[]) newEls.toArray(added);
+
+ // Update the event.
+ ElementEdit edit = new ElementEdit(bidiRoot, removeFrom, removed, added);
+ ev.addEdit(edit);
+
+ // Update the structure.
+ bidiRoot.replace(removeFrom, numRemoved, added);
+ }
+
+ /**
+ * Determines the Bidi objects for the paragraphs in the specified range.
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @return the Bidi analysers for the paragraphs in the range
+ */
+ private Bidi[] getBidis(int start, int end)
+ {
+ // Determine the default run direction from the document property.
+ Boolean defaultDir = null;
+ Object o = getProperty(TextAttribute.RUN_DIRECTION);
+ if (o instanceof Boolean)
+ defaultDir = (Boolean) o;
+
+ // Scan paragraphs and add their level arrays to the overall levels array.
+ ArrayList bidis = new ArrayList();
+ Segment s = new Segment();
+ for (int i = start; i < end;)
+ {
+ Element par = getParagraphElement(i);
+ int pStart = par.getStartOffset();
+ int pEnd = par.getEndOffset();
+
+ // Determine the default run direction of the paragraph.
+ Boolean dir = defaultDir;
+ o = par.getAttributes().getAttribute(TextAttribute.RUN_DIRECTION);
+ if (o instanceof Boolean)
+ dir = (Boolean) o;
+
+ // Bidi over the paragraph.
+ try
+ {
+ getText(pStart, pEnd - pStart, s);
+ }
+ catch (BadLocationException ex)
+ {
+ assert false : "Must not happen";
+ }
+ int flag = Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
+ if (dir != null)
+ {
+ if (TextAttribute.RUN_DIRECTION_LTR.equals(dir))
+ flag = Bidi.DIRECTION_LEFT_TO_RIGHT;
+ else
+ flag = Bidi.DIRECTION_RIGHT_TO_LEFT;
+ }
+ Bidi bidi = new Bidi(s.array, s.offset, null, 0, s.count, flag);
+ bidis.add(bidi);
+ i = pEnd;
+ }
+ Bidi[] ret = new Bidi[bidis.size()];
+ ret = (Bidi[]) bidis.toArray(ret);
+ return ret;
}
/**
@@ -662,6 +1030,7 @@ public abstract class AbstractDocument implements Document, Serializable
{
while (currentWriter != null || numWritersWaiting > 0)
{
+
try
{
documentCV.wait();
@@ -814,21 +1183,28 @@ public abstract class AbstractDocument implements Document, Serializable
if (length == 0
&& (text == null || text.length() == 0))
return;
-
- if (documentFilter == null)
+
+ writeLock();
+ try
{
- // It is important to call the methods which again do the checks
- // of the arguments and the DocumentFilter because subclasses may
- // have overridden these methods and provide crucial behavior
- // which would be skipped if we call the non-checking variants.
- // An example for this is PlainDocument where insertString can
- // provide a filtering of newlines.
- remove(offset, length);
- insertString(offset, text, attributes);
+ if (documentFilter == null)
+ {
+ // It is important to call the methods which again do the checks
+ // of the arguments and the DocumentFilter because subclasses may
+ // have overridden these methods and provide crucial behavior
+ // which would be skipped if we call the non-checking variants.
+ // An example for this is PlainDocument where insertString can
+ // provide a filtering of newlines.
+ remove(offset, length);
+ insertString(offset, text, attributes);
+ }
+ else
+ documentFilter.replace(getBypass(), offset, length, text, attributes);
+ }
+ finally
+ {
+ writeUnlock();
}
- else
- documentFilter.replace(getBypass(), offset, length, text, attributes);
-
}
void replaceImpl(int offset, int length, String text,
@@ -948,7 +1324,8 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public void setAsynchronousLoadPriority(int p)
{
- // TODO: Implement this properly.
+ Integer val = p >= 0 ? new Integer(p) : null;
+ putProperty(AsyncLoadPriority, val);
}
/**
@@ -1039,6 +1416,7 @@ public abstract class AbstractDocument implements Document, Serializable
public void dump(PrintStream out)
{
((AbstractElement) getDefaultRootElement()).dump(out, 0);
+ ((AbstractElement) getBidiRootElement()).dump(out, 0);
}
/**
@@ -1255,7 +1633,7 @@ public abstract class AbstractDocument implements Document, Serializable
AttributeContext ctx = getAttributeContext();
attributes = ctx.getEmptySet();
if (s != null)
- attributes = ctx.addAttributes(attributes, s);
+ addAttributes(s);
}
/**
@@ -1567,7 +1945,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public String getName()
{
- return (String) getAttribute(NameAttribute);
+ return (String) attributes.getAttribute(ElementNameAttribute);
}
/**
@@ -1644,6 +2022,11 @@ public abstract class AbstractDocument implements Document, Serializable
b.append('\n');
}
}
+ if (getAttributeCount() > 0)
+ {
+ for (int i = 0; i < indent; ++i)
+ b.append(' ');
+ }
b.append(">\n");
// Dump element content for leaf elements.
@@ -1705,6 +2088,11 @@ public abstract class AbstractDocument implements Document, Serializable
private int numChildren;
/**
+ * The last found index in getElementIndex(). Used for faster searching.
+ */
+ private int lastIndex;
+
+ /**
* Creates a new <code>BranchElement</code> with the specified
* parent and attributes.
*
@@ -1717,6 +2105,7 @@ public abstract class AbstractDocument implements Document, Serializable
super(parent, attributes);
children = new Element[1];
numChildren = 0;
+ lastIndex = -1;
}
/**
@@ -1726,7 +2115,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public Enumeration children()
{
- if (children.length == 0)
+ if (numChildren == 0)
return null;
Vector tmp = new Vector();
@@ -1785,35 +2174,73 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getElementIndex(int offset)
{
- // If offset is less than the start offset of our first child,
- // return 0
- if (offset < getStartOffset())
- return 0;
+ // Implemented using an improved linear search.
+ // This makes use of the fact that searches are not random but often
+ // close to the previous search. So we try to start the binary
+ // search at the last found index.
- // XXX: There is surely a better algorithm
- // as beginning from first element each time.
- for (int index = 0; index < numChildren - 1; ++index)
+ int i0 = 0; // The lower bounds.
+ int i1 = numChildren - 1; // The upper bounds.
+ int index = -1; // The found index.
+
+ int p0 = getStartOffset();
+ int p1; // Start and end offset local variables.
+
+ if (numChildren == 0)
+ index = 0;
+ else if (offset >= getEndOffset())
+ index = numChildren - 1;
+ else
{
- Element elem = children[index];
-
- if ((elem.getStartOffset() <= offset)
- && (offset < elem.getEndOffset()))
- return index;
- // If the next element's start offset is greater than offset
- // then we have to return the closest Element, since no Elements
- // will contain the offset
- if (children[index + 1].getStartOffset() > offset)
+ // Try lastIndex.
+ if (lastIndex >= i0 && lastIndex <= i1)
{
- if ((offset - elem.getEndOffset()) > (children[index + 1].getStartOffset() - offset))
- return index + 1;
+ Element last = getElement(lastIndex);
+ p0 = last.getStartOffset();
+ p1 = last.getEndOffset();
+ if (offset >= p0 && offset < p1)
+ index = lastIndex;
else
- return index;
+ {
+ // Narrow the search bounds using the lastIndex, even
+ // if it hasn't been a hit.
+ if (offset < p0)
+ i1 = lastIndex;
+ else
+ i0 = lastIndex;
+ }
+ }
+ // The actual search.
+ int i = 0;
+ while (i0 <= i1 && index == -1)
+ {
+ i = i0 + (i1 - i0) / 2;
+ Element el = getElement(i);
+ p0 = el.getStartOffset();
+ p1 = el.getEndOffset();
+ if (offset >= p0 && offset < p1)
+ {
+ // Found it!
+ index = i;
+ }
+ else if (offset < p0)
+ i1 = i - 1;
+ else
+ i0 = i + 1;
}
- }
- // If offset is greater than the index of the last element, return
- // the index of the last element.
- return getElementCount() - 1;
+ if (index == -1)
+ {
+ // Didn't find it. Return the boundary index.
+ if (offset < p0)
+ index = i;
+ else
+ index = i + 1;
+ }
+
+ lastIndex = index;
+ }
+ return index;
}
/**
@@ -2333,7 +2760,63 @@ public abstract class AbstractDocument implements Document, Serializable
+ getStartOffset() + "," + getEndOffset() + "\n");
}
}
-
+
+ /**
+ * The root element for bidirectional text.
+ */
+ private class BidiRootElement
+ extends BranchElement
+ {
+ /**
+ * Creates a new bidi root element.
+ */
+ BidiRootElement()
+ {
+ super(null, null);
+ }
+
+ /**
+ * Returns the name of the element.
+ *
+ * @return the name of the element
+ */
+ public String getName()
+ {
+ return BidiRootName;
+ }
+ }
+
+ /**
+ * A leaf element for the bidi structure.
+ */
+ private class BidiElement
+ extends LeafElement
+ {
+ /**
+ * Creates a new BidiElement.
+ *
+ * @param parent the parent element
+ * @param start the start offset
+ * @param end the end offset
+ * @param level the bidi level
+ */
+ BidiElement(Element parent, int start, int end, int level)
+ {
+ super(parent, new SimpleAttributeSet(), start, end);
+ addAttribute(StyleConstants.BidiLevel, new Integer(level));
+ }
+
+ /**
+ * Returns the name of the element.
+ *
+ * @return the name of the element
+ */
+ public String getName()
+ {
+ return BidiElementName;
+ }
+ }
+
/** A class whose methods delegate to the insert, remove and replace methods
* of this document which do not check for an installed DocumentFilter.
*/
diff --git a/javax/swing/text/BoxView.java b/javax/swing/text/BoxView.java
index 27e3c0f9a..7e8f19f74 100644
--- a/javax/swing/text/BoxView.java
+++ b/javax/swing/text/BoxView.java
@@ -476,8 +476,8 @@ public class BoxView
{
View child = getView(i);
min += child.getMinimumSpan(axis);
- pref = child.getPreferredSpan(axis);
- max = child.getMaximumSpan(axis);
+ pref += child.getPreferredSpan(axis);
+ max += child.getMaximumSpan(axis);
}
res.minimum = (int) min;
@@ -568,9 +568,9 @@ public class BoxView
boolean result = false;
if (myAxis == X_AXIS)
- result = x > r.x;
+ result = x > r.x + r.width;
else
- result = y > r.y;
+ result = y > r.y + r.height;
return result;
}
@@ -623,9 +623,6 @@ public class BoxView
*/
protected void childAllocation(int index, Rectangle a)
{
- if (! isAllocationValid())
- layout(a.width, a.height);
-
a.x += offsets[X_AXIS][index];
a.y += offsets[Y_AXIS][index];
a.width = spans[X_AXIS][index];
@@ -776,7 +773,7 @@ public class BoxView
View child = getView(i);
int max = (int) child.getMaximumSpan(axis);
if (max < targetSpan)
- {System.err.println("align: " + child);
+ {
// Align child when it can't be made as wide as the target span.
float align = child.getAlignment(axis);
offsets[i] = (int) ((targetSpan - max) * align);
@@ -811,7 +808,7 @@ public class BoxView
*/
public int getWidth()
{
- return span[X_AXIS];
+ return span[X_AXIS] + getLeftInset() - getRightInset();
}
/**
@@ -821,7 +818,7 @@ public class BoxView
*/
public int getHeight()
{
- return span[Y_AXIS];
+ return span[Y_AXIS] + getTopInset() - getBottomInset();
}
/**
@@ -833,7 +830,8 @@ public class BoxView
*/
public void setSize(float width, float height)
{
- layout((int) width, (int) height);
+ layout((int) (width - getLeftInset() - getRightInset()),
+ (int) (height - getTopInset() - getBottomInset()));
}
/**
@@ -1024,6 +1022,8 @@ public class BoxView
*/
private void updateRequirements(int axis)
{
+ if (axis != Y_AXIS && axis != X_AXIS)
+ throw new IllegalArgumentException("Illegal axis: " + axis);
if (! requirementsValid[axis])
{
if (axis == myAxis)
diff --git a/javax/swing/text/DefaultHighlighter.java b/javax/swing/text/DefaultHighlighter.java
index 59f77316e..69563e473 100644
--- a/javax/swing/text/DefaultHighlighter.java
+++ b/javax/swing/text/DefaultHighlighter.java
@@ -1,4 +1,4 @@
-/* DefaultHighlighter.java --
+/* DefaultHighlighter.java -- The default highlight for Swing
Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,18 +38,21 @@ exception statement from your version. */
package javax.swing.text;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Shape;
import java.util.ArrayList;
+import java.util.Iterator;
import javax.swing.SwingUtilities;
import javax.swing.plaf.TextUI;
+/**
+ * The default highlight for Swing text components. It highlights text
+ * by filling the background with a rectangle.
+ */
public class DefaultHighlighter extends LayeredHighlighter
{
public static class DefaultHighlightPainter
@@ -68,11 +71,6 @@ public class DefaultHighlighter extends LayeredHighlighter
return color;
}
- private void paintHighlight(Graphics g, Rectangle rect)
- {
- g.fillRect(rect.x, rect.y, rect.width, rect.height);
- }
-
public void paint(Graphics g, int p0, int p1, Shape bounds,
JTextComponent t)
{
@@ -81,30 +79,31 @@ public class DefaultHighlighter extends LayeredHighlighter
Rectangle rect = bounds.getBounds();
- if (color == null)
- g.setColor(t.getSelectionColor());
- else
- g.setColor(color);
+ Color col = getColor();
+ if (col == null)
+ col = t.getSelectionColor();
+ g.setColor(col);
TextUI ui = t.getUI();
try
- {
-
- Rectangle l0 = ui.modelToView(t, p0, null);
- Rectangle l1 = ui.modelToView(t, p1, null);
-
- // Note: The computed locations may lie outside of the allocation
- // area if the text is scrolled.
+ {
+
+ Rectangle l0 = ui.modelToView(t, p0, null);
+ Rectangle l1 = ui.modelToView(t, p1, null);
- if (l0.y == l1.y)
+ // Note: The computed locations may lie outside of the allocation
+ // area if the text is scrolled.
+
+ if (l0.y == l1.y)
{
SwingUtilities.computeUnion(l0.x, l0.y, l0.width, l0.height, l1);
// Paint only inside the allocation area.
- SwingUtilities.computeIntersection(rect.x, rect.y, rect.width, rect.height, l1);
+ SwingUtilities.computeIntersection(rect.x, rect.y, rect.width,
+ rect.height, l1);
- paintHighlight(g, l1);
+ g.fillRect(l1.x, l1.y, l1.width, l1.height);
}
else
{
@@ -115,77 +114,71 @@ public class DefaultHighlighter extends LayeredHighlighter
// out the bounds.
// 3. The final line is painted from the left border to the
// position of p1.
-
- // Highlight first line until the end.
- // If rect.x is non-zero the calculation will properly adjust the
- // area to be painted.
- l0.x -= rect.x;
- l0.width = rect.width - l0.x - rect.x;
-
- paintHighlight(g, l0);
-
- int posBelow = Utilities.getPositionBelow(t, p0, l0.x);
- int p1RowStart = Utilities.getRowStart(t, p1);
- if (posBelow != -1
- && posBelow != p0
- && Utilities.getRowStart(t, posBelow)
- != p1RowStart)
- {
- Rectangle grow = ui.modelToView(t, posBelow);
- grow.x = rect.x;
- grow.width = rect.width;
-
- // Find further lines which have to be highlighted completely.
- int nextPosBelow = posBelow;
- while (nextPosBelow != -1
- && Utilities.getRowStart(t, nextPosBelow) != p1RowStart)
- {
- posBelow = nextPosBelow;
- nextPosBelow = Utilities.getPositionBelow(t, posBelow, l0.x);
-
- if (nextPosBelow == posBelow)
- break;
- }
- // Now posBelow is an offset on the last line which has to be painted
- // completely. (newPosBelow is on the same line as p1)
-
- // Retrieve the rectangle of posBelow and use its y and height
- // value to calculate the final height of the multiple line
- // spanning rectangle.
- Rectangle end = ui.modelToView(t, posBelow);
- grow.height = end.y + end.height - grow.y;
-
- paintHighlight(g, grow);
- }
-
- // Paint last line from its beginning to the position of p1.
- l1.width = l1.x + l1.width - rect.x;
- l1.x = rect.x;
- paintHighlight(g, l1);
- }
+
+ int firstLineWidth = rect.x + rect.width - l0.x;
+ g.fillRect(l0.x, l0.y, firstLineWidth, l0.height);
+ if (l0.y + l0.height != l1.y)
+ {
+ g.fillRect(rect.x, l0.y + l0.height, rect.width,
+ l1.y - l0.y - l0.height);
+ }
+ g.fillRect(rect.x, l1.y, l1.x - rect.x, l1.height);
+ }
}
catch (BadLocationException ex)
{
- AssertionError err = new AssertionError("Unexpected bad location exception");
- err.initCause(ex);
- throw err;
+ // Can't render. Comment out for debugging.
+ // ex.printStackTrace();
}
}
public Shape paintLayer(Graphics g, int p0, int p1, Shape bounds,
JTextComponent c, View view)
{
- throw new InternalError();
+ Color col = getColor();
+ if (col == null)
+ col = c.getSelectionColor();
+ g.setColor(col);
+
+ Rectangle rect = null;
+ if (p0 == view.getStartOffset() && p1 == view.getEndOffset())
+ {
+ // Paint complete bounds region.
+ rect = bounds instanceof Rectangle ? (Rectangle) bounds
+ : bounds.getBounds();
+ }
+ else
+ {
+ // Only partly inside the view.
+ try
+ {
+ Shape s = view.modelToView(p0, Position.Bias.Forward,
+ p1, Position.Bias.Backward,
+ bounds);
+ rect = s instanceof Rectangle ? (Rectangle) s : s.getBounds();
+ }
+ catch (BadLocationException ex)
+ {
+ // Can't render the highlight.
+ }
+ }
+
+ if (rect != null)
+ {
+ g.fillRect(rect.x, rect.y, rect.width, rect.height);
+ }
+ return rect;
}
}
private class HighlightEntry implements Highlighter.Highlight
{
- int p0;
- int p1;
+ Position p0;
+ Position p1;
Highlighter.HighlightPainter painter;
- public HighlightEntry(int p0, int p1, Highlighter.HighlightPainter painter)
+ public HighlightEntry(Position p0, Position p1,
+ Highlighter.HighlightPainter painter)
{
this.p0 = p0;
this.p1 = p1;
@@ -194,12 +187,12 @@ public class DefaultHighlighter extends LayeredHighlighter
public int getStartOffset()
{
- return p0;
+ return p0.getOffset();
}
public int getEndOffset()
{
- return p1;
+ return p1.getOffset();
}
public Highlighter.HighlightPainter getPainter()
@@ -209,6 +202,58 @@ public class DefaultHighlighter extends LayeredHighlighter
}
/**
+ * A HighlightEntry that is used for LayerPainter painters. In addition
+ * to the info maintained by the HighlightEntry, this class maintains
+ * a painting rectangle. This is used as repaint region when the
+ * highlight changes and the text component needs repainting.
+ */
+ private class LayerHighlightEntry
+ extends HighlightEntry
+ {
+
+ /**
+ * The paint rectangle.
+ */
+ Rectangle paintRect = new Rectangle();
+
+ LayerHighlightEntry(Position p0, Position p1,
+ Highlighter.HighlightPainter p)
+ {
+ super(p0, p1, p);
+ }
+
+ /**
+ * Paints the highlight by calling the LayerPainter. This
+ * restricts the area to be painted by startOffset and endOffset
+ * and manages the paint rectangle.
+ */
+ void paintLayeredHighlight(Graphics g, int p0, int p1, Shape bounds,
+ JTextComponent tc, View view)
+ {
+ p0 = Math.max(getStartOffset(), p0);
+ p1 = Math.min(getEndOffset(), p1);
+
+ Highlighter.HighlightPainter painter = getPainter();
+ if (painter instanceof LayerPainter)
+ {
+ LayerPainter layerPainter = (LayerPainter) painter;
+ Shape area = layerPainter.paintLayer(g, p0, p1, bounds, tc, view);
+ Rectangle rect;
+ if (area instanceof Rectangle && paintRect != null)
+ rect = (Rectangle) area;
+ else
+ rect = area.getBounds();
+
+ if (paintRect.width == 0 || paintRect.height == 0)
+ paintRect = rect.getBounds();
+ else
+ paintRect = SwingUtilities.computeUnion(rect.x, rect.y, rect.width,
+ rect.height, paintRect);
+ }
+ }
+ }
+
+ /**
* @specnote final as of 1.4
*/
public static final LayeredHighlighter.LayerPainter DefaultPainter =
@@ -254,11 +299,19 @@ public class DefaultHighlighter extends LayeredHighlighter
textComponent = null;
}
- public Object addHighlight(int p0, int p1, Highlighter.HighlightPainter painter)
+ public Object addHighlight(int p0, int p1,
+ Highlighter.HighlightPainter painter)
throws BadLocationException
{
checkPositions(p0, p1);
- HighlightEntry entry = new HighlightEntry(p0, p1, painter);
+ HighlightEntry entry;
+ Document doc = textComponent.getDocument();
+ Position pos0 = doc.createPosition(p0);
+ Position pos1 = doc.createPosition(p1);
+ if (getDrawsLayeredHighlights() && painter instanceof LayerPainter)
+ entry = new LayerHighlightEntry(pos0, pos1, painter);
+ else
+ entry = new HighlightEntry(pos0, pos1, painter);
highlights.add(entry);
textComponent.getUI().damageRange(textComponent, p0, p1);
@@ -268,16 +321,67 @@ public class DefaultHighlighter extends LayeredHighlighter
public void removeHighlight(Object tag)
{
+ HighlightEntry entry = (HighlightEntry) tag;
+ if (entry instanceof LayerHighlightEntry)
+ {
+ LayerHighlightEntry lEntry = (LayerHighlightEntry) entry;
+ Rectangle paintRect = lEntry.paintRect;
+ textComponent.repaint(paintRect.x, paintRect.y, paintRect.width,
+ paintRect.height);
+ }
+ else
+ {
+ textComponent.getUI().damageRange(textComponent,
+ entry.getStartOffset(),
+ entry.getEndOffset());
+ }
highlights.remove(tag);
- HighlightEntry entry = (HighlightEntry) tag;
- textComponent.getUI().damageRange(textComponent,
- entry.p0,
- entry.p1);
}
public void removeAllHighlights()
{
+ // Repaint damaged region.
+ int minX = 0;
+ int maxX = 0;
+ int minY = 0;
+ int maxY = 0;
+ int p0 = -1;
+ int p1 = -1;
+ for (Iterator i = highlights.iterator(); i.hasNext();)
+ {
+ HighlightEntry e = (HighlightEntry) i.next();
+ if (e instanceof LayerHighlightEntry)
+ {
+ LayerHighlightEntry le = (LayerHighlightEntry) e;
+ Rectangle r = le.paintRect;
+ minX = Math.min(r.x, minX);
+ maxX = Math.max(r.x + r.width, maxX);
+ minY = Math.min(r.y, minY);
+ maxY = Math.max(r.y + r.height, maxY);
+ }
+ else
+ {
+ if (p0 == -1 || p1 == -1)
+ {
+ p0 = e.getStartOffset();
+ p1 = e.getEndOffset();
+ }
+ else
+ {
+ p0 = Math.min(p0, e.getStartOffset());
+ p1 = Math.max(p1, e.getEndOffset());
+ }
+ }
+ if (minX != maxX && minY != maxY)
+ textComponent.repaint(minX, minY, maxX - minX, maxY - minY);
+ if (p0 != -1 && p1 != -1)
+ {
+ TextUI ui = textComponent.getUI();
+ ui.damageRange(textComponent, p0, p1);
+ }
+
+ }
highlights.clear();
}
@@ -290,94 +394,61 @@ public class DefaultHighlighter extends LayeredHighlighter
public void changeHighlight(Object tag, int n0, int n1)
throws BadLocationException
{
- int o0, o1;
-
- checkPositions(n0, n1);
- HighlightEntry entry = (HighlightEntry) tag;
- o0 = entry.p0;
- o1 = entry.p1;
-
- // Prevent useless write & repaint operations.
- if (o0 == n0 && o1 == n1)
- return;
-
- entry.p0 = n0;
- entry.p1 = n1;
-
+ Document doc = textComponent.getDocument();
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))
+ if (tag instanceof LayerHighlightEntry)
{
- // [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)
+ LayerHighlightEntry le = (LayerHighlightEntry) tag;
+ Rectangle r = le.paintRect;
+ if (r.width > 0 && r.height > 0)
+ textComponent.repaint(r.x, r.y, r.width, r.height);
+ r.width = 0;
+ r.height = 0;
+ le.p0 = doc.createPosition(n0);
+ le.p1 = doc.createPosition(n1);
+ ui.damageRange(textComponent, Math.min(n0, n1), Math.max(n0, n1));
+ }
+ else if (tag instanceof HighlightEntry)
+ {
+ HighlightEntry e = (HighlightEntry) tag;
+ int p0 = e.getStartOffset();
+ int p1 = e.getEndOffset();
+ if (p0 == n0)
{
- // Final region will be painted as the
- // old highlight region finishes first
- sds = o1;
- sde = n1;
+ ui.damageRange(textComponent, Math.min(p1, n1),
+ Math.max(p1, n1));
}
- else
+ else if (n1 == p1)
{
- // Final region will be cleared as the
- // new highlight region finishes first.
- sds = n1;
- sde = o1;
+ ui.damageRange(textComponent, Math.min(p0, n0),
+ Math.max(p0, n0));
}
-
- // 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);
+ ui.damageRange(textComponent, p0, p1);
+ ui.damageRange(textComponent, n0, n1);
}
+ e.p0 = doc.createPosition(n0);
+ e.p1 = doc.createPosition(n1);
}
- 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,
Shape viewBounds, JTextComponent editor,
View view)
- throws NotImplementedException
{
- // TODO: Implement this properly.
+ for (Iterator i = highlights.iterator(); i.hasNext();)
+ {
+ Object o = i.next();
+ if (o instanceof LayerHighlightEntry)
+ {
+ LayerHighlightEntry entry = (LayerHighlightEntry) o;
+ int start = entry.getStartOffset();
+ int end = entry.getEndOffset();
+ if ((p0 < start && p1 > start) || (p0 >= start && p0 < end))
+ entry.paintLayeredHighlight(g, p0, p1, viewBounds, editor, view);
+ }
+ }
}
public void paint(Graphics g)
@@ -399,7 +470,9 @@ public class DefaultHighlighter extends LayeredHighlighter
for (int index = 0; index < size; ++index)
{
HighlightEntry entry = (HighlightEntry) highlights.get(index);
- entry.painter.paint(g, entry.p0, entry.p1, bounds, textComponent);
+ if (! (entry instanceof LayerHighlightEntry))
+ entry.painter.paint(g, entry.getStartOffset(), entry.getEndOffset(),
+ bounds, textComponent);
}
}
}
diff --git a/javax/swing/text/DefaultStyledDocument.java b/javax/swing/text/DefaultStyledDocument.java
index 8aee51e5c..5705bde17 100644
--- a/javax/swing/text/DefaultStyledDocument.java
+++ b/javax/swing/text/DefaultStyledDocument.java
@@ -41,7 +41,9 @@ package javax.swing.text;
import java.awt.Color;
import java.awt.Font;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Enumeration;
+import java.util.Iterator;
import java.util.Stack;
import java.util.Vector;
@@ -424,6 +426,58 @@ public class DefaultStyledDocument extends AbstractDocument implements
*/
public class ElementBuffer implements Serializable
{
+ /**
+ * 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. */
+ ArrayList removed = new ArrayList();
+
+ /** The added elements. */
+ ArrayList added = new ArrayList();
+
+ /**
+ * Indicates if this edit contains a fracture.
+ */
+ boolean isFracture;
+
+ /**
+ * Creates a new Edit for the specified element at index i.
+ *
+ * @param el the element
+ * @param i the index
+ */
+ Edit(Element el, int i)
+ {
+ this(el, i, false);
+ }
+
+ /**
+ * Creates a new Edit for the specified element at index i.
+ *
+ * @param el the element
+ * @param i the index
+ * @param frac if this is a fracture edit or not
+ */
+ Edit(Element el, int i, boolean frac)
+ {
+ e = el;
+ index = i;
+ isFracture = frac;
+ }
+
+ }
+
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = 1688745877691146623L;
@@ -442,11 +496,25 @@ public class DefaultStyledDocument extends AbstractDocument implements
/** Holds the position of the change. */
private int pos;
- /** 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 ElementChange that describes the latest changes.
+ */
+ private DefaultDocumentEvent documentEvent;
+
+ /**
+ * The parent of the fracture.
+ */
+ private Element fracturedParent;
+
+ /**
+ * The fractured child.
+ */
+ private Element fracturedChild;
+
+ /**
+ * Indicates if a fracture has been created.
+ */
+ private boolean createdFracture;
/**
* The current position in the element tree. This is used for bulk inserts
@@ -454,10 +522,17 @@ public class DefaultStyledDocument extends AbstractDocument implements
*/
private Stack elementStack;
+ private Edit[] insertPath;
+
+ private boolean recreateLeafs;
+
/**
- * The ElementChange that describes the latest changes.
+ * Vector that contains all the edits. Maybe replace by a HashMap.
*/
- DefaultDocumentEvent documentEvent;
+ private ArrayList edits;
+
+ private boolean offsetLastIndex;
+ private boolean offsetLastIndexReplace;
/**
* Creates a new <code>ElementBuffer</code> for the specified
@@ -469,7 +544,6 @@ public class DefaultStyledDocument extends AbstractDocument implements
public ElementBuffer(Element root)
{
this.root = root;
- elementStack = new Stack();
}
/**
@@ -495,13 +569,9 @@ public class DefaultStyledDocument extends AbstractDocument implements
*/
public void remove(int offs, int len, DefaultDocumentEvent ev)
{
- if (len == 0)
- return;
- offset = offs;
- length = len;
- pos = offset;
- documentEvent = ev;
+ prepareEdit(offs, len);
removeUpdate();
+ finishEdit(ev);
}
/**
@@ -511,109 +581,241 @@ public class DefaultStyledDocument extends AbstractDocument implements
*/
protected void removeUpdate()
{
- int startParagraph = root.getElementIndex(offset);
- int endParagraph = root.getElementIndex(offset + length);
- Element[] empty = new Element[0];
- int removeStart = -1;
- int removeEnd = -1;
- for (int i = startParagraph; i < endParagraph; i++)
+ removeElements(root, offset, endOffset);
+ }
+
+ private boolean removeElements(Element elem, int rmOffs0, int rmOffs1)
+ {
+ boolean ret = false;
+ if (! elem.isLeaf())
{
- BranchElement paragraph = (BranchElement) root.getElement(i);
- int contentStart = paragraph.getElementIndex(offset);
- int contentEnd = paragraph.getElementIndex(offset + length);
- if (contentStart == paragraph.getStartOffset()
- && contentEnd == paragraph.getEndOffset())
+ // Update stack for changes.
+ int index0 = elem.getElementIndex(rmOffs0);
+ int index1 = elem.getElementIndex(rmOffs1);
+ elementStack.push(new Edit(elem, index0));
+ Edit ec = (Edit) elementStack.peek();
+
+ // If the range is contained by one element,
+ // we just forward the request
+ if (index0 == index1)
{
- // In this case we only need to remove the whole paragraph. We
- // do this in one go after this loop and only record the indices
- // here.
- if (removeStart == -1)
+ Element child0 = elem.getElement(index0);
+ if(rmOffs0 <= child0.getStartOffset()
+ && rmOffs1 >= child0.getEndOffset())
{
- removeStart = i;
- removeEnd = i;
+ // Element totally removed.
+ ec.removed.add(child0);
+ }
+ else if (removeElements(child0, rmOffs0, rmOffs1))
+ {
+ ec.removed.add(child0);
}
- else
- removeEnd = i;
}
else
{
- // In this case we remove a couple of child elements from this
- // paragraph.
- int removeLen = contentEnd - contentStart;
- Element[] removed = new Element[removeLen];
- for (int j = contentStart; j < contentEnd; j++)
- removed[j] = paragraph.getElement(j);
- Edit edit = getEditForParagraphAndIndex(paragraph, contentStart);
- edit.addRemovedElements(removed);
+ // The removal range spans elements. If we can join
+ // the two endpoints, do it. Otherwise we remove the
+ // interior and forward to the endpoints.
+ Element child0 = elem.getElement(index0);
+ Element child1 = elem.getElement(index1);
+ boolean containsOffs1 = (rmOffs1 < elem.getEndOffset());
+ if (containsOffs1 && canJoin(child0, child1))
+ {
+ // Remove and join.
+ for (int i = index0; i <= index1; i++)
+ {
+ ec.removed.add(elem.getElement(i));
+ }
+ Element e = join(elem, child0, child1, rmOffs0, rmOffs1);
+ ec.added.add(e);
+ }
+ else
+ {
+ // Remove interior and forward.
+ int rmIndex0 = index0 + 1;
+ int rmIndex1 = index1 - 1;
+ if (child0.getStartOffset() == rmOffs0
+ || (index0 == 0 && child0.getStartOffset() > rmOffs0
+ && child0.getEndOffset() <= rmOffs1))
+ {
+ // Start element completely consumed.
+ child0 = null;
+ rmIndex0 = index0;
+ }
+ if (! containsOffs1)
+ {
+ child1 = null;
+ rmIndex1++;
+ }
+ else if (child1.getStartOffset() == rmOffs1)
+ {
+ // End element not touched.
+ child1 = null;
+ }
+ if (rmIndex0 <= rmIndex1)
+ {
+ ec.index = rmIndex0;
+ }
+ for (int i = rmIndex0; i <= rmIndex1; i++)
+ {
+ ec.removed.add(elem.getElement(i));
+ }
+ if (child0 != null)
+ {
+ if(removeElements(child0, rmOffs0, rmOffs1))
+ {
+ ec.removed.add(0, child0);
+ ec.index = index0;
+ }
+ }
+ if (child1 != null)
+ {
+ if(removeElements(child1, rmOffs0, rmOffs1))
+ {
+ ec.removed.add(child1);
+ }
+ }
}
+ }
+
+ // Perform changes.
+ pop();
+
+ // Return true if we no longer have any children.
+ if(elem.getElementCount() == (ec.removed.size() - ec.added.size()))
+ ret = true;
}
- // Now we remove paragraphs from the root that have been tagged for
- // removal.
- if (removeStart != -1)
+ return ret;
+ }
+
+ private boolean canJoin(Element e0, Element e1)
+ {
+ boolean ret = false;
+ if ((e0 != null) && (e1 != null))
{
- int removeLen = removeEnd - removeStart;
- Element[] removed = new Element[removeLen];
- for (int i = removeStart; i < removeEnd; i++)
- removed[i] = root.getElement(i);
- Edit edit = getEditForParagraphAndIndex((BranchElement) root,
- removeStart);
- edit.addRemovedElements(removed);
+ // Don't join a leaf to a branch.
+ boolean isLeaf0 = e0.isLeaf();
+ boolean isLeaf1 = e1.isLeaf();
+ if(isLeaf0 == isLeaf1)
+ {
+ if (isLeaf0)
+ {
+ // Only join leaves if the attributes match, otherwise
+ // style information will be lost.
+ ret = e0.getAttributes().isEqual(e1.getAttributes());
+ }
+ else
+ {
+ // Only join non-leafs if the names are equal. This may result
+ // in loss of style information, but this is typically
+ // acceptable for non-leafs.
+ String name0 = e0.getName();
+ String name1 = e1.getName();
+ if (name0 != null)
+ ret = name0.equals(name1);
+ else if (name1 != null)
+ ret = name1.equals(name0);
+ else // Both names null.
+ ret = true;
+ }
+ }
}
+ return ret;
}
- /**
- * 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()
+ private Element join(Element p, Element left, Element right, int rmOffs0,
+ int rmOffs1)
{
- // Split up the element at the start offset if necessary.
- Element el = getCharacterElement(offset);
- 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)
+ Element joined = null;
+ if (left.isLeaf() && right.isLeaf())
+ {
+ joined = createLeafElement(p, left.getAttributes(),
+ left.getStartOffset(),
+ right.getEndOffset());
+ }
+ else if ((! left.isLeaf()) && (! right.isLeaf()))
{
- Element[] removed;
- Element[] added;
- if (res[0] == null)
+ // Join two branch elements. This copies the children before
+ // the removal range on the left element, and after the removal
+ // range on the right element. The two elements on the edge
+ // are joined if possible and needed.
+ joined = createBranchElement(p, left.getAttributes());
+ int ljIndex = left.getElementIndex(rmOffs0);
+ int rjIndex = right.getElementIndex(rmOffs1);
+ Element lj = left.getElement(ljIndex);
+ if (lj.getStartOffset() >= rmOffs0)
+ {
+ lj = null;
+ }
+ Element rj = right.getElement(rjIndex);
+ if (rj.getStartOffset() == rmOffs1)
+ {
+ rj = null;
+ }
+ ArrayList children = new ArrayList();
+ // Transfer the left.
+ for (int i = 0; i < ljIndex; i++)
+ {
+ children.add(clone(joined, left.getElement(i)));
+ }
+
+ // Transfer the join/middle.
+ if (canJoin(lj, rj))
{
- removed = new Element[0];
- added = new Element[] { res[1] };
- index++;
+ Element e = join(joined, lj, rj, rmOffs0, rmOffs1);
+ children.add(e);
}
else
{
- removed = new Element[] { el };
- added = new Element[] { res[0], res[1] };
+ if (lj != null)
+ {
+ children.add(cloneAsNecessary(joined, lj, rmOffs0, rmOffs1));
+ }
+ if (rj != null)
+ {
+ children.add(cloneAsNecessary(joined, rj, rmOffs0, rmOffs1));
+ }
+ }
+
+ // Transfer the right.
+ int n = right.getElementCount();
+ for (int i = (rj == null) ? rjIndex : rjIndex + 1; i < n; i++)
+ {
+ children.add(clone(joined, right.getElement(i)));
}
- edit.addRemovedElements(removed);
- edit.addAddedElements(added);
+ // Install the children.
+ Element[] c = new Element[children.size()];
+ c = (Element[]) children.toArray(c);
+ ((BranchElement) joined).replace(0, 0, c);
+ }
+ else
+ {
+ assert false : "Must not happen";
}
+ return joined;
+ }
- int endOffset = offset + length;
- el = getCharacterElement(endOffset);
- res = split(el, endOffset, 0, el.getElementIndex(endOffset));
- par = (BranchElement) el.getParentElement();
- if (res[0] != null)
+ /**
+ * 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()
+ {
+ boolean didEnd = split(offset, length);
+ if (! didEnd)
{
- Element[] removed;
- Element[] added;
- if (res[1] == null)
- {
- removed = new Element[0];
- added = new Element[] { res[1] };
- }
- else
+ // need to do the other end
+ while (elementStack.size() != 0)
{
- removed = new Element[] { el };
- added = new Element[] { res[0], res[1] };
+ pop();
}
- edit.addRemovedElements(removed);
- edit.addAddedElements(added);
+ split(offset + length, 0);
+ }
+ while (elementStack.size() != 0)
+ {
+ pop();
}
}
@@ -683,6 +885,39 @@ public class DefaultStyledDocument extends AbstractDocument implements
return clone;
}
+ private Element cloneAsNecessary(Element parent, Element clonee,
+ int rmOffs0, int rmOffs1)
+ {
+ Element cloned;
+ if (clonee.isLeaf())
+ {
+ cloned = createLeafElement(parent, clonee.getAttributes(),
+ clonee.getStartOffset(),
+ clonee.getEndOffset());
+ }
+ else
+ {
+ Element e = createBranchElement(parent, clonee.getAttributes());
+ int n = clonee.getElementCount();
+ ArrayList childrenList = new ArrayList(n);
+ for (int i = 0; i < n; i++)
+ {
+ Element elem = clonee.getElement(i);
+ if (elem.getStartOffset() < rmOffs0
+ || elem.getEndOffset() > rmOffs1)
+ {
+ childrenList.add(cloneAsNecessary(e, elem, rmOffs0,
+ rmOffs1));
+ }
+ }
+ Element[] children = new Element[childrenList.size()];
+ children = (Element[]) childrenList.toArray(children);
+ ((BranchElement) e).replace(0, 0, children);
+ cloned = e;
+ }
+ return cloned;
+ }
+
/**
* Inserts new <code>Element</code> in the document at the specified
* position. Most of the work is done by {@link #insertUpdate}, after some
@@ -701,70 +936,98 @@ public class DefaultStyledDocument extends AbstractDocument implements
public void insert(int offset, int length, ElementSpec[] data,
DefaultDocumentEvent ev)
{
- if (length == 0)
- return;
-
+ if (length > 0)
+ {
+ prepareEdit(offset, length);
+ insertUpdate(data);
+ finishEdit(ev);
+ }
+ }
+
+ /**
+ * Prepares the state of this object for performing an insert.
+ *
+ * @param offset the offset at which is inserted
+ * @param length the length of the inserted region
+ */
+ private void prepareEdit(int offset, int length)
+ {
this.offset = offset;
this.pos = offset;
this.endOffset = offset + length;
this.length = length;
- documentEvent = ev;
-
- edits.removeAllElements();
- elementStack.removeAllElements();
- lastFractured = null;
- fracNotCreated = false;
- insertUpdate(data);
+
+ if (edits == null)
+ edits = new ArrayList();
+ else
+ edits.clear();
+
+ if (elementStack == null)
+ elementStack = new Stack();
+ else
+ elementStack.clear();
+
+ fracturedParent = null;
+ fracturedChild = null;
+ offsetLastIndex = false;
+ offsetLastIndexReplace = false;
+ }
+
+ /**
+ * Finishes an insert. This applies all changes and updates
+ * the DocumentEvent.
+ *
+ * @param ev the document event
+ */
+ private void finishEdit(DefaultDocumentEvent ev)
+ {
// 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);
- }
- }
- }
+ for (Iterator i = edits.iterator(); i.hasNext();)
+ {
+ Edit edits = (Edit) i.next();
+ Element[] removed = new Element[edits.removed.size()];
+ removed = (Element[]) edits.removed.toArray(removed);
+ Element[] added = new Element[edits.added.size()];
+ added = (Element[]) edits.added.toArray(added);
+ int index = edits.index;
+ BranchElement parent = (BranchElement) edits.e;
+ parent.replace(index, removed.length, added);
+ ElementEdit ee = new ElementEdit(parent, index, removed, added);
+ ev.addEdit(ee);
+ }
}
/**
- * Inserts new content
+ * Inserts new content.
*
- * @param data
- * the element specifications for the elements to be inserted
+ * @param data the element specifications for the elements to be inserted
*/
protected void insertUpdate(ElementSpec[] data)
{
- // Push the root and the paragraph at offset onto the element stack.
+ // Push the current path to the stack.
Element current = root;
- int index;
- while (!current.isLeaf())
+ int index = current.getElementIndex(offset);
+ while (! current.isLeaf())
{
+ Element child = current.getElement(index);
+ int editIndex = child.isLeaf() ? index : index + 1;
+ Edit edit = new Edit(current, editIndex);
+ elementStack.push(edit);
+ current = child;
index = current.getElementIndex(offset);
- elementStack.push(current);
- current = current.getElement(index);
}
-
+
+ // Create a copy of the original path.
+ insertPath = new Edit[elementStack.size()];
+ insertPath = (Edit[]) elementStack.toArray(insertPath);
+
+ // No fracture yet.
+ createdFracture = false;
+
+ // Insert first content tag.
int i = 0;
+ recreateLeafs = false;
int type = data[0].getType();
if (type == ElementSpec.ContentType)
{
@@ -784,123 +1047,129 @@ public class DefaultStyledDocument extends AbstractDocument implements
// Handle each ElementSpec individually.
for (; i < data.length; i++)
{
- BranchElement paragraph = (BranchElement) elementStack.peek();
- switch (data[i].getType())
+ insertElement(data[i]);
+ }
+
+ // Fracture if we haven't done yet.
+ if (! createdFracture)
+ fracture(-1);
+
+ // Pop the remaining stack.
+ while (elementStack.size() != 0)
+ pop();
+
+ // Offset last index if necessary.
+ if (offsetLastIndex && offsetLastIndexReplace)
+ insertPath[insertPath.length - 1].index++;
+
+ // Make sure we havea an Edit for each path item that has a change.
+ for (int p = insertPath.length - 1; p >= 0; p--)
+ {
+ Edit edit = insertPath[p];
+ if (edit.e == fracturedParent)
+ edit.added.add(fracturedChild);
+ if ((edit.added.size() > 0 || edit.removed.size() > 0)
+ && ! edits.contains(edit))
+ edits.add(edit);
+ }
+
+ // Remove element that would be created by an insert at 0 with
+ // an initial end tag.
+ if (offset == 0 && fracturedParent != null
+ && data[0].getType() == ElementSpec.EndTagType)
+ {
+ for (int p = 0;
+ p < data.length && data[p].getType() == ElementSpec.EndTagType;
+ p++)
{
- case ElementSpec.StartTagType:
- 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:
- // 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;
- case ElementSpec.EndTagType:
- elementStack.pop();
- break;
- case ElementSpec.ContentType:
- insertContentTag(data[i]);
- offset = pos;
- break;
+ Edit edit = insertPath[insertPath.length - p - 1];
+ edit.index--;
+ edit.removed.add(0, edit.e.getElement(edit.index));
}
}
}
-
- /**
- * Inserts a new paragraph.
- *
- * @param par -
- * the parent
- * @param offset -
- * the offset
- * @return the new paragraph
- */
- private Element insertParagraph(BranchElement par, int offset)
+
+ private void pop()
+ {
+ Edit edit = (Edit) elementStack.peek();
+ elementStack.pop();
+ if ((edit.added.size() > 0) || (edit.removed.size() > 0))
+ {
+ edits.add(edit);
+ }
+ else if (! elementStack.isEmpty())
+ {
+ Element e = edit.e;
+ if (e.getElementCount() == 0)
+ {
+ // If we pushed a branch element that didn't get
+ // used, make sure its not marked as having been added.
+ edit = (Edit) elementStack.peek();
+ edit.added.remove(e);
+ }
+ }
+ }
+
+ private void insertElement(ElementSpec spec)
{
- 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)
+ Edit edit = (Edit) elementStack.peek();
+ switch (spec.getType())
{
- Element[] removed;
- Element[] added;
- if (res[0] == null)
+ case ElementSpec.StartTagType:
+ switch (spec.getDirection())
{
- removed = new Element[0];
- if (res[1] instanceof BranchElement)
+ case ElementSpec.JoinFractureDirection:
+ // Fracture the tree and ensure the appropriate element
+ // is on top of the stack.
+ if (! createdFracture)
{
- added = new Element[] { res[1] };
- ret = res[1];
+ fracture(elementStack.size() - 1);
}
- else
+ if (! edit.isFracture)
{
- ret = createBranchElement(par, null);
- added = new Element[] { ret, res[1] };
+ // If the parent isn't a fracture, then the fracture is
+ // in fracturedChild.
+ Edit newEdit = new Edit(fracturedChild, 0, true);
+ elementStack.push(newEdit);
}
- index++;
- }
- else
- {
- removed = new Element[] { current };
- if (res[1] instanceof BranchElement)
+ else
{
- ret = res[1];
- added = new Element[] { res[0], res[1] };
+ // Otherwise use the parent's first child.
+ Element el = edit.e.getElement(0);
+ Edit newEdit = new Edit(el, 0, true);
+ elementStack.push(newEdit);
}
- else
+ break;
+ case ElementSpec.JoinNextDirection:
+ // Push the next paragraph element onto the stack so
+ // future insertions are added to it.
+ Element parent = edit.e.getElement(edit.index);
+ if (parent.isLeaf())
{
- ret = createBranchElement(par, null);
- added = new Element[] { res[0], ret, res[1] };
+ if (edit.index + 1 < edit.e.getElementCount())
+ parent = edit.e.getElement(edit.index + 1);
+ else
+ assert false; // Must not happen.
}
+ elementStack.push(new Edit(parent, 0, true));
+ break;
+ default:
+ Element branch = createBranchElement(edit.e,
+ spec.getAttributes());
+ edit.added.add(branch);
+ elementStack.push(new Edit(branch, 0));
+ break;
}
-
- e.addAddedElements(added);
- e.addRemovedElements(removed);
- }
- else
- {
- ret = createBranchElement(par, null);
- e.addAddedElement(ret);
+ break;
+ case ElementSpec.EndTagType:
+ pop();
+ break;
+ case ElementSpec.ContentType:
+ insertContentTag(spec, edit);
+ break;
}
- return ret;
}
-
+
/**
* Inserts the first tag into the document.
*
@@ -910,67 +1179,71 @@ public class DefaultStyledDocument extends AbstractDocument implements
private void insertFirstContentTag(ElementSpec[] data)
{
ElementSpec first = data[0];
- BranchElement paragraph = (BranchElement) elementStack.peek();
- int index = paragraph.getElementIndex(pos);
- Element current = paragraph.getElement(index);
- int newEndOffset = pos + first.length;
+ Edit edit = (Edit) elementStack.peek();
+ Element current = edit.e.getElement(edit.index);
+ int firstEndOffset = offset + first.length;
boolean onlyContent = data.length == 1;
- Edit edit = getEditForParagraphAndIndex(paragraph, index);
switch (first.getDirection())
{
case ElementSpec.JoinPreviousDirection:
- if (current.getEndOffset() != newEndOffset && !onlyContent)
+ if (current.getEndOffset() != firstEndOffset && ! onlyContent)
{
- Element newEl1 = createLeafElement(paragraph,
+ Element newEl1 = createLeafElement(edit.e,
current.getAttributes(),
current.getStartOffset(),
- newEndOffset);
- edit.addAddedElement(newEl1);
- edit.addRemovedElement(current);
- offset = newEndOffset;
+ firstEndOffset);
+ edit.added.add(newEl1);
+ edit.removed.add(current);
+ if (current.getEndOffset() != endOffset)
+ recreateLeafs = true;
+ else
+ offsetLastIndex = true;
+ }
+ else
+ {
+ offsetLastIndex = true;
+ offsetLastIndexReplace = true;
}
break;
case ElementSpec.JoinNextDirection:
- if (pos != 0)
+ if (offset != 0)
{
- Element newEl1 = createLeafElement(paragraph,
+ Element newEl1 = createLeafElement(edit.e,
current.getAttributes(),
current.getStartOffset(),
- pos);
- edit.addAddedElement(newEl1);
- Element next = paragraph.getElement(index + 1);
-
+ offset);
+ edit.added.add(newEl1);
+ Element next = edit.e.getElement(edit.index + 1);
if (onlyContent)
- newEl1 = createLeafElement(paragraph, next.getAttributes(),
- pos, next.getEndOffset());
+ newEl1 = createLeafElement(edit.e, next.getAttributes(),
+ offset, next.getEndOffset());
else
{
- newEl1 = createLeafElement(paragraph, next.getAttributes(),
- pos, newEndOffset);
- pos = newEndOffset;
+ newEl1 = createLeafElement(edit.e, next.getAttributes(),
+ offset, firstEndOffset);
}
- edit.addAddedElement(newEl1);
- edit.addRemovedElement(current);
- edit.addRemovedElement(next);
+ edit.added.add(newEl1);
+ edit.removed.add(current);
+ edit.removed.add(next);
}
break;
- default:
- if (current.getStartOffset() != pos)
+ default: // OriginateDirection.
+ if (current.getStartOffset() != offset)
{
- Element newEl = createLeafElement(paragraph,
+ Element newEl = createLeafElement(edit.e,
current.getAttributes(),
current.getStartOffset(),
- pos);
- edit.addAddedElement(newEl);
+ offset);
+ edit.added.add(newEl);
}
- edit.addRemovedElement(current);
- Element newEl1 = createLeafElement(paragraph, first.getAttributes(),
- pos, newEndOffset);
- edit.addAddedElement(newEl1);
+ edit.removed.add(current);
+ Element newEl1 = createLeafElement(edit.e, first.getAttributes(),
+ offset, firstEndOffset);
+ edit.added.add(newEl1);
if (current.getEndOffset() != endOffset)
- recreateLeaves(newEndOffset, paragraph, onlyContent);
+ recreateLeafs = true;
else
- offset = newEndOffset;
+ offsetLastIndex = true;
break;
}
}
@@ -981,391 +1254,353 @@ public class DefaultStyledDocument extends AbstractDocument implements
* @param tag -
* the element spec
*/
- private void insertContentTag(ElementSpec tag)
+ private void insertContentTag(ElementSpec tag, Edit edit)
{
- BranchElement paragraph = (BranchElement) elementStack.peek();
int len = tag.getLength();
int dir = tag.getDirection();
AttributeSet tagAtts = tag.getAttributes();
if (dir == ElementSpec.JoinNextDirection)
{
- int index = paragraph.getElementIndex(pos);
- Element target = paragraph.getElement(index);
- 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)))
+ if (! edit.isFracture)
{
- Element next = paragraph.getElement(index + 1);
- Element newEl = createLeafElement(paragraph,
- next.getAttributes(), pos,
- next.getEndOffset());
- edit.addAddedElement(newEl);
- edit.addRemovedElement(next);
- edit.addRemovedElement(target);
+ Element first = null;
+ if (insertPath != null)
+ {
+ for (int p = insertPath.length - 1; p >= 0; p--)
+ {
+ if (insertPath[p] == edit)
+ {
+ if (p != insertPath.length - 1)
+ first = edit.e.getElement(edit.index);
+ break;
+ }
+ }
+ }
+ if (first == null)
+ first = edit.e.getElement(edit.index + 1);
+ Element leaf = createLeafElement(edit.e, first.getAttributes(),
+ pos, first.getEndOffset());
+ edit.added.add(leaf);
+ edit.removed.add(first);
}
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);
- }
+ Element first = edit.e.getElement(0);
+ Element leaf = createLeafElement(edit.e, first.getAttributes(),
+ pos, first.getEndOffset());
+ edit.added.add(leaf);
+ edit.removed.add(first);
}
}
else
{
- int end = pos + len;
- Element leaf = createLeafElement(paragraph, tag.getAttributes(), pos, end);
-
- // Check for overlap with other leaves/branches
- if (paragraph.getElementCount() > 0)
- {
- 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);
- }
- else
- paragraph.replace(0, 0, new Element[] { leaf });
+ Element leaf = createLeafElement(edit.e, tag.getAttributes(), pos,
+ pos + len);
+ edit.added.add(leaf);
}
-
+
pos += len;
+
}
/**
- * This method fractures the child at offset.
+ * This method fractures bottomost leaf in the elementStack. This
+ * happens when the first inserted tag is not content.
*
* @param data
* the ElementSpecs used for the entire insertion
*/
private void createFracture(ElementSpec[] data)
{
- BranchElement paragraph = (BranchElement) elementStack.peek();
- int index = paragraph.getElementIndex(offset);
- Element child = paragraph.getElement(index);
- Edit edit = getEditForParagraphAndIndex(paragraph, index);
- AttributeSet atts = child.getAttributes();
-
+ Edit edit = (Edit) elementStack.peek();
+ Element child = edit.e.getElement(edit.index);
if (offset != 0)
{
- Element newEl1 = createLeafElement(paragraph, atts,
- child.getStartOffset(), offset);
- edit.addAddedElement(newEl1);
- edit.addRemovedElement(child);
+ Element newChild = createLeafElement(edit.e, child.getAttributes(),
+ child.getStartOffset(), offset);
+ edit.added.add(newChild);
}
+ edit.removed.add(child);
+ if (child.getEndOffset() != endOffset)
+ recreateLeafs = true;
+ else
+ offsetLastIndex = true;
}
- /**
- * 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)
+ private void fracture(int depth)
{
- int index = paragraph.getElementIndex(start);
- Element child = paragraph.getElement(index);
- AttributeSet atts = child.getAttributes();
-
- if (!onlyContent)
+ int len = insertPath.length;
+ int lastIndex = -1;
+ boolean recreate = recreateLeafs;
+ Edit lastEdit = insertPath[len - 1];
+ boolean childChanged = lastEdit.index + 1 < lastEdit.e.getElementCount();
+ int deepestChangedIndex = recreate ? len : - 1;
+ int lastChangedIndex = len - 1;
+ createdFracture = true;
+ for (int i = len - 2; i >= 0; i--)
{
- 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();
+ Edit edit = insertPath[i];
+ if (edit.added.size() > 0 || i == depth)
+ {
+ lastIndex = i;
+ if (! recreate && childChanged)
+ {
+ recreate = true;
+ if (deepestChangedIndex == -1)
+ deepestChangedIndex = lastChangedIndex + 1;
+ }
+ }
+ if (! childChanged && edit.index < edit.e.getElementCount())
+ {
+ childChanged = true;
+ lastChangedIndex = i;
+ }
}
- else
+ if (recreate)
{
- Element newLeaf = createLeafElement(paragraph, atts, start,
- child.getEndOffset());
- Edit edit = getEditForParagraphAndIndex(paragraph, index);
- edit.addAddedElement(newLeaf);
+ if (lastIndex == -1)
+ lastIndex = len - 1;
+ recreate(lastIndex, deepestChangedIndex);
}
}
-
- /**
- * 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 Element[] split(Element el, int offset, int space, int editIndex)
+
+ private void recreate(int startIndex, int endIndex)
{
- // 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)
+ // Recreate the element representing the inserted index.
+ Edit edit = insertPath[startIndex];
+ Element child;
+ Element newChild;
+ int changeLength = insertPath.length;
+
+ if (startIndex + 1 == changeLength)
+ child = edit.e.getElement(edit.index);
+ else
+ child = edit.e.getElement(edit.index - 1);
+
+ if(child.isLeaf())
{
- 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)
- {
- // 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[] {};
+ newChild = createLeafElement(edit.e, child.getAttributes(),
+ Math.max(endOffset, child.getStartOffset()),
+ child.getEndOffset());
+ }
+ else
+ {
+ newChild = createBranchElement(edit.e, child.getAttributes());
+ }
+ fracturedParent = edit.e;
+ fracturedChild = newChild;
- }
- // This is the case when we may not keep the first
- // element.
+ // Recreate all the elements to the right of the insertion point.
+ Element parent = newChild;
+ while (++startIndex < endIndex)
+ {
+ boolean isEnd = (startIndex + 1) == endIndex;
+ boolean isEndLeaf = (startIndex + 1) == changeLength;
+
+ // Create the newChild, a duplicate of the elment at
+ // index. This isn't done if isEnd and offsetLastIndex are true
+ // indicating a join previous was done.
+ edit = insertPath[startIndex];
+
+ // Determine the child to duplicate, won't have to duplicate
+ // if at end of fracture, or offseting index.
+ if(isEnd)
+ {
+ if(offsetLastIndex || ! isEndLeaf)
+ child = null;
else
+ child = edit.e.getElement(edit.index);
+ }
+ else
+ {
+ child = edit.e.getElement(edit.index - 1);
+ }
+
+ // Duplicate it.
+ if(child != null)
+ {
+ if(child.isLeaf())
{
- removed = new Element[count - index];
- newAdded = new Element[count - index];
- added = new Element[] { result[0] };
+ newChild = createLeafElement(parent, child.getAttributes(),
+ Math.max(endOffset, child.getStartOffset()),
+ child.getEndOffset());
}
- newAdded[0] = result[1];
- for (int i = index; i < count; i++)
+ else
{
- Element el2 = el.getElement(i);
- int ind = i - count + removed.length;
- removed[ind] = el2;
- if (ind != 0)
- newAdded[ind] = el2;
+ newChild = createBranchElement(parent,
+ child.getAttributes());
}
-
- 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
- {
- 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 };
+ newChild = null;
+
+ // Recreate the remaining children (there may be none).
+ int childrenToMove = edit.e.getElementCount() - edit.index;
+ Element[] children;
+ int moveStartIndex;
+ int childStartIndex = 1;
+
+ if (newChild == null)
+ {
+ // Last part of fracture.
+ if (isEndLeaf)
+ {
+ childrenToMove--;
+ moveStartIndex = edit.index + 1;
+ }
+ else
+ {
+ moveStartIndex = edit.index;
+ }
+ childStartIndex = 0;
+ children = new Element[childrenToMove];
+ }
+ else
+ {
+ if (! isEnd)
+ {
+ // Branch.
+ childrenToMove++;
+ moveStartIndex = edit.index;
}
+ else
+ {
+ // Last leaf, need to recreate part of it.
+ moveStartIndex = edit.index + 1;
+ }
+ children = new Element[childrenToMove];
+ children[0] = newChild;
}
- 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;
+
+ for (int c = childStartIndex; c < childrenToMove; c++)
+ {
+ Element toMove = edit.e.getElement(moveStartIndex++);
+ children[c] = recreateFracturedElement(parent, toMove);
+ edit.removed.add(toMove);
+ }
+ ((BranchElement) parent).replace(0, 0, children);
+ parent = newChild;
+ }
+
}
- /**
- * Inserts a fracture into the document structure.
- *
- * @param tag -
- * the element spec.
- */
- private void insertFracture(ElementSpec tag)
+ private Element recreateFracturedElement(Element parent, Element toCopy)
{
- // 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)
+ Element recreated;
+ if(toCopy.isLeaf())
{
- // 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)
+ recreated = createLeafElement(parent, toCopy.getAttributes(),
+ Math.max(toCopy.getStartOffset(), endOffset),
+ toCopy.getEndOffset());
+ }
+ else
+ {
+ Element newParent = createBranchElement(parent,
+ toCopy.getAttributes());
+ int childCount = toCopy.getElementCount();
+ Element[] newChildren = new Element[childCount];
+ for (int i = 0; i < childCount; i++)
{
- added = new Element[] { rightBranch };
-
- // don't try to remove left part of tree
- parentIndex++;
+ newChildren[i] = recreateFracturedElement(newParent,
+ toCopy.getElement(i));
}
- else
- {
- leftBranch =
- (BranchElement) createBranchElement(parent, parentAtts);
- added = new Element[] { leftBranch, rightBranch };
+ ((BranchElement) newParent).replace(0, 0, newChildren);
+ recreated = newParent;
+ }
+ return recreated;
+ }
- // add fracture to leftBranch
- if (fracStart != pos)
- {
- Element leftFracturedLeaf =
- createLeafElement(leftBranch, atts, fracStart, pos);
- leftBranch.replace(leftIns, 0,
- new Element[] { leftFracturedLeaf });
- }
- }
+ private boolean split(int offs, int len)
+ {
+ boolean splitEnd = false;
+ // Push the path to the stack.
+ Element e = root;
+ int index = e.getElementIndex(offs);
+ while (! e.isLeaf())
+ {
+ elementStack.push(new Edit(e, index));
+ e = e.getElement(index);
+ index = e.getElementIndex(offs);
+ }
- if (!toFracture.isLeaf())
+ Edit ec = (Edit) elementStack.peek();
+ Element child = ec.e.getElement(ec.index);
+ // Make sure there is something to do. If the
+ // offset is already at a boundary then there is
+ // nothing to do.
+ if (child.getStartOffset() < offs && offs < child.getEndOffset())
+ {
+ // We need to split, now see if the other end is within
+ // the same parent.
+ int index0 = ec.index;
+ int index1 = index0;
+ if (((offs + len) < ec.e.getEndOffset()) && (len != 0))
{
- // add all non-fracture elements to the branches
- if (indexOfFrac > 0 && leftBranch != null)
+ // It's a range split in the same parent.
+ index1 = ec.e.getElementIndex(offs+len);
+ if (index1 == index0)
{
- 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);
+ // It's a three-way split.
+ ec.removed.add(child);
+ e = createLeafElement(ec.e, child.getAttributes(),
+ child.getStartOffset(), offs);
+ ec.added.add(e);
+ e = createLeafElement(ec.e, child.getAttributes(),
+ offs, offs + len);
+ ec.added.add(e);
+ e = createLeafElement(ec.e, child.getAttributes(),
+ offs + len, child.getEndOffset());
+ ec.added.add(e);
+ return true;
}
-
- int count = size - indexOfFrac - 1;
- if (count > 0)
+ else
{
- 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);
+ child = ec.e.getElement(index1);
+ if ((offs + len) == child.getStartOffset())
+ {
+ // End is already on a boundary.
+ index1 = index0;
+ }
}
+ splitEnd = true;
}
-
- // 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))
+
+ // Split the first location.
+ pos = offs;
+ child = ec.e.getElement(index0);
+ ec.removed.add(child);
+ e = createLeafElement(ec.e, child.getAttributes(),
+ child.getStartOffset(), pos);
+ ec.added.add(e);
+ e = createLeafElement(ec.e, child.getAttributes(),
+ pos, child.getEndOffset());
+ ec.added.add(e);
+
+ // Pick up things in the middle.
+ for (int i = index0 + 1; i < index1; i++)
{
- end = next.getEndOffset();
- rm = 1;
+ child = ec.e.getElement(i);
+ ec.removed.add(child);
+ ec.added.add(child);
}
- 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)
+ if (index1 != index0)
{
- 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());
+ child = ec.e.getElement(index1);
+ pos = offs + len;
+ ec.removed.add(child);
+ e = createLeafElement(ec.e, child.getAttributes(),
+ child.getStartOffset(), pos);
+ ec.added.add(e);
+ e = createLeafElement(ec.e, child.getAttributes(),
+ pos, child.getEndOffset());
+
+ ec.added.add(e);
}
-
- edit.addAddedElements(added);
- edit.addAddedElements(added2);
- elementStack.push(rightBranch);
- lastFractured = rightFracturedLeaf;
}
- else
- fracNotCreated = true;
+ return splitEnd;
+
}
/**
@@ -1420,190 +1655,6 @@ public class DefaultStyledDocument extends AbstractDocument implements
}
}
- /**
- * 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]);
- }
- }
-
- /**
- * 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
@@ -1674,11 +1725,6 @@ public class DefaultStyledDocument extends AbstractDocument implements
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()
@@ -2079,147 +2125,220 @@ public class DefaultStyledDocument extends AbstractDocument implements
*/
protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr)
{
- super.insertUpdate(ev, attr);
- // If the attribute set is null, use an empty attribute set.
+ int offs = ev.getOffset();
+ int len = ev.getLength();
+ int endOffs = offs + len;
if (attr == null)
attr = SimpleAttributeSet.EMPTY;
- int offset = ev.getOffset();
- int length = ev.getLength();
- int endOffset = offset + length;
- AttributeSet paragraphAttributes = getParagraphElement(endOffset).getAttributes();
- Segment txt = new Segment();
+
+ // Paragraph attributes are fetched from the point _after_ the insertion.
+ Element paragraph = getParagraphElement(endOffs);
+ AttributeSet pAttr = paragraph.getAttributes();
+ // Character attributes are fetched from the actual insertion point.
+ Element paragraph2 = getParagraphElement(offs);
+ int contIndex = paragraph2.getElementIndex(offs);
+ Element content = paragraph2.getElement(contIndex);
+ AttributeSet cAttr = content.getAttributes();
+
+ boolean insertAtBoundary = content.getEndOffset() == endOffs;
try
{
- getText(offset, length, txt);
- }
- catch (BadLocationException ex)
- {
- AssertionError ae = new AssertionError("Unexpected bad location");
- ae.initCause(ex);
- throw ae;
- }
+ Segment s = new Segment();
+ ArrayList buf = new ArrayList();
+ ElementSpec lastStartTag = null;
+ boolean insertAfterNewline = false;
+ short lastStartDir = ElementSpec.OriginateDirection;
+
+ // Special handle if we are inserting after a newline.
+ if (offs > 0)
+ {
+ getText(offs - 1, 1, s);
+ if (s.array[s.offset] == '\n')
+ {
+ insertAfterNewline = true;
+ lastStartDir = insertAfterNewline(paragraph, paragraph2,
+ pAttr, buf, offs,
+ endOffs);
+ // Search last start tag.
+ for (int i = buf.size() - 1; i >= 0 && lastStartTag == null;
+ i--)
+ {
+ ElementSpec tag = (ElementSpec) buf.get(i);
+ if (tag.getType() == ElementSpec.StartTagType)
+ {
+ lastStartTag = tag;
+ }
+ }
+ }
- int len = 0;
- Vector specs = new Vector();
- ElementSpec finalStartTag = null;
- short finalStartDirection = ElementSpec.OriginateDirection;
- boolean prevCharWasNewline = false;
- Element prev = getCharacterElement(offset);
- Element next = getCharacterElement(endOffset);
- Element prevParagraph = getParagraphElement(offset);
- Element paragraph = getParagraphElement(endOffset);
+ }
- int segmentEnd = txt.offset + txt.count;
+ // If we are not inserting after a newline, the paragraph attributes
+ // come from the paragraph under the insertion point.
+ if (! insertAfterNewline)
+ pAttr = paragraph2.getAttributes();
- // Check to see if we're inserting immediately after a newline.
- if (offset > 0)
- {
- try
+ // Scan text and build up the specs.
+ getText(offs, len, s);
+ int end = s.offset + s.count;
+ int last = s.offset;
+ for (int i = s.offset; i < end; i++)
{
- String s = getText(offset - 1, 1);
- if (s.equals("\n"))
+ if (s.array[i] == '\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);
+ int breakOffs = i + 1;
+ buf.add(new ElementSpec(attr, ElementSpec.ContentType,
+ breakOffs - last));
+ buf.add(new ElementSpec(null, ElementSpec.EndTagType));
+ lastStartTag = new ElementSpec(pAttr,
+ ElementSpec.StartTagType);
+ buf.add(lastStartTag);
+ last = breakOffs;
}
}
- catch (BadLocationException ble)
+
+ // Need to add a tailing content tag if we didn't finish at a boundary.
+ if (last < end)
{
- // This shouldn't happen.
- AssertionError ae = new AssertionError();
- ae.initCause(ble);
- throw ae;
+ buf.add(new ElementSpec(attr, ElementSpec.ContentType,
+ end - last));
}
- }
- for (int i = txt.offset; i < segmentEnd; ++i)
- {
- len++;
- if (txt.array[i] == '\n')
+ // Now we need to fix up the directions of the specs.
+ ElementSpec first = (ElementSpec) buf.get(0);
+ int doclen = getLength();
+
+ // Maybe join-previous the first tag if it is content and has
+ // the same attributes as the previous character run.
+ if (first.getType() == ElementSpec.ContentType && cAttr.isEqual(attr))
+ first.setDirection(ElementSpec.JoinPreviousDirection);
+
+ // Join-fracture or join-next the last start tag if necessary.
+ if (lastStartTag != null)
+ {
+ if (insertAfterNewline)
+ lastStartTag.setDirection(lastStartDir);
+ else if (paragraph2.getEndOffset() != endOffs)
+ lastStartTag.setDirection(ElementSpec.JoinFractureDirection);
+ else
+ {
+ Element par = paragraph2.getParentElement();
+ int par2Index = par.getElementIndex(offs);
+ if (par2Index + 1 < par.getElementCount()
+ && ! par.getElement(par2Index + 1).isLeaf())
+ lastStartTag.setDirection(ElementSpec.JoinNextDirection);
+ }
+ }
+
+ // Join-next last tag if possible.
+ if (insertAtBoundary && endOffs < doclen)
{
- // Add the ElementSpec for the content.
- 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);
- specs.add(finalStartTag);
- len = 0;
+ ElementSpec lastTag = (ElementSpec) buf.get(buf.size() - 1);
+ if (lastTag.getType() == ElementSpec.ContentType
+ && ((lastStartTag == null
+ && (paragraph == paragraph2 || insertAfterNewline))
+ || (lastStartTag != null
+ && lastStartTag.getDirection() != ElementSpec.OriginateDirection)))
+ {
+ int nextIndex = paragraph.getElementIndex(endOffs);
+ Element nextRun = paragraph.getElement(nextIndex);
+ if (nextRun.isLeaf() && attr.isEqual(nextRun.getAttributes()))
+ lastTag.setDirection(ElementSpec.JoinNextDirection);
+ }
+ }
+
+ else if (! insertAtBoundary && lastStartTag != null
+ && lastStartTag.getDirection() == ElementSpec.JoinFractureDirection)
+ {
+ ElementSpec lastTag = (ElementSpec) buf.get(buf.size() - 1);
+ if (lastTag.getType() == ElementSpec.ContentType
+ && lastTag.getDirection() != ElementSpec.JoinPreviousDirection
+ && attr.isEqual(cAttr))
+ {
+ lastTag.setDirection(ElementSpec.JoinNextDirection);
+ }
}
- }
- // Create last element if last character hasn't been a newline.
- if (len > 0)
- specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));
+ ElementSpec[] specs = new ElementSpec[buf.size()];
+ specs = (ElementSpec[]) buf.toArray(specs);
+ buffer.insert(offs, len, specs, ev);
+ }
+ catch (BadLocationException ex)
+ {
+ // Ignore this. Comment out for debugging.
+ ex.printStackTrace();
+ }
+ super.insertUpdate(ev, attr);
+ }
- // 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)
+ private short insertAfterNewline(Element par1, Element par2,
+ AttributeSet attr, ArrayList buf,
+ int offs, int endOffs)
+ {
+ short dir = 0;
+ if (par1.getParentElement() == par2.getParentElement())
{
- if (prevCharWasNewline)
- finalStartTag.setDirection(finalStartDirection);
- else if (prevParagraph.getEndOffset() != endOffset)
- finalStartTag.setDirection(ElementSpec.JoinFractureDirection);
+ ElementSpec tag = new ElementSpec(attr, ElementSpec.EndTagType);
+ buf.add(tag);
+ tag = new ElementSpec(attr, ElementSpec.StartTagType);
+ buf.add(tag);
+ if (par2.getEndOffset() != endOffs)
+ dir = ElementSpec.JoinFractureDirection;
else
{
- // If there is an element AFTER this one, then set the
- // direction to JoinNextDirection.
- Element parent = prevParagraph.getParentElement();
- int index = parent.getElementIndex(offset);
- if (index + 1 < parent.getElementCount()
- && !parent.getElement(index + 1).isLeaf())
- finalStartTag.setDirection(ElementSpec.JoinNextDirection);
+ Element par = par2.getParentElement();
+ if (par.getElementIndex(offs) + 1 < par.getElementCount())
+ dir = 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.
- ElementSpec last = (ElementSpec) specs.lastElement();
- if (last.getType() == ElementSpec.ContentType)
+ else
{
- Element currentRun = prevParagraph.getElement(prevParagraph.getElementIndex(offset));
- if (currentRun.getEndOffset() == endOffset)
+ // For text with more than 2 levels, find the common parent of
+ // par1 and par2.
+ ArrayList parentsLeft = new ArrayList();
+ ArrayList parentsRight = new ArrayList();
+ Element e = par2;
+ while (e != null)
{
- if (endOffset < getLength() && next.getAttributes().isEqual(attr)
- && last.getType() == ElementSpec.ContentType)
- last.setDirection(ElementSpec.JoinNextDirection);
+ parentsLeft.add(e);
+ e = e.getParentElement();
}
- else
+ e = par1;
+ int leftIndex = -1;
+ while (e != null && (leftIndex = parentsLeft.indexOf(e)) == 1)
+ {
+ parentsRight.add(e);
+ e = e.getParentElement();
+ }
+
+ if (e != null)
+
{
- if (finalStartTag != null
- && finalStartTag.getDirection() == ElementSpec.JoinFractureDirection
- && currentRun.getAttributes().isEqual(attr))
+ // e is now the common parent.
+ // Insert the end tags.
+ for (int c = 0; c < leftIndex; c++)
+ {
+ buf.add(new ElementSpec(null, ElementSpec.EndTagType));
+ }
+ // Insert the start tags.
+ for (int c = parentsRight.size() - 1; c >= 0; c--)
{
- last.setDirection(ElementSpec.JoinNextDirection);
+ Element el = (Element) parentsRight.get(c);
+ ElementSpec tag = new ElementSpec(el.getAttributes(),
+ ElementSpec.StartTagType);
+ if (c > 0)
+ tag.setDirection(ElementSpec.JoinNextDirection);
+ buf.add(tag);
}
+ if (parentsRight.size() > 0)
+ dir = ElementSpec.JoinNextDirection;
+ else
+ dir = ElementSpec.JoinFractureDirection;
}
+ else
+ assert false;
}
-
- // 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()]);
- buffer.insert(offset, length, elSpecs, ev);
+ return dir;
}
/**
diff --git a/javax/swing/text/GapContent.java b/javax/swing/text/GapContent.java
index 760e396a2..7b1502777 100644
--- a/javax/swing/text/GapContent.java
+++ b/javax/swing/text/GapContent.java
@@ -195,10 +195,52 @@ public class GapContent
}
}
+ /**
+ * Stores a reference to a mark that can be resetted to the original value
+ * after a mark has been moved. This is used for undoing actions.
+ */
+ private class UndoPosRef
+ {
+ /**
+ * The mark that might need to be reset.
+ */
+ private Mark mark;
+
+ /**
+ * The original offset to reset the mark to.
+ */
+ private int undoOffset;
+
+ /**
+ * Creates a new UndoPosRef.
+ *
+ * @param m the mark
+ */
+ UndoPosRef(Mark m)
+ {
+ mark = m;
+ undoOffset = mark.getOffset();
+ }
+
+ /**
+ * Resets the position of the mark to the value that it had when
+ * creating this UndoPosRef.
+ */
+ void reset()
+ {
+ if (undoOffset <= gapStart)
+ mark.mark = undoOffset;
+ else
+ mark.mark = (gapEnd - gapStart) + undoOffset;
+ }
+ }
+
private class InsertUndo extends AbstractUndoableEdit
{
public int where, length;
String text;
+ private Vector positions;
+
public InsertUndo(int start, int len)
{
where = start;
@@ -209,27 +251,33 @@ public class GapContent
{
super.undo();
try
- {
- text = getString(where, length);
- remove(where, length);
- }
+ {
+ positions = getPositionsInRange(null, where, length);
+ text = getString(where, length);
+ remove(where, length);
+ }
catch (BadLocationException ble)
- {
- throw new CannotUndoException();
- }
+ {
+ throw new CannotUndoException();
+ }
}
public void redo () throws CannotUndoException
{
super.redo();
try
- {
- insertString(where, text);
- }
+ {
+ insertString(where, text);
+ if (positions != null)
+ {
+ updateUndoPositions(positions, where, length);
+ positions = null;
+ }
+ }
catch (BadLocationException ble)
- {
- throw new CannotRedoException();
- }
+ {
+ throw new CannotRedoException();
+ }
}
}
@@ -238,10 +286,17 @@ public class GapContent
{
public int where;
String text;
+
+ /**
+ * The positions in the removed range.
+ */
+ private Vector positions;
+
public UndoRemove(int start, String removedText)
{
where = start;
text = removedText;
+ positions = getPositionsInRange(null, start, removedText.length());
}
public void undo () throws CannotUndoException
@@ -250,6 +305,8 @@ public class GapContent
try
{
insertString(where, text);
+ if (positions != null)
+ updateUndoPositions(positions, where, text.length());
}
catch (BadLocationException ble)
{
@@ -261,13 +318,15 @@ public class GapContent
{
super.redo();
try
- {
- remove(where, text.length());
- }
+ {
+ text = getString(where, text.length());
+ positions = getPositionsInRange(null, where, text.length());
+ remove(where, text.length());
+ }
catch (BadLocationException ble)
- {
- throw new CannotRedoException();
- }
+ {
+ throw new CannotRedoException();
+ }
}
}
@@ -403,9 +462,10 @@ public class GapContent
throw new BadLocationException("The where argument cannot be greater"
+ " than the content length", where);
+ InsertUndo undo = new InsertUndo(where, strLen);
replace(where, 0, str.toCharArray(), strLen);
- return new InsertUndo(where, strLen);
+ return undo;
}
/**
@@ -429,9 +489,10 @@ public class GapContent
+ " than the content length", where + nitems);
String removedText = getString(where, nitems);
+ UndoRemove undoRemove = new UndoRemove(where, removedText);
replace(where, nitems, null, 0);
- return new UndoRemove(where, removedText);
+ return undoRemove;
}
/**
@@ -495,29 +556,43 @@ public class GapContent
if (len < 0)
throw new BadLocationException("negative length not allowed: ", len);
- // check if requested segment is contiguous
- if ((where < gapStart) && ((gapStart - where) < len))
- {
- // requested segment is not contiguous -> copy the pieces together
- char[] copy = new char[len];
- int lenFirst = gapStart - where; // the length of the first segment
- System.arraycopy(buffer, where, copy, 0, lenFirst);
- System.arraycopy(buffer, gapEnd, copy, lenFirst, len - lenFirst);
- txt.array = copy;
- txt.offset = 0;
- txt.count = len;
- }
- else
- {
- // requested segment is contiguous -> we can simply return the
- // actual content
- txt.array = buffer;
- if (where < gapStart)
+ // Optimized to copy only when really needed.
+ if (where + len <= gapStart)
+ {
+ // Simple case: completely before gap.
+ txt.array = buffer;
txt.offset = where;
- else
- txt.offset = where + (gapEnd - gapStart);
- txt.count = len;
- }
+ txt.count = len;
+ }
+ else if (where > gapStart)
+ {
+ // Completely after gap, adjust offset.
+ txt.array = buffer;
+ txt.offset = gapEnd + where - gapStart;
+ txt.count = len;
+ }
+ else
+ {
+ // Spans the gap.
+ int beforeGap = gapStart - where;
+ if (txt.isPartialReturn())
+ {
+ // Return the part before the gap when partial return is allowed.
+ txt.array = buffer;
+ txt.offset = where;
+ txt.count = beforeGap;
+ }
+ else
+ {
+ // Copy pieces together otherwise.
+ txt.array = new char[len];
+ txt.offset = 0;
+ System.arraycopy(buffer, where, txt.array, 0, beforeGap);
+ System.arraycopy(buffer, gapEnd, txt.array, beforeGap,
+ len - beforeGap);
+ txt.count = len;
+ }
+ }
}
/**
@@ -736,8 +811,6 @@ public class GapContent
Vector res = v;
if (res == null)
res = new Vector();
- else
- res.clear();
int endOffs = offset + length;
@@ -746,8 +819,8 @@ public class GapContent
{
GapContentPosition p = (GapContentPosition) i.next();
int offs = p.getOffset();
- if (offs >= offset && offs < endOffs)
- res.add(p);
+ if (offs >= offset && offs <= endOffs)
+ res.add(new UndoPosRef(p.mark));
}
return res;
@@ -844,14 +917,26 @@ 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.
+ * Resets the positions in the specified range to their original offset
+ * after a undo operation is performed. For example, after removing some
+ * content, the positions in the removed range will all be set to one
+ * offset. This method restores the positions to their original offsets
+ * after an undo.
+ *
+ * @param positions the positions to update
+ * @param offset
+ * @param length
*/
protected void updateUndoPositions(Vector positions, int offset, int length)
{
- // We do nothing here.
+ for (Iterator i = positions.iterator(); i.hasNext();)
+ {
+ UndoPosRef undoPosRef = (UndoPosRef) i.next();
+ undoPosRef.reset();
+ }
+
+ // Resort marks.
+ Collections.sort(marks);
}
/**
diff --git a/javax/swing/text/GlyphView.java b/javax/swing/text/GlyphView.java
index d505274c9..65025dd08 100644
--- a/javax/swing/text/GlyphView.java
+++ b/javax/swing/text/GlyphView.java
@@ -39,6 +39,7 @@ exception statement from your version. */
package javax.swing.text;
import java.awt.Color;
+import java.awt.Container;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
@@ -354,11 +355,14 @@ public class GlyphView extends View implements TabableView, Cloneable
Font font = view.getFont();
FontMetrics fm = view.getContainer().getFontMetrics(font);
Segment txt = view.getText(el.getStartOffset(), pos);
- int width = fm.charsWidth(txt.array, txt.offset, txt.count);
+ Rectangle bounds = a instanceof Rectangle ? (Rectangle) a
+ : a.getBounds();
+ TabExpander expander = view.getTabExpander();
+ int width = Utilities.getTabbedTextWidth(txt, fm, bounds.x, expander,
+ view.getStartOffset());
int height = fm.getHeight();
- Rectangle bounds = a.getBounds();
Rectangle result = new Rectangle(bounds.x + width, bounds.y,
- bounds.x + width, height);
+ 0, height);
return result;
}
@@ -536,9 +540,24 @@ public class GlyphView extends View implements TabableView, Cloneable
*/
public void paint(Graphics g, Shape a)
{
- Element el = getElement();
checkPainter();
- getGlyphPainter().paint(this, g, a, getStartOffset(), getEndOffset());
+ int p0 = getStartOffset();
+ int p1 = getEndOffset();
+
+ Container c = getContainer();
+ // Paint layered highlights if there are any.
+ if (c instanceof JTextComponent)
+ {
+ JTextComponent tc = (JTextComponent) c;
+ Highlighter h = tc.getHighlighter();
+ if (h instanceof LayeredHighlighter)
+ {
+ LayeredHighlighter lh = (LayeredHighlighter) h;
+ lh.paintLayeredHighlights(g, p0, p1, a, tc, this);
+ }
+ }
+
+ getGlyphPainter().paint(this, g, a, p0, p1);
}
diff --git a/javax/swing/text/JTextComponent.java b/javax/swing/text/JTextComponent.java
index 6da84bfe7..68ba1f428 100644
--- a/javax/swing/text/JTextComponent.java
+++ b/javax/swing/text/JTextComponent.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.text;
-import gnu.classpath.NotImplementedException;
-
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Container;
@@ -47,6 +45,7 @@ import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
+import java.awt.Shape;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
@@ -59,6 +58,7 @@ import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
+import java.text.BreakIterator;
import java.util.Enumeration;
import java.util.Hashtable;
@@ -67,6 +67,7 @@ import javax.accessibility.AccessibleAction;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleEditableText;
import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleState;
import javax.accessibility.AccessibleStateSet;
import javax.accessibility.AccessibleText;
import javax.swing.Action;
@@ -105,12 +106,7 @@ public abstract class JTextComponent extends JComponent
/**
* The caret's offset.
*/
- int dot = 0;
-
- /**
- * The current JTextComponent.
- */
- JTextComponent textComp = JTextComponent.this;
+ private int caretDot;
/**
* Construct an AccessibleJTextComponent.
@@ -118,7 +114,8 @@ public abstract class JTextComponent extends JComponent
public AccessibleJTextComponent()
{
super();
- textComp.addCaretListener(this);
+ JTextComponent.this.addCaretListener(this);
+ caretDot = getCaretPosition();
}
/**
@@ -129,8 +126,7 @@ public abstract class JTextComponent extends JComponent
*/
public int getCaretPosition()
{
- dot = textComp.getCaretPosition();
- return dot;
+ return JTextComponent.this.getCaretPosition();
}
/**
@@ -141,7 +137,7 @@ public abstract class JTextComponent extends JComponent
*/
public String getSelectedText()
{
- return textComp.getSelectedText();
+ return JTextComponent.this.getSelectedText();
}
/**
@@ -156,9 +152,10 @@ public abstract class JTextComponent extends JComponent
*/
public int getSelectionStart()
{
- if (getSelectedText() == null || (textComp.getText().equals("")))
+ if (getSelectedText() == null
+ || (JTextComponent.this.getText().equals("")))
return 0;
- return textComp.getSelectionStart();
+ return JTextComponent.this.getSelectionStart();
}
/**
@@ -173,9 +170,7 @@ public abstract class JTextComponent extends JComponent
*/
public int getSelectionEnd()
{
- if (getSelectedText() == null || (textComp.getText().equals("")))
- return 0;
- return textComp.getSelectionEnd();
+ return JTextComponent.this.getSelectionEnd();
}
/**
@@ -185,10 +180,20 @@ public abstract class JTextComponent extends JComponent
* @param e - the caret update event
*/
public void caretUpdate(CaretEvent e)
- throws NotImplementedException
{
- // TODO: fire appropriate event.
- dot = e.getDot();
+ int dot = e.getDot();
+ int mark = e.getMark();
+ if (caretDot != dot)
+ {
+ firePropertyChange(ACCESSIBLE_CARET_PROPERTY, new Integer(caretDot),
+ new Integer(dot));
+ caretDot = dot;
+ }
+ if (mark != dot)
+ {
+ firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, null,
+ getSelectedText());
+ }
}
/**
@@ -197,10 +202,10 @@ public abstract class JTextComponent extends JComponent
* @return the accessible state set of this component
*/
public AccessibleStateSet getAccessibleStateSet()
- throws NotImplementedException
{
AccessibleStateSet state = super.getAccessibleStateSet();
- // TODO: Figure out what state must be added here to the super's state.
+ if (isEditable())
+ state.add(AccessibleState.EDITABLE);
return state;
}
@@ -248,9 +253,9 @@ public abstract class JTextComponent extends JComponent
* @param e - the insertion event
*/
public void insertUpdate(DocumentEvent e)
- throws NotImplementedException
{
- // TODO
+ firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null,
+ new Integer(e.getOffset()));
}
/**
@@ -261,9 +266,9 @@ public abstract class JTextComponent extends JComponent
* @param e - the removal event
*/
public void removeUpdate(DocumentEvent e)
- throws NotImplementedException
{
- // TODO
+ firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null,
+ new Integer(e.getOffset()));
}
/**
@@ -274,9 +279,9 @@ public abstract class JTextComponent extends JComponent
* @param e - text change event
*/
public void changedUpdate(DocumentEvent e)
- throws NotImplementedException
{
- // TODO
+ firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null,
+ new Integer(e.getOffset()));
}
/**
@@ -289,9 +294,8 @@ public abstract class JTextComponent extends JComponent
* @return a character index, or -1
*/
public int getIndexAtPoint(Point p)
- throws NotImplementedException
{
- return 0; // TODO
+ return viewToModel(p);
}
/**
@@ -305,9 +309,51 @@ public abstract class JTextComponent extends JComponent
* @return a character's bounding box, or null
*/
public Rectangle getCharacterBounds(int index)
- throws NotImplementedException
{
- return null; // TODO
+ // This is basically the same as BasicTextUI.modelToView().
+
+ Rectangle bounds = null;
+ if (index >= 0 && index < doc.getLength() - 1)
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ try
+ {
+ TextUI ui = getUI();
+ if (ui != null)
+ {
+ // Get editor rectangle.
+ Rectangle rect = new Rectangle();
+ Insets insets = getInsets();
+ rect.x = insets.left;
+ rect.y = insets.top;
+ rect.width = getWidth() - insets.left - insets.right;
+ rect.height = getHeight() - insets.top - insets.bottom;
+ View rootView = ui.getRootView(JTextComponent.this);
+ if (rootView != null)
+ {
+ rootView.setSize(rect.width, rect.height);
+ Shape s = rootView.modelToView(index,
+ Position.Bias.Forward,
+ index + 1,
+ Position.Bias.Backward,
+ rect);
+ if (s != null)
+ bounds = s.getBounds();
+ }
+ }
+ }
+ catch (BadLocationException ex)
+ {
+ // Ignore (return null).
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
+ }
+ return bounds;
}
/**
@@ -317,7 +363,7 @@ public abstract class JTextComponent extends JComponent
*/
public int getCharCount()
{
- return textComp.getText().length();
+ return JTextComponent.this.getText().length();
}
/**
@@ -329,9 +375,26 @@ public abstract class JTextComponent extends JComponent
* @return the character's attributes
*/
public AttributeSet getCharacterAttribute(int index)
- throws NotImplementedException
{
- return null; // TODO
+ AttributeSet atts;
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ try
+ {
+ Element el = doc.getDefaultRootElement();
+ while (! el.isLeaf())
+ {
+ int i = el.getElementIndex(index);
+ el = el.getElement(i);
+ }
+ atts = el.getAttributes();
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
+ return atts;
}
/**
@@ -344,9 +407,8 @@ public abstract class JTextComponent extends JComponent
* @return the part of text at that index, or null
*/
public String getAtIndex(int part, int index)
- throws NotImplementedException
{
- return null; // TODO
+ return getAtIndexImpl(part, index, 0);
}
/**
@@ -359,9 +421,8 @@ public abstract class JTextComponent extends JComponent
* @return the part of text after that index, or null
*/
public String getAfterIndex(int part, int index)
- throws NotImplementedException
{
- return null; // TODO
+ return getAtIndexImpl(part, index, 1);
}
/**
@@ -374,11 +435,84 @@ public abstract class JTextComponent extends JComponent
* @return the part of text before that index, or null
*/
public String getBeforeIndex(int part, int index)
- throws NotImplementedException
{
- return null; // TODO
+ return getAtIndexImpl(part, index, -1);
}
-
+
+ /**
+ * Implements getAtIndex(), getBeforeIndex() and getAfterIndex().
+ *
+ * @param part the part to return, either CHARACTER, WORD or SENTENCE
+ * @param index the index
+ * @param dir the direction, -1 for backwards, 0 for here, +1 for forwards
+ *
+ * @return the resulting string
+ */
+ private String getAtIndexImpl(int part, int index, int dir)
+ {
+ String ret = null;
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ try
+ {
+ BreakIterator iter = null;
+ switch (part)
+ {
+ case CHARACTER:
+ iter = BreakIterator.getCharacterInstance(getLocale());
+ break;
+ case WORD:
+ iter = BreakIterator.getWordInstance(getLocale());
+ break;
+ case SENTENCE:
+ iter = BreakIterator.getSentenceInstance(getLocale());
+ break;
+ default:
+ break;
+ }
+ String text = doc.getText(0, doc.getLength() - 1);
+ iter.setText(text);
+ int start = index;
+ int end = index;
+ switch (dir)
+ {
+ case 0:
+ if (iter.isBoundary(index))
+ {
+ start = index;
+ end = iter.following(index);
+ }
+ else
+ {
+ start = iter.preceding(index);
+ end = iter.next();
+ }
+ break;
+ case 1:
+ start = iter.following(index);
+ end = iter.next();
+ break;
+ case -1:
+ end = iter.preceding(index);
+ start = iter.previous();
+ break;
+ default:
+ assert false;
+ }
+ ret = text.substring(start, end);
+ }
+ catch (BadLocationException ex)
+ {
+ // Ignore (return null).
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
+ return ret;
+ }
+
/**
* Returns the number of actions for this object. The zero-th
* object represents the default action.
@@ -386,9 +520,8 @@ public abstract class JTextComponent extends JComponent
* @return the number of actions (0-based).
*/
public int getAccessibleActionCount()
- throws NotImplementedException
{
- return 0; // TODO
+ return getActions().length;
}
/**
@@ -400,10 +533,12 @@ public abstract class JTextComponent extends JComponent
* @return description of the i-th action
*/
public String getAccessibleActionDescription(int i)
- throws NotImplementedException
{
- // TODO: Not implemented fully
- return super.getAccessibleDescription();
+ String desc = null;
+ Action[] actions = getActions();
+ if (i >= 0 && i < actions.length)
+ desc = (String) actions[i].getValue(Action.NAME);
+ return desc;
}
/**
@@ -415,9 +550,17 @@ public abstract class JTextComponent extends JComponent
* @return true if the action was performed successfully
*/
public boolean doAccessibleAction(int i)
- throws NotImplementedException
{
- return false; // TODO
+ boolean ret = false;
+ Action[] actions = getActions();
+ if (i >= 0 && i < actions.length)
+ {
+ ActionEvent ev = new ActionEvent(JTextComponent.this,
+ ActionEvent.ACTION_PERFORMED, null);
+ actions[i].actionPerformed(ev);
+ ret = true;
+ }
+ return ret;
}
/**
@@ -426,9 +569,8 @@ public abstract class JTextComponent extends JComponent
* @param s - the new text contents.
*/
public void setTextContents(String s)
- throws NotImplementedException
{
- // TODO
+ setText(s);
}
/**
@@ -438,9 +580,16 @@ public abstract class JTextComponent extends JComponent
* @param s - the new text
*/
public void insertTextAtIndex(int index, String s)
- throws NotImplementedException
{
- replaceText(index, index, s);
+ try
+ {
+ doc.insertString(index, s, null);
+ }
+ catch (BadLocationException ex)
+ {
+ // What should we do with this?
+ ex.printStackTrace();
+ }
}
/**
@@ -453,7 +602,7 @@ public abstract class JTextComponent extends JComponent
{
try
{
- return textComp.getText(start, end - start);
+ return JTextComponent.this.getText(start, end - start);
}
catch (BadLocationException ble)
{
@@ -481,8 +630,8 @@ public abstract class JTextComponent extends JComponent
*/
public void cut(int start, int end)
{
- textComp.select(start, end);
- textComp.cut();
+ JTextComponent.this.select(start, end);
+ JTextComponent.this.cut();
}
/**
@@ -492,8 +641,8 @@ public abstract class JTextComponent extends JComponent
*/
public void paste(int start)
{
- textComp.setCaretPosition(start);
- textComp.paste();
+ JTextComponent.this.setCaretPosition(start);
+ JTextComponent.this.paste();
}
/**
@@ -506,8 +655,8 @@ public abstract class JTextComponent extends JComponent
*/
public void replaceText(int start, int end, String s)
{
- textComp.select(start, end);
- textComp.replaceSelection(s);
+ JTextComponent.this.select(start, end);
+ JTextComponent.this.replaceSelection(s);
}
/**
@@ -518,7 +667,7 @@ public abstract class JTextComponent extends JComponent
*/
public void selectText(int start, int end)
{
- textComp.select(start, end);
+ JTextComponent.this.select(start, end);
}
/**
@@ -529,9 +678,12 @@ public abstract class JTextComponent extends JComponent
* @param s - the new attribute set for the text in the range
*/
public void setAttributes(int start, int end, AttributeSet s)
- throws NotImplementedException
{
- // TODO
+ if (doc instanceof StyledDocument)
+ {
+ StyledDocument sdoc = (StyledDocument) doc;
+ sdoc.setCharacterAttributes(start, end - start, s, true);
+ }
}
}
diff --git a/javax/swing/text/LabelView.java b/javax/swing/text/LabelView.java
index 03279c4b2..a00a49c24 100644
--- a/javax/swing/text/LabelView.java
+++ b/javax/swing/text/LabelView.java
@@ -39,9 +39,11 @@ exception statement from your version. */
package javax.swing.text;
import java.awt.Color;
+import java.awt.Container;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Shape;
+import java.awt.Toolkit;
import javax.swing.event.DocumentEvent;
@@ -90,6 +92,11 @@ public class LabelView extends GlyphView
boolean superscript;
/**
+ * Indicates if the attributes must be refetched.
+ */
+ private boolean valid;
+
+ /**
* Creates a new <code>GlyphView</code> for the given <code>Element</code>.
*
* @param element the element that is rendered by this GlyphView
@@ -97,7 +104,7 @@ public class LabelView extends GlyphView
public LabelView(Element element)
{
super(element);
- setPropertiesFromAttributes();
+ valid = false;
}
/**
@@ -115,10 +122,10 @@ public class LabelView extends GlyphView
// when background == null anyway.
background = (Color) atts.getAttribute(StyleConstants.Background);
foreground = StyleConstants.getForeground(atts);
- strikeThrough = StyleConstants.isStrikeThrough(atts);
- subscript = StyleConstants.isSubscript(atts);
- superscript = StyleConstants.isSuperscript(atts);
- underline = StyleConstants.isUnderline(atts);
+ setStrikeThrough(StyleConstants.isStrikeThrough(atts));
+ setSubscript(StyleConstants.isSubscript(atts));
+ setSuperscript(StyleConstants.isSuperscript(atts));
+ setUnderline(StyleConstants.isUnderline(atts));
// Determine the font.
String family = StyleConstants.getFontFamily(atts);
@@ -129,6 +136,7 @@ public class LabelView extends GlyphView
if (StyleConstants.isItalic(atts))
style |= Font.ITALIC;
font = new Font(family, style, size);
+ valid = true;
}
/**
@@ -142,7 +150,8 @@ public class LabelView extends GlyphView
*/
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory vf)
{
- setPropertiesFromAttributes();
+ valid = false;
+ super.changedUpdate(e, a, vf);
}
/**
@@ -152,6 +161,8 @@ public class LabelView extends GlyphView
*/
public Color getBackground()
{
+ if (! valid)
+ setPropertiesFromAttributes();
return background;
}
@@ -175,6 +186,8 @@ public class LabelView extends GlyphView
*/
public Color getForeground()
{
+ if (! valid)
+ setPropertiesFromAttributes();
return foreground;
}
@@ -185,6 +198,8 @@ public class LabelView extends GlyphView
*/
public Font getFont()
{
+ if (! valid)
+ setPropertiesFromAttributes();
return font;
}
@@ -197,7 +212,16 @@ public class LabelView extends GlyphView
*/
protected FontMetrics getFontMetrics()
{
- return getContainer().getGraphics().getFontMetrics(font);
+ if (! valid)
+ setPropertiesFromAttributes();
+
+ Container c = getContainer();
+ FontMetrics fm;
+ if (c != null)
+ fm = c.getFontMetrics(font);
+ else
+ fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
+ return fm;
}
/**
@@ -209,6 +233,8 @@ public class LabelView extends GlyphView
*/
public boolean isUnderline()
{
+ if (! valid)
+ setPropertiesFromAttributes();
return underline;
}
@@ -255,6 +281,8 @@ public class LabelView extends GlyphView
*/
public boolean isSuperscript()
{
+ if (! valid)
+ setPropertiesFromAttributes();
return superscript;
}
@@ -278,6 +306,8 @@ public class LabelView extends GlyphView
*/
public boolean isStrikeThrough()
{
+ if (! valid)
+ setPropertiesFromAttributes();
return strikeThrough;
}
diff --git a/javax/swing/text/PlainView.java b/javax/swing/text/PlainView.java
index 48fe37ce8..5d0ce4a37 100644
--- a/javax/swing/text/PlainView.java
+++ b/javax/swing/text/PlainView.java
@@ -87,6 +87,16 @@ public class PlainView extends View implements TabExpander
*/
private transient Segment lineBuffer;
+ /**
+ * The base offset for tab calculations.
+ */
+ private int tabBase;
+
+ /**
+ * The tab size.
+ */
+ private int tabSize;
+
public PlainView(Element elem)
{
super(elem);
@@ -104,6 +114,7 @@ public class PlainView extends View implements TabExpander
{
this.font = font;
metrics = component.getFontMetrics(font);
+ tabSize = getTabSize() * metrics.charWidth('m');
}
}
@@ -115,7 +126,7 @@ public class PlainView extends View implements TabExpander
// Ensure metrics are up-to-date.
updateMetrics();
- Rectangle rect = a.getBounds();
+ Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
int fontHeight = metrics.getHeight();
return new Rectangle(rect.x, rect.y + (line * fontHeight),
rect.width, fontHeight);
@@ -132,13 +143,14 @@ public class PlainView extends View implements TabExpander
// Get rectangle of the line containing position.
int lineIndex = getElement().getElementIndex(position);
Rectangle rect = lineToRect(a, lineIndex);
+ tabBase = rect.x;
// Get the rectangle for position.
Element line = getElement().getElement(lineIndex);
int lineStart = line.getStartOffset();
Segment segment = getLineBuffer();
document.getText(lineStart, position - lineStart, segment);
- int xoffset = Utilities.getTabbedTextWidth(segment, metrics, rect.x,
+ int xoffset = Utilities.getTabbedTextWidth(segment, metrics, tabBase,
this, lineStart);
// Calc the real rectangle.
@@ -262,17 +274,39 @@ public class PlainView extends View implements TabExpander
selectionStart = textComponent.getSelectionStart();
selectionEnd = textComponent.getSelectionEnd();
- Rectangle rect = s.getBounds();
+ Rectangle rect = s instanceof Rectangle ? (Rectangle) s : s.getBounds();
+ tabBase = rect.x;
// FIXME: Text may be scrolled.
Document document = textComponent.getDocument();
- Element root = document.getDefaultRootElement();
+ Element root = getElement();
int y = rect.y + metrics.getAscent();
int height = metrics.getHeight();
-
+
+ // For layered highlighters we need to paint the layered highlights
+ // before painting any text.
+ LayeredHighlighter hl = null;
+ Highlighter h = textComponent.getHighlighter();
+ if (h instanceof LayeredHighlighter)
+ hl = (LayeredHighlighter) h;
+
int count = root.getElementCount();
+
for (int i = 0; i < count; i++)
{
+ if (hl != null)
+ {
+ Element lineEl = root.getElement(i);
+ // Exclude the trailing newline from beeing highlighted.
+ if (i == count)
+ hl.paintLayeredHighlights(g, lineEl.getStartOffset(),
+ lineEl.getEndOffset(), s, textComponent,
+ this);
+ else
+ hl.paintLayeredHighlights(g, lineEl.getStartOffset(),
+ lineEl.getEndOffset() - 1, s,
+ textComponent, this);
+ }
drawLine(i, g, rect.x, y);
y += height;
}
@@ -303,8 +337,13 @@ public class PlainView extends View implements TabExpander
*/
public float nextTabStop(float x, int tabStop)
{
- float tabSizePixels = getTabSize() * metrics.charWidth('m');
- return (float) (Math.floor(x / tabSizePixels) + 1) * tabSizePixels;
+ float next = x;
+ if (tabSize != 0)
+ {
+ int numTabs = (((int) x) - tabBase) / tabSize;
+ next = tabBase + (numTabs + 1) * tabSize;
+ }
+ return next;
}
/**
@@ -390,41 +429,58 @@ public class PlainView extends View implements TabExpander
*/
public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
{
- Rectangle rec = a.getBounds();
- Document doc = getDocument();
- 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.
- // 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.
- int end = line.getEndOffset() - 1;
- try
- {
- doc.getText(start, end - start, s);
- }
- catch (BadLocationException ble)
+ Rectangle rec = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
+ tabBase = rec.x;
+
+ int pos;
+ if ((int) y < rec.y)
+ // Above our area vertically. Return start offset.
+ pos = getStartOffset();
+ else if ((int) y > rec.y + rec.height)
+ // Below our area vertically. Return end offset.
+ pos = getEndOffset() - 1;
+ else
{
- AssertionError ae = new AssertionError("Unexpected bad location");
- ae.initCause(ble);
- throw ae;
+ // Inside the allocation vertically. Determine line and X offset.
+ Document doc = getDocument();
+ Element root = doc.getDefaultRootElement();
+ int line = Math.abs(((int) y - rec.y) / metrics.getHeight());
+ if (line >= root.getElementCount())
+ pos = getEndOffset() - 1;
+ else
+ {
+ Element lineEl = root.getElement(line);
+ if (x < rec.x)
+ // To the left of the allocation area.
+ pos = lineEl.getStartOffset();
+ else if (x > rec.x + rec.width)
+ // To the right of the allocation area.
+ pos = lineEl.getEndOffset() - 1;
+ else
+ {
+ try
+ {
+ int p0 = lineEl.getStartOffset();
+ int p1 = lineEl.getEndOffset();
+ Segment s = new Segment();
+ doc.getText(p0, p1 - p0, s);
+ tabBase = rec.x;
+ pos = p0 + Utilities.getTabbedTextOffset(s, metrics,
+ tabBase, (int) x,
+ this, p0);
+ }
+ catch (BadLocationException ex)
+ {
+ // Should not happen.
+ pos = -1;
+ }
+ }
+
+ }
}
-
- int pos = Utilities.getTabbedTextOffset(s, metrics, rec.x, (int)x, this, start);
- return Math.max (0, pos);
+ // Bias is always forward.
+ b[0] = Position.Bias.Forward;
+ return pos;
}
/**
@@ -654,7 +710,7 @@ public class PlainView extends View implements TabExpander
throw err;
}
- return Utilities.getTabbedTextWidth(buffer, metrics, 0, this,
+ return Utilities.getTabbedTextWidth(buffer, metrics, tabBase, this,
lineEl.getStartOffset());
}
}
diff --git a/javax/swing/text/Utilities.java b/javax/swing/text/Utilities.java
index 36361f497..f75906a0f 100644
--- a/javax/swing/text/Utilities.java
+++ b/javax/swing/text/Utilities.java
@@ -43,7 +43,6 @@ import java.awt.Graphics;
import java.awt.Point;
import java.text.BreakIterator;
-import javax.swing.SwingConstants;
import javax.swing.text.Position.Bias;
/**
@@ -109,7 +108,7 @@ public class Utilities
for (int offset = s.offset; offset < end; ++offset)
{
char c = buffer[offset];
- if (c == '\t' || c == '\n')
+ if (c == '\t')
{
if (len > 0) {
g.drawChars(buffer, pos, len, pixelX, pixelY + ascent);
@@ -131,11 +130,6 @@ public class Utilities
else
pixelX += metrics.charWidth(' ');
break;
- case '\n':
- // In case we have a newline, we must jump to the next line.
- pixelY += metrics.getHeight();
- pixelX = x;
- break;
default:
++len;
pixelWidth += metrics.charWidth(buffer[offset]);
diff --git a/javax/swing/text/WrappedPlainView.java b/javax/swing/text/WrappedPlainView.java
index a6c369a4c..8cb2f4fb5 100644
--- a/javax/swing/text/WrappedPlainView.java
+++ b/javax/swing/text/WrappedPlainView.java
@@ -449,10 +449,34 @@ public class WrappedPlainView extends BoxView implements TabExpander
int currStart = getStartOffset();
int currEnd;
int count = 0;
+
+ // Determine layered highlights.
+ Container c = getContainer();
+ LayeredHighlighter lh = null;
+ JTextComponent tc = null;
+ if (c instanceof JTextComponent)
+ {
+ tc = (JTextComponent) c;
+ Highlighter h = tc.getHighlighter();
+ if (h instanceof LayeredHighlighter)
+ lh = (LayeredHighlighter) h;
+ }
+
while (currStart < end)
{
currEnd = calculateBreakPosition(currStart, end);
+ // Paint layered highlights, if any.
+ if (lh != null)
+ {
+ // Exclude trailing newline in last line.
+ if (currEnd == end)
+ lh.paintLayeredHighlights(g, currStart, currEnd - 1, s, tc,
+ this);
+ else
+ lh.paintLayeredHighlights(g, currStart, currEnd, s, tc, this);
+
+ }
drawLine(currStart, currEnd, g, rect.x, rect.y + metrics.getAscent());
rect.y += lineHeight;