Project

General

Profile

Download (29.3 KB) Statistics
| Branch: | Tag: | Revision:
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 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
 *******************************************************************************/
11
package org.eclipse.gef.editparts;
12

    
13
import java.util.ArrayList;
14
import java.util.Collections;
15
import java.util.HashMap;
16
import java.util.Iterator;
17
import java.util.List;
18
import java.util.Map;
19

    
20
import org.eclipse.swt.accessibility.ACC;
21
import org.eclipse.swt.accessibility.AccessibleControlEvent;
22

    
23
import org.eclipse.core.runtime.IAdaptable;
24

    
25
import org.eclipse.draw2d.IFigure;
26
import org.eclipse.draw2d.LayoutManager;
27
import org.eclipse.draw2d.geometry.Point;
28
import org.eclipse.draw2d.geometry.Rectangle;
29

    
30
import org.eclipse.gef.AccessibleAnchorProvider;
31
import org.eclipse.gef.AccessibleEditPart;
32
import org.eclipse.gef.AccessibleHandleProvider;
33
import org.eclipse.gef.ConnectionEditPart;
34
import org.eclipse.gef.DragTracker;
35
import org.eclipse.gef.EditPart;
36
import org.eclipse.gef.EditPartFactory;
37
import org.eclipse.gef.EditPartViewer;
38
import org.eclipse.gef.EditPolicy;
39
import org.eclipse.gef.GraphicalEditPart;
40
import org.eclipse.gef.NodeListener;
41
import org.eclipse.gef.Request;
42

    
43
/**
44
 * Default implementation for {@link org.eclipse.gef.GraphicalEditPart}.
45
 * <P>
46
 * This is an implementation class, and the documentation here is targeted at
47
 * subclassing this class. Callers of public API should refer to the interface's
48
 * documentation.
49
 */
50
public abstract class AbstractGraphicalEditPart extends AbstractEditPart
51
		implements GraphicalEditPart {
52

    
53
	/**
54
	 * The Figure
55
	 */
56
	protected IFigure figure;
57

    
58
	/**
59
	 * List of <i>source</i> ConnectionEditParts
60
	 */
61
	protected List sourceConnections;
62

    
63
	/**
64
	 * List of <i>source</i> ConnectionEditParts
65
	 */
66
	protected List targetConnections;
67

    
68
	/**
69
	 * A default implementation of {@link AccessibleEditPart}. Subclasses can
70
	 * extend this implementation to get base accessibility for free.
71
	 * 
72
	 * @since 2.0
73
	 */
74
	protected abstract class AccessibleGraphicalEditPart extends
75
			AccessibleEditPart {
76
		/**
77
		 * @see AccessibleEditPart#getChildCount(AccessibleControlEvent)
78
		 */
79
		public void getChildCount(AccessibleControlEvent e) {
80
			e.detail = AbstractGraphicalEditPart.this.getChildren().size();
81
		}
82

    
83
		/**
84
		 * @see AccessibleEditPart#getChildren(AccessibleControlEvent)
85
		 */
86
		public void getChildren(AccessibleControlEvent e) {
87
			List list = AbstractGraphicalEditPart.this.getChildren();
88
			Object children[] = new Object[list.size()];
89
			for (int i = 0; i < list.size(); i++) {
90
				EditPart part = (EditPart) list.get(i);
91
				AccessibleEditPart access = (AccessibleEditPart) part
92
						.getAdapter(AccessibleEditPart.class);
93
				if (access == null)
94
					return; // fail if any children aren't accessible.
95
				children[i] = new Integer(access.getAccessibleID());
96
			}
97
			e.children = children;
98
		}
99

    
100
		/**
101
		 * @see AccessibleEditPart#getLocation(AccessibleControlEvent)
102
		 */
103
		public void getLocation(AccessibleControlEvent e) {
104
			Rectangle bounds = getFigure().getBounds().getCopy();
105
			getFigure().translateToAbsolute(bounds);
106
			org.eclipse.swt.graphics.Point p = new org.eclipse.swt.graphics.Point(
107
					0, 0);
108
			p = getViewer().getControl().toDisplay(p);
109
			e.x = bounds.x + p.x;
110
			e.y = bounds.y + p.y;
111
			e.width = bounds.width;
112
			e.height = bounds.height;
113
		}
114

    
115
		/**
116
		 * @see AccessibleEditPart#getState(AccessibleControlEvent)
117
		 */
118
		public void getState(AccessibleControlEvent e) {
119
			e.detail = ACC.STATE_SELECTABLE | ACC.STATE_FOCUSABLE;
120
			if (getSelected() != EditPart.SELECTED_NONE)
121
				e.detail |= ACC.STATE_SELECTED;
122
			if (getViewer().getFocusEditPart() == AbstractGraphicalEditPart.this)
123
				e.detail |= ACC.STATE_FOCUSED;
124
		}
125

    
126
		/**
127
		 * @see AccessibleEditPart#getRole(AccessibleControlEvent)
128
		 */
129
		public void getRole(AccessibleControlEvent e) {
130
			e.detail = ACC.ROLE_LABEL;
131
		}
132
	}
133

    
134
	/**
135
	 * The default implementation of {@link AccessibleAnchorProvider} returned
136
	 * in {@link #getAdapter(Class)}. This implementation creates an accessible
137
	 * location located along the right edge of the EditPart's Figure.
138
	 * 
139
	 * @since 2.0
140
	 */
141
	protected class DefaultAccessibleAnchorProvider implements
142
			AccessibleAnchorProvider {
143
		private List getDefaultLocations() {
144
			List list = new ArrayList();
145
			Rectangle r = getFigure().getBounds();
146
			Point p = r.getTopRight().translate(-1, r.height / 3);
147
			getFigure().translateToAbsolute(p);
148
			list.add(p);
149
			return list;
150
		}
151

    
152
		/**
153
		 * @see AccessibleAnchorProvider#getSourceAnchorLocations()
154
		 */
155
		public List getSourceAnchorLocations() {
156
			return getDefaultLocations();
157
		}
158

    
159
		/**
160
		 * @see AccessibleAnchorProvider#getTargetAnchorLocations()
161
		 */
162
		public List getTargetAnchorLocations() {
163
			return getDefaultLocations();
164
		}
165
	}
166

    
167
	static class MergedAccessibleHandles implements AccessibleHandleProvider {
168
		List locations = new ArrayList();
169

    
170
		MergedAccessibleHandles(EditPolicyIterator iter) {
171
			while (iter.hasNext()) {
172
				EditPolicy policy = iter.next();
173
				if (!(policy instanceof IAdaptable))
174
					continue;
175
				IAdaptable adaptable = (IAdaptable) policy;
176
				AccessibleHandleProvider adapter = (AccessibleHandleProvider) adaptable
177
						.getAdapter(AccessibleHandleProvider.class);
178
				if (adapter != null)
179
					locations.addAll(adapter.getAccessibleHandleLocations());
180
			}
181
		}
182

    
183
		public List getAccessibleHandleLocations() {
184
			return locations;
185
		}
186
	}
187

    
188
	/**
189
	 * Extends {@link AbstractEditPart#activate()} to also activate all
190
	 * <i>source</i> ConnectionEditParts.
191
	 * 
192
	 * @see org.eclipse.gef.EditPart#activate()
193
	 */
194
	public void activate() {
195
		super.activate();
196
		List l = getSourceConnections();
197
		for (int i = 0; i < l.size(); i++)
198
			((EditPart) l.get(i)).activate();
199
	}
200

    
201
	/**
202
	 * Adds the child's Figure to the {@link #getContentPane() contentPane}.
203
	 * 
204
	 * @see org.eclipse.gef.editparts.AbstractEditPart#addChildVisual(EditPart,
205
	 *      int)
206
	 */
207
	protected void addChildVisual(EditPart childEditPart, int index) {
208
		IFigure child = ((GraphicalEditPart) childEditPart).getFigure();
209
		getContentPane().add(child, index);
210
	}
211

    
212
	/**
213
	 * @see org.eclipse.gef.GraphicalEditPart#addNodeListener(org.eclipse.gef.NodeListener)
214
	 */
215
	public void addNodeListener(NodeListener listener) {
216
		eventListeners.addListener(NodeListener.class, listener);
217
	}
218

    
219
	/**
220
	 * @see org.eclipse.gef.EditPart#addNotify()
221
	 */
222
	public void addNotify() {
223
		super.addNotify();
224
		List conns;
225
		conns = getSourceConnections();
226
		for (int i = 0; i < conns.size(); i++)
227
			((ConnectionEditPart) conns.get(i)).setSource(this);
228
		conns = getTargetConnections();
229
		for (int i = 0; i < conns.size(); i++)
230
			((ConnectionEditPart) conns.get(i)).setTarget(this);
231
	}
232

    
233
	/**
234
	 * Adds a <i>source</i> ConnectionEditPart at the specified index. This
235
	 * method is called from {@link #refreshSourceConnections()}. There should
236
	 * be no reason to call or override this method. Source connection are
237
	 * created as a result of overriding {@link #getModelSourceConnections()}.
238
	 * <P>
239
	 * {@link #primAddSourceConnection(ConnectionEditPart, int)} is called to
240
	 * perform the actual update of the {@link #sourceConnections}
241
	 * <code>List</code>. The connection will have its source set to
242
	 * <code>this</code>.
243
	 * <P>
244
	 * If active, this EditPart will activate the ConnectionEditPart.
245
	 * <P>
246
	 * Finally, all {@link NodeListener}s are notified of the new connection.
247
	 * 
248
	 * @param connection
249
	 *            Connection being added
250
	 * @param index
251
	 *            Index where it is being added
252
	 */
253
	protected void addSourceConnection(ConnectionEditPart connection, int index) {
254
		primAddSourceConnection(connection, index);
255

    
256
		GraphicalEditPart source = (GraphicalEditPart) connection.getSource();
257
		if (source != null)
258
			source.getSourceConnections().remove(connection);
259

    
260
		connection.setSource(this);
261
		if (isActive())
262
			connection.activate();
263
		fireSourceConnectionAdded(connection, index);
264
	}
265

    
266
	/**
267
	 * Adds a <i>target</i> ConnectionEditPart at the specified index. This
268
	 * method is called from {@link #refreshTargetConnections()}. There should
269
	 * be no reason to call or override this method. Target connection are
270
	 * created as a result of overriding {@link #getModelTargetConnections()}.
271
	 * <P>
272
	 * {@link #primAddTargetConnection(ConnectionEditPart, int)} is called to
273
	 * perform the actual update of the {@link #targetConnections}
274
	 * <code>List</code>. The connection will have its target set to
275
	 * <code>this</code>.
276
	 * <P>
277
	 * Finally, all {@link NodeListener}s are notified of the new connection.
278
	 * 
279
	 * @param connection
280
	 *            Connection being added
281
	 * @param index
282
	 *            Index where it is being added
283
	 */
284
	protected void addTargetConnection(ConnectionEditPart connection, int index) {
285
		primAddTargetConnection(connection, index);
286

    
287
		GraphicalEditPart target = (GraphicalEditPart) connection.getTarget();
288
		if (target != null)
289
			target.getTargetConnections().remove(connection);
290

    
291
		connection.setTarget(this);
292
		fireTargetConnectionAdded(connection, index);
293
	}
294

    
295
	/**
296
	 * Creates a {@link ConnectionEditPart} for the given model. Similar to
297
	 * {@link AbstractEditPart#createChild(Object)}. This method is called
298
	 * indirectly during {@link #refreshSourceConnections()}, and
299
	 * {@link #refreshTargetConnections()}.
300
	 * <P>
301
	 * The default implementation goes to the EditPartViewer's
302
	 * {@link EditPartFactory} to create the connection. This method should not
303
	 * be overridden unless factories are not being used.
304
	 * 
305
	 * @param model
306
	 *            the connection model object
307
	 * @return the new ConnectionEditPart
308
	 */
309
	protected ConnectionEditPart createConnection(Object model) {
310
		return (ConnectionEditPart) getViewer().getEditPartFactory()
311
				.createEditPart(this, model);
312
	}
313

    
314
	/**
315
	 * Creates the <code>Figure</code> to be used as this part's <i>visuals</i>.
316
	 * This is called from {@link #getFigure()} if the figure has not been
317
	 * created.
318
	 * 
319
	 * @return a Figure
320
	 */
321
	protected abstract IFigure createFigure();
322

    
323
	/**
324
	 * Searches for an existing <code>ConnectionEditPart</code> in the Viewer's
325
	 * {@link EditPartViewer#getEditPartRegistry() EditPart registry} and
326
	 * returns it if one is found. Otherwise, {@link #createConnection(Object)}
327
	 * is called to create a new ConnectionEditPart. Override this method only
328
	 * if you need to find an existing connection some other way.
329
	 * 
330
	 * @param model
331
	 *            the Connection's model
332
	 * @return the ConnectionEditPart
333
	 */
334
	protected ConnectionEditPart createOrFindConnection(Object model) {
335
		ConnectionEditPart conx = (ConnectionEditPart) getViewer()
336
				.getEditPartRegistry().get(model);
337
		if (conx != null)
338
			return conx;
339
		return createConnection(model);
340
	}
341

    
342
	/**
343
	 * Extends {@link AbstractEditPart#deactivate()} to also deactivate the
344
	 * source ConnectionEditParts. Subclasses should <em>extend</em> this method
345
	 * to remove any listeners added in {@link #activate}.
346
	 * 
347
	 * @see org.eclipse.gef.EditPart#deactivate()
348
	 */
349
	public void deactivate() {
350
		List l = getSourceConnections();
351
		for (int i = 0; i < l.size(); i++)
352
			((EditPart) l.get(i)).deactivate();
353

    
354
		super.deactivate();
355
	}
356

    
357
	/**
358
	 * Notifies listeners that a source connection has been removed. Called from
359
	 * {@link #removeSourceConnection(ConnectionEditPart)}. There is no reason
360
	 * for subclasses to call or override this method.
361
	 * 
362
	 * @param connection
363
	 *            <code>ConnectionEditPart</code> being added as child.
364
	 * @param index
365
	 *            Position child is being added into.
366
	 */
367
	protected void fireRemovingSourceConnection(ConnectionEditPart connection,
368
			int index) {
369
		if (eventListeners == null)
370
			return;
371
		Iterator listeners = eventListeners.getListeners(NodeListener.class);
372
		NodeListener listener = null;
373
		while (listeners.hasNext()) {
374
			listener = (NodeListener) listeners.next();
375
			listener.removingSourceConnection(connection, index);
376
		}
377
	}
378

    
379
	/**
380
	 * Notifies listeners that a target connection has been removed. Called from
381
	 * {@link #removeTargetConnection(ConnectionEditPart)}. There is no reason
382
	 * for subclasses to call or override this method.
383
	 * 
384
	 * @param connection
385
	 *            <code>ConnectionEditPart</code> being added as child.
386
	 * @param index
387
	 *            Position child is being added into.
388
	 */
389
	protected void fireRemovingTargetConnection(ConnectionEditPart connection,
390
			int index) {
391
		if (eventListeners == null)
392
			return;
393
		Iterator listeners = eventListeners.getListeners(NodeListener.class);
394
		NodeListener listener = null;
395
		while (listeners.hasNext()) {
396
			listener = (NodeListener) listeners.next();
397
			listener.removingTargetConnection(connection, index);
398
		}
399
	}
400

    
401
	/**
402
	 * Notifies listeners that a source connection has been added. Called from
403
	 * {@link #addSourceConnection(ConnectionEditPart, int)}. There is no reason
404
	 * for subclasses to call or override this method.
405
	 * 
406
	 * @param connection
407
	 *            <code>ConnectionEditPart</code> being added as child.
408
	 * @param index
409
	 *            Position child is being added into.
410
	 */
411
	protected void fireSourceConnectionAdded(ConnectionEditPart connection,
412
			int index) {
413
		if (eventListeners == null)
414
			return;
415
		Iterator listeners = eventListeners.getListeners(NodeListener.class);
416
		NodeListener listener = null;
417
		while (listeners.hasNext()) {
418
			listener = (NodeListener) listeners.next();
419
			listener.sourceConnectionAdded(connection, index);
420
		}
421
	}
422

    
423
	/**
424
	 * Notifies listeners that a target connection has been added. Called from
425
	 * {@link #addTargetConnection(ConnectionEditPart, int)}. There is no reason
426
	 * for subclasses to call or override this method.
427
	 * 
428
	 * @param connection
429
	 *            <code>ConnectionEditPart</code> being added as child.
430
	 * @param index
431
	 *            Position child is being added into.
432
	 */
433
	protected void fireTargetConnectionAdded(ConnectionEditPart connection,
434
			int index) {
435
		if (eventListeners == null)
436
			return;
437
		Iterator listeners = eventListeners.getListeners(NodeListener.class);
438
		NodeListener listener = null;
439
		while (listeners.hasNext()) {
440
			listener = (NodeListener) listeners.next();
441
			listener.targetConnectionAdded(connection, index);
442
		}
443
	}
444

    
445
	/**
446
	 * Extends {@link AbstractEditPart#getAdapter(Class)} to handle additional
447
	 * adapter types. Currently, these types include
448
	 * {@link AccessibleHandleProvider} and {@link AccessibleAnchorProvider}.
449
	 * Subclasses should <em>extend</em> this method to support additional
450
	 * adapter types, or to replace the default provided adapaters.
451
	 * 
452
	 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class)
453
	 */
454
	public Object getAdapter(Class key) {
455
		if (key == AccessibleHandleProvider.class)
456
			return new MergedAccessibleHandles(getEditPolicyIterator());
457

    
458
		if (key == AccessibleAnchorProvider.class)
459
			return new DefaultAccessibleAnchorProvider();
460

    
461
		return super.getAdapter(key);
462
	}
463

    
464
	/**
465
	 * Implemented to delegate to {@link #getFigure()} by default. Subclasses
466
	 * may overwrite in case the {@link IFigure} returned by
467
	 * {@link #getFigure()} is a composite figure and child figures should be
468
	 * added to one of its children instead of the figure itself.
469
	 * 
470
	 * @see GraphicalEditPart#getContentPane()
471
	 */
472
	public IFigure getContentPane() {
473
		return getFigure();
474
	}
475

    
476
	/**
477
	 * Overridden to return a default <code>DragTracker</code> for
478
	 * GraphicalEditParts.
479
	 * 
480
	 * @see org.eclipse.gef.EditPart#getDragTracker(Request)
481
	 */
482
	public DragTracker getDragTracker(Request request) {
483
		return new org.eclipse.gef.tools.DragEditPartsTracker(this);
484
	}
485

    
486
	/**
487
	 * The default implementation calls {@link #createFigure()} if the figure is
488
	 * currently <code>null</code>.
489
	 * 
490
	 * @see org.eclipse.gef.GraphicalEditPart#getFigure()
491
	 */
492
	public IFigure getFigure() {
493
		if (figure == null)
494
			setFigure(createFigure());
495
		return figure;
496
	}
497

    
498
	/**
499
	 * A convenience method for obtaining the specified layer from the
500
	 * <code>LayerManager</code>.
501
	 * 
502
	 * @param layer
503
	 *            ID of the Layer
504
	 * @return The requested layer or <code>null</code> if it doesn't exist
505
	 */
506
	protected IFigure getLayer(Object layer) {
507
		LayerManager manager = (LayerManager) getViewer().getEditPartRegistry()
508
				.get(LayerManager.ID);
509
		return manager.getLayer(layer);
510
	}
511

    
512
	/**
513
	 * Returns the <code>List</code> of the connection model objects for which
514
	 * this EditPart's model is the <b>source</b>.
515
	 * {@link #refreshSourceConnections()} calls this method. For each
516
	 * connection model object, {@link #createConnection(Object)} will be called
517
	 * automatically to obtain a corresponding {@link ConnectionEditPart}.
518
	 * <P>
519
	 * Callers must not modify the returned List.
520
	 * 
521
	 * @return the List of model source connections
522
	 */
523
	protected List getModelSourceConnections() {
524
		return Collections.EMPTY_LIST;
525
	}
526

    
527
	/**
528
	 * Returns the <code>List</code> of the connection model objects for which
529
	 * this EditPart's model is the <b>target</b>.
530
	 * {@link #refreshTargetConnections()} calls this method. For each
531
	 * connection model object, {@link #createConnection(Object)} will be called
532
	 * automatically to obtain a corresponding {@link ConnectionEditPart}.
533
	 * <P>
534
	 * Callers must not modify the returned List.
535
	 * 
536
	 * @return the List of model target connections
537
	 */
538
	protected List getModelTargetConnections() {
539
		return Collections.EMPTY_LIST;
540
	}
541

    
542
	/**
543
	 * @see org.eclipse.gef.GraphicalEditPart#getSourceConnections()
544
	 */
545
	public List getSourceConnections() {
546
		if (sourceConnections == null)
547
			return Collections.EMPTY_LIST;
548
		return sourceConnections;
549
	}
550

    
551
	/**
552
	 * @see org.eclipse.gef.GraphicalEditPart#getTargetConnections()
553
	 */
554
	public List getTargetConnections() {
555
		if (targetConnections == null)
556
			return Collections.EMPTY_LIST;
557
		return targetConnections;
558
	}
559

    
560
	/**
561
	 * A GraphicalEditPart is considered selectable, if it is active and its
562
	 * figure is showing.
563
	 * 
564
	 * @see org.eclipse.gef.editparts.AbstractEditPart#isSelectable()
565
	 */
566
	public boolean isSelectable() {
567
		return super.isSelectable() && getFigure() != null
568
				&& getFigure().isShowing();
569
	}
570

    
571
	/**
572
	 * Adds the specified source <code>ConnectionEditPart</code> at an index.
573
	 * This method is used to update the {@link #sourceConnections} List. This
574
	 * method is called from
575
	 * {@link #addSourceConnection(ConnectionEditPart, int)}. Subclasses should
576
	 * not call or override this method.
577
	 * 
578
	 * @param connection
579
	 *            the ConnectionEditPart
580
	 * @param index
581
	 *            the index of the add
582
	 */
583
	protected void primAddSourceConnection(ConnectionEditPart connection,
584
			int index) {
585
		if (sourceConnections == null)
586
			sourceConnections = new ArrayList();
587
		sourceConnections.add(index, connection);
588
	}
589

    
590
	/**
591
	 * Adds the specified target <code>ConnectionEditPart</code> at an index.
592
	 * This method is used to update the {@link #targetConnections} List. This
593
	 * method is called from
594
	 * {@link #addTargetConnection(ConnectionEditPart, int)}. Subclasses should
595
	 * not call or override this method.
596
	 * 
597
	 * @param connection
598
	 *            the ConnectionEditPart
599
	 * @param index
600
	 *            the index of the add
601
	 */
602
	protected void primAddTargetConnection(ConnectionEditPart connection,
603
			int index) {
604
		if (targetConnections == null)
605
			targetConnections = new ArrayList();
606
		targetConnections.add(index, connection);
607
	}
608

    
609
	/**
610
	 * Removes the specified source <code>ConnectionEditPart</code> from the
611
	 * {@link #sourceConnections} List. This method is called from
612
	 * {@link #removeSourceConnection(ConnectionEditPart)}. Subclasses should
613
	 * not call or override this method.
614
	 * 
615
	 * @param connection
616
	 *            Connection to remove.
617
	 */
618
	protected void primRemoveSourceConnection(ConnectionEditPart connection) {
619
		sourceConnections.remove(connection);
620
	}
621

    
622
	/**
623
	 * Removes the specified target <code>ConnectionEditPart</code> from the
624
	 * {@link #targetConnections} List. This method is called from
625
	 * {@link #removeTargetConnection(ConnectionEditPart)}. Subclasses should
626
	 * not call or override this method.
627
	 * 
628
	 * @param connection
629
	 *            Connection to remove.
630
	 */
631
	protected void primRemoveTargetConnection(ConnectionEditPart connection) {
632
		targetConnections.remove(connection);
633
	}
634

    
635
	/**
636
	 * Extends {@link AbstractEditPart#refresh()} to refresh two additional
637
	 * structural features: <i>source</i> and <i>target</i> connections.
638
	 * Subclasses should probably override
639
	 * {@link AbstractEditPart#refreshVisuals()} instead of this method.
640
	 * 
641
	 * @see org.eclipse.gef.EditPart#refresh()
642
	 */
643
	public void refresh() {
644
		super.refresh();
645
		refreshSourceConnections();
646
		refreshTargetConnections();
647
	}
648

    
649
	/**
650
	 * Updates the set of <i>source</i> ConnectionEditParts so that it is in
651
	 * sync with the model source connections. This method is called from
652
	 * {@link #refresh()}, and may also be called in response to notification
653
	 * from the model.
654
	 * <P>
655
	 * The update is performed by comparing the existing source
656
	 * ConnectionEditParts with the set of model source connections returned
657
	 * from {@link #getModelSourceConnections()}. EditParts whose model no
658
	 * longer exists are {@link #removeSourceConnection(ConnectionEditPart)
659
	 * removed}. New models have their ConnectionEditParts
660
	 * {@link #createConnection(Object) created}. Subclasses should override
661
	 * <code>getModelSourceChildren()</code>.
662
	 * <P>
663
	 * This method should <em>not</em> be overridden.
664
	 */
665
	protected void refreshSourceConnections() {
666
		int i;
667
		ConnectionEditPart editPart;
668
		Object model;
669

    
670
		List sourceConnections = getSourceConnections();
671
		int size = sourceConnections.size();
672
		Map modelToEditPart = Collections.EMPTY_MAP;
673
		if (size > 0) {
674
			modelToEditPart = new HashMap(size);
675
			for (i = 0; i < size; i++) {
676
				editPart = (ConnectionEditPart) sourceConnections.get(i);
677
				modelToEditPart.put(editPart.getModel(), editPart);
678
			}
679
		}
680

    
681
		List modelObjects = getModelSourceConnections();
682
		if (modelObjects == null) {
683
			modelObjects = Collections.EMPTY_LIST;
684
		}
685
		for (i = 0; i < modelObjects.size(); i++) {
686
			model = modelObjects.get(i);
687

    
688
			if (i < sourceConnections.size()
689
					&& ((EditPart) sourceConnections.get(i)).getModel() == model)
690
				continue;
691

    
692
			editPart = (ConnectionEditPart) modelToEditPart.get(model);
693
			if (editPart != null)
694
				reorderSourceConnection(editPart, i);
695
			else {
696
				editPart = createOrFindConnection(model);
697
				addSourceConnection(editPart, i);
698
			}
699
		}
700

    
701
		// Remove the remaining EditParts
702
		size = sourceConnections.size();
703
		if (i < size) {
704
			List trash = new ArrayList(size - i);
705
			for (; i < size; i++)
706
				trash.add(sourceConnections.get(i));
707
			for (i = 0; i < trash.size(); i++)
708
				removeSourceConnection((ConnectionEditPart) trash.get(i));
709
		}
710
	}
711

    
712
	/**
713
	 * Updates the set of <i>target</i> ConnectionEditParts so that it is in
714
	 * sync with the model target connections. This method is called from
715
	 * {@link #refresh()}, and may also be called in response to notification
716
	 * from the model.
717
	 * <P>
718
	 * The update is performed by comparing the existing source
719
	 * ConnectionEditParts with the set of model source connections returned
720
	 * from {@link #getModelTargetConnections()}. EditParts whose model no
721
	 * longer exists are {@link #removeTargetConnection(ConnectionEditPart)
722
	 * removed}. New models have their ConnectionEditParts
723
	 * {@link #createConnection(Object) created}. Subclasses should override
724
	 * <code>getModelTargetChildren()</code>.
725
	 * <P>
726
	 * This method should <em>not</em> be overridden.
727
	 */
728
	protected void refreshTargetConnections() {
729
		int i;
730
		ConnectionEditPart editPart;
731
		Object model;
732

    
733
		List targetConnections = getTargetConnections();
734
		int size = targetConnections.size();
735
		Map modelToEditPart = Collections.EMPTY_MAP;
736
		if (size > 0) {
737
			modelToEditPart = new HashMap(size);
738
			for (i = 0; i < size; i++) {
739
				editPart = (ConnectionEditPart) targetConnections.get(i);
740
				modelToEditPart.put(editPart.getModel(), editPart);
741
			}
742
		}
743

    
744
		List modelObjects = getModelTargetConnections();
745
		if (modelObjects == null) {
746
			modelObjects = Collections.EMPTY_LIST;
747
		}
748
		for (i = 0; i < modelObjects.size(); i++) {
749
			model = modelObjects.get(i);
750

    
751
			if (i < targetConnections.size()
752
					&& ((EditPart) targetConnections.get(i)).getModel() == model)
753
				continue;
754

    
755
			editPart = (ConnectionEditPart) modelToEditPart.get(model);
756
			if (editPart != null)
757
				reorderTargetConnection(editPart, i);
758
			else {
759
				editPart = createOrFindConnection(model);
760
				addTargetConnection(editPart, i);
761
			}
762
		}
763

    
764
		// Remove the remaining EditParts
765
		size = targetConnections.size();
766
		if (i < size) {
767
			List trash = new ArrayList(size - i);
768
			for (; i < size; i++)
769
				trash.add(targetConnections.get(i));
770
			for (i = 0; i < trash.size(); i++)
771
				removeTargetConnection((ConnectionEditPart) trash.get(i));
772
		}
773
	}
774

    
775
	/**
776
	 * Registers the EditPart's Figure in the Viewer. This is what makes it
777
	 * possible for the Viewer to map a mouse location to an EditPart.
778
	 * 
779
	 * @see org.eclipse.gef.editparts.AbstractEditPart#registerVisuals()
780
	 */
781
	protected void registerVisuals() {
782
		getViewer().getVisualPartMap().put(getFigure(), this);
783
	}
784

    
785
	/**
786
	 * Remove the child's Figure from the {@link #getContentPane() contentPane}.
787
	 * 
788
	 * @see AbstractEditPart#removeChildVisual(EditPart)
789
	 */
790
	protected void removeChildVisual(EditPart childEditPart) {
791
		IFigure child = ((GraphicalEditPart) childEditPart).getFigure();
792
		getContentPane().remove(child);
793
	}
794

    
795
	/**
796
	 * @see org.eclipse.gef.GraphicalEditPart#removeNodeListener(org.eclipse.gef.NodeListener)
797
	 */
798
	public void removeNodeListener(NodeListener listener) {
799
		eventListeners.removeListener(NodeListener.class, listener);
800
	}
801

    
802
	/**
803
	 * Extends {@link AbstractEditPart#removeNotify()} to cleanup
804
	 * <code>ConnectionEditParts</code>.
805
	 * 
806
	 * @see EditPart#removeNotify()
807
	 */
808
	public void removeNotify() {
809
		List conns;
810
		ConnectionEditPart cep;
811
		conns = getSourceConnections();
812
		for (int i = 0; i < conns.size(); i++) {
813
			cep = (ConnectionEditPart) conns.get(i);
814
			if (cep.getSource() == this)
815
				cep.setSource(null);
816
		}
817
		conns = getTargetConnections();
818
		for (int i = 0; i < conns.size(); i++) {
819
			cep = (ConnectionEditPart) conns.get(i);
820
			if (cep.getTarget() == this)
821
				cep.setTarget(null);
822
		}
823
		super.removeNotify();
824
	}
825

    
826
	/**
827
	 * Removes the given connection for which this EditPart is the
828
	 * <B>source</b>. <BR>
829
	 * Fires notification. <BR>
830
	 * Inverse of {@link #addSourceConnection(ConnectionEditPart, int)}
831
	 * 
832
	 * @param connection
833
	 *            Connection being removed
834
	 */
835
	protected void removeSourceConnection(ConnectionEditPart connection) {
836
		fireRemovingSourceConnection(connection, getSourceConnections()
837
				.indexOf(connection));
838
		if (connection.getSource() == this) {
839
			connection.deactivate();
840
			connection.setSource(null);
841
		}
842
		primRemoveSourceConnection(connection);
843
	}
844

    
845
	/**
846
	 * Removes the given connection for which this EditPart is the
847
	 * <B>target</b>. <BR>
848
	 * Fires notification. <BR>
849
	 * Inverse of {@link #addTargetConnection(ConnectionEditPart, int)}
850
	 * 
851
	 * @param connection
852
	 *            Connection being removed
853
	 */
854
	protected void removeTargetConnection(ConnectionEditPart connection) {
855
		fireRemovingTargetConnection(connection, getTargetConnections()
856
				.indexOf(connection));
857
		if (connection.getTarget() == this)
858
			connection.setTarget(null);
859
		primRemoveTargetConnection(connection);
860
	}
861

    
862
	/**
863
	 * This method is extended to preserve a LayoutManager constraint if one
864
	 * exists.
865
	 * 
866
	 * @see org.eclipse.gef.editparts.AbstractEditPart#reorderChild(EditPart,
867
	 *      int)
868
	 */
869
	protected void reorderChild(EditPart child, int index) {
870
		// Save the constraint of the child so that it does not
871
		// get lost during the remove and re-add.
872
		IFigure childFigure = ((GraphicalEditPart) child).getFigure();
873
		LayoutManager layout = getContentPane().getLayoutManager();
874
		Object constraint = null;
875
		if (layout != null)
876
			constraint = layout.getConstraint(childFigure);
877

    
878
		super.reorderChild(child, index);
879
		setLayoutConstraint(child, childFigure, constraint);
880
	}
881

    
882
	/**
883
	 * Moves a source <code>ConnectionEditPart</code> into a lower index than it
884
	 * currently occupies. This method is called from
885
	 * {@link #refreshSourceConnections()}.
886
	 * 
887
	 * @param connection
888
	 *            the ConnectionEditPart
889
	 * @param index
890
	 *            the new index
891
	 */
892
	protected void reorderSourceConnection(ConnectionEditPart connection,
893
			int index) {
894
		primRemoveSourceConnection(connection);
895
		primAddSourceConnection(connection, index);
896
	}
897

    
898
	/**
899
	 * Moves a target <code>ConnectionEditPart</code> into a lower index than it
900
	 * currently occupies. This method is called from
901
	 * {@link #refreshTargetConnections()}.
902
	 * 
903
	 * @param connection
904
	 *            the ConnectionEditPart
905
	 * @param index
906
	 *            the new index
907
	 */
908
	protected void reorderTargetConnection(ConnectionEditPart connection,
909
			int index) {
910
		primRemoveTargetConnection(connection);
911
		primAddTargetConnection(connection, index);
912
	}
913

    
914
	/**
915
	 * Sets the Figure
916
	 * 
917
	 * @param figure
918
	 *            the Figure
919
	 */
920
	protected void setFigure(IFigure figure) {
921
		this.figure = figure;
922
	}
923

    
924
	/**
925
	 * @see GraphicalEditPart#setLayoutConstraint(EditPart, IFigure, Object)
926
	 */
927
	public void setLayoutConstraint(EditPart child, IFigure childFigure,
928
			Object constraint) {
929
		childFigure.getParent().setConstraint(childFigure, constraint);
930
	}
931

    
932
	/**
933
	 * Implemented to remove the Figure from the Viewer's registry.
934
	 * 
935
	 * @see AbstractEditPart#unregisterVisuals()
936
	 */
937
	protected void unregisterVisuals() {
938
		getViewer().getVisualPartMap().remove(getFigure());
939
	}
940

    
941
}
(3-3/21)