View Javadoc

1   /*
2    * This file is a part of CAST project.
3    * (c) Copyright 2007, AGH University of Science & Technology
4    * https://caribou.iisg.agh.edu.pl/trac/cast
5    *
6    * Licensed under the Eclipse Public License, Version 1.0 (the "License").
7    * You may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    * http://www.eclipse.org/legal/epl-v10.html
10   */
11  /*
12   * File: ConnectionGroup.java
13   * Created: 2007-00-00
14   * Author: awos
15   * $Id: ConnectionGroup.java 2955 2009-06-04 09:20:08Z tmilos $
16   */
17  
18  package pl.edu.agh.cast.model.visual.backward;
19  
20  import java.util.HashSet;
21  import java.util.LinkedList;
22  import java.util.List;
23  import java.util.Set;
24  
25  import pl.edu.agh.cast.common.HexColor;
26  import pl.edu.agh.cast.model.attributes.AttributeManager;
27  import pl.edu.agh.cast.model.attributes.AttributeValue;
28  import pl.edu.agh.cast.model.attributes.ConnectionGroupAttributeManager;
29  
30  /**
31   * Stores list of all connections between two nodes.
32   *
33   * @author AGH CAST Team
34   */
35  public class ConnectionGroup extends ModelElement {
36  
37  	/*
38  	 * XXX: If you add a new property to this class, you must add it to CloneSelectionHelperTest and
39  	 * CloneSelectionHelper.
40  	 */
41  
42  	private static final long serialVersionUID = -3863944666693937115L;
43  
44  	// BEGIN Events fired by connection group
45  
46  	/**
47  	 * Name of the <em>Connection count changed</em> event.
48  	 */
49  	public static final String CONNECTION_COUNT_CHANGED = "ConnectionGroup_ConnCountChanged"; //$NON-NLS-1$
50  
51  	/**
52  	 * Name of the <em>Connection single line label changed</em> event.
53  	 */
54  	public static final String SINGLE_CONNECTION_LABEL = "ConnectionGroup_SingleLineLabel"; //$NON-NLS-1$
55  
56  	/**
57  	 * Name of the <em>Connection double line source-to-target label changed</em> event.
58  	 */
59  	public static final String DOUBLE_CONNECTION_SOURCE_LABEL = "ConnectionGroup_DoubleLineSourceToTargetLabel"; //$NON-NLS-1$
60  
61  	/**
62  	 * Name of the <em>Connection double line target-to-source label changed</em> event.
63  	 */
64  	public static final String DOUBLE_CONNECTION_TARGET_LABEL = "ConnectionGroup_DoubleLineTargetToSourceLabel"; //$NON-NLS-1$
65  
66  	/**
67  	 * Name of the <em>Variable thickness line label changed</em> event.
68  	 */
69  	public static final String VARIABLE_THICKNESS_CONNECTION_LABEL = "ConnectionGroup_VariableThicknessLineLabel"; //$NON-NLS-1$
70  
71  	/**
72  	 * Name of the <em>Line thickness changed</em> event.
73  	 */
74  	public static final String LINE_THICKNESS = "ConnectionGroup_LineThickness"; //$NON-NLS-1$
75  
76  	/**
77  	 * Name of the <em>Line color changed</em> event.
78  	 */
79  	public static final String LINE_COLOR = "ConnectionGroup_LineColor"; //$NON-NLS-1$
80  
81  	// END Events fired by connection group
82  
83  	private static final String NO_SUCH_NODE_MESSAGE = "Node does not belong to this connection group"; //$NON-NLS-1$
84  
85  	private Node left;
86  
87  	private Node right;
88  
89  	/**
90  	 * List of connections originating from left node.
91  	 */
92  	private List<Connection> leftConnections = new LinkedList<Connection>();
93  
94  	/**
95  	 * List of connections originating from right node.
96  	 */
97  	private List<Connection> rightConnections = new LinkedList<Connection>();
98  
99  	private ConnectionGroupAttributeManager attributeManager;
100 
101 	/**
102 	 * Creates a connection group.
103 	 *
104 	 * @param left
105 	 *            left side node; may not be null
106 	 * @param right
107 	 *            right side node; may not be null
108 	 * @param attributeManager
109 	 *            {@link AttributeManager} for this {@link ConnectionGroup}
110 	 */
111 	public ConnectionGroup(Node left, Node right, ConnectionGroupAttributeManager attributeManager) {
112 		super();
113 		setSource(left);
114 		setTarget(right);
115 		this.attributeManager = attributeManager;
116 
117 		bindToAttributeManager();
118 		setMandatoryProperties();
119 	}
120 
121 	private void setMandatoryProperties() {
122 		setAttributeValue(SINGLE_CONNECTION_LABEL, Integer.toString(leftConnections.size() + rightConnections.size()));
123 		setAttributeValue(DOUBLE_CONNECTION_SOURCE_LABEL, Integer.toString(leftConnections.size()));
124 		setAttributeValue(DOUBLE_CONNECTION_TARGET_LABEL, Integer.toString(rightConnections.size()));
125 		setAttributeValue(LINE_THICKNESS, 1);
126 		setAttributeValue(LINE_COLOR, new HexColor(0, 0, 0));
127 	}
128 
129 	public int getConnectionCount() {
130 		return leftConnections.size() + rightConnections.size();
131 	}
132 
133 	/**
134 	 * Returns the number of connections from target to source for given {@link Node}.
135 	 *
136 	 * @param node
137 	 *            the node to count connections for
138 	 * @return number of connections from target to source
139 	 */
140 	public int getTargetConnectionCountFor(Node node) {
141 		if (right.equals(node)) {
142 			return leftConnections.size();
143 		} else if (left.equals(node)) {
144 			return rightConnections.size();
145 		}
146 		throw new IllegalArgumentException(NO_SUCH_NODE_MESSAGE);
147 	}
148 
149 	/**
150 	 * Returns the number of connections from source to target for given {@link Node}.
151 	 *
152 	 * @param node
153 	 *            the node to count connections for
154 	 * @return number of connections from source to target
155 	 */
156 	public int getSourceConnectionCountFor(Node node) {
157 		if (left.equals(node)) {
158 			return leftConnections.size();
159 		} else if (right.equals(node)) {
160 			return rightConnections.size();
161 		}
162 		throw new IllegalArgumentException(NO_SUCH_NODE_MESSAGE);
163 	}
164 
165 	/**
166 	 * Returns list of connections originating from left node.
167 	 *
168 	 * @return list of connections originating from left node
169 	 *
170 	 * @deprecated Use {@link #getSourceConnectionsFor(Node)}
171 	 */
172 	@Deprecated
173 	public List<Connection> getLeftConnections() {
174 		return leftConnections;
175 	}
176 
177 	/**
178 	 * Returns list of connections originating from right node.
179 	 *
180 	 * @return list of connections originating from right node
181 	 *
182 	 * @deprecated Use {@link #getTargetConnectionsFor(Node)}
183 	 */
184 	@Deprecated
185 	public List<Connection> getRightConnections() {
186 		return rightConnections;
187 	}
188 
189 	/**
190 	 * Returns a list of source {@link Connection}s for <code>node</code>.
191 	 *
192 	 * @param node
193 	 *            {@link Node} to get source {@link Connection}s for
194 	 * @return list of source connections for the <code>node</code>
195 	 */
196 	public List<Connection> getSourceConnectionsFor(Node node) {
197 		if (left.equals(node)) {
198 			return leftConnections;
199 		} else if (right.equals(node)) {
200 			return rightConnections;
201 		}
202 		throw new IllegalArgumentException(NO_SUCH_NODE_MESSAGE);
203 
204 	}
205 
206 	/**
207 	 * Returns a list of target {@link Connection}s for <code>node</code>.
208 	 *
209 	 * @param node
210 	 *            {@link Node} to get target {@link Connection}s for
211 	 * @return list of target connections for the <code>node</code>
212 	 */
213 	public List<Connection> getTargetConnectionsFor(Node node) {
214 		if (right.equals(node)) {
215 			return leftConnections;
216 		} else if (left.equals(node)) {
217 			return rightConnections;
218 		}
219 		throw new IllegalArgumentException(NO_SUCH_NODE_MESSAGE);
220 
221 	}
222 
223 	/**
224 	 * Returns the list of all {@link Connection}s in this group.
225 	 *
226 	 * @return list of all {@link Connection}s in this group
227 	 */
228 	public List<Connection> getAllConnections() {
229 		Set<Connection> connections = new HashSet<Connection>();
230 		connections.addAll(leftConnections);
231 		connections.addAll(rightConnections);
232 		List<Connection> result = new LinkedList<Connection>();
233 		result.addAll(connections);
234 		return result;
235 	}
236 
237 	public Node getSource() {
238 		return left;
239 	}
240 
241 	/**
242 	 * Sets source node of this connection group.
243 	 *
244 	 * @param node
245 	 *            source node; may not be null
246 	 * @throws IllegalArgumentException
247 	 *             if node is null
248 	 */
249 	public void setSource(Node node) {
250 		if (node == null) {
251 			throw new IllegalArgumentException("source may not be null"); //$NON-NLS-1$
252 		}
253 		left = node;
254 	}
255 
256 	public Node getTarget() {
257 		return right;
258 	}
259 
260 	/**
261 	 * Sets target node of this connection group.
262 	 *
263 	 * @param node
264 	 *            target node; may not be null
265 	 * @throws IllegalArgumentException
266 	 *             if node is null
267 	 */
268 	public void setTarget(Node node) {
269 		if (node == null) {
270 			throw new IllegalArgumentException("target may not be null"); //$NON-NLS-1$
271 		}
272 		right = node;
273 	}
274 
275 	/**
276 	 * Updates attribute value only if it was a numerical value (i.e. it can be assumed it was the default connection
277 	 * count in the group).
278 	 *
279 	 * @param name
280 	 *            name of the attribute
281 	 * @param newValue
282 	 *            new value of the attribute
283 	 */
284 	private void updateProperty(String name, int newValue) {
285 		AttributeValue property = getAttributeValue(name);
286 
287 		try {
288 			Object value = property.getValue();
289 			if (value instanceof String) {
290 				Integer.parseInt((String)value);
291 			}
292 
293 			setAttributeValue(name, Integer.toString(newValue));
294 		} catch (NumberFormatException ex) {
295 			// if property value is not of type integer we do not update it
296 		}
297 	}
298 
299 	private void updateProperties() {
300 		// Update single line label
301 		updateProperty(SINGLE_CONNECTION_LABEL, leftConnections.size() + rightConnections.size());
302 		updateProperty(DOUBLE_CONNECTION_SOURCE_LABEL, leftConnections.size());
303 		updateProperty(DOUBLE_CONNECTION_TARGET_LABEL, rightConnections.size());
304 	}
305 
306 	/**
307 	 * Adds a new {@link Connection} originating from left node.
308 	 *
309 	 * @param connection
310 	 *            new {@link Connection} originating from left node
311 	 */
312 	public void addLeftConnection(Connection connection) {
313 		int oldSourceConnectionCount = leftConnections.size();
314 		leftConnections.add(connection);
315 
316 		updateProperties();
317 
318 		firePropertyChange(CONNECTION_COUNT_CHANGED, oldSourceConnectionCount, leftConnections.size());
319 	}
320 
321 	/**
322 	 * Adds a new {@link Connection} originating from right node.
323 	 *
324 	 * @param connection
325 	 *            new {@link Connection} originating from right node
326 	 */
327 	public void addRightConnection(Connection connection) {
328 		int oldTargetConnectionCount = rightConnections.size();
329 		rightConnections.add(connection);
330 
331 		updateProperties();
332 
333 		firePropertyChange(CONNECTION_COUNT_CHANGED, oldTargetConnectionCount, rightConnections.size());
334 	}
335 
336 	/**
337 	 * Removes a {@link Connection} originating from left node.
338 	 *
339 	 * @param connection
340 	 *            {@link Connection} originating from left node
341 	 */
342 	public void removeLeftConnection(Connection connection) {
343 		if (!leftConnections.contains(connection)) {
344 			return;
345 		}
346 		int oldSourceConnectionCount = leftConnections.size();
347 		leftConnections.remove(connection);
348 
349 		updateProperties();
350 
351 		firePropertyChange(CONNECTION_COUNT_CHANGED, oldSourceConnectionCount, leftConnections.size());
352 	}
353 
354 	/**
355 	 * Removes a {@link Connection} originating from right node.
356 	 *
357 	 * @param connection
358 	 *            {@link Connection} originating from right node
359 	 */
360 	public void removeRightConnection(Connection connection) {
361 		if (!rightConnections.contains(connection)) {
362 			return;
363 		}
364 		int oldTargetConnectionCount = rightConnections.size();
365 		rightConnections.remove(connection);
366 
367 		updateProperties();
368 
369 		firePropertyChange(CONNECTION_COUNT_CHANGED, oldTargetConnectionCount, rightConnections.size());
370 	}
371 
372 	/**
373 	 * Adds this connection group to both nodes.
374 	 */
375 	public void addConnectionGroupToNodes() {
376 		left.addConnectionGroup(this);
377 		right.addConnectionGroup(this);
378 	}
379 
380 	/**
381 	 * Removes this connection group from both nodes - counterpart of {@link #addConnectionGroupToNodes()}.
382 	 */
383 	public void removeConnectionGroupFromNodes() {
384 		left.removeConnectionGroup(this);
385 		right.removeConnectionGroup(this);
386 	}
387 
388 	/**
389 	 * Checks if this connection group is between two given nodes.
390 	 *
391 	 * @param node1
392 	 *            first node
393 	 * @param node2
394 	 *            second node
395 	 * @return <code>true</code> if this connection group is between two given nodes
396 	 */
397 	public boolean isBetween(Node node1, Node node2) {
398 		return (node1.equals(left) && node2.equals(right)) || (node1.equals(right) && node2.equals(left));
399 	}
400 
401 	/**
402 	 * Adds new {@link Connection} to this group.
403 	 *
404 	 * @param connection
405 	 *            new {@link Connection}
406 	 */
407 	public void addConnection(Connection connection) {
408 		if (connection.getSourceNode().equals(left) || connection.getSourceNode().equals(right)) {
409 			if (connection.getSourceNode().equals(left)) {
410 				addLeftConnection(connection);
411 			}
412 			if (connection.getSourceNode().equals(right)) {
413 				addRightConnection(connection);
414 			}
415 		} else {
416 			throw new IllegalArgumentException(NO_SUCH_NODE_MESSAGE);
417 		}
418 	}
419 
420 	/**
421 	 * Removes {@link Connection} to this group.
422 	 *
423 	 * @param connection
424 	 *            {@link Connection} to remove
425 	 */
426 	public void removeConnection(Connection connection) {
427 		if (connection.getSourceNode().equals(left)) {
428 			removeLeftConnection(connection);
429 		} else if (connection.getSourceNode().equals(right)) {
430 			removeRightConnection(connection);
431 		} else {
432 			throw new IllegalArgumentException(NO_SUCH_NODE_MESSAGE);
433 		}
434 	}
435 
436 	/**
437 	 * {@inheritDoc}
438 	 *
439 	 * @see java.lang.Object#toString()
440 	 */
441 	@Override
442 	public String toString() {
443 		return "CG " + left.getLabel() + ":" + right.getLabel(); //$NON-NLS-1$//$NON-NLS-2$
444 	}
445 
446 	public ConnectionGroupAttributeManager getPropertyManager() {
447 		return attributeManager;
448 	}
449 
450 	/**
451 	 * Two {@link ConnectionGroup}s are equal if their sources and targets are equal.
452 	 *
453 	 * {@inheritDoc}
454 	 *
455 	 * @see java.lang.Object#equals(java.lang.Object)
456 	 */
457 	@Override
458 	public boolean equals(Object obj) {
459 		if (obj == this) {
460 			return true;
461 		}
462 		if (!(obj instanceof ConnectionGroup)) {
463 			return false;
464 		}
465 		ConnectionGroup that = (ConnectionGroup)obj;
466 
467 		if (!this.left.equals(that.left)) {
468 			return false;
469 		}
470 		if (!this.right.equals(that.right)) {
471 			return false;
472 		}
473 
474 		return true;
475 	}
476 
477 	/**
478 	 * {@inheritDoc}
479 	 *
480 	 * @see java.lang.Object#hashCode()
481 	 */
482 	@Override
483 	public int hashCode() {
484 		return (left.getId() + right.getId()).hashCode();
485 	}
486 
487 	/**
488 	 * Copies all fields of this {@link ConnectionGroup} instance to <code>that</code> instance.
489 	 *
490 	 * @param that
491 	 *            instance of {@link ConnectionGroup} to copy this instance to
492 	 */
493 	public void copyTo(ConnectionGroup that) {
494 		// do not copy source and target - these are handled differently
495 		that.attributeManager = attributeManager;
496 		copyAttributes(that);
497 	}
498 
499 	/**
500 	 * {@inheritDoc}
501 	 *
502 	 * @see pl.edu.agh.cast.model.visual.backward.ModelElement#getAttributeManager()
503 	 */
504 	@Override
505 	public AttributeManager getAttributeManager() {
506 		return attributeManager;
507 	}
508 }