I see that the events are not really compatible with Map events, so maybe BeanMap is not the best approach. However, firing these events from BeanDictionary itself should be OK.

BTW, I like the "propertyChanged" event, but the "eventFired" event seems a bit odd. The two seem to overlap, and I'm not sure what the use case might be for a generic "eventFired" event.


On Oct 26, 2009, at 10:07 AM, Greg Brown wrote:

BeanDictionary already has a "bean" property. It is currently read- only, but we could add a setter.

I don't think it is especially heavy to add this functionality to BeanDictionary, because we wouldn't have to monitor the bean unless the caller adds a listener. Alternatively, we could create a BeanMap class that extends BeanDictionary (or simply replace BeanDictionary with BeanMap). I think either of these approaches would be preferable to a separate BeanMonitor class.

On Oct 26, 2009, at 9:58 AM, Todd Volkert wrote:

I thought about that, and maybe we could. It seemed kinda heavy for most bean dictionary use cases though. We'd also need to make BeanDictionary have a source property and fire source changed events as well (since the
caller will leak memory without calling BeanMonitor.setSource(null).

I'm not averse to integrating the two, but I feel like we might want to keep BeanDictionary lighter than BeanMonitor. Other than that, I'm very
happy with how BeanMonitor came out.

-T

On Mon, Oct 26, 2009 at 9:53 AM, Greg Brown <[email protected]> wrote:

Could we not put this functionality in BeanDictionary itself?


On Oct 26, 2009, at 9:48 AM, [email protected] wrote:

Author: tvolkert
Date: Mon Oct 26 13:48:09 2009
New Revision: 829797

URL: http://svn.apache.org/viewvc?rev=829797&view=rev
Log:
Added BeanMonitor, changed EventLogger tool to use it, hooked up events to
component inspector tool

Added:
incubator/pivot/trunk/core/src/org/apache/pivot/beans/ BeanMonitor.java

incubator/pivot/trunk/core/src/org/apache/pivot/beans/ BeanMonitorListener.java
Modified:

incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ ComponentInspectorSkin.java

incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ EventLogger.java

incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ component_inspector_skin.wtkx

Added:
incubator/pivot/trunk/core/src/org/apache/pivot/beans/ BeanMonitor.java
URL:
http://svn.apache.org/viewvc/incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanMonitor.java?rev=829797&view=auto

= = = = = = = = = = = =================================================================== --- incubator/pivot/trunk/core/src/org/apache/pivot/beans/ BeanMonitor.java
(added)
+++ incubator/pivot/trunk/core/src/org/apache/pivot/beans/ BeanMonitor.java
Mon Oct 26 13:48:09 2009
@@ -0,0 +1,364 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.beans;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.Comparator;
+
+import org.apache.pivot.collections.ArrayList;
+import org.apache.pivot.collections.HashMap;
+import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.collections.immutable.ImmutableList;
+import org.apache.pivot.util.ListenerList;
+import org.apache.pivot.util.ThreadUtilities;
+import org.apache.pivot.util.Vote;
+
+/**
+ * Notifies listeners of events fired from a source bean.
+ */
+public class BeanMonitor {
+ private static class EventComparator implements Comparator<Method> {
+        @Override
+        public int compare(Method event1, Method event2) {
+            int result = 0;
+
+ Class<?> listenerInterface1 = event1.getDeclaringClass(); + Class<?> listenerInterface2 = event2.getDeclaringClass();
+
+            if (listenerInterface1 != listenerInterface2) {
+                result =
listenerInterface1.getName().compareTo(listenerInterface2.getName ());
+            }
+
+            if (result == 0) {
+ result = event1.getName().compareTo (event2.getName());
+            }
+
+            return result;
+        }
+    }
+
+    private static class PropertyNameComparator implements
Comparator<String> {
+        @Override
+ public int compare(String propertyName1, String propertyName2) {
+            return propertyName1.compareTo(propertyName2);
+        }
+    }
+
+ private class MonitorInvocationHandler implements InvocationHandler {
+        @Override
+        public Object invoke(Object proxy, Method event, Object[]
arguments) throws Throwable {
+ beanMonitorListeners.eventFired(BeanMonitor.this, event,
arguments);
+
+            String eventName = event.getName();
+            if (eventName.endsWith(PROPERTY_CHANGE_SUFFIX)) {
+                String propertyName = eventName.substring(0,
eventName.length()
+                    - PROPERTY_CHANGE_SUFFIX.length());
+
+ if (notifyingProperties.indexOf(propertyName) >= 0) {
+
beanMonitorListeners.propertyChanged(BeanMonitor.this, propertyName);
+                }
+            }
+
+            Object result = null;
+            Class<?> returnType = event.getReturnType();
+            if (returnType == Vote.class) {
+                result = Vote.APPROVE;
+            } else if (returnType == Boolean.TYPE) {
+                result = false;
+            }
+
+            return result;
+        }
+    }
+
+    private static class BeanMonitorListenerList extends
ListenerList<BeanMonitorListener>
+        implements BeanMonitorListener {
+        @Override
+        public void sourceChanged(BeanMonitor beanMonitor, Object
previousSource) {
+            for (BeanMonitorListener listener : this) {
+ listener.sourceChanged(beanMonitor, previousSource);
+            }
+        }
+
+        @Override
+ public void eventFired(BeanMonitor beanMonitor, Method event,
Object[] arguments) {
+            for (BeanMonitorListener listener : this) {
+ listener.eventFired(beanMonitor, event, arguments);
+            }
+        }
+
+        @Override
+ public void propertyChanged(BeanMonitor beanMonitor, String
propertyName) {
+            for (BeanMonitorListener listener : this) {
+ listener.propertyChanged(beanMonitor, propertyName);
+            }
+        }
+    }
+
+    private Object source = null;
+
+    private HashMap<Class<?>, Object> eventListenerProxies = new
HashMap<Class<?>, Object>();
+ private MonitorInvocationHandler monitorInvocationHandler = new
MonitorInvocationHandler();
+
+    private ArrayList<Method> declaredEvents = new
ArrayList<Method>(eventComparator);
+    private ArrayList<String> notifyingProperties = new
ArrayList<String>(propertyNameComparator);
+
+    private BeanMonitorListenerList beanMonitorListeners = new
BeanMonitorListenerList();
+
+    private static EventComparator eventComparator = new
EventComparator();
+ private static PropertyNameComparator propertyNameComparator = new
PropertyNameComparator();
+
+ private static final String PROPERTY_CHANGE_SUFFIX = "Changed";
+
+    /**
+ * Creates a new bean monitor that is initially associated with no
source
+     * object.
+     */
+    public BeanMonitor() {
+        this(null);
+    }
+
+    /**
+ * Creates a new bean monitor that will monitor the specified source
+     * object.
+     * <p>
+ * <b>NOTE</b>: failing to clear the source of a bean monitor may
result in
+ * memory leaks, as the source object will maintain references to the
bean
+     * monitor as long as the source is set.
+     */
+    public BeanMonitor(Object source) {
+        setSource(source);
+    }
+
+    /**
+     * Gets the source of the bean monitor.
+     *
+     * @return
+ * The source object, or <tt>null</tt> if no source has been set.
+     */
+    public Object getSource() {
+        return source;
+    }
+
+    /**
+     * Sets the source of the bean monitor.
+     * <p>
+ * <b>NOTE</b>: failing to clear the source of a bean monitor may
result in
+ * memory leaks, as the source object will maintain references to the
bean
+     * monitor as long as the source is set.
+     *
+     * @param source
+     * The source object, or <tt>null</tt> to clear the source.
+     */
+    public void setSource(Object source) {
+        Object previousSource = this.source;
+
+        if (source != previousSource) {
+            this.source = source;
+
+            if (previousSource != null) {
+                unregisterEventListeners(previousSource);
+            }
+
+            declaredEvents.clear();
+            notifyingProperties.clear();
+
+            if (source != null) {
+                registerEventListeners(source);
+            }
+
+ beanMonitorListeners.sourceChanged(this, previousSource);
+        }
+    }
+
+    /**
+     * Gets the list of events that the source bean may fire.
+     *
+     * @return
+     * The event listener methods that the source bean may invoke.
+     */
+    public Sequence<Method> getDeclaredEvents() {
+        return new ImmutableList<Method>(declaredEvents);
+    }
+
+    /**
+ * Gets the list of source bean property names for which property
change
+     * events will be fired.
+     *
+     * @return
+     * The property names that fire change events.
+     */
+    public Sequence<String> getNotifyingProperties() {
+        return new ImmutableList<String>(notifyingProperties);
+    }
+
+    /**
+ * Tells whether or not the specified property fires change events.
+     *
+     * @return
+ * <tt>true</tt> if the property fires change events; <tt>false</tt>
+     * otherwise.
+     */
+    public boolean isNotifyingProperty(String propertyName) {
+        return (notifyingProperties.indexOf(propertyName) >= 0);
+    }
+
+    /**
+     * Registers event listeners on a bean.
+     */
+    private void registerEventListeners(Object bean) {
+        BeanDictionary beanDictionary = new BeanDictionary(bean);
+        Method[] methods = bean.getClass().getMethods();
+
+        for (int i = 0; i < methods.length; i++) {
+            Method method = methods[i];
+
+            if
(ListenerList.class.isAssignableFrom(method.getReturnType())
+ && (method.getModifiers() & Modifier.STATIC) == 0) {
+                ParameterizedType genericType =
(ParameterizedType)method.getGenericReturnType();
+                Type[] typeArguments =
genericType.getActualTypeArguments();
+
+                if (typeArguments.length == 1) {
+                    Class<?> listenerInterface =
(Class<?>)typeArguments[0];
+
+                    if (!listenerInterface.isInterface()) {
+                        throw new
RuntimeException(listenerInterface.getName()
+                            + " is not an interface.");
+                    }
+
+                    Method[] interfaceMethods =
listenerInterface.getMethods();
+ for (int j = 0; j < interfaceMethods.length; j++) { + Method interfaceMethod = interfaceMethods [j];
+                        String interfaceMethodName =
interfaceMethod.getName();
+
+                        declaredEvents.add(interfaceMethod);
+
+                        if
(interfaceMethodName.endsWith(PROPERTY_CHANGE_SUFFIX)) {
+                            String propertyName =
interfaceMethodName.substring(0,
+                                interfaceMethodName.length() -
PROPERTY_CHANGE_SUFFIX.length());
+
+ if (beanDictionary.containsKey (propertyName))
{
+ notifyingProperties.add (propertyName);
+                            }
+                        }
+                    }
+
+                    // Get the listener list
+                    Object listenerList;
+                    try {
+                        listenerList = method.invoke(bean);
+ } catch (InvocationTargetException exception) {
+                        throw new RuntimeException(exception);
+                    } catch (IllegalAccessException exception) {
+                        throw new RuntimeException(exception);
+                    }
+
+                    // Get the listener for this interface
+                    Object listener =
eventListenerProxies.get(listenerInterface);
+                    if (listener == null) {
+                        listener =
Proxy.newProxyInstance(ThreadUtilities.getClassLoader(),
+                            new Class[]{listenerInterface},
monitorInvocationHandler);
+ eventListenerProxies.put (listenerInterface,
listener);
+                    }
+
+                    // Add the listener
+ Class<?> listenerListClass = listenerList.getClass();
+                    Method addMethod;
+                    try {
+ addMethod = listenerListClass.getMethod ("add",
+                            new Class<?>[] {Object.class});
+                    } catch (NoSuchMethodException exception) {
+                        throw new RuntimeException(exception);
+                    }
+
+                    try {
+ addMethod.invoke(listenerList, new Object []
{listener});
+                    } catch (IllegalAccessException exception) {
+                        throw new RuntimeException(exception);
+ } catch (InvocationTargetException exception) {
+                        throw new RuntimeException(exception);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Un-registers event listeners on a bean.
+     */
+    private void unregisterEventListeners(Object bean) {
+        Method[] methods = bean.getClass().getMethods();
+
+        for (int i = 0; i < methods.length; i++) {
+            Method method = methods[i];
+
+            if
(ListenerList.class.isAssignableFrom(method.getReturnType())
+ && (method.getModifiers() & Modifier.STATIC) == 0) {
+                ParameterizedType genericType =
(ParameterizedType)method.getGenericReturnType();
+                Type[] typeArguments =
genericType.getActualTypeArguments();
+
+                if (typeArguments.length == 1) {
+                    Class<?> listenerInterface =
(Class<?>)typeArguments[0];
+
+                    // Get the listener list
+                    Object listenerList;
+                    try {
+                        listenerList = method.invoke(bean);
+ } catch (InvocationTargetException exception) {
+                        throw new RuntimeException(exception);
+                    } catch (IllegalAccessException exception) {
+                        throw new RuntimeException(exception);
+                    }
+
+                    // Get the listener for this interface
+                    Object listener =
eventListenerProxies.get(listenerInterface);
+                    if (listener == null) {
+ throw new IllegalStateException ("Listener proxy
is null.");
+                    }
+
+                    // Remove the listener
+ Class<?> listenerListClass = listenerList.getClass();
+                    Method removeMethod;
+                    try {
+                        removeMethod =
listenerListClass.getMethod("remove",
+                            new Class<?>[] {Object.class});
+                    } catch (NoSuchMethodException exception) {
+                        throw new RuntimeException(exception);
+                    }
+
+                    try {
+ removeMethod.invoke(listenerList, new Object[]
{listener});
+                    } catch (IllegalAccessException exception) {
+                        throw new RuntimeException(exception);
+ } catch (InvocationTargetException exception) {
+                        throw new RuntimeException(exception);
+                    }
+                }
+            }
+        }
+    }
+
+ public ListenerList<BeanMonitorListener> getBeanMonitorListeners() {
+        return beanMonitorListeners;
+    }
+}

Added:
incubator/pivot/trunk/core/src/org/apache/pivot/beans/ BeanMonitorListener.java
URL:
http://svn.apache.org/viewvc/incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanMonitorListener.java?rev=829797&view=auto

= = = = = = = = = = = ===================================================================
---
incubator/pivot/trunk/core/src/org/apache/pivot/beans/ BeanMonitorListener.java
(added)
+++
incubator/pivot/trunk/core/src/org/apache/pivot/beans/ BeanMonitorListener.java
Mon Oct 26 13:48:09 2009
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.beans;
+
+import java.lang.reflect.Method;
+
+/**
+ * Bean monitor listener interface.
+ */
+public interface BeanMonitorListener {
+    /**
+     * Bean monitor listener adapter.
+     */
+    public static class Adapter implements BeanMonitorListener {
+        @Override
+        public void sourceChanged(BeanMonitor beanMonitor, Object
previousSource) {
+        }
+
+        @Override
+ public void eventFired(BeanMonitor beanMonitor, Method event,
Object[] arguments) {
+        }
+
+        @Override
+ public void propertyChanged(BeanMonitor beanMonitor, String
propertyName) {
+        }
+    }
+
+    /**
+     * Called when a bean monitor's source has changed.
+     *
+     * @param beanMonitor
+     * @param previousSource
+     */
+    public void sourceChanged(BeanMonitor beanMonitor, Object
previousSource);
+
+    /**
+ * Called when an event has been fired by the bean monitor's source.
+     *
+     * @param beanMonitor
+     * @param event
+     * @param arguments
+     */
+    public void eventFired(BeanMonitor beanMonitor, Method event,
Object[] arguments);
+
+    /**
+ * Called when a property of the bean monitor's source has changed.
+     *
+     * @param beanMonitor
+     * @param propertyName
+     */
+    public void propertyChanged(BeanMonitor beanMonitor, String
propertyName);
+}

Modified:
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ ComponentInspectorSkin.java
URL:
http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentInspectorSkin.java?rev=829797&r1=829796&r2=829797&view=diff

= = = = = = = = = = = ===================================================================
---
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ ComponentInspectorSkin.java
(original)
+++
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ ComponentInspectorSkin.java
Mon Oct 26 13:48:09 2009
@@ -21,11 +21,12 @@
import java.util.Comparator;

import org.apache.pivot.beans.BeanDictionary;
+import org.apache.pivot.beans.BeanMonitor;
+import org.apache.pivot.beans.BeanMonitorListener;
import org.apache.pivot.collections.ArrayList;
import org.apache.pivot.collections.EnumList;
import org.apache.pivot.collections.HashMap;
import org.apache.pivot.collections.List;
-import org.apache.pivot.collections.Map;
import org.apache.pivot.serialization.SerializationException;
import org.apache.pivot.util.Resources;
import org.apache.pivot.wtk.BoxPane;
@@ -33,6 +34,7 @@
import org.apache.pivot.wtk.ButtonStateListener;
import org.apache.pivot.wtk.Checkbox;
import org.apache.pivot.wtk.Component;
+import org.apache.pivot.wtk.ComponentStateListener;
import org.apache.pivot.wtk.Dimensions;
import org.apache.pivot.wtk.FlowPane;
import org.apache.pivot.wtk.Form;
@@ -42,7 +44,6 @@
import org.apache.pivot.wtk.ListButtonSelectionListener;
import org.apache.pivot.wtk.Orientation;
import org.apache.pivot.wtk.Point;
-import org.apache.pivot.wtk.Rollup;
import org.apache.pivot.wtk.TextInput;
import org.apache.pivot.wtk.skin.ContainerSkin;
import org.apache.pivot.wtk.text.validation.IntValidator;
@@ -76,13 +77,41 @@

 private Component content = null;

-    @WTKX private BoxPane propertiesPane = null;
+    @WTKX private Form propertiesForm = null;
 @WTKX private BoxPane stylesPane = null;

+    private BeanDictionary beanDictionary = null;
+    private BeanMonitor beanMonitor = new BeanMonitor();
+
+    private HashMap<String, Component> inspectorComponents = new
HashMap<String, Component>();
+
 private static PropertyNameComparator propertyNameComparator = new
PropertyNameComparator();
 private static PropertySourceTypeComparator
propertySourceTypeComparator =
     new PropertySourceTypeComparator();

+    public ComponentInspectorSkin() {
+        beanMonitor.getBeanMonitorListeners().add(new
BeanMonitorListener.Adapter() {
+            @Override
+ public void propertyChanged(BeanMonitor beanMonitor, String
propertyName) {
+                Class<?> propertyType =
beanDictionary.getType(propertyName);
+
+                if (propertyType == Boolean.TYPE) {
+                    updateBooleanControl(propertyName);
+                } else if (propertyType == Integer.TYPE) {
+                    updateIntControl(propertyName);
+                } else if (propertyType.isEnum()) {
+                    updateEnumControl(propertyName);
+                } else if (propertyType == Point.class) {
+                    updatePointControl(propertyName);
+                } else if (propertyType == Dimensions.class) {
+                    updateDimensionsControl(propertyName);
+                } else if (propertyType == Limits.class) {
+                    updateLimitsControl(propertyName);
+                }
+            }
+        });
+    }
+
 @Override
 public void install(Component component) {
     super.install(component);
@@ -139,25 +168,26 @@

 @Override
 public void sourceChanged(ComponentInspector componentInspector,
Component previousSource) {
-        propertiesPane.remove(0, propertiesPane.getLength());
+        Form.SectionSequence propertiesSections =
propertiesForm.getSections();
+ propertiesSections.remove(0, propertiesSections.getLength ());
+
     stylesPane.remove(0, stylesPane.getLength());

     Component source = componentInspector.getSource();

+        beanDictionary = null;
+        beanMonitor.setSource(source);
+
     if (source != null) {
-            Class<?> sourceType = source.getClass();
- BeanDictionary beanDictionary = new BeanDictionary (source);
+            beanDictionary = new BeanDictionary(source);

-            Map<Class<?>, List<String>> propertyBuckets =
+            Class<?> sourceType = source.getClass();
+            HashMap<Class<?>, List<String>> propertyBuckets =
             new HashMap<Class<?>,
List<String>>(propertySourceTypeComparator);

         for (String propertyName : beanDictionary) {
-                boolean readOnly =
beanDictionary.isReadOnly(propertyName);
-
-                if (!readOnly) {
-                    // TODO?
-                    // Class<?> propertyType =
beanDictionary.getType(propertyName);
-
+                if (beanMonitor.isNotifyingProperty(propertyName)
+                    && !beanDictionary.isReadOnly(propertyName)) {
                 Method method =
BeanDictionary.getGetterMethod(sourceType, propertyName);
Class<?> declaringClass = method.getDeclaringClass();

@@ -172,47 +202,42 @@
         }

         for (Class<?> declaringClass : propertyBuckets) {
-                Rollup rollup = new Rollup();
-                propertiesPane.add(rollup);
- Label label = new Label (declaringClass.getSimpleName());
-                label.getStyles().put("color", 16);
-                label.getStyles().put("font", "{bold:true}");
-                rollup.setHeading(label);
-
-                Form form = new Form();
-                form.getStyles().put("rightAlignLabels", true);
             Form.Section section = new Form.Section();
-                form.getSections().add(section);
-                rollup.setContent(form);
+ section.setHeading(declaringClass.getSimpleName ());
+                propertiesSections.add(section);

             for (String propertyName :
propertyBuckets.get(declaringClass)) {
-                    addPropertyControl(propertyName, section,
beanDictionary);
+                    addPropertyControl(propertyName, section);
             }
         }
     }
 }

- private void addPropertyControl(String propertyName, Form.Section
section,
-        BeanDictionary beanDictionary) {
+ private void addPropertyControl(String propertyName, Form.Section
section) {
     Class<?> propertyType = beanDictionary.getType(propertyName);

+        Component inspectorComponent = null;
+
     if (propertyType == Boolean.TYPE) {
- addBooleanControl(propertyName, section, beanDictionary);
+            inspectorComponent = addBooleanControl(propertyName,
section);
     } else if (propertyType == Integer.TYPE) {
-            addIntControl(propertyName, section, beanDictionary);
+ inspectorComponent = addIntControl(propertyName, section);
     } else if (propertyType.isEnum()) {
-            addEnumControl(propertyName, section, beanDictionary);
+ inspectorComponent = addEnumControl(propertyName, section);
     } else if (propertyType == Point.class) {
- addPointControl(propertyName, section, beanDictionary); + inspectorComponent = addPointControl(propertyName, section);
     } else if (propertyType == Dimensions.class) {
- addDimensionsControl(propertyName, section, beanDictionary); + inspectorComponent = addDimensionsControl (propertyName,
section);
     } else if (propertyType == Limits.class) {
- addLimitsControl(propertyName, section, beanDictionary); + inspectorComponent = addLimitsControl(propertyName, section);
+        }
+
+        if (inspectorComponent != null) {
+ inspectorComponents.put(propertyName, inspectorComponent);
     }
 }

-    private void addBooleanControl(final String propertyName,
Form.Section section,
-        final BeanDictionary beanDictionary) {
+    private Component addBooleanControl(final String propertyName,
Form.Section section) {
boolean propertyValue = (Boolean)beanDictionary.get (propertyName);

     Checkbox checkbox = new Checkbox();
@@ -226,11 +251,20 @@
             beanDictionary.put(propertyName, button.isSelected());
         }
     });
+
+        return checkbox;
 }

- private void addIntControl(final String propertyName, Form.Section
section,
-        final BeanDictionary beanDictionary) {
-        /*
+    private void updateBooleanControl(String propertyName) {
+        Checkbox checkbox =
(Checkbox)inspectorComponents.get(propertyName);
+
+        if (checkbox != null) {
+            boolean propertyValue =
(Boolean)beanDictionary.get(propertyName);
+            checkbox.setSelected(propertyValue);
+        }
+    }
+
+    private Component addIntControl(final String propertyName,
Form.Section section) {
     int propertyValue = (Integer)beanDictionary.get(propertyName);

     TextInput textInput = new TextInput();
@@ -244,21 +278,33 @@
     textInput.getComponentStateListeners().add(new
ComponentStateListener.Adapter() {
         @Override
         public void focusedChanged(Component component, Component
obverseComponent) {
-                TextInput textInput = (TextInput)component;
-                try {
-                    beanDictionary.put(propertyName,
Integer.parseInt(textInput.getText()));
-                } catch (Exception exception) {
-                    Object propertyValue =
beanDictionary.get(propertyName);
- textInput.setText(String.valueOf (propertyValue));
+                if (!component.isFocused()) {
+                    TextInput textInput = (TextInput)component;
+
+                    try {
+                        beanDictionary.put(propertyName,
Integer.parseInt(textInput.getText()));
+                    } catch (Exception exception) {
+                        Object propertyValue =
beanDictionary.get(propertyName);
+ textInput.setText(String.valueOf (propertyValue));
+                    }
             }
         }
     });
-        */
+
+        return textInput;
+    }
+
+    private void updateIntControl(String propertyName) {
+        TextInput textInput =
(TextInput)inspectorComponents.get(propertyName);
+
+        if (textInput != null) {
+            int propertyValue =
(Integer)beanDictionary.get(propertyName);
+            textInput.setText(String.valueOf(propertyValue));
+        }
 }

 @SuppressWarnings("unchecked")
- private void addEnumControl(final String propertyName, Form.Section
section,
-        final BeanDictionary beanDictionary) {
+    private Component addEnumControl(final String propertyName,
Form.Section section) {
     Class<?> propertyType = beanDictionary.getType(propertyName);
Enum<?> propertyValue = (Enum<?>)beanDictionary.get (propertyName);

@@ -274,10 +320,20 @@
             beanDictionary.put(propertyName,
listButton.getSelectedItem());
         }
     });
+
+        return listButton;
 }

- private void addPointControl(final String propertyName, Form.Section
section,
-        final BeanDictionary beanDictionary) {
+    private void updateEnumControl(String propertyName) {
+        ListButton listButton =
(ListButton)inspectorComponents.get(propertyName);
+
+        if (listButton != null) {
+            Enum<?> propertyValue =
(Enum<?>)beanDictionary.get(propertyName);
+            listButton.setSelectedItem(propertyValue);
+        }
+    }
+
+    private Component addPointControl(final String propertyName,
Form.Section section) {
     Point point = (Point)beanDictionary.get(propertyName);

     BoxPane boxPane = new BoxPane(Orientation.VERTICAL);
@@ -296,6 +352,23 @@
     textInput.setText(String.valueOf(point.x));
     flowPane.add(textInput);

+        textInput.getComponentStateListeners().add(new
ComponentStateListener.Adapter() {
+            @Override
+ public void focusedChanged(Component component, Component
obverseComponent) {
+                if (!component.isFocused()) {
+                    TextInput textInput = (TextInput)component;
+                    Point point =
(Point)beanDictionary.get(propertyName);
+
+                    try {
+ int x = Integer.parseInt (textInput.getText()); + beanDictionary.put(propertyName, new Point(x,
point.y));
+                    } catch (Exception exception) {
+ textInput.setText(String.valueOf (point.x));
+                    }
+                }
+            }
+        });
+
     Label label = new Label("x");
     label.getStyles().put("font", "{italic:true}");
     flowPane.add(label);
@@ -312,13 +385,45 @@
     textInput.setText(String.valueOf(point.y));
     flowPane.add(textInput);

+        textInput.getComponentStateListeners().add(new
ComponentStateListener.Adapter() {
+            @Override
+ public void focusedChanged(Component component, Component
obverseComponent) {
+                if (!component.isFocused()) {
+                    TextInput textInput = (TextInput)component;
+                    Point point =
(Point)beanDictionary.get(propertyName);
+
+                    try {
+ int y = Integer.parseInt (textInput.getText());
+                        beanDictionary.put(propertyName, new
Point(point.x, y));
+                    } catch (Exception exception) {
+ textInput.setText(String.valueOf (point.y));
+                    }
+                }
+            }
+        });
+
     label = new Label("y");
     label.getStyles().put("font", "{italic:true}");
     flowPane.add(label);
+
+        return boxPane;
 }

-    private void addDimensionsControl(final String propertyName,
Form.Section section,
-        final BeanDictionary beanDictionary) {
+    private void updatePointControl(String propertyName) {
+ BoxPane boxPane = (BoxPane)inspectorComponents.get (propertyName);
+
+        if (boxPane != null) {
+            Point point = (Point)beanDictionary.get(propertyName);
+
+            TextInput xTextInput =
(TextInput)((FlowPane)boxPane.get(0)).get(0);
+            TextInput yTextInput =
(TextInput)((FlowPane)boxPane.get(1)).get(0);
+
+            xTextInput.setText(String.valueOf(point.x));
+            yTextInput.setText(String.valueOf(point.y));
+        }
+    }
+
+ private Component addDimensionsControl(final String propertyName,
Form.Section section) {
     Dimensions dimensions =
(Dimensions)beanDictionary.get(propertyName);

     BoxPane boxPane = new BoxPane(Orientation.VERTICAL);
@@ -337,6 +442,23 @@
     textInput.setText(String.valueOf(dimensions.width));
     flowPane.add(textInput);

+        textInput.getComponentStateListeners().add(new
ComponentStateListener.Adapter() {
+            @Override
+ public void focusedChanged(Component component, Component
obverseComponent) {
+                if (!component.isFocused()) {
+                    TextInput textInput = (TextInput)component;
+                    Dimensions dimensions =
(Dimensions)beanDictionary.get(propertyName);
+
+                    try {
+                        int width =
Integer.parseInt(textInput.getText());
+                        beanDictionary.put(propertyName, new
Dimensions(width, dimensions.height));
+                    } catch (Exception exception) {
+
textInput.setText(String.valueOf(dimensions.width));
+                    }
+                }
+            }
+        });
+
     Label label = new Label("width");
     label.getStyles().put("font", "{italic:true}");
     flowPane.add(label);
@@ -353,13 +475,45 @@
     textInput.setText(String.valueOf(dimensions.height));
     flowPane.add(textInput);

+        textInput.getComponentStateListeners().add(new
ComponentStateListener.Adapter() {
+            @Override
+ public void focusedChanged(Component component, Component
obverseComponent) {
+                if (!component.isFocused()) {
+                    TextInput textInput = (TextInput)component;
+                    Dimensions dimensions =
(Dimensions)beanDictionary.get(propertyName);
+
+                    try {
+                        int height =
Integer.parseInt(textInput.getText());
+                        beanDictionary.put(propertyName, new
Dimensions(dimensions.width, height));
+                    } catch (Exception exception) {
+
textInput.setText(String.valueOf(dimensions.height));
+                    }
+                }
+            }
+        });
+
     label = new Label("height");
     label.getStyles().put("font", "{italic:true}");
     flowPane.add(label);
+
+        return boxPane;
+    }
+
+    private void updateDimensionsControl(String propertyName) {
+ BoxPane boxPane = (BoxPane)inspectorComponents.get (propertyName);
+
+        if (boxPane != null) {
+            Dimensions dimensions =
(Dimensions)beanDictionary.get(propertyName);
+
+            TextInput widthTextInput =
(TextInput)((FlowPane)boxPane.get(0)).get(0);
+            TextInput heightTextInput =
(TextInput)((FlowPane)boxPane.get(1)).get(0);
+
+ widthTextInput.setText(String.valueOf (dimensions.width)); + heightTextInput.setText(String.valueOf (dimensions.height));
+        }
 }

- private void addLimitsControl(final String propertyName, Form.Section
section,
-        final BeanDictionary beanDictionary) {
+    private Component addLimitsControl(final String propertyName,
Form.Section section) {
     Limits limits = (Limits)beanDictionary.get(propertyName);

     BoxPane boxPane = new BoxPane(Orientation.VERTICAL);
@@ -378,6 +532,23 @@
     textInput.setText(String.valueOf(limits.min));
     flowPane.add(textInput);

+        textInput.getComponentStateListeners().add(new
ComponentStateListener.Adapter() {
+            @Override
+ public void focusedChanged(Component component, Component
obverseComponent) {
+                if (!component.isFocused()) {
+                    TextInput textInput = (TextInput)component;
+                    Limits limits =
(Limits)beanDictionary.get(propertyName);
+
+                    try {
+ int min = Integer.parseInt (textInput.getText()); + beanDictionary.put(propertyName, new Limits(min,
limits.max));
+                    } catch (Exception exception) {
+ textInput.setText(String.valueOf (limits.min));
+                    }
+                }
+            }
+        });
+
     Label label = new Label("min");
     label.getStyles().put("font", "{italic:true}");
     flowPane.add(label);
@@ -394,8 +565,41 @@
     textInput.setText(String.valueOf(limits.max));
     flowPane.add(textInput);

+        textInput.getComponentStateListeners().add(new
ComponentStateListener.Adapter() {
+            @Override
+ public void focusedChanged(Component component, Component
obverseComponent) {
+                if (!component.isFocused()) {
+                    TextInput textInput = (TextInput)component;
+                    Limits limits =
(Limits)beanDictionary.get(propertyName);
+
+                    try {
+ int max = Integer.parseInt (textInput.getText());
+                        beanDictionary.put(propertyName, new
Limits(limits.min, max));
+                    } catch (Exception exception) {
+ textInput.setText(String.valueOf (limits.max));
+                    }
+                }
+            }
+        });
+
     label = new Label("max");
     label.getStyles().put("font", "{italic:true}");
     flowPane.add(label);
+
+        return boxPane;
+    }
+
+    private void updateLimitsControl(String propertyName) {
+ BoxPane boxPane = (BoxPane)inspectorComponents.get (propertyName);
+
+        if (boxPane != null) {
+ Limits limits = (Limits)beanDictionary.get (propertyName);
+
+            TextInput minTextInput =
(TextInput)((FlowPane)boxPane.get(0)).get(0);
+            TextInput maxTextInput =
(TextInput)((FlowPane)boxPane.get(1)).get(0);
+
+            minTextInput.setText(String.valueOf(limits.min));
+            maxTextInput.setText(String.valueOf(limits.max));
+        }
 }
}

Modified:
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ EventLogger.java
URL:
http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/EventLogger.java?rev=829797&r1=829796&r2=829797&view=diff

= = = = = = = = = = = ===================================================================
---
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ EventLogger.java
(original)
+++
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ EventLogger.java
Mon Oct 26 13:48:09 2009
@@ -16,68 +16,19 @@
*/
package org.apache.pivot.tools.wtk;

-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Proxy;
-import java.lang.reflect.Type;
-import java.util.Comparator;

-import org.apache.pivot.collections.ArrayList;
+import org.apache.pivot.beans.BeanMonitor;
+import org.apache.pivot.beans.BeanMonitorListener;
import org.apache.pivot.collections.Group;
-import org.apache.pivot.collections.HashMap;
import org.apache.pivot.collections.HashSet;
import org.apache.pivot.collections.Sequence;
-import org.apache.pivot.collections.immutable.ImmutableList;
import org.apache.pivot.collections.immutable.ImmutableSet;
import org.apache.pivot.util.ListenerList;
-import org.apache.pivot.util.ThreadUtilities;
-import org.apache.pivot.util.Vote;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.Container;

public class EventLogger extends Container {
- private static class EventComparator implements Comparator<Method> {
-        @Override
-        public int compare(Method event1, Method event2) {
-            int result = 0;
-
- Class<?> listenerInterface1 = event1.getDeclaringClass(); - Class<?> listenerInterface2 = event2.getDeclaringClass();
-
-            if (listenerInterface1 != listenerInterface2) {
-                result =
listenerInterface1.getName().compareTo(listenerInterface2.getName ());
-            }
-
-            if (result == 0) {
- result = event1.getName().compareTo (event2.getName());
-            }
-
-            return result;
-        }
-    }
-
- private class LoggerInvocationHandler implements InvocationHandler {
-        @Override
-        public Object invoke(Object proxy, Method event, Object[]
arguments) throws Throwable {
-            if (includeEvents.contains(event)) {
- eventLoggerListeners.eventFired (EventLogger.this, event,
arguments);
-            }
-
-            Object result = null;
-            Class<?> returnType = event.getReturnType();
-            if (returnType == Vote.class) {
-                result = Vote.APPROVE;
-            } else if (returnType == Boolean.TYPE) {
-                result = false;
-            }
-
-            return result;
-        }
-    }
-
 private static class EventLoggerListenerList extends
ListenerList<EventLoggerListener>
     implements EventLoggerListener {
     @Override
@@ -109,12 +60,21 @@
     }
 }

-    private Component source = null;
+    private BeanMonitorListener beanMonitorHandler = new
BeanMonitorListener.Adapter() {
+        @Override
+        public void sourceChanged(BeanMonitor meanMonitor, Object
previousSource) {
+            eventLoggerListeners.sourceChanged(EventLogger.this,
(Component)previousSource);
+        }

-    private HashMap<Class<?>, Object> eventListenerProxies = new
HashMap<Class<?>, Object>();
-    private LoggerInvocationHandler loggerInvocationHandler = new
LoggerInvocationHandler();
+        @Override
+ public void eventFired(BeanMonitor meanMonitor, Method event,
Object[] arguments) {
+            if (includeEvents.contains(event)) {
+ eventLoggerListeners.eventFired (EventLogger.this, event,
arguments);
+            }
+        }
+    };

- private ArrayList<Method> declaredEvents = new ArrayList<Method>(new
EventComparator());
+    private BeanMonitor beanMonitor = new BeanMonitor();

 private HashSet<Method> includeEvents = new HashSet<Method>();

@@ -125,34 +85,21 @@
 }

 public EventLogger(Component source) {
+ beanMonitor.getBeanMonitorListeners().add (beanMonitorHandler);
     setSource(source);
     setSkin(new EventLoggerSkin());
 }

 public Component getSource() {
-        return source;
+        return (Component)beanMonitor.getSource();
 }

 public void setSource(Component source) {
-        Component previousSource = this.source;
-
-        if (source != previousSource) {
-            this.source = source;
-
-            if (previousSource != null) {
-                unregisterEventListeners(previousSource);
-            }
-
-            if (source != null) {
-                registerEventListeners(source);
-            }
-
- eventLoggerListeners.sourceChanged(this, previousSource);
-        }
+        beanMonitor.setSource(source);
 }

 public Sequence<Method> getDeclaredEvents() {
-        return new ImmutableList<Method>(declaredEvents);
+        return beanMonitor.getDeclaredEvents();
 }

 public Group<Method> getIncludeEvents() {
@@ -177,79 +124,6 @@
     return includeEvents.contains(event);
 }

-    private void registerEventListeners(Component source) {
-        declaredEvents.clear();
-
-        Method[] methods = source.getClass().getMethods();
-
-        for (int i = 0; i < methods.length; i++) {
-            Method method = methods[i];
-
-            if
(ListenerList.class.isAssignableFrom(method.getReturnType())
- && (method.getModifiers() & Modifier.STATIC) == 0) {
-                ParameterizedType genericType =
(ParameterizedType)method.getGenericReturnType();
-                Type[] typeArguments =
genericType.getActualTypeArguments();
-
-                if (typeArguments.length == 1) {
-                    Class<?> listenerInterface =
(Class<?>)typeArguments[0];
-
-                    if (!listenerInterface.isInterface()) {
-                        throw new
RuntimeException(listenerInterface.getName()
-                            + " is not an interface.");
-                    }
-
-                    Method[] interfaceMethods =
listenerInterface.getMethods();
- for (int j = 0; j < interfaceMethods.length; j++) { - Method interfaceMethod = interfaceMethods [j];
-                        declaredEvents.add(interfaceMethod);
-                    }
-
-                    // Get the listener list
-                    Object listenerList;
-                    try {
-                        listenerList = method.invoke(source);
- } catch (InvocationTargetException exception) {
-                        throw new RuntimeException(exception);
-                    } catch (IllegalAccessException exception) {
-                        throw new RuntimeException(exception);
-                    }
-
-                    // Get the listener for this interface
-                    Object listener =
eventListenerProxies.get(listenerInterface);
-                    if (listener == null) {
-                        listener =
Proxy.newProxyInstance(ThreadUtilities.getClassLoader(),
-                            new Class[]{listenerInterface},
loggerInvocationHandler);
- eventListenerProxies.put (listenerInterface,
listener);
-                    }
-
-                    // Add the listener
- Class<?> listenerListClass = listenerList.getClass();
-                    Method addMethod;
-                    try {
- addMethod = listenerListClass.getMethod ("add",
-                            new Class<?>[] {Object.class});
-                    } catch (NoSuchMethodException exception) {
-                        throw new RuntimeException(exception);
-                    }
-
-                    try {
- addMethod.invoke(listenerList, new Object []
{listener});
-                    } catch (IllegalAccessException exception) {
-                        throw new RuntimeException(exception);
- } catch (InvocationTargetException exception) {
-                        throw new RuntimeException(exception);
-                    }
-                }
-            }
-        }
-    }
-
-    private void unregisterEventListeners(Component source) {
-        declaredEvents.clear();
-
-        // TODO
-    }
-
public ListenerList<EventLoggerListener> getEventLoggerListeners () {
     return eventLoggerListeners;
 }

Modified:
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ component_inspector_skin.wtkx
URL:
http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/component_inspector_skin.wtkx?rev=829797&r1=829796&r2=829797&view=diff

= = = = = = = = = = = ===================================================================
---
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ component_inspector_skin.wtkx
(original)
+++
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ component_inspector_skin.wtkx
Mon Oct 26 13:48:09 2009
@@ -22,7 +22,10 @@
 <view>
     <BoxPane orientation="vertical" styles="{fill:true,
horizontalAlignment:'right'}">
<Label text="%properties" styles="{padding:{left:10, top: 5},
font:{bold:true}}"/>
- <BoxPane wtkx:id="propertiesPane" orientation="vertical"
styles="{padding:{left:10}}"/>
+ <BoxPane orientation="vertical" styles="{padding: {left:10}}">
+                <Form wtkx:id="propertiesForm"
+                    styles="{rightAlignLabels:true,
showFirstSectionHeading:true}"/>
+            </BoxPane>
         <Separator/>
         <Label text="%styles" styles="{padding:{left:10},
font:{bold:true}}"/>
         <BoxPane wtkx:id="stylesPane" orientation="vertical"
styles="{padding:{left:10}}"/>






Reply via email to