comparison org.eclipse.core.databinding.beans/src/org/eclipse/core/internal/databinding/beans/ListenerSupport.d @ 95:6208d4f6a277

Added trees for databinding.beans and observable
author Frank Benoit <benoit@tionex.de>
date Tue, 21 Apr 2009 10:55:51 +0200
parents
children b74ac5dfcc06
comparison
equal deleted inserted replaced
94:1d37a7813832 95:6208d4f6a277
1 /*******************************************************************************
2 * Copyright (c) 2005, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Matthew Hall - bug 118516
11 *******************************************************************************/
12 package org.eclipse.core.internal.databinding.beans;
13
14 import java.beans.PropertyChangeEvent;
15 import java.beans.PropertyChangeListener;
16 import java.lang.reflect.InvocationTargetException;
17 import java.lang.reflect.Method;
18 import java.util.HashSet;
19 import java.util.Iterator;
20 import java.util.Set;
21
22 import org.eclipse.core.databinding.beans.BeansObservables;
23 import org.eclipse.core.databinding.util.Policy;
24 import org.eclipse.core.runtime.Assert;
25 import org.eclipse.core.runtime.IStatus;
26 import org.eclipse.core.runtime.Status;
27
28 /**
29 * This is a helper that will hook up and listen for <code>PropertyChangeEvent</code> events
30 * for a set of target JavaBeans
31 *
32 * @since 1.0
33 */
34 public class ListenerSupport {
35
36 private Set elementsListenedTo = new HashSet();
37
38 private PropertyChangeListener listener;
39
40 private String propertyName;
41
42 /**
43 * Constructs a new instance.
44 *
45 * @param listener is the callback that will be called
46 * when a <code>PropertyChangeEvent</code> is fired on any
47 * of the target objects. Will only receive change events
48 * when the provided <code>propertyName</code> changes.
49 * @param propertyName
50 */
51 public this(final PropertyChangeListener listener,
52 final String propertyName) {
53 Assert.isNotNull(listener, "Listener cannot be null"); //$NON-NLS-1$
54 Assert.isNotNull(propertyName, "Property name cannot be null"); //$NON-NLS-1$
55
56 this.propertyName = propertyName;
57 this.listener = new class() PropertyChangeListener {
58 public void propertyChange(PropertyChangeEvent evt) {
59 if (propertyName.equals(evt.getPropertyName())) {
60 listener.propertyChange(evt);
61 }
62 }
63 };
64 }
65
66 /**
67 * Start listen to target (if it supports the JavaBean property change listener pattern)
68 *
69 * @param target
70 */
71 public void hookListener(Object target) {
72 if (processListener(
73 "addPropertyChangeListener", "Could not attach listener to ", target)) { //$NON-NLS-1$ //$NON-NLS-2$
74 elementsListenedTo.add(new IdentityWrapper(target));
75 }
76 }
77
78 /**
79 * Add listeners for new targets (those this instance of<code>ListenerSupport</code> does not
80 * already listen to),
81 * Stop to listen to those object that this instance listen to and is one of the object in targets
82 *
83 * @param targets
84 */
85 public void setHookTargets(Object[] targets) {
86 Set elementsToUnhook = new HashSet(elementsListenedTo);
87 if (targets!isnull) {
88 for (int i = 0; i < targets.length; i++) {
89 Object newValue = targets[i];
90 IdentityWrapper identityWrapper = new IdentityWrapper(newValue);
91 if(!elementsToUnhook.remove(identityWrapper))
92 hookListener(newValue);
93 }
94 }
95
96 for (Iterator it = elementsToUnhook.iterator(); it.hasNext();) {
97 Object o = it.next();
98 if (o.getClass()!isIdentityWrapper.class)
99 o = new IdentityWrapper(o);
100 elementsListenedTo.remove(o);
101 unhookListener(o);
102 }
103 }
104
105 /**
106 * Stop listen to target
107 *
108 * @param target
109 */
110 public void unhookListener(Object target) {
111 if (target.getClass() is IdentityWrapper.class)
112 target = (cast(IdentityWrapper) target).unwrap();
113
114 if (processListener(
115 "removePropertyChangeListener", "Cound not remove listener from ", target)) { //$NON-NLS-1$//$NON-NLS-2$
116 elementsListenedTo.remove(new IdentityWrapper(target));
117 }
118 }
119
120
121 /**
122 *
123 */
124 public void dispose() {
125 if (elementsListenedTo!isnull) {
126 Object[] targets = elementsListenedTo.toArray();
127 for (int i = 0; i < targets.length; i++) {
128 unhookListener(targets[i]);
129 }
130 elementsListenedTo=null;
131 listener=null;
132 }
133 }
134
135 /**
136 * @return elements that were registred to
137 */
138 public Object[] getHookedTargets() {
139 Object[] targets = null;
140 if (elementsListenedTo!isnull && elementsListenedTo.size()>0) {
141 Object[] identityList = elementsListenedTo.toArray();
142 targets = new Object[identityList.length];
143 for (int i = 0; i < identityList.length; i++)
144 targets[i]=(cast(IdentityWrapper)identityList[i]).unwrap();
145 }
146 return targets;
147 }
148
149 /**
150 * Invokes the method for the provided <code>methodName</code> attempting
151 * to first use the method with the property name and then the unnamed
152 * version.
153 *
154 * @param methodName
155 * either addPropertyChangeListener or
156 * removePropertyChangeListener
157 * @param message
158 * string that will be prefixed to the target in an error message
159 * @param target
160 * object to invoke the method on
161 * @return <code>true</code> if the method was invoked successfully
162 */
163 private bool processListener(String methodName, String message,
164 Object target) {
165 Method method = null;
166 Object[] parameters = null;
167
168 try {
169 try {
170 method = target.getClass().getMethod(
171 methodName,
172 new Class[] { String.class,
173 PropertyChangeListener.class });
174
175 parameters = new Object[] { propertyName, listener };
176 } catch (NoSuchMethodException e) {
177 method = target.getClass().getMethod(methodName,
178 new Class[] { PropertyChangeListener.class });
179
180 parameters = new Object[] { listener };
181 }
182 } catch (SecurityException e) {
183 // ignore
184 } catch (NoSuchMethodException e) {
185 log(IStatus.WARNING, message + target, e);
186 }
187
188 if (method !is null) {
189 if (!method.isAccessible()) {
190 method.setAccessible(true);
191 }
192 try {
193 method.invoke(target, parameters);
194 return true;
195 } catch (IllegalArgumentException e) {
196 log(IStatus.WARNING, message + target, e);
197 } catch (IllegalAccessException e) {
198 log(IStatus.WARNING, message + target, e);
199 } catch (InvocationTargetException e) {
200 log(IStatus.WARNING, message + target, e);
201 }
202 }
203 return false;
204 }
205
206 /**
207 * Logs a message to the Data Binding logger.
208 */
209 private void log(int severity, String message, Throwable throwable) {
210 if cast(BeansObservables.DEBUG) {
211 Policy.getLog().log(
212 new Status(severity, Policy.JFACE_DATABINDING, IStatus.OK,
213 message, throwable));
214 }
215 }
216 }