You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2010/04/22 00:19:52 UTC

svn commit: r936543 - in /pivot/trunk: core/src/org/apache/pivot/beans/ tools/src/org/apache/pivot/tools/wtk/

Author: gbrown
Date: Wed Apr 21 22:19:51 2010
New Revision: 936543

URL: http://svn.apache.org/viewvc?rev=936543&view=rev
Log:
Move bean monitoring functionality out of BeanDictionary into org.apache.pivot.tools.wtk.BeanMonitor.

Added:
    pivot/trunk/tools/src/org/apache/pivot/tools/wtk/BeanMonitor.java
    pivot/trunk/tools/src/org/apache/pivot/tools/wtk/PropertyChangeListener.java
Removed:
    pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionaryListener.java
Modified:
    pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionary.java
    pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentPropertyInspectorSkin.java

Modified: pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionary.java
URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionary.java?rev=936543&r1=936542&r2=936543&view=diff
==============================================================================
--- pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionary.java (original)
+++ pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionary.java Wed Apr 21 22:19:51 2010
@@ -17,22 +17,13 @@
 package org.apache.pivot.beans;
 
 import java.lang.reflect.Field;
-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.Iterator;
 import java.util.NoSuchElementException;
 
 import org.apache.pivot.collections.Dictionary;
-import org.apache.pivot.collections.HashMap;
-import org.apache.pivot.collections.HashSet;
-import org.apache.pivot.util.ListenerList;
-import org.apache.pivot.util.ThreadUtilities;
-import org.apache.pivot.util.Vote;
 
 /**
  * Exposes Java bean properties of an object via the {@link Dictionary}
@@ -139,63 +130,13 @@ public class BeanDictionary implements D
         }
     }
 
-    private class BeanInvocationHandler implements InvocationHandler {
-        @Override
-        public Object invoke(Object proxy, Method event, Object[] arguments) throws Throwable {
-            String eventName = event.getName();
-            if (eventName.endsWith(PROPERTY_CHANGE_SUFFIX)) {
-                String propertyName = eventName.substring(0, eventName.length()
-                    - PROPERTY_CHANGE_SUFFIX.length());
-
-                if (notifyingProperties.contains(propertyName)) {
-                    beanDictionaryListeners.propertyChanged(BeanDictionary.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 BeanDictionaryListenerList extends ListenerList<BeanDictionaryListener>
-        implements BeanDictionaryListener {
-        @Override
-        public void beanChanged(BeanDictionary beanDictionary, Object previousBean) {
-            for (BeanDictionaryListener listener : this) {
-                listener.beanChanged(beanDictionary, previousBean);
-            }
-        }
-
-        @Override
-        public void propertyChanged(BeanDictionary beanDictionary, String propertyName) {
-            for (BeanDictionaryListener listener : this) {
-                listener.propertyChanged(beanDictionary, propertyName);
-            }
-        }
-    }
-
     private Object bean;
     private boolean ignoreReadOnlyProperties;
 
-    private HashMap<Class<?>, Object> beanListenerProxies = null;
-    private BeanInvocationHandler invocationHandler = null;
-    private HashSet<String> notifyingProperties = null;
-
-    private BeanDictionaryListenerList beanDictionaryListeners = null;
-
     public static final String GET_PREFIX = "get";
     public static final String IS_PREFIX = "is";
     public static final String SET_PREFIX = "set";
     public static final String FIELD_PREFIX = "~";
-    public static final String LISTENERS_SUFFIX = "Listeners";
-    public static final String PROPERTY_CHANGE_SUFFIX = "Changed";
 
     /**
      * Creates a new bean dictionary that is not associated with a bean.
@@ -221,8 +162,8 @@ public class BeanDictionary implements D
      * The bean object to wrap.
      */
     public BeanDictionary(Object bean, boolean ignoreReadOnlyProperties) {
+        this.bean = bean;
         this.ignoreReadOnlyProperties = ignoreReadOnlyProperties;
-        setBean(bean);
     }
 
     /**
@@ -236,37 +177,6 @@ public class BeanDictionary implements D
     }
 
     /**
-     * Sets the bean object that this dictionary will wrap.
-     * <p>
-     * <b>NOTE</b>: failing to clear the bean of a bean dictionary may result in
-     * memory leaks, as the bean object may maintain references to the bean
-     * dictionary as long as it is set.
-     *
-     * @param bean
-     * The bean object, or <tt>null</tt> to clear the bean.
-     */
-    public void setBean(Object bean) {
-        Object previousBean = this.bean;
-
-        if (bean != previousBean) {
-            if (beanDictionaryListeners != null
-                && previousBean != null) {
-                unregisterBeanListeners();
-            }
-
-            this.bean = bean;
-
-            if (beanDictionaryListeners != null) {
-                if (bean != null) {
-                    registerBeanListeners();
-                }
-
-                beanDictionaryListeners.beanChanged(this, previousBean);
-            }
-        }
-    }
-
-    /**
      * Invokes the getter method for the given property.
      *
      * @param key
@@ -463,33 +373,6 @@ public class BeanDictionary implements D
     }
 
     /**
-     * Tells whether or not the specified property fires change events.
-     *
-     * @param key
-     * The property name.
-     *
-     * @return
-     * <tt>true</tt> if the property fires change events; <tt>false</tt>
-     * otherwise.
-     */
-    public boolean isNotifying(String key) {
-        if (bean == null) {
-            throw new IllegalStateException("bean is null.");
-        }
-
-        if (beanDictionaryListeners == null) {
-            beanDictionaryListeners = new BeanDictionaryListenerList();
-            beanListenerProxies = new HashMap<Class<?>, Object>();
-            invocationHandler = new BeanInvocationHandler();
-            notifyingProperties = new HashSet<String>();
-
-            registerBeanListeners();
-        }
-
-        return notifyingProperties.contains(key);
-    }
-
-    /**
      * Returns the type of a property.
      *
      * @param key
@@ -563,142 +446,6 @@ public class BeanDictionary implements D
     }
 
     /**
-     * Registers event listeners on the bean so that the dictionary can fire
-     * property change events and report which properties can fire change
-     * events.
-     */
-    private void registerBeanListeners() {
-        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();
-
-                        if (interfaceMethodName.endsWith(PROPERTY_CHANGE_SUFFIX)) {
-                            String propertyName = interfaceMethodName.substring(0,
-                                interfaceMethodName.length() - PROPERTY_CHANGE_SUFFIX.length());
-
-                            if (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 = beanListenerProxies.get(listenerInterface);
-                    if (listener == null) {
-                        listener = Proxy.newProxyInstance(ThreadUtilities.getClassLoader(),
-                            new Class<?>[]{listenerInterface}, invocationHandler);
-                        beanListenerProxies.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 the bean.
-     */
-    private void unregisterBeanListeners() {
-        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 = beanListenerProxies.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);
-                    }
-                }
-            }
-        }
-
-        notifyingProperties.clear();
-    }
-
-    /**
      * Tests the read-only state of a property. Note that is no such property
      * exists, this method will return <tt>true</tt> (it will <u>not</u> throw
      * an exception).
@@ -959,19 +706,4 @@ public class BeanDictionary implements D
 
         return coercedValue;
     }
-
-    public ListenerList<BeanDictionaryListener> getBeanDictionaryListeners() {
-        if (beanDictionaryListeners == null) {
-            beanDictionaryListeners = new BeanDictionaryListenerList();
-            beanListenerProxies = new HashMap<Class<?>, Object>();
-            invocationHandler = new BeanInvocationHandler();
-            notifyingProperties = new HashSet<String>();
-
-            if (bean != null) {
-                registerBeanListeners();
-            }
-        }
-
-        return beanDictionaryListeners;
-    }
 }

Added: pivot/trunk/tools/src/org/apache/pivot/tools/wtk/BeanMonitor.java
URL: http://svn.apache.org/viewvc/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/BeanMonitor.java?rev=936543&view=auto
==============================================================================
--- pivot/trunk/tools/src/org/apache/pivot/tools/wtk/BeanMonitor.java (added)
+++ pivot/trunk/tools/src/org/apache/pivot/tools/wtk/BeanMonitor.java Wed Apr 21 22:19:51 2010
@@ -0,0 +1,282 @@
+/*
+ * 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.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 org.apache.pivot.beans.BeanDictionary;
+import org.apache.pivot.collections.HashMap;
+import org.apache.pivot.collections.HashSet;
+import org.apache.pivot.util.ListenerList;
+import org.apache.pivot.util.ThreadUtilities;
+import org.apache.pivot.util.Vote;
+
+/**
+ * Class for monitoring Java bean property changes.
+ */
+public class BeanMonitor {
+    private class BeanInvocationHandler implements InvocationHandler {
+        @Override
+        public Object invoke(Object proxy, Method event, Object[] arguments) throws Throwable {
+            String eventName = event.getName();
+            if (eventName.endsWith(PROPERTY_CHANGE_SUFFIX)) {
+                String propertyName = eventName.substring(0, eventName.length()
+                    - PROPERTY_CHANGE_SUFFIX.length());
+
+                if (notifyingProperties.contains(propertyName)) {
+                    propertyChangeListeners.propertyChanged(bean, 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 PropertyChangeListenerList extends ListenerList<PropertyChangeListener>
+        implements PropertyChangeListener {
+        public void propertyChanged(Object bean, String propertyName) {
+            for (PropertyChangeListener listener : this) {
+                listener.propertyChanged(bean, propertyName);
+            }
+        }
+    }
+
+    private Object bean = null;
+
+    private HashMap<Class<?>, Object> beanListenerProxies = new HashMap<Class<?>, Object>();
+    private BeanInvocationHandler invocationHandler = new BeanInvocationHandler();
+    private HashSet<String> notifyingProperties = new HashSet<String>();
+
+    private PropertyChangeListenerList propertyChangeListeners = new PropertyChangeListenerList();
+
+    public static final String LISTENERS_SUFFIX = "Listeners";
+    public static final String PROPERTY_CHANGE_SUFFIX = "Changed";
+
+    public BeanMonitor() {
+        this(null);
+    }
+
+    public BeanMonitor(Object bean) {
+        setBean(bean);
+    }
+
+    /**
+     * Returns the bean object that this monitor wraps.
+     */
+    public Object getBean() {
+        return bean;
+    }
+
+    /**
+     * Sets the bean object that this monitor will wrap.
+     * <p>
+     * <b>NOTE</b>: failing to clear the bean of a bean monitor may result in
+     * memory leaks, as the bean object may maintain references to the bean
+     * monitor as long as it is set.
+     *
+     * @param bean
+     * The bean object, or <tt>null</tt> to clear the bean.
+     */
+    public void setBean(Object bean) {
+        Object previousBean = this.bean;
+
+        if (bean != previousBean) {
+            if (previousBean != null) {
+                unregisterBeanListeners();
+            }
+
+            this.bean = bean;
+
+            if (bean != null) {
+                registerBeanListeners();
+            }
+        }
+    }
+
+    /**
+     * Tells whether or not the specified property fires change events.
+     *
+     * @param key
+     * The property name.
+     *
+     * @return
+     * <tt>true</tt> if the property fires change events; <tt>false</tt>
+     * otherwise.
+     */
+    public boolean isNotifying(String key) {
+        if (bean == null) {
+            throw new IllegalStateException("bean is null.");
+        }
+
+        return notifyingProperties.contains(key);
+    }
+
+    /**
+     * Registers event listeners on the bean so that the dictionary can fire
+     * property change events and report which properties can fire change
+     * events.
+     */
+    private void registerBeanListeners() {
+        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();
+
+                        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 = beanListenerProxies.get(listenerInterface);
+                    if (listener == null) {
+                        listener = Proxy.newProxyInstance(ThreadUtilities.getClassLoader(),
+                            new Class<?>[]{listenerInterface}, invocationHandler);
+                        beanListenerProxies.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 the bean.
+     */
+    private void unregisterBeanListeners() {
+        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 = beanListenerProxies.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);
+                    }
+                }
+            }
+        }
+
+        notifyingProperties.clear();
+    }
+
+    public ListenerList<PropertyChangeListener> getPropertyChangeListeners() {
+        return propertyChangeListeners;
+    }
+}

Modified: pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentPropertyInspectorSkin.java
URL: http://svn.apache.org/viewvc/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentPropertyInspectorSkin.java?rev=936543&r1=936542&r2=936543&view=diff
==============================================================================
--- pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentPropertyInspectorSkin.java (original)
+++ pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentPropertyInspectorSkin.java Wed Apr 21 22:19:51 2010
@@ -20,7 +20,6 @@ import java.lang.reflect.Method;
 import java.util.Comparator;
 
 import org.apache.pivot.beans.BeanDictionary;
-import org.apache.pivot.beans.BeanDictionaryListener;
 import org.apache.pivot.collections.ArrayList;
 import org.apache.pivot.collections.HashMap;
 import org.apache.pivot.collections.List;
@@ -52,15 +51,16 @@ class ComponentPropertyInspectorSkin ext
         }
     }
 
-    private BeanDictionary beanDictionary = new BeanDictionary();
+    private BeanMonitor beanMonitor = new BeanMonitor();
 
     private static NameComparator nameComparator = new NameComparator();
     private static ClassComparator classComparator = new ClassComparator();
 
     public ComponentPropertyInspectorSkin() {
-        beanDictionary.getBeanDictionaryListeners().add(new BeanDictionaryListener.Adapter() {
+        beanMonitor.getPropertyChangeListeners().add(new PropertyChangeListener() {
             @Override
-            public void propertyChanged(BeanDictionary beanDictionary, String propertyName) {
+            public void propertyChanged(Object bean, String propertyName) {
+                BeanDictionary beanDictionary = new BeanDictionary(bean);
                 Class<?> type = beanDictionary.getType(propertyName);
                 updateControl(beanDictionary, propertyName, type);
             }
@@ -77,7 +77,7 @@ class ComponentPropertyInspectorSkin ext
         Form.SectionSequence sections = form.getSections();
         sections.remove(0, sections.getLength());
 
-        beanDictionary.setBean(source);
+        beanMonitor.setBean(source);
 
         if (source != null) {
             Class<?> sourceType = source.getClass();
@@ -85,8 +85,9 @@ class ComponentPropertyInspectorSkin ext
                 new HashMap<Class<?>, List<String>>(classComparator);
 
             // Partition the properties by their declaring class
+            BeanDictionary beanDictionary = new BeanDictionary(source);
             for (String propertyName : beanDictionary) {
-                if (beanDictionary.isNotifying(propertyName)
+                if (beanMonitor.isNotifying(propertyName)
                     && !beanDictionary.isReadOnly(propertyName)) {
                     Method method = BeanDictionary.getGetterMethod(sourceType, propertyName);
                     Class<?> declaringClass = method.getDeclaringClass();

Added: pivot/trunk/tools/src/org/apache/pivot/tools/wtk/PropertyChangeListener.java
URL: http://svn.apache.org/viewvc/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/PropertyChangeListener.java?rev=936543&view=auto
==============================================================================
--- pivot/trunk/tools/src/org/apache/pivot/tools/wtk/PropertyChangeListener.java (added)
+++ pivot/trunk/tools/src/org/apache/pivot/tools/wtk/PropertyChangeListener.java Wed Apr 21 22:19:51 2010
@@ -0,0 +1,30 @@
+/*
+ * 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.tools.wtk;
+
+/**
+ * Java bean property change listener.
+ */
+public interface PropertyChangeListener {
+    /**
+     * Called when a Java bean property has changed.
+     *
+     * @param bean
+     * @param propertyName
+     */
+    public void propertyChanged(Object bean, String propertyName);
+}