Changeset 1111
- Timestamp:
- 12/18/06 00:47:55 (2 years ago)
- Files:
-
- gaphor/branches/new-canvas/gaphor/UML/elementfactory.py (modified) (1 diff)
- gaphor/branches/new-canvas/gaphor/adapters/connectors.py (modified) (3 diffs)
- gaphor/branches/new-canvas/gaphor/diagram/activitynodes.py (modified) (5 diffs)
- gaphor/branches/new-canvas/gaphor/diagram/diagramitem.py (modified) (1 diff)
- gaphor/branches/new-canvas/gaphor/diagram/flow.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
gaphor/branches/new-canvas/gaphor/UML/elementfactory.py
r1109 r1111 166 166 if element.__class__ is not new_class: 167 167 element.__class__ = new_class 168 self.notify(element,'__class__')168 element.notify('__class__') 169 169 170 170 def connect(self, callback, *data): gaphor/branches/new-canvas/gaphor/adapters/connectors.py
r1109 r1111 934 934 line = self.line 935 935 element = self.element 936 # TODO: connect opposite side again (in case it's a join/fork or 937 # decision/merge node) 936 938 if isinstance(line.head.connected_to, items.ObjectNodeItem) \ 937 939 or isinstance(line.tail.connected_to, items.ObjectNodeItem): … … 955 957 956 958 957 class FlowFork NodeConnect(FlowConnect):958 """ 959 Connect Flow to a ForkNode960 """961 component.adapts(items.ForkNodeItem, items.FlowItem)959 class FlowForkDecisionNodeConnect(FlowConnect): 960 """ 961 Abstract class with common behaviour for Fork/Join node and 962 Decision/Merge node. 963 """ 962 964 963 965 def glue(self, handle, x, y): … … 984 986 # If one side of self.element has more than one edge, the 985 987 # type of node is determined (either join or fork). 986 if handle is line.head and len(subject.incoming) > 1 and len(subject.outgoing) > 0: 987 return None 988 989 if handle is line.tail and len(subject.incoming) > 0 and len(subject.outgoing) > 1: 990 return None 991 992 return super(FlowForkNodeConnect, self).glue(handle, x, y) 993 994 def connect_subject(self): 995 super(FlowForkNodeConnect, self).connect_subject() 988 # 989 # TODO: remove these restrictions and create a combined join/fork or 990 # decision/merge node 991 #if handle is line.head and len(subject.incoming) > 1 and len(subject.outgoing) > 0: 992 # return None 993 # 994 #if handle is line.tail and len(subject.incoming) > 0 and len(subject.outgoing) > 1: 995 # return None 996 997 return super(FlowForkDecisionNodeConnect, self).glue(handle, x, y) 998 999 def combine_nodes(self, fork_node_class, join_node_class): 1000 """ 1001 Combine join/fork or decision/methe nodes into one diagram item. 1002 """ 1003 line = self.line 1004 element = self.element 1005 join_node = element.subject 1006 if element.combined: 1007 return 1008 1009 # determine flow class: 1010 if [ f for f in join_node.incoming if isinstance(f, UML.ObjectFlow) ]: 1011 flow_class = UML.ObjectFlow 1012 else: 1013 flow_class = UML.ControlFlow 1014 1015 UML.swap_element(join_node, join_node_class) 1016 fork_node = UML.create(UML.ForkNode) 1017 for flow in join_node.outgoing: 1018 flow.source = fork_node 1019 flow = UML.create(flow_class) 1020 flow.source = join_node 1021 flow.target = fork_node 1022 1023 element.combined = fork_node 1024 1025 def decombine_nodes(self, fork_node_class, join_node_class): 1026 """ 1027 Decombine join/fork or decision/merge nodes. 1028 """ 1029 line = self.line 1030 element = self.element 1031 if element.combined: 1032 join_node = element.subject 1033 flow = subject.outgoing[0] 1034 fork_node = flow.target 1035 assert fork_node is element.combined 1036 assert isinstance(join_node, join_node_class) 1037 assert isinstance(fork_node, fork_node_class) 1038 1039 if len(join_node.incoming) < 2 or len(fork_node.outgoing) < 2: 1040 # Move all outgoing edges to the first node (the join node): 1041 for flow in fork_node.outgoing: 1042 flow.source = join_node 1043 flow.unlink() 1044 fork_node.unlink() 1045 1046 # swap subject to fork node if outgoing > 1 1047 if len(subject.outgoing) > 1: 1048 assert len(subject.incoming) < 2 1049 UML.swap_element(subject, fork_node_class) 1050 else: 1051 # Illegal state! 1052 pass 1053 element.combined = None 1054 1055 def connect_subject(self, fork_node_class, join_node_class): 1056 """ 1057 In addition to a subject connect, the subject of the element may 1058 be changed. 1059 For readability, parameters are named afther the classes used by 1060 Join/Fork nodes. 1061 """ 1062 super(FlowForkDecisionNodeConnect, self).connect_subject() 996 1063 997 1064 # Switch class for self.element Join/Fork depending on the number 998 1065 # of incoming/outgoing edges. 999 subject = self.element.subject 1066 element = self.element 1067 subject = element.subject 1000 1068 if len(subject.incoming) > 1 and len(subject.outgoing) < 2: 1001 UML.swap_element(subject, UML.JoinNode) 1069 UML.swap_element(subject, join_node_class) 1070 element.request_update() 1002 1071 elif len(subject.incoming) < 2 and len(subject.outgoing) > 1: 1003 UML.swap_element(subject, UML.ForkNode) 1072 UML.swap_element(subject, fork_node_class) 1073 element.request_update() 1004 1074 elif len(subject.incoming) > 1 and len(subject.outgoing) > 1: 1005 raise RuntimeError, 'Inconsistent state' 1075 self.combine_nodes(fork_node_class, join_node_class) 1076 1077 def disconnect_subject(self, fork_node_class=None, join_node_class=None): 1078 super(FlowForkDecisionNodeConnect, self).disconnect_subject() 1079 if self.element.combined: 1080 self.decombine_nodes(fork_node_class, join_node_class) 1081 # TODO: if combined node: un-combine if only one incoming or outgoing 1082 # egde on one side. 1083 1084 1085 class FlowForkNodeConnect(FlowForkDecisionNodeConnect): 1086 """ 1087 Connect Flow to a ForkNode 1088 """ 1089 component.adapts(items.ForkNodeItem, items.FlowItem) 1090 1091 def connect_subject(self): 1092 super(FlowForkNodeConnect, self).connect_subject(join_node_class=UML.JoinNode, fork_node_class=UML.ForkNode) 1006 1093 1007 1094 component.provideAdapter(FlowForkNodeConnect) 1008 1095 1009 1096 1010 class FlowDecisionNodeConnect(Flow Connect):1011 """ 1012 Connect Flow to a ForkNode1097 class FlowDecisionNodeConnect(FlowForkDecisionNodeConnect): 1098 """ 1099 Connect Flow to a DecisionNode 1013 1100 """ 1014 1101 component.adapts(items.DecisionNodeItem, items.FlowItem) 1015 1102 1016 def glue(self, handle, x, y):1017 """1018 In addition to the normal check, one end should have at most one1019 edge (incoming or outgoing).1020 """1021 opposite = self.line.opposite(handle)1022 line = self.line1023 element = self.element1024 subject = element.subject1025 connected_to = opposite.connected_to1026 1027 # Element can not connect back to itself1028 if connected_to is element:1029 return None1030 1031 # Same goes for subjects:1032 if connected_to and \1033 (not (connected_to.subject or element.subject)) \1034 and connected_to.subject is element.subject:1035 return None1036 1037 # If one side of self.element has more than one edge, the1038 # type of node is determined (either join or fork).1039 if handle is line.head and len(subject.incoming) > 1 and len(subject.outgoing) > 0:1040 return None1041 1042 if handle is line.tail and len(subject.incoming) > 0 and len(subject.outgoing) > 1:1043 return None1044 1045 return super(FlowDecisionNodeConnect, self).glue(handle, x, y)1046 1047 1103 def connect_subject(self): 1048 super(FlowDecisionNodeConnect, self).connect_subject() 1049 1050 # Switch class for self.element Join/Fork depending on the number 1051 # of incoming/outgoing edges. 1052 subject = self.element.subject 1053 if len(subject.incoming) > 1 and len(subject.outgoing) < 2: 1054 UML.swap_element(subject, UML.MergeNode) 1055 elif len(subject.incoming) < 2 and len(subject.outgoing) > 1: 1056 UML.swap_element(subject, UML.DecisionNode) 1057 elif len(subject.incoming) > 1 and len(subject.outgoing) > 1: 1058 raise RuntimeError, 'Inconsistent state' 1104 super(FlowDecisionNodeConnect, self).connect_subject(join_node_class=UML.MergeNode, fork_node_class=UML.DecisionNode) 1059 1105 1060 1106 component.provideAdapter(FlowDecisionNodeConnect) gaphor/branches/new-canvas/gaphor/diagram/activitynodes.py
r1110 r1111 119 119 120 120 121 class F DNode(ActivityNodeItem):121 class ForkDecisionNodeItem(ActivityNodeItem): 122 122 """ 123 123 Abstract class for fork and decision UI nodes. These nodes contain … … 129 129 def __init__(self, id=None): 130 130 ActivityNodeItem.__init__(self, id) 131 self._combined = False131 self._combined = None 132 132 self.set_prop_persistent('combined') 133 133 134 135 def do_set_property(self, pspec, value): 136 if pspec.name == 'combined': 137 self.preserve_property('combined') 138 self._combined = value 139 else: 140 ActivityNodeItem.do_set_property(self, pspec, value) 141 142 143 def do_get_property(self, pspec): 144 if pspec.name == 'combined': 145 return self._combined 146 else: 147 return ActivityNodeItem.do_get_property(self, pspec) 148 149 150 151 class DecisionNodeItem(FDNode): 134 def _set_combined(self, value): 135 self.preserve_property('combined') 136 self._combined = value 137 138 combined = property(lambda s: s._combined, _set_combined) 139 140 141 class DecisionNodeItem(ForkDecisionNodeItem): 152 142 """ 153 143 Representation of decision or merge node. … … 181 171 182 172 183 class ForkNodeItem(F DNode):173 class ForkNodeItem(ForkDecisionNodeItem): 184 174 """ 185 175 Representation of fork and join node. … … 193 183 194 184 def __init__(self, id=None): 195 F DNode.__init__(self, id)185 ForkDecisionNodeItem.__init__(self, id) 196 186 197 187 self._join_spec = 'join spec test' … … 238 228 text element. 239 229 """ 240 F DNode.on_subject_notify(self, pspec, notifiers)230 ForkDecisionNodeItem.on_subject_notify(self, pspec, notifiers) 241 231 if self.subject and isinstance(self.subject, UML.JoinNode): 242 232 if not self.subject.joinSpec: gaphor/branches/new-canvas/gaphor/diagram/diagramitem.py
r1087 r1111 200 200 # save persistent properties 201 201 for p in self._persistent_props: 202 save_func(p, getattr(self, p.replace('-', '_')) )202 save_func(p, getattr(self, p.replace('-', '_')), reference=True) 203 203 204 204 gaphor/branches/new-canvas/gaphor/diagram/flow.py
r1104 r1111 445 445 if is_fd(node): 446 446 source = target 447 move_collection(node, source, 'incoming')447 move_collection(node, target, 'incoming') 448 448 449 449 # create new fork node 450 cls = node_classes[ source.__class__]450 cls = node_classes[target.__class__] 451 451 log.debug('creating %s' % cls) 452 452 target = factory.create(cls) … … 454 454 else: 455 455 # fork node is created, referenced by target 456 move_collection( source, target, 'outgoing')456 move_collection(node, target, 'outgoing') 457 457 458 458 assert not is_fd(source)
