1# -*- coding: utf-8 -*-2# Copyright 2011 Takeshi KOMIYA3#4# Licensed under the Apache License, Version 2.0 (the "License");5# you may not use this file except in compliance with the License.6# You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing, software11# distributed under the License is distributed on an "AS IS" BASIS,12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13# See the License for the specific language governing permissions and14# limitations under the License.1516from __future__ import division1718from blockdiag.utils import XY, unquote1920from packetdiag import parser21from packetdiag.elements import Diagram, DiagramNode, FieldItem222324class DiagramTreeBuilder:25 def build(self, tree):26 self.diagram = Diagram()27 self.instantiate(tree)2829 return self.diagram3031 def instantiate(self, tree):32 for stmt in tree.stmts:33 if isinstance(stmt, parser.Attr):34 self.diagram.set_attribute(stmt)35 elif isinstance(stmt, parser.FieldItem):36 item = FieldItem(stmt.begin, stmt.end, unquote(stmt.label))37 item.set_attributes(stmt.attrs)3839 if item.number is None:40 if len(self.diagram.fields) == 0:41 item.number = 042 else:43 last_item = self.diagram.fields[-1]44 item.number = last_item.number + last_item.colwidth4546 self.diagram.fields.append(item)4748 elif isinstance(stmt, parser.AttrPlugin):49 self.diagram.set_plugin(stmt.name, stmt.attrs)505152class DiagramLayoutManager:53 def __init__(self, diagram):54 self.diagram = diagram5556 def split_field_by_column(self):57 for field in self.diagram.fields:58 while True:59 x = field.number % self.diagram.colwidth60 if x + field.colwidth <= self.diagram.colwidth:61 break62 else:63 colwidth = self.diagram.colwidth - x6465 splitted = field.duplicate()66 splitted.colwidth = colwidth67 if self.diagram.scale_direction == "left_to_right":68 splitted.separated_right = True69 else:70 splitted.separated_left = True7172 self.diagram.fields.append(splitted)7374 field.number += colwidth75 field.colwidth -= colwidth76 if self.diagram.scale_direction == "left_to_right":77 field.separated_left = True78 else:79 field.separated_right = True8081 yield field8283 def run(self):84 filled = {}85 for field in self.split_field_by_column():86 x = field.number % self.diagram.colwidth87 y = field.number // self.diagram.colwidth8889 if filled.get(y) is None:90 filled[y] = {}9192 for rx in range(x, x + field.colwidth):93 if filled[y].get(rx):94 msg = ("Field '%s' is conflicted to other field\n" %95 field.label)96 raise AttributeError(msg)97 filled[y][rx] = True9899 if self.diagram.scale_direction == "right_to_left":100 x = self.diagram.colwidth - x - field.colwidth101102 field.xy = XY(x, y)103104 self.diagram.fixiate()105106107class ScreenNodeBuilder:108109 def build(cls, tree):110 DiagramNode.clear()111 Diagram.clear()112113 return cls(tree).run()114115 def __init__(self, tree):116 self.diagram = DiagramTreeBuilder().build(tree)117118 def run(self):119 DiagramLayoutManager(self.diagram).run()120 return self.diagram