def build(self, tree): self.diagram = Diagram() self.diagram = self.instantiate(self.diagram, None, tree) self.update_node_order() self.update_edge_order() self.update_altblock_ylevel() self.diagram.colwidth = len(self.diagram.nodes) self.diagram.colheight = len(self.diagram.edges) + 1 for sep in self.diagram.separators: self.diagram.edges.remove(sep) if self.diagram.activation != 'none': self.create_activities() if self.diagram.autonumber: self.update_label_numbered() return self.diagram
class DiagramTreeBuilder(object): def build(self, tree): self.diagram = Diagram() self.diagram = self.instantiate(self.diagram, None, tree) self.update_node_order() self.update_edge_order() self.update_altblock_ylevel() self.diagram.colwidth = len(self.diagram.nodes) self.diagram.colheight = len(self.diagram.edges) + 1 for sep in self.diagram.separators: self.diagram.edges.remove(sep) if self.diagram.activation != 'none': self.create_activities() if self.diagram.autonumber: self.update_label_numbered() return self.diagram def update_edge_order(self): for i, edge in enumerate(self.diagram.edges): edge.order = i height = len(self.diagram.edges) + 1 for group in self.diagram.groups: group.colheight = height def update_altblock_ylevel(self): altblocks = self.diagram.altblocks for i in range(len(self.diagram.edges) + 1): blocks = [b for b in altblocks if b.edges[0].order == i] for j, altblock in enumerate(reversed(blocks)): altblock.ylevel_top = j + 1 blocks = [b for b in altblocks if b.edges[-1].order == i] for j, altblock in enumerate(reversed(blocks)): altblock.ylevel_bottom = j + 1 def update_label_numbered(self): for i, edge in enumerate(self.diagram.edges): edge.label = "%d. %s" % (i + 1, edge.label or "") def create_activities(self): if len(self.diagram.edges) == 0: return first_node = self.diagram.edges[0].node1 active_nodes = {first_node: 1} for node in self.diagram.nodes: if node.activated: active_nodes[node] = 1 edge_count = len(self.diagram.edges) + len(self.diagram.separators) for i in range(edge_count): match = [e for e in self.diagram.edges if e.order == i] if match: edge = match[0] if edge.activate is False: pass elif edge.dir == 'forward': if edge.node2 in active_nodes: active_nodes[edge.node2] += 1 else: active_nodes[edge.node2] = 1 elif edge.dir == 'back': if edge.node2 in active_nodes: active_nodes[edge.node2] -= 1 else: active_nodes[edge.node2] = 0 for node in active_nodes: if active_nodes[node] > 0: for index in range(active_nodes[node]): node.activate(i, index) for node in self.diagram.nodes: node.deactivate() def update_node_order(self): x = 0 uniq = [] for node in self.diagram.nodes: if node not in uniq: node.xy = XY(x, 0) uniq.append(node) x += 1 if node.group: for subnode in node.group.nodes: if subnode not in uniq: subnode.xy = XY(x, 0) uniq.append(subnode) x += 1 for group in self.diagram.groups: x = min(node.xy.x for node in group.nodes) group.xy = XY(x, 0) group.colwidth = len(group.nodes) def append_node(self, node, group): if node not in self.diagram.nodes: self.diagram.nodes.append(node) if isinstance(group, NodeGroup) and node not in group.nodes: if node.group: msg = "DiagramNode could not belong to two groups" raise RuntimeError(msg) group.nodes.append(node) node.group = group def instantiate(self, group, block, tree): for stmt in tree.stmts: if isinstance(stmt, parser.Node): node = DiagramNode.get(stmt.id) node.set_attributes(stmt.attrs) self.append_node(node, group) elif isinstance(stmt, parser.Edge): self.instantiate_edge(group, block, stmt) elif isinstance(stmt, parser.Group): node = NodeGroup.get(None) self.instantiate(node, block, stmt) self.diagram.groups.append(node) elif isinstance(stmt, parser.Attr): if block: block.set_attribute(stmt) else: group.set_attribute(stmt) elif isinstance(stmt, parser.Separator): sep = EdgeSeparator(stmt.type, unquote(stmt.value)) sep.group = group self.diagram.separators.append(sep) group.edges.append(sep) elif isinstance(stmt, parser.Fragment): subblock = AltBlock(stmt.type, stmt.id) if block: subblock.xlevel = block.xlevel + 1 self.diagram.altblocks.append(subblock) self.instantiate(group, subblock, stmt) if block: for edge in subblock.edges: block.edges.append(edge) elif isinstance(stmt, parser.Extension): if stmt.type == 'class': name = unquote(stmt.name) Diagram.classes[name] = stmt elif stmt.type == 'plugin': self.diagram.set_plugin(stmt.name, stmt.attrs) return group def instantiate_edge(self, group, block, stmt): from_node = DiagramNode.get(stmt.from_node) self.append_node(from_node, group) to_node = DiagramNode.get(stmt.to_node) self.append_node(to_node, group) edge = DiagramEdge(from_node, to_node) edge.set_dir(stmt.edge_type) edge.set_attributes(stmt.attrs) if edge.dir in ('forward', 'both'): forward = edge.duplicate() forward.dir = 'forward' group.edges.append(forward) if block: block.edges.append(forward) if stmt.followers: followers = list(stmt.followers) next_edge_type, next_to_node = followers.pop(0) nested = parser.Edge(stmt.to_node, next_edge_type, next_to_node, followers, stmt.attrs, stmt.edge_block) self.instantiate_edge(group, block, nested) elif stmt.edge_block: self.instantiate(group, block, stmt.edge_block) if edge.dir in ('back', 'both'): reverse = edge.duplicate() reverse.dir = 'back' if edge.dir == 'both': reverse.style = 'dashed' reverse.label = edge.return_label reverse.leftnote = None reverse.rightnote = None group.edges.append(reverse) if block: block.edges.append(reverse)
class DiagramTreeBuilder(object): def build(self, tree): self.diagram = Diagram() self.diagram = self.instantiate(self.diagram, None, tree) self.update_node_order() self.update_edge_order() self.update_altblock_ylevel() self.diagram.colwidth = len(self.diagram.nodes) self.diagram.colheight = len(self.diagram.edges) + 1 for sep in self.diagram.separators: self.diagram.edges.remove(sep) if self.diagram.activation != 'none': self.create_activities() if self.diagram.autonumber: self.update_label_numbered() return self.diagram def update_edge_order(self): for i, edge in enumerate(self.diagram.edges): edge.order = i height = len(self.diagram.edges) + 1 for group in self.diagram.groups: group.colheight = height def update_altblock_ylevel(self): altblocks = self.diagram.altblocks for i in range(len(self.diagram.edges) + 1): blocks = [b for b in altblocks if b.edges[0].order == i] for j, altblock in enumerate(reversed(blocks)): altblock.ylevel_top = j + 1 blocks = [b for b in altblocks if b.edges[-1].order == i] for j, altblock in enumerate(reversed(blocks)): altblock.ylevel_bottom = j + 1 def update_label_numbered(self): for i, edge in enumerate(self.diagram.edges): edge.label = u("%d. %s") % (i + 1, edge.label or "") def create_activities(self): if len(self.diagram.edges) == 0: return first_node = self.diagram.edges[0].node1 active_nodes = {first_node: 1} for node in self.diagram.nodes: if node.activated: active_nodes[node] = 1 edge_count = len(self.diagram.edges) + len(self.diagram.separators) for i in range(edge_count): match = [e for e in self.diagram.edges if e.order == i] if match: edge = match[0] if edge.node1 == edge.node2: pass elif edge.activate is False: pass elif edge.dir == 'forward': if edge.node2 in active_nodes: active_nodes[edge.node2] += 1 else: active_nodes[edge.node2] = 1 elif edge.dir == 'back': if edge.node2 in active_nodes: active_nodes[edge.node2] -= 1 else: active_nodes[edge.node2] = 0 for node in active_nodes: if active_nodes[node] > 0: for index in range(active_nodes[node]): node.activate(i, index) for node in self.diagram.nodes: node.deactivate() def update_node_order(self): x = 0 uniq = [] for node in self.diagram.nodes: if node not in uniq: node.xy = XY(x, 0) uniq.append(node) x += 1 if node.group: for subnode in node.group.nodes: if subnode not in uniq: subnode.xy = XY(x, 0) uniq.append(subnode) x += 1 for group in self.diagram.groups: x = min(node.xy.x for node in group.nodes) group.xy = XY(x, 0) group.colwidth = len(group.nodes) def append_node(self, node, group): if node not in self.diagram.nodes: self.diagram.nodes.append(node) if isinstance(group, NodeGroup) and node not in group.nodes: if node.group: msg = "DiagramNode could not belong to two groups" raise RuntimeError(msg) group.nodes.append(node) node.group = group def instantiate(self, group, block, tree): for stmt in tree.stmts: if isinstance(stmt, parser.Node): node = DiagramNode.get(stmt.id) node.set_attributes(stmt.attrs) self.append_node(node, group) elif isinstance(stmt, parser.Edge): self.instantiate_edge(group, block, stmt) elif isinstance(stmt, parser.Group): node = NodeGroup.get(None) self.instantiate(node, block, stmt) self.diagram.groups.append(node) elif isinstance(stmt, parser.Attr): if block: block.set_attribute(stmt) else: group.set_attribute(stmt) elif isinstance(stmt, parser.Separator): sep = EdgeSeparator(stmt.type, unquote(stmt.value)) sep.group = group self.diagram.separators.append(sep) group.edges.append(sep) elif isinstance(stmt, parser.Fragment): subblock = AltBlock(stmt.type, stmt.id) if block: subblock.xlevel = block.xlevel + 1 self.diagram.altblocks.append(subblock) self.instantiate(group, subblock, stmt) if block: for edge in subblock.edges: block.edges.append(edge) elif isinstance(stmt, parser.Extension): if stmt.type == 'class': name = unquote(stmt.name) Diagram.classes[name] = stmt elif stmt.type == 'plugin': self.diagram.set_plugin(stmt.name, stmt.attrs) return group def instantiate_edge(self, group, block, stmt): from_node = DiagramNode.get(stmt.from_node) self.append_node(from_node, group) to_node = DiagramNode.get(stmt.to_node) self.append_node(to_node, group) edge = DiagramEdge(from_node, to_node) edge.set_dir(stmt.edge_type) edge.set_attributes(stmt.attrs) if edge.dir in ('forward', 'both'): forward = edge.duplicate() forward.dir = 'forward' group.edges.append(forward) if block: block.edges.append(forward) if stmt.followers: followers = list(stmt.followers) next_edge_type, next_to_node = followers.pop(0) nested = parser.Edge(stmt.to_node, next_edge_type, next_to_node, followers, stmt.attrs, stmt.edge_block) self.instantiate_edge(group, block, nested) elif stmt.edge_block: self.instantiate(group, block, stmt.edge_block) if edge.dir in ('back', 'both') and edge.node1 != edge.node2: reverse = edge.duplicate() reverse.dir = 'back' if edge.dir == 'both': reverse.style = 'dashed' reverse.label = edge.return_label reverse.leftnote = None reverse.rightnote = None group.edges.append(reverse) if block: block.edges.append(reverse)