Changeset 1100
- Timestamp:
- 12/07/06 07:56:40 (2 years ago)
- Files:
-
- gaphor/branches/new-canvas/gaphor/actions/placementactions.py (modified) (2 diffs)
- gaphor/branches/new-canvas/gaphor/actions/tests/test_placementactions.py (modified) (1 diff)
- gaphor/branches/new-canvas/gaphor/diagram/association.py (modified) (3 diffs)
- gaphor/branches/new-canvas/gaphor/diagram/connector.py (modified) (1 diff)
- gaphor/branches/new-canvas/gaphor/diagram/flow.py (modified) (12 diffs)
- gaphor/branches/new-canvas/gaphor/diagram/interaction.py (modified) (2 diffs)
- gaphor/branches/new-canvas/gaphor/diagram/items.py (modified) (1 diff)
- gaphor/branches/new-canvas/gaphor/diagram/itemtool.py (deleted)
- gaphor/branches/new-canvas/gaphor/diagram/lifeline.py (modified) (1 diff)
- gaphor/branches/new-canvas/gaphor/diagram/message.py (modified) (1 diff)
- gaphor/branches/new-canvas/gaphor/diagram/objectnode.py (modified) (3 diffs)
- gaphor/branches/new-canvas/gaphor/diagram/util.py (deleted)
- gaphor/branches/new-canvas/utils/genUML2.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
gaphor/branches/new-canvas/gaphor/actions/placementactions.py
r1063 r1100 300 300 301 301 302 #class ObjectNodePlacementAction(NamespacePlacementAction):303 #id = 'InsertObjectNode'304 #label = 'Object Node'305 #tooltip = 'Create a new object node'306 #stock_id = 'gaphor-object-node'307 #name = 'Object'308 # type = diagram.ObjectNodeItem309 #subject_type = UML.ObjectNode310 # 311 #register_action(ObjectNodePlacementAction)302 class ObjectNodePlacementAction(NamespacePlacementAction): 303 id = 'InsertObjectNode' 304 label = 'Object Node' 305 tooltip = 'Create a new object node' 306 stock_id = 'gaphor-object-node' 307 name = 'Object' 308 type = items.ObjectNodeItem 309 subject_type = UML.ObjectNode 310 311 register_action(ObjectNodePlacementAction) 312 312 313 313 … … 396 396 397 397 398 #class FlowPlacementAction(PlacementAction):399 #id = 'InsertFlow'400 #label = 'Control/Object _Flow'401 #tooltip = 'Create a new control/object flow'402 #stock_id = 'gaphor-control-flow'403 #name = 'Flow'404 # type = diagram.FlowItem405 # 406 #register_action(FlowPlacementAction)398 class FlowPlacementAction(PlacementAction): 399 id = 'InsertFlow' 400 label = 'Control/Object _Flow' 401 tooltip = 'Create a new control/object flow' 402 stock_id = 'gaphor-control-flow' 403 name = 'Flow' 404 type = items.FlowItem 405 406 register_action(FlowPlacementAction) 407 407 408 408 gaphor/branches/new-canvas/gaphor/actions/tests/test_placementactions.py
r1046 r1100 104 104 self.do_test_placement(placementactions.FlowFinalNodePlacementAction()) 105 105 106 def test_flow_placement(self): 107 self.do_test_placement(placementactions.FlowPlacementAction()) 108 106 109 107 110 # vim:sw=4:et:ai gaphor/branches/new-canvas/gaphor/diagram/association.py
r1097 r1100 609 609 if h: 610 610 name_dx = ofs 611 name_dy = -ofs - name_h # - height611 name_dy = -ofs - name_h 612 612 mult_dx = ofs 613 613 mult_dy = ofs 614 614 else: 615 615 name_dx = -ofs - name_w 616 name_dy = -ofs - name_h # - height616 name_dy = -ofs - name_h 617 617 mult_dx = -ofs - mult_w 618 618 mult_dy = ofs … … 620 620 #print 'vertical line' 621 621 if v: 622 name_dx = -ofs - name_w # - width622 name_dx = -ofs - name_w 623 623 name_dy = ofs 624 624 mult_dx = ofs 625 625 mult_dy = ofs 626 626 else: 627 name_dx = -ofs - name_w # - width628 name_dy = -ofs - name_h # - height627 name_dx = -ofs - name_w 628 name_dy = -ofs - name_h 629 629 mult_dx = ofs 630 mult_dy = -ofs - mult_h # - height630 mult_dy = -ofs - mult_h 631 631 else: 632 632 r = abs_rc < 1.0 … … 637 637 mult_dx = ofs 638 638 else: 639 name_dx = -ofs - name_w # - width640 mult_dx = -ofs - mult_w # - width639 name_dx = -ofs - name_w 640 mult_dx = -ofs - mult_w 641 641 if align_bottom: 642 name_dy = -ofs - name_h # - height643 mult_dy = -ofs - name_h - mult_h # - height642 name_dy = -ofs - name_h 643 mult_dy = -ofs - name_h - mult_h 644 644 else: 645 645 name_dy = ofs gaphor/branches/new-canvas/gaphor/diagram/connector.py
r926 r1100 50 50 """ 51 51 52 import diacanvas53 52 from gaphor import resource, UML 54 53 from diagramline import DiagramLine, FreeLine gaphor/branches/new-canvas/gaphor/diagram/flow.py
r935 r1100 4 4 Contains also implementation to split flows using activity edge connectors. 5 5 """ 6 # vim:sw=4:et:ai 7 8 from __future__ import generators 9 10 import diacanvas 6 7 from math import atan, pi, sin, cos 11 8 12 9 from gaphor import resource 10 13 11 from gaphor import UML 14 from gaphor.diagram import TextElement15 12 from gaphor.diagram.diagramline import DiagramLine 16 17 import gaphor.diagram.util 13 from gaphas.geometry import Rectangle 14 from gaphas.util import text_extents, text_multiline 18 15 19 16 import itertools 20 17 21 18 22 class FlowBase(DiagramLine): 23 """ 24 Control flow and object flow abstract class. Allows to create flows 25 with name and guard. 19 node_classes = { 20 UML.ForkNode: UML.JoinNode, 21 UML.DecisionNode: UML.MergeNode, 22 UML.JoinNode: UML.ForkNode, 23 UML.MergeNode: UML.DecisionNode, 24 } 25 26 27 class FlowItem(DiagramLine): 28 """ 29 Representation of control flow and object flow. Flow item has name and 30 guard. It can be splitted into two flows with activity edge connectors. 26 31 """ 27 32 28 33 __uml__ = UML.ControlFlow 29 __relationship__ = 'source', 'outgoing', 'target', 'incoming' 34 35 popup_menu = DiagramLine.popup_menu + ( 36 'separator', 37 'SplitFlow', 38 ) 30 39 31 40 def __init__(self, id = None): 32 GroupBase.__init__(self)33 41 DiagramLine.__init__(self, id) 34 35 self.set(has_tail=1, tail_fill_color=0, 36 tail_a=0.0, tail_b=15.0, tail_c=6.0, tail_d=6.0) 37 38 39 def create_name(self): 40 self._name = TextElement('name') 41 self.add(self._name) 42 43 44 def create_guard(self): 45 self._guard = TextElement('value') 46 self.add(self._guard) 42 self._name_bounds = None 43 self._guard_bounds = None 44 45 #self.set(has_tail=1, tail_fill_color=0, 46 # tail_a=0.0, tail_b=15.0, tail_c=6.0, tail_d=6.0) 47 47 48 48 49 49 def on_subject_notify(self, pspec, notifiers = ()): 50 DiagramLine.on_subject_notify(self, pspec, notifiers) 51 52 if hasattr(self, '_guard'): 53 if self.subject: 54 self._guard.subject = self.subject.guard 55 else: 56 self._guard.subject = None 57 58 if hasattr(self, '_name'): 59 self._name.subject = self.subject 50 DiagramLine.on_subject_notify(self, pspec, ('guard', 'guard.value',) + notifiers) 60 51 61 52 self.request_update() 62 53 63 64 def update_name(self, affine): 65 handles = self.handles 54 def on_subject_notify__guard(self, subject, pspec=None): 55 self.request_update() 56 57 def on_subject_notify__guard_value(self, subject, pspec=None): 58 self.request_update() 59 60 def update_name(self, context): 61 handles = self._handles 66 62 67 63 def get_pos(p1, p2, width, height): … … 72 68 return x, y 73 69 74 p1 = handles[-2]. get_pos_i()75 p2 = handles[-1]. get_pos_i()76 w, h = self._name.get_size()70 p1 = handles[-2].pos 71 p2 = handles[-1].pos 72 w, h = text_extents(context.cairo, self.subject and self.subject.name) 77 73 x, y = get_pos(p1, p2, w, h) 78 self._name .update_label(x, y)79 80 81 def update_guard(self, affine):82 handles = self. handles74 self._name_bounds = Rectangle(x, y, width=max(10, w), height=max(10, h)) 75 76 77 def update_guard(self, context): 78 handles = self._handles 83 79 middle = len(handles)/2 84 80 … … 90 86 return x, y 91 87 92 p1 = handles[middle-1]. get_pos_i()93 p2 = handles[middle]. get_pos_i()94 w, h = self._guard.get_size()88 p1 = handles[middle-1].pos 89 p2 = handles[middle].pos 90 w, h = text_extents(context.cairo, self.subject and self.subject.guard and self.subject.guard.value) 95 91 x, y = get_pos_centered(p1, p2, w, h) 96 self._guard.update_label(x, y) 97 98 99 def on_update(self, affine): 100 DiagramLine.on_update(self, affine) 101 GroupBase.on_update(self, affine) 102 103 104 def allow_connect_handle(self, handle, connecting_to): 105 """See DiagramLine.allow_connect_handle(). 106 """ 107 can_connect = False 108 109 subject = connecting_to.subject 110 if isinstance(subject, UML.ActivityNode): 111 source = self.handles[0] 112 target = self.handles[-1] 113 114 # forbid flow source to connect to final node 115 # forbid flow target to connect to initial nodes 116 can_connect = True 117 if source is handle and isinstance(subject, UML.FinalNode) \ 118 or target is handle and isinstance(subject, UML.InitialNode): 119 can_connect = False 120 121 return can_connect 122 123 124 def connect_items(self, c1, c2): 125 if c1 and c2: 126 s1 = c1.subject 127 if isinstance(s1, tuple(gaphor.diagram.util.node_classes.keys())) \ 128 and c1.props.combined: 129 log.debug('getting combined node for flow source') 130 s1 = s1.outgoing[0].target 131 132 s2 = c2.subject 133 relation = self.relationship 134 if not relation: 135 factory = resource(UML.ElementFactory) 136 137 # if we connect to object node than flow uml class should 138 # be ObjectFlow 139 if isinstance(s1, UML.ObjectNode) \ 140 or isinstance(s2, UML.ObjectNode): 141 relcls = UML.ObjectFlow 142 else: 143 relcls = UML.ControlFlow 144 assert relcls == UML.ObjectFlow or relcls == UML.ControlFlow 145 146 relation = factory.create(relcls) 147 relation.source = s1 148 relation.target = s2 149 relation.guard = factory.create(UML.LiteralSpecification) 150 self.subject = relation 151 152 gaphor.diagram.util.determine_node_on_connect(c1) 153 gaphor.diagram.util.determine_node_on_connect(c2) 154 155 156 def disconnect_items(self, c1, c2, was_connected_to): 157 if not c1: 158 c1 = was_connected_to 159 if not c2: 160 c2 = was_connected_to 161 162 self.set_subject(None) 163 164 if c1: 165 gaphor.diagram.util.determine_node_on_disconnect(c1) 166 if c2: 167 gaphor.diagram.util.determine_node_on_disconnect(c2) 168 169 170 171 class FlowItem(FlowBase): 172 """ 173 Representation of control flow and object flow. Flow item has name and 174 guard. It can be splitted into two flows with activity edge connectors. 175 """ 176 177 popup_menu = DiagramLine.popup_menu + ( 178 'separator', 179 'SplitFlow', 180 ) 181 182 def __init__(self, id = None): 183 FlowBase.__init__(self, id) 184 185 self.create_name() 186 self.create_guard() 187 188 189 def on_update(self, affine): 190 self.update_name(affine) 191 self.update_guard(affine) 192 FlowBase.on_update(self, affine) 193 194 195 # Gaphor Connection Protocol 196 197 def confirm_connect_handle (self, handle): 198 """See DiagramLine.confirm_connect_handle(). 199 """ 200 c1 = self.handles[0].connected_to # source 201 c2 = self.handles[-1].connected_to # target 202 self.connect_items(c1, c2) 203 204 205 def confirm_disconnect_handle (self, handle, was_connected_to): 206 """See DiagramLine.confirm_disconnect_handle(). 207 """ 208 c1 = self.handles[0].connected_to # source 209 c2 = self.handles[-1].connected_to # target 210 self.disconnect_items(c1, c2, was_connected_to) 211 212 213 214 class ACItem(TextElement): 92 self._guard_bounds = Rectangle(x, y, width=max(10, w), height=max(10, h)) 93 94 95 def pre_update(self, context): 96 self.update_name(context) 97 self.update_guard(context) 98 99 100 def draw_tail(self, context): 101 cr = context.cairo 102 cr.line_to(0, 0) 103 cr.stroke() 104 cr.move_to(15, -6) 105 cr.line_to(0, 0) 106 cr.line_to(15, 6) 107 108 def draw(self, context): 109 super(FlowItem, self).draw(context) 110 cr= context.cairo 111 if self.subject: 112 text_multiline(cr, self._name_bounds[0], self._name_bounds[3], self.subject.name) 113 text_multiline(cr, self._guartd_bounds[0], self._guard_bounds[3], self.subject.guard and self.subject.guard.value) 114 115 if context.hovered or context.focused or context.draw_all: 116 cr.set_line_width(0.5) 117 b = self._name_bounds 118 cr.rectangle(b.x0, b.y0, b.width, b.height) 119 cr.stroke() 120 b = self._guard_bounds 121 cr.rectangle(b.x0, b.y0, b.width, b.height) 122 cr.stroke() 123 124 125 #class ACItem(TextElement): 126 class ACItem(object): 215 127 """ 216 128 Activity edge connector. It is a circle with name inside. … … 219 131 RADIUS = 10 220 132 def __init__(self, id): 221 TextElement.__init__(self, id)222 self._circle = diacanvas.shape.Ellipse()223 self._circle.set_line_width(2.0)224 self._circle.set_fill_color(diacanvas.color(255, 255, 255))225 self._circle.set_fill(diacanvas.shape.FILL_SOLID)226 self.show_border = False133 #TextElement.__init__(self, id) 134 #self._circle = diacanvas.shape.Ellipse() 135 #self._circle.set_line_width(2.0) 136 #self._circle.set_fill_color(diacanvas.color(255, 255, 255)) 137 #self._circle.set_fill(diacanvas.shape.FILL_SOLID) 138 #self.show_border = False 227 139 228 140 # set new value notification function to change activity edge … … 284 196 285 197 286 class CFlowItem(Flow Base):198 class CFlowItem(FlowItem): 287 199 """ 288 200 Abstract class for flows with activity edge connector. Flow with … … 300 212 301 213 def __init__(self, id = None): 302 Flow Base.__init__(self, id)214 FlowItem.__init__(self, id) 303 215 304 216 self._connector = ACItem('value') … … 324 236 Save connector name and opposite flow with activity edge connector. 325 237 """ 326 Flow Base.save(self, save_func)238 FlowItem.save(self, save_func) 327 239 save_func('opposite', self._opposite, True) 328 240 save_func('connector-name', self._connector.subject.value) … … 338 250 self._opposite = value 339 251 else: 340 Flow Base.load(self, name, value)252 FlowItem.load(self, name, value) 341 253 342 254 … … 354 266 x = p1[0] < p2[0] and -r or r 355 267 y = 0 356 x, y = gaphor.diagram.util.rotate(p1, p2, x, y, p1[0], p1[1])268 x, y = rotate(p1, p2, x, y, p1[0], p1[1]) 357 269 358 270 self._connector.move_center(x, y) 359 271 360 Flow Base.on_update(self, affine)272 FlowItem.on_update(self, affine) 361 273 362 274 … … 380 292 if handle == self.get_inactive_handle(): 381 293 return False 382 return Flow Base.allow_connect_handle(self, handle, connecting_to)294 return FlowItem.allow_connect_handle(self, handle, connecting_to) 383 295 384 296 … … 395 307 class CFlowItemA(CFlowItem): 396 308 """ 309 * Is used for split flows, as is CFlowItemB * 310 397 311 Flow with activity edge connector, which starts from node and points to 398 312 activity edge connector. … … 462 376 """ 463 377 return self.handles[0] 378 379 380 381 382 def move_collection(src, target, name): 383 """ 384 Copy collection from one object to another. 385 386 src - source object 387 target - target object 388 name - name of attribute, which is collection to copy 389 """ 390 # first make of copy of collection, because assigning 391 # element to target collection moves this element 392 for flow in list(getattr(src, name)): 393 getattr(target, name).append(flow) 394 395 396 def is_fd(node): 397 """ 398 Check if node is fork or decision node. 399 """ 400 return isinstance(node, (UML.ForkNode, UML.DecisionNode)) 401 402 403 def change_node_class(node): 404 """ 405 If UML constraints for fork, join, decision and merge nodes are not 406 met, then create new node depending on input node class, i.e. create 407 fork node from join node or merge node from decision node. 408 409 If constraints are met, then return node itself. 410 """ 411 if is_fd(node) and len(node.incoming) > 1 \ 412 or not is_fd(node) and len(node.incoming) < 2: 413 414 factory = resource(UML.ElementFactory) 415 cls = node_classes[node.__class__] 416 log.debug('creating %s' % cls) 417 nn = factory.create(cls) 418 move_collection(node, nn, 'incoming') 419 move_collection(node, nn, 'outgoing') 420 else: 421 nn = node 422 423 assert nn is not None 424 425 # we have to accept zero of outgoing edges in case of fork/descision 426 # nodes 427 assert is_fd(nn) and len(nn.incoming) <= 1 \ 428 or not is_fd(nn) and len(nn.incoming) >= 1, '%s' % nn 429 assert is_fd(nn) and len(nn.outgoing) >= 0 \ 430 or not is_fd(nn) and len(nn.outgoing) <= 1, '%s' % nn 431 return nn 432 433 434 def combine_nodes(node): 435 """ 436 Create fork/join (decision/merge) nodes combination as described in UML 437 specification. 438 """ 439 log.debug('combining nodes') 440 441 cls = node_classes[node.__class__] 442 log.debug('creating %s' % cls) 443 factory = resource(UML.ElementFactory) 444 target = factory.create(cls) 445 446 source = node 447 if is_fd(node): 448 source = target 449 move_collection(node, source, 'incoming') 450 451 # create new fork node 452 cls = node_classes[source.__class__] 453 log.debug('creating %s' % cls) 454 target = factory.create(cls) 455 move_collection(node, target, 'outgoing') 456 else: 457 # fork node is created, referenced by target 458 move_collection(source, target, 'outgoing') 459 460 assert not is_fd(source) 461 assert is_fd(target) 462 463 # create flow 464 c1 = count_object_flows(source, 'incoming') 465 c2 = count_object_flows(target, 'outgoing') 466 467 if c1 > 0 or c2 > 0: 468 flow = factory.create(UML.ControlFlow) 469 else: 470 flow = factory.create(UML.ObjectFlow) 471 flow.source = source 472 flow.target = target 473 474 assert len(source.incoming) > 1 475 assert len(source.outgoing) == 1 476 477 assert len(target.incoming) == 1 478 assert len(target.outgoing) > 1 479 480 return source 481 482 483 def decombine_nodes(source): 484 """ 485 Create node depending on source argument which denotes combination of 486 fork/join (decision/merge) nodes as described in UML specification. 487 488 Combination of nodes is destroyed. 489 """ 490 log.debug('decombining nodes') 491 flow = source.outgoing[0] 492 target = flow.target 493 494 if len(source.incoming) < 2: 495 # create fork or decision 496 cls = target.__class__ 497 else: 498 # create join or merge 499 cls = source.__class__ 500 501 factory = resource(UML.ElementFactory) 502 node = factory.create(cls) 503 504 move_collection(source, node, 'incoming') 505 move_collection(target, node, 'outgoing') 506 507 assert source != node 508 509 # delete target and combining flow 510 # source should be deleted by caller 511 target.unlink() 512 flow.unlink() 513 514 # return new node 515 return node 516 517 518 def determine_node_on_connect(el): 519 """ 520 Determine classes of nodes depending on amount of incoming 521 and outgoing edges. This method is called when flow is attached 522 to node. 523 524 If there is more than one incoming edge and more than one 525 outgoing edge, then create two nodes and combine them with 526 flow as described in UML specification. 527 """ 528 subject = el.subject 529 if not isinstance(subject, tuple(node_classes.keys())): 530 return 531 532 new_subject = subject 533 534 if len(subject.incoming) > 1 and len(subject.outgoing) > 1: 535 new_subject = combine_nodes(subject) 536 el.props.combined = True 537 538 else: 539 new_subject = change_node_class(subject) 540 541 change_node_subject(el, new_subject) 542 543 if el.props.combined: 544 check_combining_flow(el) 545 546 547 def determine_node_on_disconnect(el): 548 """ 549 Determine classes of nodes depending on amount of incoming 550 and outgoing edges. This method is called when flow is dettached 551 from node. 552 553 If there are combined nodes and there is no need for them, then replace 554 combination with appropriate node (i.e. replace with fork node when 555 there are less than two incoming edges). This way data model is kept as 556 simple as possible. 557 """ 558 subject = el.subject 559 if not isinstance(subject, tuple(node_classes.keys())): 560 return 561 562 new_subject = subject 563 564 if el.props.combined: 565 cs = subject.outgoing[0].target 566 # decombine node when there is no more than one incoming 567 # and no more than one outgoing flow 568 if len(subject.incoming) < 2 or len(cs.outgoing) < 2: 569 new_subject = decombine_nodes(subject) 570 el.props.combined = False 571 else: 572 check_combining_flow(el) 573 574 else: 575 new_subject = change_node_class(subject) 576 577 change_node_subject(el, new_subject) 578 579 580 def change_node_subject(el, new_subject): 581 """ 582 Change element's subject if new subject is different than element's 583 subject. If subject is changed, then old subject is destroyed. 584 """ 585 subject = el.subject 586 if new_subject != subject: 587 log.debug('changing subject of ui node %s' % el) 588 el.set_subject(new_subject) 589 590 log.debug('deleting node %s' % subject) 591 subject.unlink() 592 593 594 def create_flow(cls, flow): 595 """ 596 Create new flow of class cls. Flow data from flow argument are copied 597 to new created flow. Old flow is destroyed. 598 """ 599 factory = resource(UML.ElementFactory) 600 f = factory.create(cls) 601 f.source = flow.source 602 f.target = flow.target 603 flow.unlink() 604 return f 605 606 607 def count_object_flows(node, attr): 608 """ 609 Count incoming or outgoing object flows. 610 """ 611 return len(getattr(node, attr) 612 .select(lambda flow: isinstance(flow, UML.ObjectFlow))) 613 614 615 def check_combining_flow(el): 616 """ 617 Set object flow as combining flow when incoming or outgoing flow count 618 is greater than zero. Otherwise change combining flow to control flow. 619 """ 620 subject = el.subject 621 flow = subject.outgoing[0] # combining flow 622 combined = flow.target # combined node 623 624 c1 = count_object_flows(subject, 'incoming') 625 c2 = count_object_flows(combined, 'outgoing') 626 627 log.debug('combined incoming and outgoing object flow count: (%d, %d)' % (c1, c2)) 628 629 if (c1 > 0 or c2 > 0) and isinstance(flow, UML.ControlFlow): 630 log.debug('changing combing flow to object flow') 631 create_flow(UML.ObjectFlow, flow) 632 elif c1 == 0 and c2 == 0 and isinstance(flow, UML.ObjectFlow): 633 log.debug('changing combing flow to control flow') 634 create_flow(UML.ControlFlow, flow) 635 636 637 def create_connector_end(connector, role): 638 """ 639 Create Connector End, set role and attach created end to 640 connector. 641 """ 642 end = resource(UML.ElementFactory).create(UML.ConnectorEnd) 643 end.role = role 644 connector.end = end 645 assert end in role.end 646 return end 647 648 649 def rotate(p1, p2, a, b, x, y): 650 """ 651 Rotate point (a, b) by angle, which is determined by line (p1, p2). 652 653 Rotated point is moved by vector (x, y). 654 """ 655 try: 656 angle = atan((p1[1] - p2[1]) / (p1[0] - p2[0])) 657 except ZeroDivisionError: 658 da = p1[1] < p2[1] and 1.5 or -1.5 659 angle = pi * da 660 661 sin_angle = sin(angle) 662 cos_angle = cos(angle) 663 return (cos_angle * a - sin_angle * b + x, 664 sin_angle * a + cos_angle * b + y) 665 666 # vim:sw=4:et:ai gaphor/branches/new-canvas/gaphor/diagram/interaction.py
r772 r1100 2 2 InteractionItem diagram item 3 3 ''' 4 # vim:sw=4:et5 4 6 from __future__ import generators7 8 import gobject9 import pango10 import diacanvas11 5 from gaphor import UML 12 6 from nameditem import NamedItem … … 134 128 def on_groupable_iter(self): 135 129 return iter(self._children) 130 131 # vim:sw=4:et gaphor/branches/new-canvas/gaphor/diagram/items.py
r1081 r1100 36 36 from gaphor.diagram.activitynodes import DecisionNodeItem 37 37 from gaphor.diagram.activitynodes import ForkNodeItem 38 from gaphor.diagram.flow import FlowItem 38 39 39 40 # Use Cases: gaphor/branches/new-canvas/gaphor/diagram/lifeline.py
r926 r1100 3 3 """ 4 4 5 import gobject6 import pango7 import diacanvas8 5 from gaphor import UML 9 6 from gaphor.diagram.align import V_ALIGN_MIDDLE 10 7 from gaphor.diagram.diagramline import FreeLine 11 from gaphor.diagram.groupable import GroupBase12 8 from gaphor.diagram.nameditem import NamedItem 13 9 gaphor/branches/new-canvas/gaphor/diagram/message.py
r773 r1100 5 5 import itertools 6 6 7 import gobject8 import pango9 import diacanvas10 11 7 from gaphor import resource, UML 12 8 13 9 from gaphor.diagram.diagramline import DiagramLine 14 10 from gaphor.diagram.lifeline import LifelineItem, LifetimeItem 15 from gaphor.diagram import TextElement 16 from gaphor.diagram.groupable import GroupBase 11 #from gaphor.diagram import TextElement 17 12 18 13 # gaphor/branches/new-canvas/gaphor/diagram/objectnode.py
r1097 r1100 40 40 NamedItem.__init__(self, id) 41 41 42 self._upper_bound = TextElement('value', '{ upperBound = %s }', '*') 43 self.add(self._upper_bound) 42 self._tag = '' #TextElement('value', '{ upperBound = %s }', '*') 43 self._tag_bounds = None 44 #self.add(self._upper_bound) 44 45 45 self._ordering = diacanvas.shape.Text()46 self._ordering.set_font_description(pango.FontDescription(font.FONT))47 self._ordering.set_alignment(pango.ALIGN_CENTER)48 self._ordering.set_markup(False)46 #self._ordering = diacanvas.shape.Text() 47 #self._ordering.set_font_description(pango.FontDescription(font.FONT)) 48 #self._ordering.set_alignment(pango.ALIGN_CENTER) 49 #self._ordering.set_markup(False) 49 50 50 51 self._show_ordering = False 52 53 def _set_ordering(self, ordering): 54 """ 55 Set ordering of object node. 56 """ 57 self.subject.ordering = ordering 58 self.request_update() 59 60 ordering = property(lambda s: s.subject.ordering, _set_ordering) 61 62 def _set_show_ordering(self, value): 63 #self.preserve_property(pspec.name) 64 self._show_ordering = value 65 self.request_update() 66 67 show_ordering = property(lambda s: s._show_ordering, _set_show_ordering) 51 68 52 69 def save(self, save_func): … … 67 84 NamedItem.on_subject_notify(self, pspec, notifiers) 68 85 if self.subject: 69 factory = UML70 86 if not self.subject.upperBound: 71 self.subject.upperBound = factory.create(UML.LiteralSpecification)87 self.subject.upperBound = UML.create(UML.LiteralSpecification) 72 88 self.subject.upperBound.value = '*' 73 self._upper_bound.subject = self.subject.upperBound74 else:75 self._upper_bound.subject = None89 #self._upper_bound.subject = self.subject.upperBound 90 #else: 91 # self._upper_bound.subject = None 76 92 self.request_update() 77 93 78 79 def do_set_property(self, pspec, value): 80 """ 81 Request update of item in case of ordering visibility. 82 """ 83 if pspec.name == 'show-ordering': 84 self.preserve_property(pspec.name) 85 self._show_ordering = value 86 self.request_update() 87 else: 88 NamedItem.do_set_property(self, pspec, value) 89 90 91 def do_get_property(self, pspec): 92 if pspec.name == 'show-ordering': 93 return self._show_ordering 94 else: 95 return NamedItem.do_get_property(self, pspec) 96 97 98 def _set_ordering(self, ordering): 99 """ 100 Set ordering of object node. 101 """ 102 self.subject.ordering = ordering 103 self.request_update() 104 105 106 ordering = property(lambda s: s.subject.ordering, _set_ordering) 107 108 def update(self, context): 94 def pre_update(self, context): 109 95 """ 110 96 Update object node, its ordering and upper bound specification. … … 112 98 NamedItem.update(self, context) 113 99 114 if self.subject: 115 self._ordering.set_text('{ ordering = %s }' % self.subject.ordering) 116 else: 117 self._ordering.set_text('') 100 # TODO: format tag properly: 101 if self.subject.upperBound: 102 self._tag = '{ upperBound = %s }' % self.subject.upperBound.value 118 103 119 # 120 # object ordering 121 # 122 if self.props.show_ordering: 123 # center ordering below border 124 ord_width, ord_height = self._ordering.to_pango_layout(True).get_pixel_size() 125 x = (self.width - ord_width) / 2 126 self._ordering.set_pos((x, self.height + self.style.margin[0])) 104 self._tag += '{ ordering = %s }' % self.subject.ordering 127 105 128 self._ordering.set_max_width(ord_width) 129 self._ordering.set_max_height(ord_height) 130 131 self.set_bounds((min(0, x), 0, 132 max(self.width, ord_width), self.height + self.style.margin[0] + ord_height)) 133 else: 134 ord_width, ord_height = 0, 0 135 136 # 137 # upper bound 138 # 139 ub_width, ub_height = self._upper_bound.get_size() 140 x = (self.width - ub_width) / 2 141 y = self.height + ord_height + self.style.margin[0] 142 self._upper_bound.update_label(x, y) 143 144 106 w, h = text_extents(self._tag) 107 x = (self.width - w) / 2 108 y = self.height + self.style.margin[0] 109 self._tag_bounds = Rectangle(x, y, width=w, height=h) 145 110 146 111 def draw(self, context): 112 cr = context.cairo 113 cr.rectangle(0, 0, self.width, self.height) 114 cr.stroke() 115 147 116 super(ObjectNodeItem, self).draw(context) 148 117 149 def on_shape_iter(self): 150 it = NamedItem.on_shape_iter(self) 151 if self.props.show_ordering: 152 return itertools.chain(it, iter([self._ordering])) 153 else: 154 return it 118 if self._tag: 119 text_multiline(cr, self._tag_bounds[0], self._tag_bounds[1], self._tag) 120 if context.hovered or context.focused or context.draw_all: 121 cr.set_line_width(0.5) 122 b = self._tag_bounds 123 cr.rectangle(b.x0, b.y0, b.width, b.height) 124 cr.stroke() 155 125 156 126 gaphor/branches/new-canvas/utils/genUML2.py
r1023 r1100 284 284 tag = tag.value 285 285 286 print 'scanning tags: %s' % tag286 #print 'scanning tags: %s' % tag 287 287 288 288 if tag and tag.find('subsets') != -1:
