aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Quinn <jlquinn@gcc.gnu.org>2004-07-14 22:58:30 +0000
committerJerry Quinn <jlquinn@gcc.gnu.org>2004-07-14 22:58:30 +0000
commit12e8e7ea6db5d330599ac86ec971d228e2c2a59b (patch)
tree7c44e660e32d252e2f041e2f9a3a74d9fa12a630
parent08b0dc1be57ef0eca483f684c76e3add21fbd507 (diff)
downloadgcc-12e8e7ea6db5d330599ac86ec971d228e2c2a59b.zip
gcc-12e8e7ea6db5d330599ac86ec971d228e2c2a59b.tar.gz
gcc-12e8e7ea6db5d330599ac86ec971d228e2c2a59b.tar.bz2
EventHandler.java: New file.
2004-07-14 Jerry Quinn <jlquinn@optonline.net> * java/beans/EventHandler.java: New file. * Makefile.am (awt_java_source_files): Add EventHandler.java. * Makefile.in, gcj/Makefile.in, include/Makefile.in, testsuite/Makefile.in: Regenerate. From-SVN: r84714
-rw-r--r--libjava/ChangeLog9
-rw-r--r--libjava/Makefile.am1
-rw-r--r--libjava/Makefile.in6
-rw-r--r--libjava/gcj/Makefile.in8
-rw-r--r--libjava/include/Makefile.in8
-rw-r--r--libjava/java/beans/EventHandler.java393
-rw-r--r--libjava/testsuite/Makefile.in2
7 files changed, 415 insertions, 12 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 2ef5d03..172c372 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,10 @@
+2004-07-14 Jerry Quinn <jlquinn@optonline.net>
+
+ * java/beans/EventHandler.java: New file.
+ * Makefile.am (awt_java_source_files): Add EventHandler.java.
+ * Makefile.in, gcj/Makefile.in, include/Makefile.in,
+ testsuite/Makefile.in: Regenerate.
+
2004-07-14 Andreas Tobler <a.tobler@schweiz.ch>
* testsuite/libjava.jacks/jacks.exp (gcj_jacks_write): Add deprecation
@@ -20,7 +27,7 @@
2004-07-14 Michael Koch <konqueror@gmx.de>
Matthias Klose <doko@debian.org>
- * java/awt/im/InputContext.java: Initialze in, line.
+ * java/awt/im/InputContext.java: Initialize in, line.
2004-07-13 Ulrich Weigand <uweigand@de.ibm.com>
diff --git a/libjava/Makefile.am b/libjava/Makefile.am
index dea851d..fb77561 100644
--- a/libjava/Makefile.am
+++ b/libjava/Makefile.am
@@ -1284,6 +1284,7 @@ java/beans/BeanInfo.java \
java/beans/Beans.java \
java/beans/Customizer.java \
java/beans/DesignMode.java \
+java/beans/EventHandler.java \
java/beans/EventSetDescriptor.java \
java/beans/ExceptionListener.java \
java/beans/Expression.java \
diff --git a/libjava/Makefile.in b/libjava/Makefile.in
index 1e90c35..d9c8a5f 100644
--- a/libjava/Makefile.in
+++ b/libjava/Makefile.in
@@ -963,6 +963,7 @@ java/beans/BeanInfo.java \
java/beans/Beans.java \
java/beans/Customizer.java \
java/beans/DesignMode.java \
+java/beans/EventHandler.java \
java/beans/EventSetDescriptor.java \
java/beans/ExceptionListener.java \
java/beans/Expression.java \
@@ -3075,7 +3076,7 @@ libgcj-test.spec.in libgcj.pc.in libgcj.spec.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-TAR = gtar
+TAR = tar
GZIP_ENV = --best
DIST_SUBDIRS = @DIRLTDL@ testsuite gcj include @DIRLTDL@ gcj include
DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
@@ -3732,7 +3733,8 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/java/awt/print/PrinterJob.P .deps/java/beans/AppletInitializer.P \
.deps/java/beans/BeanDescriptor.P .deps/java/beans/BeanInfo.P \
.deps/java/beans/Beans.P .deps/java/beans/Customizer.P \
-.deps/java/beans/DesignMode.P .deps/java/beans/EventSetDescriptor.P \
+.deps/java/beans/DesignMode.P .deps/java/beans/EventHandler.P \
+.deps/java/beans/EventSetDescriptor.P \
.deps/java/beans/ExceptionListener.P .deps/java/beans/Expression.P \
.deps/java/beans/FeatureDescriptor.P \
.deps/java/beans/IndexedPropertyDescriptor.P \
diff --git a/libjava/gcj/Makefile.in b/libjava/gcj/Makefile.in
index 9a262ce..1e4e84a 100644
--- a/libjava/gcj/Makefile.in
+++ b/libjava/gcj/Makefile.in
@@ -1,6 +1,6 @@
-# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
-# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -172,7 +172,7 @@ DIST_COMMON = ./stamp-h2.in Makefile.am Makefile.in libgcj-config.h.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-TAR = gtar
+TAR = tar
GZIP_ENV = --best
all: all-redirect
.SUFFIXES:
@@ -260,7 +260,7 @@ TAGS: $(HEADERS) $(SOURCES) libgcj-config.h.in $(TAGS_DEPENDENCIES) $(LISP)
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)libgcj-config.h.in$$unique$(LISP)$$tags" \
- || (cd $(srcdir) && etags -o $$here/TAGS $(ETAGS_ARGS) $$tags libgcj-config.h.in $$unique $(LISP))
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags libgcj-config.h.in $$unique $(LISP) -o $$here/TAGS)
mostlyclean-tags:
diff --git a/libjava/include/Makefile.in b/libjava/include/Makefile.in
index e1e0955..72e0a25 100644
--- a/libjava/include/Makefile.in
+++ b/libjava/include/Makefile.in
@@ -1,6 +1,6 @@
-# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
-# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -168,7 +168,7 @@ DIST_COMMON = ./stamp-h1.in Makefile.am Makefile.in config.h.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-TAR = gtar
+TAR = tar
GZIP_ENV = --best
all: all-redirect
.SUFFIXES:
@@ -241,7 +241,7 @@ TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
- || (cd $(srcdir) && etags -o $$here/TAGS $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP))
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
mostlyclean-tags:
diff --git a/libjava/java/beans/EventHandler.java b/libjava/java/beans/EventHandler.java
new file mode 100644
index 0000000..6a7d185
--- /dev/null
+++ b/libjava/java/beans/EventHandler.java
@@ -0,0 +1,393 @@
+/* java.beans.EventHandler
+ Copyright (C) 2004 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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 java.beans;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * class EventHandler
+ *
+ * EventHandler forms a bridge between dynamically created listeners and
+ * arbitrary properties and methods. The idea is that a Proxy that implements
+ * a listener class calls the EventHandler when a listener method is called.
+ * The Proxy calls invoke(), which dispatches the event to a method, called
+ * the action, in another object, called the target.
+ *
+ * The event passed to the listener method is used to access a prespecified
+ * property, which in turn is passed to the action method.
+ *
+ * Normally, call EventHandler.create(), which constructs an EventHandler and
+ * a Proxy for the listener interface. When the listenerMethod gets called on
+ * the proxy, it in turn calls invoke on the attached EventHandler. The
+ * invoke call extracts the bean property from the event object and passes it
+ * to the action method of target object.
+ *
+ * TODO: Add examples of using this thing.
+ *
+ * @author Jerry Quinn (jlquinn@optonline.net)
+ * @since 1.4
+ */
+public class EventHandler implements InvocationHandler
+{
+ // The name of the method that will be implemented. If null, any method.
+ private String listenerMethod;
+
+ // The object to call action on.
+ private Object target;
+
+ // The name of the method or property setter in target.
+ private String action;
+
+ // The property to extract from an event passed to listenerMethod.
+ private String property;
+
+ // String class doesn't already have a capitalize routine.
+ final private String capitalize(String s)
+ {
+ return s.substring(0, 1).toUpperCase() + s.substring(1);
+ }
+
+ /**
+ * Creates a new <code>EventHandler</code> instance.
+ *
+ * Typical creation is done with the create method, not by newing an
+ * EventHandler.
+ *
+ * This constructs an EventHandler that will connect the method
+ * listenerMethodName to target.action, extracting eventPropertyName from
+ * the first argument of listenerMethodName. and sending it to action.
+ *
+ *
+ *
+ * @param target Object that will perform the action.
+ * @param action A property or method of the target.
+ * @param eventPropertyName A readable property of the inbound event.
+ * @param listenerMethodName The listener method name triggering the action.
+ */
+ public EventHandler(Object target, String action, String eventPropertyName,
+ String listenerMethodName)
+ {
+ this.target = target;
+ this.action = action; // Turn this into a method or do we wait till
+ // runtime
+ property = eventPropertyName;
+ listenerMethod = listenerMethodName;
+ }
+
+ /**
+ * Return the event property name.
+ */
+ public String getEventPropertyName()
+ {
+ return property;
+ }
+
+ /**
+ * Return the listener's method name.
+ */
+ public String getListenerMethodName()
+ {
+ return listenerMethod;
+ }
+
+ /**
+ * Return the target object.
+ */
+ public Object getTarget()
+ {
+ return target;
+ }
+
+ /**
+ * Return the action method name.
+ */
+ public String getAction()
+ {
+ return action;
+ }
+
+ // Fetch a qualified property like a.b.c from object o. The properties can
+ // be boolean isProp or object getProp properties.
+ //
+ // Returns a length 2 array with the first entry containing the value
+ // extracted from the property, and the second entry contains the class of
+ // the method return type.
+ //
+ // We play this game because if the method returns a native type, the return
+ // value will be a wrapper. If we then take the type of the wrapper and use
+ // it to locate the action method that takes the native type, it won't match.
+ private Object[] getProperty(Object o, String prop)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
+ {
+ // Use the event object when the property name to extract is null.
+ if (prop == null)
+ return new Object[] {o, o.getClass()};
+
+ // Isolate the first property name from a.b.c.
+ int pos;
+ String rest = null;
+ if ((pos = prop.indexOf('.')) != -1)
+ {
+ rest = prop.substring(pos + 1);
+ prop = prop.substring(0, pos);
+ }
+
+ // Find a method named getProp. It could be isProp instead.
+ Method getter;
+ try
+ {
+ // Look for boolean property getter isProperty
+ getter = o.getClass().getMethod("is" + capitalize(prop),
+ null);
+ }
+ catch (NoSuchMethodException e)
+ {
+ // Look for regular property getter getProperty
+ getter = o.getClass().getMethod("get" + capitalize(prop),
+ null);
+ }
+ Object val = getter.invoke(o, null);
+
+ if (rest != null)
+ return getProperty(val, rest);
+
+ return new Object[] {val, getter.getReturnType()};
+ }
+
+
+ /**
+ * Invoke the event handler.
+ *
+ * Proxy is the object that was used, method is the method that was invoked
+ * on object, and arguments is the set of arguments passed to this method.
+ * We assume that the first argument is the event to extract a property
+ * from.
+ *
+ * Assuming that method matches the listener method specified when creating
+ * this EventHandler, the desired property is extracted from this argument.
+ * The property is passed to target.setAction(), if possible. Otherwise
+ * target.action() is called, where action is the string fed to the
+ * constructor.
+ *
+ * For now we punt on indexed properties. Sun docs are not clear to me
+ * about this.
+ *
+ * @param proxy The proxy object that had method invoked on it.
+ * @param method The method that was invoked.
+ * @param arguments Arguments to method.
+ * @return Result of invoking target.action on the event property
+ */
+ public Object invoke(Object proxy, Method method, Object[] arguments)
+ throws Exception
+ {
+ // Do we actually need the proxy?
+ if (method == null)
+ throw new RuntimeException("Invoking null method");
+
+ // Listener methods that weren't specified are ignored. If listenerMethod
+ // is null, then all listener methods are processed.
+ if (listenerMethod != null && !method.getName().equals(listenerMethod))
+ return null;
+
+ // Extract the first arg from arguments and do getProperty on arg
+ if (arguments == null || arguments.length == 0)
+ return null;
+ Object event = arguments[0]; // We hope :-)
+
+ // Obtain the property XXX propertyType keeps showing up null - why?
+ // because the object inside getProperty changes, but the ref variable
+ // can't change this way, dolt! need a better way to get both values out
+ // - need method and object to do the invoke and get return type
+ Object v[] = getProperty(event, property);
+ Object val = v[0];
+ Class propertyType = (Class) v[1];
+
+ System.out.println("ptype="+propertyType.getName());
+ System.out.println(" val="+((val==null)?"null":val.toString()));
+
+ // Find the actual method of target to invoke. We can't do this in the
+ // constructor since we don't know the type of the property we extracted
+ // from the event then.
+ //
+ // action can be either a property or a method. Sun's docs seem to imply
+ // that action should be treated as a property first, and then a method,
+ // but don't specifically say it.
+ //
+ // XXX check what happens with native type wrappers. The better thing to
+ // do is look at the return type of the method
+ Method actionMethod;
+ try
+ {
+ // Look for a property setter for action.
+ actionMethod =
+ target.getClass().getMethod("set" + capitalize(action),
+ new Class[] {propertyType});
+ }
+ catch (NoSuchMethodException e)
+ {
+ // If action as property didn't work, try as method.
+ try
+ {
+ actionMethod =
+ target.getClass().getMethod(action, new Class[] {propertyType});
+ }
+ catch (NoSuchMethodException e1)
+ {
+ // When event property is null, we may call action with no args
+ if (property == null)
+ {
+ actionMethod =
+ target.getClass().getMethod(action, null);
+ return actionMethod.invoke(target, null);
+ }
+ else
+ throw e1;
+ }
+ }
+
+ // Invoke target.action(property)
+ return actionMethod.invoke(target, new Object[] {val});
+ }
+
+ /**
+ * Construct a new object to dispatch events.
+ *
+ * Equivalent to:
+ * create(listenerInterface, target, action, null, null)
+ *
+ * I.e. all listenerInterface methods are mapped to
+ * target.action(EventObject) or target.action(), if the first doesn't
+ * exist.
+ *
+ * @param listenerInterface Listener interface to implement.
+ * @param target Object to invoke action on.
+ * @param action Target property or method to invoke.
+ * @return A constructed proxy object.
+ */
+ public static Object create(Class listenerInterface, Object target, String action)
+ {
+ return create(listenerInterface, target, action, null, null);
+ }
+
+ /**
+ * Construct a new object to dispatch events.
+ *
+ * Equivalent to:
+ * create(listenerInterface, target, action, eventPropertyName, null)
+ *
+ * I.e. all listenerInterface methods are mapped to
+ * target.action(event.getEventPropertyName)
+ *
+ *
+ * @param listenerInterface Listener interface to implement.
+ * @param target Object to invoke action on.
+ * @param action Target property or method to invoke.
+ * @param eventPropertyName Name of property to extract from event.
+ * @return A constructed proxy object.
+ */
+ public static Object create(Class listenerInterface, Object target,
+ String action, String eventPropertyName)
+ {
+ return create(listenerInterface, target, action, eventPropertyName, null);
+ }
+
+
+ /**
+ * Construct a new object to dispatch events.
+ *
+ * This creates an object that acts as a proxy for the method
+ * listenerMethodName in listenerInterface. When the listener method is
+ * activated, the object extracts eventPropertyName from the event. Then it
+ * passes the property to the method target.setAction, or target.action if
+ * action is not a property with a setter.
+ *
+ * For example, EventHandler.create(MouseListener.class, test, "pushed",
+ * "button", "mouseClicked") generates a proxy object that implements
+ * MouseListener, at least for the method mouseClicked(). The other methods
+ * of MouseListener are null operations. When mouseClicked is invoked, the
+ * generated object extracts the button property from the MouseEvent,
+ * i.e. event.getButton(), and calls test.setPushed() with the result. So under
+ * the covers the following happens:
+ *
+ * <CODE>
+ * object.mouseClicked(MouseEvent e) { test.setPushed(e.getButton()); }
+ * </CODE>
+ *
+ * The Sun spec specifies a hierarchical property naming scheme. Generally
+ * if the property is a.b.c, this corresponds to event.getA().getB().getC()
+ * or event.getA().getB().isC(). I don't see how you specify an indexed
+ * property, though. This may be a limitation of the Sun implementation as
+ * well. The spec doesn't seem to address it.
+ *
+ * If eventPropertyName is null, EventHandler instead uses the event object
+ * in place of a property, i.e. it calls target.action(EventObject). If
+ * there is no method named action taking an EventObject argument,
+ * EventHandler looks for a method target.action() taking no arguments.
+ *
+ * If listenerMethodName is null, every method in listenerInterface gets
+ * mapped to target.action, rather than the specified listener method.
+ *
+ * @param listenerInterface Listener interface to implement.
+ * @param target Object to invoke action on.
+ * @param action Target method name to invoke.
+ * @param eventPropertyName Name of property to extract from event.
+ * @param listenerMethodName Listener method to implement.
+ * @return A constructed proxy object.
+ */
+ public static Object create(Class listenerInterface, Object target,
+ String action, String eventPropertyName,
+ String listenerMethodName)
+ {
+ // Create EventHandler instance
+ EventHandler eh = new EventHandler(target, action, eventPropertyName,
+ listenerMethodName);
+
+ // Create proxy object passing in the event handler
+ Object proxy = Proxy.newProxyInstance(listenerInterface.getClassLoader(),
+ new Class[] {listenerInterface},
+ eh);
+
+ return proxy;
+ }
+
+}
diff --git a/libjava/testsuite/Makefile.in b/libjava/testsuite/Makefile.in
index 21c86dd..79a8283 100644
--- a/libjava/testsuite/Makefile.in
+++ b/libjava/testsuite/Makefile.in
@@ -177,7 +177,7 @@ DIST_COMMON = Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-TAR = gtar
+TAR = tar
GZIP_ENV = --best
all: all-redirect
.SUFFIXES: