Changeset 1044

Show
Ignore:
Timestamp:
10/24/06 00:45:34 (2 years ago)
Author:
arjanmol
Message:

made associations work

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • gaphor/branches/new-canvas/ChangeLog

    r1035 r1044  
     12006-10-24  arjan <arjan at yirdis dot nl> 
     2 
     3        * gaphor/diagram/association.py: Made direction and name drawing work. 
     4        * gaphor/diagram/diagramline.py: make lines easier to select (fuzzyness) 
     5 
    162006-10-17  arjan <arjan at yirdis dot nl> 
    27 
  • gaphor/branches/new-canvas/gaphor/UML/elementfactory.py

    r1026 r1044  
    139139        self.notify(None, 'flush') 
    140140        component.handle(FlushFactoryEvent(self)) 
     141 
    141142        # First flush all diagrams: 
    142143        for value in list(self.select(lambda e: isinstance(e, Diagram))): 
     
    150151        assert len(self._elements) == 0, 'Still items in the factory: %s' % str(self._elements.values()) 
    151152 
     153        # Force Garbage collection, so memory allocated by items is freed. 
    152154        import gc 
    153155        for i in range(4): gc.collect() 
  • gaphor/branches/new-canvas/gaphor/actions/itemactions.py

    r1026 r1044  
    328328        wx, wy = view.transform_point_c2w(*get_pointer(view)) 
    329329        x, y = view.canvas.get_matrix_w2i(fi).transform_point(wx, wy) 
    330         segment = fi.closest_segment(x, y) 
     330        distance, point, segment = fi.closest_segment(x, y) 
    331331        return fi, segment 
    332332 
     
    437437            item = get_parent_focus_item(self._window) 
    438438            if isinstance(item, items.AssociationItem): 
    439                 self.active = item.get_property('show-direction') 
     439                self.active = item.show_direction 
    440440        except NoFocusItemError: 
    441441            pass 
     
    444444    def execute(self): 
    445445        fi = get_parent_focus_item(self._window) 
    446         assert isinstance(fi, AssociationItem) 
    447         fi.set_property('show-direction', self.active) 
     446        assert isinstance(fi, items.AssociationItem) 
     447        fi.show_direction = self.active 
    448448 
    449449register_action(AssociationShowDirectionAction, 'ItemFocus') 
  • gaphor/branches/new-canvas/gaphor/diagram/association.py

    r1035 r1044  
    1414# tail end and visa versa. 
    1515 
    16 from math import atan, pi, sin, cos 
     16from math import atan2, atan, pi, sin, cos 
    1717 
    1818from gaphas.util import text_extents 
     
    9393        # AssociationEnds are really inseperable from the AssociationItem. 
    9494        # We give them the same id as the association item. 
    95         self._label_pos = (0, 0) 
    9695        self._head_end = AssociationEnd(owner=self, end="head") 
    97 #        self._head_end.set_child_of(self) 
    9896        self._tail_end = AssociationEnd(owner=self, end="tail") 
    99 #        self._tail_end.set_child_of(self) 
    100  
    101 #        self._label = diacanvas.shape.Text() 
    102 #        self._label.set_font_description(pango.FontDescription(AssociationItem.FONT)) 
    103         #self._label.set_alignment(pango.ALIGN_CENTER) 
    104 #        self._label.set_markup(False) 
    105         #self._label.set_max_width(100) 
    106         #self._label.set_max_height(100) 
    10797 
    10898        # Direction depends on the ends that hold the ownedEnd attributes. 
    10999        self._show_direction = False 
    110 #        self._dir = diacanvas.shape.Path() 
    111 #        self._dir.set_line_width(2.0) 
    112 #        self._dir.line(((10, 0), (10, 10), (0, 5))) 
    113 #        self._dir.set_fill_color(diacanvas.color(0,0,0)) 
    114 #        self._dir.set_fill(diacanvas.shape.FILL_SOLID) 
    115 #        self._dir.set_cyclic(True) 
    116  
    117 #        self._head_xa = diacanvas.shape.Path() 
    118 #        self._head_xa.set_line_width(2.0) 
    119  
    120 #        self._head_xb = diacanvas.shape.Path() 
    121 #        self._head_xb.set_line_width(2.0) 
    122  
    123 #        self._tail_xa = diacanvas.shape.Path() 
    124 #        self._tail_xa.set_line_width(2.0) 
    125  
    126 #        self._tail_xb = diacanvas.shape.Path() 
    127 #        self._tail_xb.set_line_width(2.0) 
     100        self._dir_angle = 0 
     101        self._dir_pos = 0, 0 
     102 
     103    def set_show_direction(self, dir): 
     104        self._show_direction = dir 
     105        self.request_update() 
     106 
     107    show_direction = property(lambda s: s._show_direction, set_show_direction) 
    128108 
    129109    def setup_canvas(self): 
     
    210190 
    211191        self.subject.memberEnd.moveDown(self.subject.memberEnd[0]) 
     192        self.request_update() 
    212193 
    213194    def on_subject_notify(self, pspec, notifiers=()): 
     
    218199 
    219200    def on_subject_notify__name(self, subject, pspec): 
    220         #log.debug('Association name = %s' % (subject and subject.name)) 
    221         #if subject: 
    222         #    self._label.set_text(subject.name or '') 
    223         #else: 
    224         #    self._label.set_text('') 
    225201        self.request_update() 
    226202 
     
    242218        y = (p1[1] + p2[1]) / 2.0 - y 
    243219 
    244         self._label_pos = (x, y) 
    245220        #log.debug('label pos = (%d, %d)' % (x, y)) 
    246221        #return x, y, max(x + 10, x + w), max(y + 10, y + h) 
    247222        return x, y, x + w, y + h 
    248223 
    249  
    250     def update_dir(self, p1, p2): 
    251         """Create a small arrow near the middle of the association line and 
    252         let it point in the direction of self.subject.memberEnd[0]. 
    253         Keep in mind that self.subject.memberEnd[0].class_ points to the class 
    254         *not* pointed to by the arrow. 
    255         """ 
    256         x = p1[0] < p2[0] and -8 or 8 
    257         y = p1[1] >= p2[1] and -8 or 8 
    258         x = (p1[0] + p2[0]) / 2.0 + x 
    259         y = (p1[1] + p2[1]) / 2.0 + y 
    260          
    261         try: 
    262             angle = atan((p1[1] - p2[1]) / (p1[0] - p2[0])) #/ pi * 180.0 
    263         except ZeroDivisionError: 
    264             angle = pi * 1.5 
    265  
    266         # Invert angle if member ends are inverted 
    267         if self.subject.memberEnd[0] is self._tail_end.subject: 
    268             angle += pi 
    269  
    270         if p1[0] < p2[0]: 
    271             angle += pi 
    272         elif p1[0] == p2[0] and p1[1] > p2[1]: 
    273             angle += pi 
    274         #log.debug('rotation angle is %s' % (angle/pi * 180.0)) 
    275  
    276         sin_angle = sin(angle) 
    277         cos_angle = cos(angle) 
    278  
    279         def r(a, b): 
    280             return (cos_angle * a - sin_angle * b + x, \ 
    281                     sin_angle * a + cos_angle * b + y) 
    282  
    283         # Create an arrow around (0, 0), so it can be easely rotated: 
    284         self._dir.line((r(-6, 0), r(6, -5), r(6, 5))) 
    285         self._dir.set_cyclic(True) 
    286  
    287         return x, y, x + 12, y + 10 
    288224 
    289225    def update(self, context): 
     
    321257                self.draw_tail = self.draw_tail_undefined 
    322258 
     259            if self._show_direction: 
     260                m = len(self._handles) / 2 
     261                h0, h1 = self._handles[m - 1], self._handles[m] 
     262                self._dir_angle = atan2(h1.y - h0.y, h1.x - h0.x) 
     263                self._dir_pos = (h0.x + h1.x) / 2, (h0.y + h1.y) / 2 
     264                if self.tail_end.subject is self.subject.memberEnd[0]: 
     265                    self._dir_angle += pi 
     266 
    323267        # update relationship after self.set calls to avoid circural updates 
    324268        DiagramLine.update(self, context) 
     
    332276                                     handles[-2].pos) 
    333277         
    334         #self.update_child(self._head_end, affine) 
    335         #self.update_child(self._tail_end, affine) 
    336  
    337278        # update name label: 
    338279        middle = len(handles)/2 
     
    340281                                               handles[middle].pos) 
    341282 
    342 #        if self._show_direction and self.subject and self.subject.memberEnd: 
    343 #            b0 = self.update_dir(handles[middle-1].pos, 
    344 #                                 handles[middle].pos) 
    345 #        else: 
    346 #            b0 = self.bounds 
    347  
    348         # bounds calculation 
    349 #        b1 = self.bounds 
    350 #        b2 = self._head_end.get_bounds(self._head_end.affine) 
    351 #        b3 = self._tail_end.get_bounds(self._tail_end.affine) 
    352 #        bv = zip(self._label_bounds, b0, b1, b2, b3) 
    353 #        self.set_bounds((min(bv[0]), min(bv[1]), max(bv[2]), max(bv[3]))) 
    354                      
    355 #    def on_shape_iter(self): 
    356 #        for s in DiagramLine.on_shape_iter(self): 
    357 #            yield s 
    358 #        yield self._label 
    359 #        if self._show_direction: 
    360 #            yield self._dir 
    361 # 
    362 #        if self._head_end.subject and self._tail_end.subject: 
    363 #            if self._tail_end.subject.aggregation == intern('none') \ 
    364 #                    and self._head_end.get_navigability() == False: 
    365 #                yield self._head_xa 
    366 #                yield self._head_xb 
    367 # 
    368 #            if self._head_end.subject.aggregation == intern('none') \ 
    369 #                    and self._tail_end.get_navigability() == False: 
    370 #                yield self._tail_xa 
    371 #                yield self._tail_xb 
    372283 
    373284    def point(self, x, y): 
     
    465376 
    466377    def draw(self, context): 
     378        cr = context.cairo 
    467379        super(AssociationItem, self).draw(context) 
    468380        self._head_end.draw(context) 
    469381        self._tail_end.draw(context) 
    470         # TODO: draw direction and association name 
    471  
    472  
    473     # 
    474     # Gaphor Connection Protocol 
    475     # 
    476  
    477     def allow_connect_handle(self, handle, connecting_to): 
    478         """This method is called by a canvas item if the user tries to connect 
    479         this object's handle. allow_connect_handle() checks if the line is 
    480         allowed to be connected. In this case that means that one end of the 
    481         line should be connected to a Classifier. 
    482         Returns: TRUE if connection is allowed, FALSE otherwise. 
    483         """ 
    484         #log.debug('AssociationItem.allow_connect_handle') 
    485         if isinstance(connecting_to.subject, UML.Classifier): 
    486             return True 
    487         return False 
    488  
    489     def confirm_connect_handle(self, handle): 
    490         """This method is called after a connection is established. This method 
    491         sets the internal state of the line and updates the data model. 
    492         """ 
    493         #log.debug('AssociationItem.confirm_connect_handle') 
    494  
    495         c1 = self.handles[0].connected_to 
    496         c2 = self.handles[-1].connected_to 
    497         if c1 and c2: 
    498             head_type = c1.subject 
    499             tail_type = c2.subject 
    500  
    501             # First check if we do not already contain the right subject: 
    502             if self.subject: 
    503                 end1 = self.subject.memberEnd[0] 
    504                 end2 = self.subject.memberEnd[1] 
    505                 if (end1.type is head_type and end2.type is tail_type) \ 
    506                    or (end2.type is head_type and end1.type is tail_type): 
    507                     return 
    508                      
    509             # Find all associations and determine if the properties on the 
    510             # association ends have a type that points to the class. 
    511             Association = UML.Association 
    512             for assoc in resource(UML.ElementFactory).itervalues(): 
    513                 if isinstance(assoc, Association): 
    514                     #print 'assoc.memberEnd', assoc.memberEnd 
    515                     end1 = assoc.memberEnd[0] 
    516                     end2 = assoc.memberEnd[1] 
    517                     if (end1.type is head_type and end2.type is tail_type) \ 
    518                        or (end2.type is head_type and end1.type is tail_type): 
    519                         # check if this entry is not yet in the diagram 
    520                         # Return if the association is not (yet) on the canvas 
    521                         for item in assoc.presentation: 
    522                             if item.canvas is self.canvas: 
    523                                 break 
    524                         else: 
    525                             #return end1, end2, assoc 
    526                             self.subject = assoc 
    527                             if (end1.type is head_type and end2.type is tail_type): 
    528                                 self._head_end.subject = end1 
    529                                 self._tail_end.subject = end2 
    530                             else: 
    531                                 self._head_end.subject = end2 
    532                                 self._tail_end.subject = end1 
    533                             return 
    534             else: 
    535                 # TODO: How should we handle other types than Class??? 
    536  
    537                 element_factory = resource(UML.ElementFactory) 
    538                 relation = element_factory.create(UML.Association) 
    539                 head_end = element_factory.create(UML.Property) 
    540                 head_end.lowerValue = element_factory.create(UML.LiteralSpecification) 
    541                 tail_end = element_factory.create(UML.Property) 
    542                 tail_end.lowerValue = element_factory.create(UML.LiteralSpecification) 
    543                 relation.package = self.canvas.diagram.namespace 
    544                 relation.memberEnd = head_end 
    545                 relation.memberEnd = tail_end 
    546                 #head_end.type = tail_end.class_ = head_type 
    547                 #tail_end.type = head_end.class_ = tail_type 
    548                 head_end.type = head_type 
    549                 tail_end.type = tail_type 
    550                 head_type.ownedAttribute = tail_end 
    551                 tail_type.ownedAttribute = head_end 
    552                 # copy text from ends to AssociationEnds: 
    553                 #head_end.name = self._head_end._name.get_property('text') 
    554                 #head_end.multiplicity = self._head__end._mult.get_property('text') 
    555                 #tail_end.name = self._tail_end._name.get_property('text') 
    556                 #tail_end.multiplicity = self._tail_end._mult.get_property('text') 
    557  
    558                 self.subject = relation 
    559                 self._head_end.subject = head_end 
    560                 self._tail_end.subject = tail_end 
    561  
    562     def confirm_disconnect_handle(self, handle, was_connected_to): 
    563         #log.debug('AssociationItem.confirm_disconnect_handle') 
    564         if self.subject: 
    565             # First delete the Property's at the ends, otherwise they will 
    566             # be interpreted as attributes. 
    567             self._head_end.set_subject(None) 
    568             self._tail_end.set_subject(None) 
    569             self.set_subject(None) 
     382        if self._show_direction: 
     383            cr.save() 
     384            try: 
     385                cr.translate(*self._dir_pos) 
     386                cr.rotate(self._dir_angle) 
     387                cr.move_to(0, 0) 
     388                cr.line_to(6, 5) 
     389                cr.line_to(0, 10) 
     390                cr.fill() 
     391            finally: 
     392                cr.restore() 
     393 
     394        if self.subject and self.subject.name: 
     395            cr.move_to(self._label_bounds[0], self._label_bounds[1]) 
     396            cr.show_text(self.subject.name) 
    570397 
    571398 
  • gaphor/branches/new-canvas/gaphor/diagram/classifier.py

    r1034 r1044  
    88from gaphor.i18n import _ 
    99 
    10 from gaphor.diagram.nameditem import NamedItem, NamedItemMeta 
     10from gaphor.diagram.nameditem import NamedItem 
    1111from gaphor.diagram.feature import FeatureItem 
    1212 
  • gaphor/branches/new-canvas/gaphor/diagram/diagramline.py

    r1023 r1044  
    1919        gaphas.Line.__init__(self) 
    2020        DiagramItem.__init__(self, id) 
     21        self.fuzzyness = 2 
    2122        self._stereotype_pos = (0, 0) 
    2223        self._stereotype_width = 0 
  • gaphor/branches/new-canvas/setup.py

    r1029 r1044  
    1919    'gaphor.actions.tests.test_placementactions', 
    2020    'gaphor.adapters.tests.test_connector', 
     21    'gaphor.adapters.tests.test_editor', 
    2122    'gaphor.diagram.tests.test_class', 
    2223    'gaphor.diagram.tests.test_action',