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
|
}
|