1 | /* |
---|
2 | * This program is free software; you can redistribute it and/or modify |
---|
3 | * it under the terms of the GNU General Public License as published by |
---|
4 | * the Free Software Foundation; either version 2 of the License, or |
---|
5 | * (at your option) any later version. |
---|
6 | * |
---|
7 | * This program is distributed in the hope that it will be useful, |
---|
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
10 | * GNU General Public License for more details. |
---|
11 | * |
---|
12 | * You should have received a copy of the GNU General Public License |
---|
13 | * along with this program; if not, write to the Free Software |
---|
14 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
15 | */ |
---|
16 | |
---|
17 | /* |
---|
18 | * BeanConnection.java |
---|
19 | * Copyright (C) 2002 University of Waikato, Hamilton, New Zealand |
---|
20 | * |
---|
21 | */ |
---|
22 | |
---|
23 | package weka.gui.beans; |
---|
24 | |
---|
25 | import java.awt.Color; |
---|
26 | import java.awt.Graphics; |
---|
27 | import java.awt.Point; |
---|
28 | import java.awt.event.ActionEvent; |
---|
29 | import java.awt.event.ActionListener; |
---|
30 | import java.beans.BeanInfo; |
---|
31 | import java.beans.EventSetDescriptor; |
---|
32 | import java.beans.IntrospectionException; |
---|
33 | import java.beans.Introspector; |
---|
34 | import java.io.Serializable; |
---|
35 | import java.lang.reflect.Method; |
---|
36 | import java.util.Vector; |
---|
37 | |
---|
38 | import javax.swing.JComponent; |
---|
39 | import javax.swing.JLabel; |
---|
40 | import javax.swing.JMenuItem; |
---|
41 | import javax.swing.JPopupMenu; |
---|
42 | import javax.swing.SwingConstants; |
---|
43 | |
---|
44 | /** |
---|
45 | * Class for encapsulating a connection between two beans. Also |
---|
46 | * maintains a list of all connections |
---|
47 | * |
---|
48 | * @author <a href="mailto:mhall@cs.waikato.ac.nz">Mark Hall</a> |
---|
49 | * @version $Revision: 5611 $ |
---|
50 | */ |
---|
51 | public class BeanConnection |
---|
52 | implements Serializable { |
---|
53 | |
---|
54 | /** for serialization */ |
---|
55 | private static final long serialVersionUID = 8804264241791332064L; |
---|
56 | |
---|
57 | /** |
---|
58 | * The list of connections |
---|
59 | */ |
---|
60 | public static Vector CONNECTIONS = new Vector(); |
---|
61 | |
---|
62 | // details for this connection |
---|
63 | private BeanInstance m_source; |
---|
64 | private BeanInstance m_target; |
---|
65 | |
---|
66 | /** |
---|
67 | * The name of the event for this connection |
---|
68 | */ |
---|
69 | private String m_eventName; |
---|
70 | |
---|
71 | // Should the connection be painted? |
---|
72 | private boolean m_hidden = false; |
---|
73 | |
---|
74 | /** |
---|
75 | * Reset the list of connections |
---|
76 | */ |
---|
77 | public static void reset() { |
---|
78 | CONNECTIONS = new Vector(); |
---|
79 | } |
---|
80 | |
---|
81 | /** |
---|
82 | * Returns the list of connections |
---|
83 | * |
---|
84 | * @return the list of connections |
---|
85 | */ |
---|
86 | public static Vector getConnections() { |
---|
87 | return CONNECTIONS; |
---|
88 | } |
---|
89 | |
---|
90 | /** |
---|
91 | * Describe <code>setConnections</code> method here. |
---|
92 | * |
---|
93 | * @param connections a <code>Vector</code> value |
---|
94 | */ |
---|
95 | public static void setConnections(Vector connections) { |
---|
96 | CONNECTIONS = connections; |
---|
97 | } |
---|
98 | |
---|
99 | /** |
---|
100 | * Returns true if there is a link between the supplied source and |
---|
101 | * target BeanInstances at an earlier index than the supplied index |
---|
102 | * |
---|
103 | * @param source the source BeanInstance |
---|
104 | * @param target the target BeanInstance |
---|
105 | * @param index the index to compare to |
---|
106 | * @return true if there is already a link at an earlier index |
---|
107 | */ |
---|
108 | private static boolean previousLink(BeanInstance source, BeanInstance target, |
---|
109 | int index) { |
---|
110 | for (int i = 0; i < CONNECTIONS.size(); i++) { |
---|
111 | BeanConnection bc = (BeanConnection)CONNECTIONS.elementAt(i); |
---|
112 | BeanInstance compSource = bc.getSource(); |
---|
113 | BeanInstance compTarget = bc.getTarget(); |
---|
114 | |
---|
115 | if (compSource == source && compTarget == target && index < i) { |
---|
116 | return true; |
---|
117 | } |
---|
118 | } |
---|
119 | return false; |
---|
120 | } |
---|
121 | |
---|
122 | /** |
---|
123 | * A candidate BeanInstance can be an input if it is in the listToCheck |
---|
124 | * and it is the source of a connection to a target that is in the |
---|
125 | * listToCheck |
---|
126 | */ |
---|
127 | private static boolean checkForSource(BeanInstance candidate, |
---|
128 | Vector listToCheck) { |
---|
129 | for (int i = 0; i < CONNECTIONS.size(); i++) { |
---|
130 | BeanConnection bc = (BeanConnection)CONNECTIONS.elementAt(i); |
---|
131 | if (bc.getSource() != candidate) { |
---|
132 | continue; |
---|
133 | } |
---|
134 | |
---|
135 | // check to see if target is in list |
---|
136 | for (int j = 0; j < listToCheck.size(); j++) { |
---|
137 | BeanInstance tempTarget = (BeanInstance)listToCheck.elementAt(j); |
---|
138 | if (bc.getTarget() == tempTarget) { |
---|
139 | return true; |
---|
140 | } |
---|
141 | } |
---|
142 | } |
---|
143 | return false; |
---|
144 | } |
---|
145 | |
---|
146 | /** |
---|
147 | * A candidate BeanInstance can't be an input if it is the target |
---|
148 | * of a connection from a source that is in the listToCheck |
---|
149 | */ |
---|
150 | private static boolean checkTargetConstraint(BeanInstance candidate, |
---|
151 | Vector listToCheck) { |
---|
152 | for (int i = 0; i < CONNECTIONS.size(); i++) { |
---|
153 | BeanConnection bc = (BeanConnection)CONNECTIONS.elementAt(i); |
---|
154 | if (bc.getTarget() == candidate) { |
---|
155 | for (int j = 0; j < listToCheck.size(); j++) { |
---|
156 | BeanInstance tempSource = (BeanInstance)listToCheck.elementAt(j); |
---|
157 | if (bc.getSource() == tempSource) { |
---|
158 | return false; |
---|
159 | } |
---|
160 | } |
---|
161 | } |
---|
162 | } |
---|
163 | return true; |
---|
164 | } |
---|
165 | |
---|
166 | /** |
---|
167 | * Returns a vector of BeanConnections associated with |
---|
168 | * the supplied vector of BeanInstances, i.e. all connections |
---|
169 | * that exist between those BeanInstances in the subFlow. |
---|
170 | * |
---|
171 | * @param subFlow a Vector of BeanInstances |
---|
172 | * @return a Vector of BeanConnections |
---|
173 | */ |
---|
174 | public static Vector associatedConnections(Vector subFlow) { |
---|
175 | Vector associatedConnections = new Vector(); |
---|
176 | for (int i = 0; i < CONNECTIONS.size(); i++) { |
---|
177 | BeanConnection bc = (BeanConnection)CONNECTIONS.elementAt(i); |
---|
178 | BeanInstance tempSource = bc.getSource(); |
---|
179 | BeanInstance tempTarget = bc.getTarget(); |
---|
180 | boolean sourceInSubFlow = false; |
---|
181 | boolean targetInSubFlow = false; |
---|
182 | for (int j = 0; j < subFlow.size(); j++) { |
---|
183 | BeanInstance toCheck = (BeanInstance)subFlow.elementAt(j); |
---|
184 | if (toCheck == tempSource) { |
---|
185 | sourceInSubFlow = true; |
---|
186 | } |
---|
187 | if (toCheck == tempTarget) { |
---|
188 | targetInSubFlow = true; |
---|
189 | } |
---|
190 | if (sourceInSubFlow && targetInSubFlow) { |
---|
191 | associatedConnections.add(bc); |
---|
192 | break; |
---|
193 | } |
---|
194 | } |
---|
195 | } |
---|
196 | return associatedConnections; |
---|
197 | } |
---|
198 | |
---|
199 | /** |
---|
200 | * Returns a vector of BeanInstances that can be considered |
---|
201 | * as inputs (or the left-hand side of a sub-flow) |
---|
202 | * |
---|
203 | * @param subset the sub-flow to examine |
---|
204 | * @return a Vector of inputs to the sub-flow |
---|
205 | */ |
---|
206 | public static Vector inputs(Vector subset) { |
---|
207 | Vector result = new Vector(); |
---|
208 | for (int i = 0; i < subset.size(); i++) { |
---|
209 | BeanInstance temp = (BeanInstance)subset.elementAt(i); |
---|
210 | // if (checkForSource(temp, subset)) { |
---|
211 | // now check target constraint |
---|
212 | if (checkTargetConstraint(temp, subset)) { |
---|
213 | result.add(temp); |
---|
214 | } |
---|
215 | // } |
---|
216 | } |
---|
217 | return result; |
---|
218 | } |
---|
219 | |
---|
220 | |
---|
221 | /** |
---|
222 | * A candidate BeanInstance can be an output if it is in the listToCheck |
---|
223 | * and it is the target of a connection from a source that is in the |
---|
224 | * listToCheck |
---|
225 | */ |
---|
226 | private static boolean checkForTarget(BeanInstance candidate, |
---|
227 | Vector listToCheck) { |
---|
228 | for (int i = 0; i < CONNECTIONS.size(); i++) { |
---|
229 | BeanConnection bc = (BeanConnection)CONNECTIONS.elementAt(i); |
---|
230 | if (bc.getTarget() != candidate) { |
---|
231 | continue; |
---|
232 | } |
---|
233 | |
---|
234 | // check to see if source is in list |
---|
235 | for (int j = 0; j < listToCheck.size(); j++) { |
---|
236 | BeanInstance tempSource = (BeanInstance)listToCheck.elementAt(j); |
---|
237 | if (bc.getSource() == tempSource) { |
---|
238 | return true; |
---|
239 | } |
---|
240 | } |
---|
241 | } |
---|
242 | return false; |
---|
243 | } |
---|
244 | |
---|
245 | private static boolean isInList(BeanInstance candidate, |
---|
246 | Vector listToCheck) { |
---|
247 | for (int i = 0; i < listToCheck.size(); i++) { |
---|
248 | BeanInstance temp = (BeanInstance)listToCheck.elementAt(i); |
---|
249 | if (candidate == temp) { |
---|
250 | return true; |
---|
251 | } |
---|
252 | } |
---|
253 | return false; |
---|
254 | } |
---|
255 | |
---|
256 | /** |
---|
257 | * A candidate BeanInstance can't be an output if it is the source |
---|
258 | * of a connection only to target(s) that are in the listToCheck |
---|
259 | */ |
---|
260 | private static boolean checkSourceConstraint(BeanInstance candidate, |
---|
261 | Vector listToCheck) { |
---|
262 | boolean result = true; |
---|
263 | for (int i = 0; i < CONNECTIONS.size(); i++) { |
---|
264 | BeanConnection bc = (BeanConnection)CONNECTIONS.elementAt(i); |
---|
265 | if (bc.getSource() == candidate) { |
---|
266 | BeanInstance cTarget = bc.getTarget(); |
---|
267 | // is the target of this connection external to the list to check? |
---|
268 | if (!isInList(cTarget, listToCheck)) { |
---|
269 | return true; |
---|
270 | } |
---|
271 | for (int j = 0; j < listToCheck.size(); j++) { |
---|
272 | BeanInstance tempTarget = (BeanInstance)listToCheck.elementAt(j); |
---|
273 | if (bc.getTarget() == tempTarget) { |
---|
274 | result = false; |
---|
275 | } |
---|
276 | } |
---|
277 | } |
---|
278 | } |
---|
279 | return result; |
---|
280 | } |
---|
281 | |
---|
282 | /** |
---|
283 | * Returns a vector of BeanInstances that can be considered |
---|
284 | * as outputs (or the right-hand side of a sub-flow) |
---|
285 | * |
---|
286 | * @param subset the sub-flow to examine |
---|
287 | * @return a Vector of outputs of the sub-flow |
---|
288 | */ |
---|
289 | public static Vector outputs(Vector subset) { |
---|
290 | Vector result = new Vector(); |
---|
291 | for (int i = 0; i < subset.size(); i++) { |
---|
292 | BeanInstance temp = (BeanInstance)subset.elementAt(i); |
---|
293 | if (checkForTarget(temp, subset)) { |
---|
294 | // now check source constraint |
---|
295 | if (checkSourceConstraint(temp, subset)) { |
---|
296 | // now check that this bean can actually produce some events |
---|
297 | try { |
---|
298 | BeanInfo bi = Introspector.getBeanInfo(temp.getBean().getClass()); |
---|
299 | EventSetDescriptor [] esd = bi.getEventSetDescriptors(); |
---|
300 | if (esd != null && esd.length > 0) { |
---|
301 | result.add(temp); |
---|
302 | } |
---|
303 | } catch (IntrospectionException ex) { |
---|
304 | // quietly ignore |
---|
305 | } |
---|
306 | } |
---|
307 | } |
---|
308 | } |
---|
309 | return result; |
---|
310 | } |
---|
311 | |
---|
312 | /** |
---|
313 | * Renders the connections and their names on the supplied graphics |
---|
314 | * context |
---|
315 | * |
---|
316 | * @param gx a <code>Graphics</code> value |
---|
317 | */ |
---|
318 | public static void paintConnections(Graphics gx) { |
---|
319 | for (int i = 0; i < CONNECTIONS.size(); i++) { |
---|
320 | BeanConnection bc = (BeanConnection)CONNECTIONS.elementAt(i); |
---|
321 | if (!bc.isHidden()) { |
---|
322 | BeanInstance source = bc.getSource(); |
---|
323 | BeanInstance target = bc.getTarget(); |
---|
324 | EventSetDescriptor srcEsd = bc.getSourceEventSetDescriptor(); |
---|
325 | BeanVisual sourceVisual = (source.getBean() instanceof Visible) ? |
---|
326 | ((Visible)source.getBean()).getVisual() : |
---|
327 | null; |
---|
328 | BeanVisual targetVisual = (target.getBean() instanceof Visible) ? |
---|
329 | ((Visible)target.getBean()).getVisual() : |
---|
330 | null; |
---|
331 | if (sourceVisual != null && targetVisual != null) { |
---|
332 | Point bestSourcePt = |
---|
333 | sourceVisual.getClosestConnectorPoint( |
---|
334 | new Point((target.getX()+(target.getWidth()/2)), |
---|
335 | (target.getY() + (target.getHeight() / 2)))); |
---|
336 | Point bestTargetPt = |
---|
337 | targetVisual.getClosestConnectorPoint( |
---|
338 | new Point((source.getX()+(source.getWidth()/2)), |
---|
339 | (source.getY() + (source.getHeight() / 2)))); |
---|
340 | gx.setColor(Color.red); |
---|
341 | boolean active = true; |
---|
342 | if (source.getBean() instanceof EventConstraints) { |
---|
343 | if (!((EventConstraints) source.getBean()). |
---|
344 | eventGeneratable(srcEsd.getName())) { |
---|
345 | gx.setColor(Color.gray); // link not active at this time |
---|
346 | active = false; |
---|
347 | } |
---|
348 | } |
---|
349 | gx.drawLine((int)bestSourcePt.getX(), (int)bestSourcePt.getY(), |
---|
350 | (int)bestTargetPt.getX(), (int)bestTargetPt.getY()); |
---|
351 | |
---|
352 | // paint an arrow head |
---|
353 | double angle; |
---|
354 | try { |
---|
355 | double a = |
---|
356 | (double)(bestSourcePt.getY() - |
---|
357 | bestTargetPt.getY()) / |
---|
358 | (double)(bestSourcePt.getX() - bestTargetPt.getX()); |
---|
359 | angle = Math.atan(a); |
---|
360 | } catch(Exception ex) { |
---|
361 | angle = Math.PI / 2; |
---|
362 | } |
---|
363 | // Point arrowstart = new Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2); |
---|
364 | Point arrowstart = new Point(bestTargetPt.x, |
---|
365 | bestTargetPt.y); |
---|
366 | Point arrowoffset = new Point((int)(7 * Math.cos(angle)), |
---|
367 | (int)(7 * Math.sin(angle))); |
---|
368 | Point arrowend; |
---|
369 | if (bestSourcePt.getX() >= bestTargetPt.getX()) { |
---|
370 | |
---|
371 | arrowend = new Point(arrowstart.x + arrowoffset.x, |
---|
372 | arrowstart.y + arrowoffset.y); |
---|
373 | } else { |
---|
374 | arrowend = new Point(arrowstart.x - arrowoffset.x, |
---|
375 | arrowstart.y - arrowoffset.y); |
---|
376 | } |
---|
377 | int xs[] = { arrowstart.x, |
---|
378 | arrowend.x + (int)(7 * Math.cos(angle + (Math.PI / 2))), |
---|
379 | arrowend.x + (int)(7 * Math.cos(angle - (Math.PI / 2)))}; |
---|
380 | int ys[] = { arrowstart.y, |
---|
381 | arrowend.y + (int)(7 * Math.sin(angle + (Math.PI / 2))), |
---|
382 | arrowend.y + (int)(7 * Math.sin(angle - (Math.PI / 2)))}; |
---|
383 | gx.fillPolygon(xs, ys, 3); |
---|
384 | // ---- |
---|
385 | |
---|
386 | // paint the connection name |
---|
387 | int midx = (int)bestSourcePt.getX(); |
---|
388 | midx += (int)((bestTargetPt.getX() - bestSourcePt.getX()) / 2); |
---|
389 | int midy = (int)bestSourcePt.getY(); |
---|
390 | midy += (int)((bestTargetPt.getY() - bestSourcePt.getY()) / 2) - 2 ; |
---|
391 | gx.setColor((active) ? Color.blue : Color.gray); |
---|
392 | if (previousLink(source, target, i)) { |
---|
393 | midy -= 15; |
---|
394 | } |
---|
395 | gx.drawString(srcEsd.getName(), midx, midy); |
---|
396 | } |
---|
397 | } |
---|
398 | } |
---|
399 | } |
---|
400 | |
---|
401 | /** |
---|
402 | * Return a list of connections within some delta of a point |
---|
403 | * |
---|
404 | * @param pt the point at which to look for connections |
---|
405 | * @param delta connections have to be within this delta of the point |
---|
406 | * @return a list of connections |
---|
407 | */ |
---|
408 | public static Vector getClosestConnections(Point pt, int delta) { |
---|
409 | Vector closestConnections = new Vector(); |
---|
410 | |
---|
411 | for (int i = 0; i < CONNECTIONS.size(); i++) { |
---|
412 | BeanConnection bc = (BeanConnection)CONNECTIONS.elementAt(i); |
---|
413 | BeanInstance source = bc.getSource(); |
---|
414 | BeanInstance target = bc.getTarget(); |
---|
415 | EventSetDescriptor srcEsd = bc.getSourceEventSetDescriptor(); |
---|
416 | BeanVisual sourceVisual = (source.getBean() instanceof Visible) ? |
---|
417 | ((Visible)source.getBean()).getVisual() : |
---|
418 | null; |
---|
419 | BeanVisual targetVisual = (target.getBean() instanceof Visible) ? |
---|
420 | ((Visible)target.getBean()).getVisual() : |
---|
421 | null; |
---|
422 | if (sourceVisual != null && targetVisual != null) { |
---|
423 | Point bestSourcePt = |
---|
424 | sourceVisual.getClosestConnectorPoint( |
---|
425 | new Point((target.getX()+(target.getWidth()/2)), |
---|
426 | (target.getY() + (target.getHeight() / 2)))); |
---|
427 | Point bestTargetPt = |
---|
428 | targetVisual.getClosestConnectorPoint( |
---|
429 | new Point((source.getX()+(source.getWidth()/2)), |
---|
430 | (source.getY() + (source.getHeight() / 2)))); |
---|
431 | |
---|
432 | int minx = (int) Math.min(bestSourcePt.getX(), bestTargetPt.getX()); |
---|
433 | int maxx = (int) Math.max(bestSourcePt.getX(), bestTargetPt.getX()); |
---|
434 | int miny = (int) Math.min(bestSourcePt.getY(), bestTargetPt.getY()); |
---|
435 | int maxy = (int) Math.max(bestSourcePt.getY(), bestTargetPt.getY()); |
---|
436 | // check to see if supplied pt is inside bounding box |
---|
437 | if (pt.getX() >= minx-delta && pt.getX() <= maxx+delta && |
---|
438 | pt.getY() >= miny-delta && pt.getY() <= maxy+delta) { |
---|
439 | // now see if the point is within delta of the line |
---|
440 | // formulate ax + by + c = 0 |
---|
441 | double a = bestSourcePt.getY() - bestTargetPt.getY(); |
---|
442 | double b = bestTargetPt.getX() - bestSourcePt.getX(); |
---|
443 | double c = (bestSourcePt.getX() * bestTargetPt.getY()) - |
---|
444 | (bestTargetPt.getX() * bestSourcePt.getY()); |
---|
445 | |
---|
446 | double distance = Math.abs((a * pt.getX()) + (b * pt.getY()) + c); |
---|
447 | distance /= Math.abs(Math.sqrt((a*a) + (b*b))); |
---|
448 | |
---|
449 | if (distance <= delta) { |
---|
450 | closestConnections.addElement(bc); |
---|
451 | } |
---|
452 | } |
---|
453 | } |
---|
454 | } |
---|
455 | return closestConnections; |
---|
456 | } |
---|
457 | |
---|
458 | /** |
---|
459 | * Remove all connections for a bean. If the bean is a target for |
---|
460 | * receiving events then it gets deregistered from the corresonding |
---|
461 | * source bean. If the bean is a source of events then all targets |
---|
462 | * implementing BeanCommon are notified via their |
---|
463 | * disconnectionNotification methods that the source (and hence the |
---|
464 | * connection) is going away. |
---|
465 | * |
---|
466 | * @param instance the bean to remove connections to/from |
---|
467 | */ |
---|
468 | public static void removeConnections(BeanInstance instance) { |
---|
469 | |
---|
470 | Vector instancesToRemoveFor = new Vector(); |
---|
471 | if (instance.getBean() instanceof MetaBean) { |
---|
472 | instancesToRemoveFor = |
---|
473 | ((MetaBean)instance.getBean()).getBeansInSubFlow(); |
---|
474 | } else { |
---|
475 | instancesToRemoveFor.add(instance); |
---|
476 | } |
---|
477 | Vector removeVector = new Vector(); |
---|
478 | for (int j = 0; j < instancesToRemoveFor.size(); j++) { |
---|
479 | BeanInstance tempInstance = |
---|
480 | (BeanInstance)instancesToRemoveFor.elementAt(j); |
---|
481 | for (int i = 0; i < CONNECTIONS.size(); i++) { |
---|
482 | // In cases where this instance is the target, deregister it |
---|
483 | // as a listener for the source |
---|
484 | BeanConnection bc = (BeanConnection)CONNECTIONS.elementAt(i); |
---|
485 | BeanInstance tempTarget = bc.getTarget(); |
---|
486 | BeanInstance tempSource = bc.getSource(); |
---|
487 | |
---|
488 | EventSetDescriptor tempEsd = bc.getSourceEventSetDescriptor(); |
---|
489 | if (tempInstance == tempTarget) { |
---|
490 | // try to deregister the target as a listener for the source |
---|
491 | try { |
---|
492 | Method deregisterMethod = tempEsd.getRemoveListenerMethod(); |
---|
493 | Object targetBean = tempTarget.getBean(); |
---|
494 | Object [] args = new Object[1]; |
---|
495 | args[0] = targetBean; |
---|
496 | deregisterMethod.invoke(tempSource.getBean(), args); |
---|
497 | // System.err.println("Deregistering listener"); |
---|
498 | removeVector.addElement(bc); |
---|
499 | } catch (Exception ex) { |
---|
500 | ex.printStackTrace(); |
---|
501 | } |
---|
502 | } else if (tempInstance == tempSource) { |
---|
503 | removeVector.addElement(bc); |
---|
504 | if (tempTarget.getBean() instanceof BeanCommon) { |
---|
505 | // tell the target that the source is going away, therefore |
---|
506 | // this type of connection is as well |
---|
507 | ((BeanCommon)tempTarget.getBean()). |
---|
508 | disconnectionNotification(tempEsd.getName(), |
---|
509 | tempSource.getBean()); |
---|
510 | } |
---|
511 | } |
---|
512 | } |
---|
513 | } |
---|
514 | for (int i = 0; i < removeVector.size(); i++) { |
---|
515 | // System.err.println("removing connection"); |
---|
516 | CONNECTIONS.removeElement((BeanConnection)removeVector.elementAt(i)); |
---|
517 | } |
---|
518 | } |
---|
519 | |
---|
520 | public static void doMetaConnection(BeanInstance source, BeanInstance target, |
---|
521 | final EventSetDescriptor esd, |
---|
522 | final JComponent displayComponent) { |
---|
523 | |
---|
524 | Object targetBean = target.getBean(); |
---|
525 | BeanInstance realTarget = null; |
---|
526 | final BeanInstance realSource = source; |
---|
527 | if (targetBean instanceof MetaBean) { |
---|
528 | Vector receivers = ((MetaBean)targetBean).getSuitableTargets(esd); |
---|
529 | if (receivers.size() == 1) { |
---|
530 | realTarget = (BeanInstance)receivers.elementAt(0); |
---|
531 | BeanConnection bc = new BeanConnection(realSource, realTarget, |
---|
532 | esd); |
---|
533 | // m_target = (BeanInstance)receivers.elementAt(0); |
---|
534 | } else { |
---|
535 | // have to do the popup thing here |
---|
536 | int menuItemCount = 0; |
---|
537 | JPopupMenu targetConnectionMenu = new JPopupMenu(); |
---|
538 | targetConnectionMenu.insert(new JLabel("Select target", |
---|
539 | SwingConstants.CENTER), |
---|
540 | menuItemCount++); |
---|
541 | for (int i = 0; i < receivers.size(); i++) { |
---|
542 | final BeanInstance tempTarget = |
---|
543 | (BeanInstance)receivers.elementAt(i); |
---|
544 | String tName = ""+(i+1)+": " |
---|
545 | + ((tempTarget.getBean() instanceof BeanCommon) |
---|
546 | ? ((BeanCommon)tempTarget.getBean()).getCustomName() |
---|
547 | : tempTarget.getBean().getClass().getName()); |
---|
548 | JMenuItem targetItem = new JMenuItem(tName); |
---|
549 | targetItem.addActionListener(new ActionListener() { |
---|
550 | public void actionPerformed(ActionEvent e) { |
---|
551 | // finalTarget.add(tempTarget); |
---|
552 | BeanConnection bc = |
---|
553 | new BeanConnection(realSource, tempTarget, |
---|
554 | esd); |
---|
555 | displayComponent.repaint(); |
---|
556 | } |
---|
557 | }); |
---|
558 | targetConnectionMenu.add(targetItem); |
---|
559 | menuItemCount++; |
---|
560 | } |
---|
561 | targetConnectionMenu.show(displayComponent, target.getX(), |
---|
562 | target.getY()); |
---|
563 | // m_target = (BeanInstance)finalTarget.elementAt(0); |
---|
564 | } |
---|
565 | } |
---|
566 | } |
---|
567 | |
---|
568 | /** |
---|
569 | * Creates a new <code>BeanConnection</code> instance. |
---|
570 | * |
---|
571 | * @param source the source bean |
---|
572 | * @param target the target bean |
---|
573 | * @param esd the EventSetDescriptor for the connection |
---|
574 | * be displayed |
---|
575 | */ |
---|
576 | public BeanConnection(BeanInstance source, BeanInstance target, |
---|
577 | EventSetDescriptor esd) { |
---|
578 | m_source = source; |
---|
579 | m_target = target; |
---|
580 | // m_sourceEsd = sourceEsd; |
---|
581 | m_eventName = esd.getName(); |
---|
582 | // System.err.println(m_eventName); |
---|
583 | |
---|
584 | // attempt to connect source and target beans |
---|
585 | Method registrationMethod = |
---|
586 | // m_sourceEsd.getAddListenerMethod(); |
---|
587 | // getSourceEventSetDescriptor().getAddListenerMethod(); |
---|
588 | esd.getAddListenerMethod(); |
---|
589 | Object targetBean = m_target.getBean(); |
---|
590 | |
---|
591 | Object [] args = new Object[1]; |
---|
592 | args[0] = targetBean; |
---|
593 | Class listenerClass = esd.getListenerType(); |
---|
594 | if (listenerClass.isInstance(targetBean)) { |
---|
595 | try { |
---|
596 | registrationMethod.invoke(m_source.getBean(), args); |
---|
597 | // if the target implements BeanCommon, then inform |
---|
598 | // it that it has been registered as a listener with a source via |
---|
599 | // the named listener interface |
---|
600 | if (targetBean instanceof BeanCommon) { |
---|
601 | ((BeanCommon)targetBean). |
---|
602 | connectionNotification(esd.getName(), m_source.getBean()); |
---|
603 | } |
---|
604 | CONNECTIONS.addElement(this); |
---|
605 | } catch (Exception ex) { |
---|
606 | System.err.println("[BeanConnection] Unable to connect beans"); |
---|
607 | ex.printStackTrace(); |
---|
608 | } |
---|
609 | } else { |
---|
610 | System.err.println("[BeanConnection] Unable to connect beans"); |
---|
611 | } |
---|
612 | } |
---|
613 | |
---|
614 | /** |
---|
615 | * Make this connection invisible on the display |
---|
616 | * |
---|
617 | * @param hidden true to make the connection invisible |
---|
618 | */ |
---|
619 | public void setHidden(boolean hidden) { |
---|
620 | m_hidden = hidden; |
---|
621 | } |
---|
622 | |
---|
623 | /** |
---|
624 | * Returns true if this connection is invisible |
---|
625 | * |
---|
626 | * @return true if connection is invisible |
---|
627 | */ |
---|
628 | public boolean isHidden() { |
---|
629 | return m_hidden; |
---|
630 | } |
---|
631 | |
---|
632 | /** |
---|
633 | * Remove this connection |
---|
634 | */ |
---|
635 | public void remove() { |
---|
636 | EventSetDescriptor tempEsd = getSourceEventSetDescriptor(); |
---|
637 | // try to deregister the target as a listener for the source |
---|
638 | try { |
---|
639 | Method deregisterMethod = tempEsd.getRemoveListenerMethod(); |
---|
640 | Object targetBean = getTarget().getBean(); |
---|
641 | Object [] args = new Object[1]; |
---|
642 | args[0] = targetBean; |
---|
643 | deregisterMethod.invoke(getSource().getBean(), args); |
---|
644 | // System.err.println("Deregistering listener"); |
---|
645 | } catch (Exception ex) { |
---|
646 | ex.printStackTrace(); |
---|
647 | } |
---|
648 | |
---|
649 | if (getTarget().getBean() instanceof BeanCommon) { |
---|
650 | // tell the target that this connection is going away |
---|
651 | ((BeanCommon)getTarget().getBean()). |
---|
652 | disconnectionNotification(tempEsd.getName(), |
---|
653 | getSource().getBean()); |
---|
654 | } |
---|
655 | |
---|
656 | CONNECTIONS.remove(this); |
---|
657 | } |
---|
658 | |
---|
659 | /** |
---|
660 | * returns the source BeanInstance for this connection |
---|
661 | * |
---|
662 | * @return a <code>BeanInstance</code> value |
---|
663 | */ |
---|
664 | public BeanInstance getSource() { |
---|
665 | return m_source; |
---|
666 | } |
---|
667 | |
---|
668 | /** |
---|
669 | * Returns the target BeanInstance for this connection |
---|
670 | * |
---|
671 | * @return a <code>BeanInstance</code> value |
---|
672 | */ |
---|
673 | public BeanInstance getTarget() { |
---|
674 | return m_target; |
---|
675 | } |
---|
676 | |
---|
677 | /** |
---|
678 | * Returns the name of the event for this conncetion |
---|
679 | * |
---|
680 | * @return the name of the event for this connection |
---|
681 | */ |
---|
682 | public String getEventName() { |
---|
683 | return m_eventName; |
---|
684 | } |
---|
685 | |
---|
686 | /** |
---|
687 | * Returns the event set descriptor for the event generated by the source |
---|
688 | * for this connection |
---|
689 | * |
---|
690 | * @return an <code>EventSetDescriptor</code> value |
---|
691 | */ |
---|
692 | protected EventSetDescriptor getSourceEventSetDescriptor() { |
---|
693 | JComponent bc = (JComponent)m_source.getBean(); |
---|
694 | try { |
---|
695 | BeanInfo sourceInfo = Introspector.getBeanInfo(bc.getClass()); |
---|
696 | if (sourceInfo == null) { |
---|
697 | System.err.println("[BeanConnection] Error getting bean info, source info is null."); |
---|
698 | } else { |
---|
699 | EventSetDescriptor [] esds = sourceInfo.getEventSetDescriptors(); |
---|
700 | for (int i = 0; i < esds.length; i++) { |
---|
701 | if (esds[i].getName().compareTo(m_eventName) == 0) { |
---|
702 | return esds[i]; |
---|
703 | } |
---|
704 | } |
---|
705 | } |
---|
706 | } catch (Exception ex) { |
---|
707 | System.err.println("[BeanConnection] Problem retrieving event set descriptor"); |
---|
708 | } |
---|
709 | return null; |
---|
710 | |
---|
711 | // return m_sourceEsd; |
---|
712 | } |
---|
713 | } |
---|