1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package pl.edu.agh.cast.model.visual.backward;
19
20 import java.beans.PropertyChangeEvent;
21 import java.beans.PropertyChangeListener;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Date;
25 import java.util.HashSet;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30
31 import org.apache.log4j.Logger;
32 import org.eclipse.core.resources.IFile;
33 import org.eclipse.core.runtime.CoreException;
34 import org.eclipse.core.runtime.IProgressMonitor;
35 import org.eclipse.core.runtime.NullProgressMonitor;
36 import org.eclipse.osgi.util.NLS;
37
38 import pl.edu.agh.cast.Activator;
39 import pl.edu.agh.cast.model.DefaultStatisticsProvider;
40 import pl.edu.agh.cast.model.attributes.Attribute;
41 import pl.edu.agh.cast.model.attributes.AttributeManager;
42 import pl.edu.agh.cast.model.attributes.AttributeMergePolicy;
43 import pl.edu.agh.cast.model.attributes.AttributeValue;
44 import pl.edu.agh.cast.model.attributes.ConnectionGroupAttributeManager;
45 import pl.edu.agh.cast.model.attributes.DiagramAttributeManager;
46 import pl.edu.agh.cast.model.attributes.NodeAttributeManager;
47 import pl.edu.agh.cast.model.attributes.ValueType;
48 import pl.edu.agh.cast.model.base.DataSet;
49 import pl.edu.agh.cast.model.base.IDataSet;
50 import pl.edu.agh.cast.model.base.IEntity;
51 import pl.edu.agh.cast.model.base.IRelation;
52 import pl.edu.agh.cast.util.Messages;
53
54 import com.thoughtworks.xstream.annotations.XStreamAlias;
55
56
57
58
59
60
61 @XStreamAlias("diagram")
62 public class Diagram extends ModelElement implements IDiagram, PropertyChangeListener {
63
64 private static final long serialVersionUID = 7475870569424703697L;
65
66
67
68
69 public static final String DUMMY_ID = "dummyEditorId";
70
71
72
73
74 public static final String NAME = "Diagram.NAME";
75
76
77
78
79 public static final String FILE = "Diagram.FILE";
80
81
82
83
84 public static final String CHILD = "Diagram.CHILD";
85
86
87
88
89 public static final String CONNECTION = "Diagram.CONNECTION";
90
91
92
93
94 public static final String CHILDREN = "Diagram.CHILDREN";
95
96
97
98
99 public static final String DESELECT = "Diagram.DESELECT";
100
101
102
103
104 protected static Logger log = Activator.getLogger();
105
106
107
108
109 protected transient IFile file;
110
111 private boolean enhancable = false;
112
113
114
115
116 @XStreamAlias("settings")
117 protected IDiagramSettings settings;
118
119
120
121
122 @XStreamAlias("nodeAttributes")
123 protected NodeAttributeManager nodeAttributeManager;
124
125
126
127
128 @XStreamAlias("connectionGroupAttributes")
129 protected ConnectionGroupAttributeManager connectionGroupAttributeManager;
130
131
132
133
134 @XStreamAlias("diagramAttributes")
135 protected DiagramAttributeManager diagramAttributeManager;
136
137
138
139
140 @XStreamAlias("connections")
141 protected final VisualModelCachingFactory visualModelFactory;
142
143
144
145
146 private boolean suppressEvents;
147
148
149
150
151
152
153
154 public Diagram(Collection<IDataSet> model) {
155 this(model, new NullProgressMonitor());
156 }
157
158
159
160
161
162
163
164
165
166
167
168 public Diagram(Collection<IDataSet> model, IProgressMonitor monitor) {
169 this(model, monitor, false);
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183
184 public Diagram(Collection<IDataSet> model, IProgressMonitor monitor, boolean enhancable) {
185 super();
186
187 this.enhancable = enhancable;
188 settings = new DiagramSettings();
189 settings.addPropertyChangeListener(this);
190 settings.setEditorId(DUMMY_ID);
191
192 nodeAttributeManager = new NodeAttributeManager(model);
193 connectionGroupAttributeManager = new ConnectionGroupAttributeManager();
194 diagramAttributeManager = new DiagramAttributeManager();
195 visualModelFactory = new VisualModelCachingFactory(nodeAttributeManager, connectionGroupAttributeManager);
196
197 bindToAttributeManager();
198
199 monitor.beginTask(Messages.Diagram_0, 2 * countConnections(model));
200 createConnections(model, monitor);
201 createConnectionGroups(monitor);
202 }
203
204 private int countConnections(Collection<IDataSet> model) {
205 int ret = 0;
206 for (IDataSet dataSet : model) {
207 ret += dataSet.getRelations().size();
208 }
209 return ret;
210 }
211
212 @Override
213 protected Object readResolve() {
214 super.readResolve();
215 if (nodeAttributeManager == null) {
216 nodeAttributeManager = new NodeAttributeManager();
217 }
218 if (connectionGroupAttributeManager == null) {
219 connectionGroupAttributeManager = new ConnectionGroupAttributeManager();
220 }
221 if (diagramAttributeManager == null) {
222 diagramAttributeManager = new DiagramAttributeManager();
223 }
224 settings.addPropertyChangeListener(this);
225 visualModelFactory.setupConnectionGroups();
226 return this;
227 }
228
229
230
231
232
233
234 @Override
235 public String toString() {
236 return settings.getDisplayName();
237 }
238
239
240
241
242
243
244 public IFile getFile() {
245 return file;
246 }
247
248
249
250
251
252
253 public void setFile(IFile file) {
254 IFile oldFile = this.file;
255 this.file = file;
256 firePropertyChange(FILE, oldFile, file);
257 }
258
259
260
261
262
263
264 public void setDisplayName(String displayName) {
265 String oldDispName = settings.getDisplayName();
266 settings.setDisplayName(displayName);
267 firePropertyChange(NAME, oldDispName, displayName);
268 try {
269 if (file != null) {
270 file.touch(null);
271 }
272 } catch (CoreException e) {
273 Activator.getLogger().error("error touching file", e);
274 }
275 }
276
277
278
279
280
281
282 public String getDisplayName() {
283 return settings.getDisplayName();
284 }
285
286
287
288
289
290
291 public List<Statistic> getStatistics() {
292 return getStatistics(new NullProgressMonitor());
293 }
294
295
296
297
298
299
300 public List<Statistic> getStatistics(IProgressMonitor monitor) {
301 return new DefaultStatisticsProvider().statistics(this, monitor);
302 }
303
304
305
306
307
308
309 public IDiagramSettings getSettings() {
310 return settings;
311 }
312
313
314
315
316
317
318 public void setSettings(IDiagramSettings settings) {
319 this.settings = settings;
320 }
321
322
323
324
325
326
327
328
329
330 private void createConnections(Collection<IDataSet> model, IProgressMonitor monitor) {
331 monitor.subTask(Messages.Diagram_1);
332 for (IDataSet dataset : model) {
333 Set<String> currentDS = new HashSet<String>();
334 for (IRelation relation : dataset.getRelations()) {
335
336 visualModelFactory.createConnection(relation, currentDS);
337 monitor.worked(1);
338 }
339 }
340 }
341
342
343
344
345
346
347
348 private void createConnectionGroups(IProgressMonitor monitor) {
349 monitor.subTask(Messages.Diagram_2);
350 for (Connection connection : visualModelFactory.getConnections()) {
351 ConnectionGroup cg = visualModelFactory.createConnectionGroup(connection);
352 cg.addConnection(connection);
353 monitor.worked(1);
354 }
355 }
356
357
358
359
360
361
362 public Node addNode(Node node) {
363 Node addedNode = addNodeInternal(node);
364 addConnectionsForNode(node);
365 firePropertyChange(CHILD, null, addedNode);
366 return addedNode;
367 }
368
369
370
371
372
373
374 public Collection<Node> addNodes(Collection<Node> nodes) {
375 Collection<Node> addedNodes = new LinkedList<Node>();
376 for (Node node : nodes) {
377 Node addedNode = addNodeInternal(node);
378
379
380
381 if (addedNode != node) {
382 addedNodes.add(addedNode);
383 }
384 }
385
386 for (Node node : nodes) {
387 addConnectionsForNode(node);
388 }
389 firePropertyChange(CHILDREN, null, addedNodes);
390 return addedNodes;
391 }
392
393
394
395
396
397
398
399 protected Node addNodeInternal(Node node) {
400
401
402 if (!visualModelFactory.wasCreatedHere(node)) {
403 return visualModelFactory.copyNode(node);
404 } else {
405 return node;
406 }
407 }
408
409
410
411
412
413
414
415 protected void addConnectionsForNode(Node node) {
416 for (ConnectionGroup cg : node.getConnectionGroups()) {
417 boolean first = true;
418 for (Connection c : cg.getAllConnections()) {
419
420 if (visualModelFactory.wasCreatedHere(c)) {
421 continue;
422 }
423
424
425
426 if (!visualModelFactory.wasCreatedHere(c.getSourceNode())
427 || !visualModelFactory.wasCreatedHere(c.getTargetNode())) {
428 continue;
429 }
430
431 Connection newConn = visualModelFactory.copyConnection(c);
432 if (first) {
433 ConnectionGroup newGroup = visualModelFactory.copyConnectionGroup(cg, newConn);
434 newGroup.addConnection(newConn);
435 first = false;
436 } else {
437 visualModelFactory.createConnectionGroup(newConn).addConnection(newConn);
438 }
439 }
440 }
441 }
442
443
444
445
446
447
448 public Connection addConnection(Connection c) {
449
450
451 Connection connection = c;
452 if (!visualModelFactory.wasCreatedHere(c)) {
453 connection = visualModelFactory.copyConnection(c);
454 }
455 ConnectionGroup cg = visualModelFactory.createConnectionGroup(connection);
456 cg.addConnection(connection);
457
458 firePropertyChange(CONNECTION, null, connection);
459 return connection;
460
461 }
462
463
464
465
466
467
468 public void addConnections(Collection<Connection> connections) {
469 for (Connection c : connections) {
470 addConnection(c);
471 }
472 }
473
474
475
476
477
478
479 public void removeNode(Node node) {
480 if (!visualModelFactory.wasCreatedHere(node)) {
481 throw new IllegalArgumentException(NLS.bind("node {0} is not a child of this model", node));
482 }
483 visualModelFactory.removeNode(node);
484
485
486
487
488
489
490 List<Connection> toRemove = new LinkedList<Connection>();
491 for (ConnectionGroup cg : node.getConnectionGroups()) {
492 if (!visualModelFactory.wasCreatedHere(cg)) {
493 continue;
494 }
495
496 for (Connection c : cg.getAllConnections()) {
497 if (!visualModelFactory.wasCreatedHere(c)) {
498 continue;
499 }
500
501 toRemove.add(c);
502 }
503 }
504 for (Connection c : toRemove) {
505 visualModelFactory.removeConnection(c);
506 }
507 firePropertyChange(CHILD, node, null);
508 }
509
510
511
512
513
514
515 public void removeNodes(Collection<Node> nodes) {
516 for (Node node : nodes) {
517 removeNode(node);
518 }
519 }
520
521
522
523
524
525
526 public void removeConnection(Connection connection) {
527 if (!visualModelFactory.wasCreatedHere(connection)) {
528 throw new IllegalArgumentException("connection is not a child of this model");
529 }
530 visualModelFactory.removeConnection(connection);
531 firePropertyChange(CONNECTION, connection, null);
532 }
533
534
535
536
537
538
539 public NodeAttributeManager getNodeAttributeManager() {
540 return nodeAttributeManager;
541 }
542
543
544
545
546
547
548 public Collection<Node> getNodes() {
549 return Collections.unmodifiableCollection(visualModelFactory.getNodes());
550 }
551
552
553
554
555
556
557 public Collection<Connection> getConnections() {
558 return Collections.unmodifiableCollection(visualModelFactory.getConnections());
559 }
560
561
562
563
564
565
566 protected final VisualModelCachingFactory getVisualModelFactory() {
567 return visualModelFactory;
568 }
569
570
571
572
573
574
575 public Node findNode(String nodeId) {
576
577
578 return visualModelFactory.findNode(nodeId);
579 }
580
581
582
583
584
585
586 public Connection findConnection(String sourceNodeId, String targetNodeId, Date date) {
587 return visualModelFactory.findConnection(sourceNodeId, targetNodeId, date);
588 }
589
590
591
592
593
594
595
596 public void addAttributesFromEntities(Collection<IEntity> entities, Collection<String> attributes,
597 Map<String, AttributeMergePolicy> mergePolicies, String nodeType, IProgressMonitor monitor) {
598
599
600 String entityIdKey = "Id";
601 addAttributesFromEntities(entities, attributes, mergePolicies, nodeType, entityIdKey,
602 NodeAttributeManager.PERMANENT_ID, monitor);
603 }
604
605
606
607
608
609
610
611
612 public void addAttributesFromEntities(Collection<IEntity> entities, Collection<String> attributes,
613 Map<String, AttributeMergePolicy> mergePolicies, String nodeType, String sourceJoinAttribute,
614 String targetJoinAttribute, IProgressMonitor monitor) {
615
616
617
618
619 IProgressMonitor monit = monitor;
620
621 if (monit == null) {
622 monit = new NullProgressMonitor();
623 }
624 monit.beginTask(NLS.bind(Messages.DiagramEnhancingMonitor_1, getDisplayName()), entities.size()
625 + visualModelFactory.getNodeCount());
626
627 monit.subTask(Messages.DiagramEnhancingMonitor_2);
628 NodeIndexer nodeIndexer = new NodeIndexer(visualModelFactory, targetJoinAttribute, nodeType, monit);
629
630 monit.subTask(Messages.DiagramEnhancingMonitor_3);
631
632 List<String> addedAttributes = new LinkedList<String>();
633
634 String[] attributeNames = null;
635 if (attributes != null) {
636 attributeNames = attributes.toArray(new String[attributes.size()]);
637 }
638
639 for (IEntity entity : entities) {
640
641
642 Object joinValue = entity.getAttribute(sourceJoinAttribute);
643 List<Node> joinedNodes = nodeIndexer.lookup(joinValue);
644
645
646
647 if (attributes == null || attributeNames == null || attributeNames.length == 0) {
648 attributeNames = entity.getAttributeNames();
649 }
650
651 if (joinedNodes != null && joinedNodes.size() > 0) {
652 for (Node node : joinedNodes) {
653 for (String attrName : attributeNames) {
654
655 Object entValue = entity.getAttribute(attrName);
656
657
658
659
660 if (!addedAttributes.contains(attrName)) {
661 if (!node.getAttributeManager().isRegisteredId(attrName)) {
662
663
664 addedAttributes.add(attrName);
665
666
667 ValueType valType = null;
668 if (entValue != null) {
669 valType = ValueType.fromValue(entValue);
670 }
671 if (valType == null) {
672 valType = ValueType.String;
673 }
674
675
676 node.getAttributeManager().registerAttribute(attrName, valType);
677 }
678 }
679
680
681 Attribute attribute = node.getAttributeManager().getAttribute(attrName);
682
683
684 attribute.setShowAsLabel(attribute.isEditable());
685
686 if (attribute.getType() == ValueType.String) {
687 entValue = entValue == null ? null : entValue.toString();
688 }
689
690 if (addedAttributes.contains(attrName)) {
691
692 node.setAttributeValue(attrName, entValue);
693 } else if (attribute.isEditable()) {
694
695 AttributeMergePolicy policy = getMergePolicy(attrName, mergePolicies);
696 AttributeValue nodeValue = node.getAttributeValue(attrName);
697 Object oldValue = nodeValue == null ? null : nodeValue.getValue();
698 Object newValue = policy.mergeValues(attribute, oldValue, entValue);
699 node.setAttributeValue(attrName, newValue);
700 }
701
702 }
703 }
704 }
705 monit.worked(1);
706 }
707 monit.done();
708 }
709
710 private AttributeMergePolicy getMergePolicy(String attribute, Map<String, AttributeMergePolicy> mergePolicies) {
711 if (mergePolicies != null) {
712 AttributeMergePolicy policy = mergePolicies.get(attribute);
713 if (policy == null) {
714 policy = mergePolicies.get(null);
715 }
716 if (policy != null) {
717 return policy;
718 }
719 }
720 return AttributeMergePolicy.MERGE_POLICY_ALWAYS_SECOND;
721 }
722
723
724
725
726
727
728 @Override
729 public void propertyChange(PropertyChangeEvent evt) {
730 if (DiagramSettings.LEGEND_SHOWN.equals(evt.getPropertyName())) {
731
732 firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
733 }
734 }
735
736
737
738
739
740
741 public void deselect() {
742 firePropertyChange(DESELECT, false, true);
743 }
744
745
746
747
748
749
750 public IDataSet getDomainModel() {
751 IDataSet data = new DataSet(getDisplayName());
752 for (IRelation relation : visualModelFactory.getRelations()) {
753 data.addRelation(relation);
754 }
755 return data;
756 }
757
758
759
760
761
762
763 public IRelation findRelation(Connection conn) {
764 return visualModelFactory.findRelation(conn);
765 }
766
767
768
769
770
771
772 @Override
773 public AttributeManager getAttributeManager() {
774 return diagramAttributeManager;
775 }
776
777
778
779
780
781
782 public boolean isEnhancable() {
783 return enhancable;
784 }
785
786
787
788
789
790
791
792 public void setSuppressEvents(boolean newSuppressEvents) {
793 suppressEvents = newSuppressEvents;
794 if (!newSuppressEvents) {
795
796 firePropertyChange(CHILDREN, null, null);
797 firePropertyChange(CONNECTION, null, null);
798 }
799 }
800
801 private boolean isSuppressEvents() {
802 return suppressEvents;
803 }
804
805
806
807
808
809
810
811 @Override
812 protected void firePropertyChange(String property, Object oldValue, Object newValue) {
813 if (!isSuppressEvents()) {
814 super.firePropertyChange(property, oldValue, newValue);
815 }
816 }
817
818 }