Changeset 1087

Show
Ignore:
Timestamp:
11/23/06 00:31:59 (2 years ago)
Author:
arjanmol
Message:
  • made line endings of association draw well
  • added tests for commentline connected to association
  • diagramitem.py: extracted code related to item.subject and
    created a special support class for it.
  • fixed notation of '<None>' in treeview
Files:

Legend:

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

    r1056 r1087  
    66 - split DiagramItem in a stereotype support, SubjectSupport and some 
    77   other support classes. 
     8 
     9 - Currently (r1085) relations (association, dependency) can be created between 
     10   model elements. Some items (e.g. comment lines) can be connected to the 
     11   relationship at the time it realizes a relation at model level (both ends 
     12   get connected). This should result in a trigger to the attached 
     13   (comment-)line so it can also establish it's relationship at model level. 
     14   This can be solved in two places: 
     15   1. handle it in the DiagramItem. This will ensure such relationship is 
     16      always up to date, but may result in weird behavior in the loading code. 
     17   2. handle it in the IConnect adapters. That's the only place where 
     18      relationship are established so doing some extra work there won't hurt 
     19   Hmm.. Option 2 I guess.. 
    820 
    921 - using stereotypes 
  • gaphor/branches/new-canvas/gaphor/actions/itemactions.py

    r1070 r1087  
    497497 
    498498    def get_association_end(self): 
    499         return get_parent_focus_item(self._window).get_property(self.end_name) 
     499        return getattr(get_parent_focus_item(self._window), self.end_name) 
    500500 
    501501    def update(self): 
     
    503503            item = get_parent_focus_item(self._window) 
    504504            if isinstance(item, items.AssociationItem): 
    505                 end = item.get_property(self.end_name) 
     505                end = getattr(item, self.end_name) 
    506506                if end.subject: 
    507507                    self.active = (end.get_navigability() == self.navigable) 
     
    520520    id = 'Head_isNavigable' 
    521521    label = 'Navigable' 
    522     end_name = 'head' 
     522    end_name = 'head_end' 
     523    group = 'head_navigable' 
    523524    navigable = True 
    524525 
     
    529530    id = 'Head_isNotNavigable' 
    530531    label = 'Non-Navigable' 
    531     end_name = 'head' 
     532    end_name = 'head_end' 
     533    group = 'head_navigable' 
    532534    navigable = False 
    533535 
     
    538540    id = 'Head_unknownNavigation' 
    539541    label = 'Unknown' 
    540     end_name = 'head' 
     542    end_name = 'head_end' 
     543    group = 'head_navigable' 
    541544    navigable = None 
    542545 
     
    547550    id = 'Tail_isNavigable' 
    548551    label = 'Navigable' 
    549     end_name = 'tail' 
     552    end_name = 'tail_end' 
     553    group = 'tail_navigable' 
    550554    navigable = True 
    551555 
     
    556560    id = 'Tail_isNotNavigable' 
    557561    label = 'Non-Navigable' 
    558     end_name = 'tail' 
     562    end_name = 'tail_end' 
     563    group = 'tail_navigable' 
    559564    navigable = False 
    560565 
     
    565570    id = 'Tail_unknownNavigation' 
    566571    label = 'Unknown' 
    567     end_name = 'tail' 
     572    end_name = 'tail_end' 
     573    group = 'tail_navigable' 
    568574    navigable = None 
    569575 
     
    579585        try: 
    580586            item = get_parent_focus_item(self._window) 
    581             if isinstance(item, AssociationItem): 
    582                 end = item.get_property(self.end_name) 
     587            if isinstance(item, items.AssociationItem): 
     588                end = getattr(item, self.end_name) 
    583589                if end.subject: 
    584590                    self.active = (end.subject.aggregation == self.aggregation) 
     
    589595    def execute(self): 
    590596        if self.active: 
    591             subject = get_parent_focus_item(self._window).get_property(self.end_name).subject 
     597            subject = getattr(get_parent_focus_item(self._window), self.end_name).subject 
    592598            assert isinstance(subject, UML.Property) 
    593599            subject.aggregation = self.aggregation 
     
    598604    label = 'None' 
    599605    group = 'head_aggregation' 
    600     end_name = 'head
     606    end_name = 'head_end
    601607    aggregation = 'none' 
    602608 
     
    608614    label = 'Shared' 
    609615    group = 'head_aggregation' 
    610     end_name = 'head
     616    end_name = 'head_end
    611617    aggregation = 'shared' 
    612618 
     
    618624    label = 'Composite' 
    619625    group = 'head_aggregation' 
    620     end_name = 'head
     626    end_name = 'head_end
    621627    aggregation = 'composite' 
    622628 
     
    628634    label = 'None' 
    629635    group = 'tail_aggregation' 
    630     end_name = 'tail
     636    end_name = 'tail_end
    631637    aggregation = 'none' 
    632638 
     
    638644    label = 'Shared' 
    639645    group = 'tail_aggregation' 
    640     end_name = 'tail
     646    end_name = 'tail_end
    641647    aggregation = 'shared' 
    642648 
     
    648654    label = 'Composite' 
    649655    group = 'tail_aggregation' 
    650     end_name = 'tail
     656    end_name = 'tail_end
    651657    aggregation = 'composite' 
    652658 
  • gaphor/branches/new-canvas/gaphor/adapters/connectors.py

    r1085 r1087  
    146146    Base class for connecting two lines to each other. 
    147147    The line that is conencted to is called 'element', as in ElementConnect. 
     148 
     149    Once a line has been connected at both ends, and a model element is 
     150    assigned to it, all items connectedt to this line (e.g. Comments) 
     151    receive a connect() call. This allows already connected lines to set 
     152    up relationships at model level too. 
    148153    """ 
    149154 
     
    281286        if super(CommentLineLineConnect, self).connect(handle, x, y): 
    282287            opposite = self.line.opposite(handle) 
    283             if opposite.connected_to
     288            if opposite.connected_to and self.element.subject
    284289                if isinstance(opposite.connected_to.subject, UML.Comment): 
    285290                    opposite.connected_to.subject.annotatedElement = self.element.subject 
     
    301306class RelationshipConnect(ElementConnect): 
    302307    """ 
    303     Base class for relationship connections, such as Association
     308    Base class for relationship connections, such as associations
    304309    dependencies and implementations. 
    305310 
     
    374379        return relation 
    375380 
     381    def trigger_connected_items(self, line): 
     382        """ 
     383        Cause items connected to @line to reconnect, allowing them to 
     384        establish or destroy relationships at model level. 
     385        """ 
     386        canvas = line.canvas 
     387        solver = canvas.solver 
     388 
     389        # First make sure coordinates match 
     390        solver.solve() 
     391        for item, handle in self.line.canvas.get_connected_items(line): 
     392            adapter = component.queryMultiAdapter((line, item), IConnect) 
     393            assert adapter 
     394            adapter.connect(handle, handle.x, handle.y) 
     395         
    376396    def glue(self, handle, x, y): 
    377397        opposite = self.line.opposite(handle) 
     
    392412        return super(RelationshipConnect, self).glue(handle, x, y) 
    393413 
     414    def connect_subject(self): 
     415        """ 
     416        Establish the relationship at model level. 
     417        """ 
     418        raise NotImplemented, 'Implement connect_subject() in a subclass' 
     419 
     420    def connect(self, handle, x, y): 
     421        """ 
     422        Connect the items to each other. The model level relationship 
     423        is created by create_subject() 
     424        """ 
     425        if super(RelationshipConnect, self).connect(handle, x, y): 
     426            opposite = self.line.opposite(handle) 
     427            if opposite.connected_to: 
     428                self.connect_subject() 
     429                line = self.line 
     430                if line.subject: 
     431                    self.trigger_connected_items(line) 
     432 
    394433    def disconnect(self, handle): 
    395434        """ 
     
    400439            old = self.line.subject 
    401440            del self.line.subject 
     441            if old: 
     442                self.trigger_connected_items(self.line) 
    402443            if old and len(old.presentation) == 0: 
    403444                old.unlink() 
     
    428469        return super(DependencyConnect, self).glue(handle, x, y) 
    429470 
    430     def connect(self, handle, x, y): 
     471    def connect_subject(self): 
    431472        """ 
    432473        TODO: cleck for existing relationships (use self.relation()) 
    433474        """ 
    434         if super(DependencyConnect, self).connect(handle, x, y): 
    435             dep = self.line 
    436             opposite = self.line.opposite(handle) 
    437             if opposite.connected_to: 
    438                 if dep.auto_dependency: 
    439                     dep.set_dependency_type() 
    440                 if dep.dependency_type is UML.Realization: 
    441                     relation = self.relationship_or_new(dep.dependency_type, 
    442                                         head=('realizingClassifier', None), 
    443                                         tail=('abstraction', 'realization')) 
    444                 else: 
    445                     relation = self.relationship_or_new(dep.dependency_type, 
    446                                         ('supplier', 'supplierDependency'), 
    447                                         ('client', 'clientDependency')) 
    448                 dep.subject = relation 
     475        line = self.line 
     476        if line.auto_dependency: 
     477            line.set_dependency_type() 
     478        if line.dependency_type is UML.Realization: 
     479            relation = self.relationship_or_new(line.dependency_type, 
     480                                head=('realizingClassifier', None), 
     481                                tail=('abstraction', 'realization')) 
     482        else: 
     483            relation = self.relationship_or_new(line.dependency_type, 
     484                                ('supplier', 'supplierDependency'), 
     485                                ('client', 'clientDependency')) 
     486        line.subject = relation 
    449487 
    450488component.provideAdapter(DependencyConnect) 
     
    479517        return super(ImplementationConnect, self).glue(handle, x, y) 
    480518 
    481     def connect(self, handle, x, y): 
    482         if super(ImplementationConnect, self).connect(handle, x, y): 
    483             line = self.line 
    484             opposite = self.line.opposite(handle) 
    485             if opposite.connected_to: 
    486                 relation = self.relationship_or_new(UML.Implementation, 
    487                             ('contract', None), 
    488                             ('implementatingClassifier', 'implementation')) 
    489                 line.subject = relation 
     519    def connect_subject(self): 
     520        relation = self.relationship_or_new(UML.Implementation, 
     521                    ('contract', None), 
     522                    ('implementatingClassifier', 'implementation')) 
     523        self.line.subject = relation 
    490524 
    491525component.provideAdapter(ImplementationConnect) 
     
    511545#        return super(GeneralizationConnect, self).glue(handle, x, y) 
    512546 
    513     def connect(self, handle, x, y): 
    514         if super(GeneralizationConnect, self).connect(handle, x, y): 
    515             line = self.line 
    516             opposite = self.line.opposite(handle) 
    517             if opposite.connected_to: 
    518                 relation = self.relationship_or_new(UML.Generalization, 
    519                             ('general', None), 
    520                             ('specific', 'generalization')) 
    521                 line.subject = relation 
     547    def connect_subject(self): 
     548        relation = self.relationship_or_new(UML.Generalization, 
     549                    ('general', None), 
     550                    ('specific', 'generalization')) 
     551        self.line.subject = relation 
    522552 
    523553component.provideAdapter(GeneralizationConnect) 
     
    542572        return super(IncludeConnect, self).glue(handle, x, y) 
    543573 
    544     def connect(self, handle, x, y): 
    545         if super(IncludeConnect, self).connect(handle, x, y): 
    546             line = self.line 
    547             opposite = self.line.opposite(handle) 
    548             if opposite.connected_to: 
    549                 relation = self.relationship_or_new(UML.Include, 
    550                             ('addition', None), 
    551                             ('includingCase', 'include')) 
    552                 line.subject = relation 
     574    def connect_subject(self): 
     575        relation = self.relationship_or_new(UML.Include, 
     576                    ('addition', None), 
     577                    ('includingCase', 'include')) 
     578        line.subject = relation 
    553579 
    554580component.provideAdapter(IncludeConnect) 
     
    573599        return super(ExtendConnect, self).glue(handle, x, y) 
    574600 
    575     def connect(self, handle, x, y): 
    576         if super(ExtendConnect, self).connect(handle, x, y): 
    577             line = self.line 
    578             opposite = self.line.opposite(handle) 
    579             if opposite.connected_to: 
    580                 relation = self.relationship_or_new(UML.Extend, 
    581                             ('extendedCase', None), 
    582                             ('extension', 'extend')) 
    583                 line.subject = relation 
     601    def connect_subject(self): 
     602        relation = self.relationship_or_new(UML.Extend, 
     603                    ('extendedCase', None), 
     604                    ('extension', 'extend')) 
     605        line.subject = relation 
    584606 
    585607component.provideAdapter(ExtendConnect) 
     
    614636        return super(ExtensionConnect, self).glue(handle, x, y) 
    615637 
    616     def connect(self, handle, x, y): 
    617         if super(ExtensionConnect, self).connect(handle, x, y): 
    618             element = self.element 
    619             line = self.line 
    620             opposite = self.line.opposite(handle) 
    621             if opposite.connected_to: 
    622                 c1 = line.head.connected_to 
    623                 c2 = line.tail.connected_to 
    624                 if c1 and c2: 
    625                     head_type = c1.subject 
    626                     tail_type = c2.subject 
    627  
    628                     # First check if we do not already contain the right subject: 
    629                     if line.subject: 
    630                         end1 = line.subject.memberEnd[0] 
    631                         end2 = line.subject.memberEnd[1] 
    632                         if (end1.type is head_type and end2.type is tail_type) \ 
    633                            or (end2.type is head_type and end1.type is tail_type): 
    634                             return 
    635                              
    636                     # Find all associations and determine if the properties on 
    637                     # the association ends have a type that points to the class. 
    638                     for assoc in UML.select(): 
    639                         if isinstance(assoc, UML.Extension): 
    640                             end1 = assoc.memberEnd[0] 
    641                             end2 = assoc.memberEnd[1] 
    642                             if (end1.type is head_type and end2.type is tail_type) \ 
    643                                or (end2.type is head_type and end1.type is tail_type): 
    644                                 # check if this entry is not yet in the diagram 
    645                                 # Return if the association is not (yet) on the canvas 
    646                                 for item in assoc.presentation: 
    647                                     if item.canvas is element.canvas: 
    648                                         break 
    649                                 else: 
    650                                     line.subject = assoc 
     638    def connect_subject(self): 
     639        element = self.element 
     640        line = self.line 
     641 
     642        c1 = line.head.connected_to 
     643        c2 = line.tail.connected_to 
     644        if c1 and c2: 
     645            head_type = c1.subject 
     646            tail_type = c2.subject 
     647 
     648            # First check if we do not already contain the right subject: 
     649            if line.subject: 
     650                end1 = line.subject.memberEnd[0] 
     651                end2 = line.subject.memberEnd[1] 
     652                if (end1.type is head_type and end2.type is tail_type) \ 
     653                   or (end2.type is head_type and end1.type is tail_type): 
     654                    return 
     655                     
     656            # Find all associations and determine if the properties on 
     657            # the association ends have a type that points to the class. 
     658            for assoc in UML.select(): 
     659                if isinstance(assoc, UML.Extension): 
     660                    end1 = assoc.memberEnd[0] 
     661                    end2 = assoc.memberEnd[1] 
     662                    if (end1.type is head_type and end2.type is tail_type) \ 
     663                       or (end2.type is head_type and end1.type is tail_type): 
     664                        # check if this entry is not yet in the diagram 
     665                        # Return if the association is not (yet) on the canvas 
     666                        for item in assoc.presentation: 
     667                            if item.canvas is element.canvas: 
     668                                break 
     669                        else: 
     670                            line.subject = assoc 
    651671#                                    if (end1.type is head_type and end2.type is tail_type): 
    652672#                                        line.head_subject = end1 
     
    655675#                                        line.head_subject = end2 
    656676#                                        line.tail_subject = end1 
    657                                     return 
    658                     else: 
    659                         # Create a new Extension relationship 
    660                         relation = UML.create(UML.Extension) 
    661                         head_end = UML.create(UML.Property) 
    662                         tail_end = UML.create(UML.ExtensionEnd) 
    663                         relation.package = element.canvas.diagram.namespace 
    664                         relation.memberEnd = head_end 
    665                         relation.memberEnd = tail_end 
    666                         relation.ownedEnd = tail_end 
    667                         head_end.type = head_type 
    668                         tail_end.type = tail_type 
    669                         tail_type.ownedAttribute = head_end 
    670                         head_end.name = 'baseClass' 
    671  
    672                 line.subject = relation 
     677                            return 
     678            else: 
     679                # Create a new Extension relationship 
     680                relation = UML.create(UML.Extension) 
     681                head_end = UML.create(UML.Property) 
     682                tail_end = UML.create(UML.ExtensionEnd) 
     683                relation.package = element.canvas.diagram.namespace 
     684                relation.memberEnd = head_end 
     685                relation.memberEnd = tail_end 
     686                relation.ownedEnd = tail_end 
     687                head_end.type = head_type 
     688                tail_end.type = tail_type 
     689                tail_type.ownedAttribute = head_end 
     690                head_end.name = 'baseClass' 
     691 
     692        line.subject = relation 
    673693 
    674694    def disconnect(self, handle): 
     
    715735        return super(AssociationConnect, self).glue(handle, x, y) 
    716736 
    717     def connect(self, handle, x, y): 
    718         if super(AssociationConnect, self).connect(handle, x, y): 
    719             element = self.element 
    720             line = self.line 
    721             opposite = self.line.opposite(handle) 
    722             if opposite.connected_to: 
    723                 c1 = line.head.connected_to 
    724                 c2 = line.tail.connected_to 
    725                 if c1 and c2: 
    726                     head_type = c1.subject 
    727                     tail_type = c2.subject 
    728  
    729                     # First check if we do not already contain the right subject: 
    730                     if line.subject: 
    731                         end1 = line.subject.memberEnd[0] 
    732                         end2 = line.subject.memberEnd[1] 
    733                         if (end1.type is head_type and end2.type is tail_type) \ 
    734                            or (end2.type is head_type and end1.type is tail_type): 
     737    def connect_subject(self): 
     738        element = self.element 
     739        line = self.line 
     740 
     741        c1 = line.head.connected_to 
     742        c2 = line.tail.connected_to 
     743        if c1 and c2: 
     744            head_type = c1.subject 
     745            tail_type = c2.subject 
     746 
     747            # First check if we do not already contain the right subject: 
     748            if line.subject: 
     749                end1 = line.subject.memberEnd[0] 
     750                end2 = line.subject.memberEnd[1] 
     751                if (end1.type is head_type and end2.type is tail_type) \ 
     752                   or (end2.type is head_type and end1.type is tail_type): 
     753                    return 
     754                     
     755            # Find all associations and determine if the properties on 
     756            # the association ends have a type that points to the class. 
     757            for assoc in UML.select(): 
     758                if isinstance(assoc, UML.Association): 
     759                    end1 = assoc.memberEnd[0] 
     760                    end2 = assoc.memberEnd[1] 
     761                    if (end1.type is head_type and end2.type is tail_type) \ 
     762                       or (end2.type is head_type and end1.type is tail_type): 
     763                        # check if this entry is not yet in the diagram 
     764                        # Return if the association is not (yet) on the canvas 
     765                        for item in assoc.presentation: 
     766                            if item.canvas is element.canvas: 
     767                                break 
     768                        else: 
     769                            line.subject = assoc 
     770                            if (end1.type is head_type and end2.type is tail_type): 
     771                                line.head_end.subject = end1 
     772                                line.tail_end.subject = end2 
     773                            else: 
     774                                line.head_end.subject = end2 
     775                                line.tail_end.subject = end1 
    735776                            return 
    736                              
    737                     # Find all associations and determine if the properties on 
    738                     # the association ends have a type that points to the class. 
    739                     for assoc in UML.select(): 
    740                         if isinstance(assoc, UML.Association): 
    741                             end1 = assoc.memberEnd[0] 
    742                             end2 = assoc.memberEnd[1] 
    743                             if (end1.type is head_type and end2.type is tail_type) \ 
    744                                or (end2.type is head_type and end1.type is tail_type): 
    745                                 # check if this entry is not yet in the diagram 
    746                                 # Return if the association is not (yet) on the canvas 
    747                                 for item in assoc.presentation: 
    748                                     if item.canvas is element.canvas: 
    749                                         break 
    750                                 else: 
    751                                     line.subject = assoc 
    752                                     if (end1.type is head_type and end2.type is tail_type): 
    753                                         line.head_end.subject = end1 
    754                                         line.tail_end.subject = end2 
    755                                     else: 
    756                                         line.head_end.subject = end2 
    757                                         line.tail_end.subject = end1 
    758                                     return 
    759                     else: 
    760                         # Create a new Extension relationship 
    761                         relation = UML.create(UML.Association) 
    762                         head_end = UML.create(UML.Property) 
    763                         head_end.lowerValue = UML.create(UML.LiteralSpecification) 
    764                         tail_end = UML.create(UML.Property) 
    765                         tail_end.lowerValue = UML.create(UML.LiteralSpecification) 
    766                         relation.package = element.canvas.diagram.namespace 
    767                         relation.memberEnd = head_end 
    768                         relation.memberEnd = tail_end 
    769                         head_end.type = head_type 
    770                         tail_end.type = tail_type 
    771                         head_type.ownedAttribute = head_end 
    772                         tail_type.ownedAttribute = head_end 
    773  
    774                         line.subject = relation 
    775                         line.head_end.subject = head_end 
    776                         line.tail_end.subject = tail_end 
     777            else: 
     778                # Create a new Extension relationship 
     779                relation = UML.create(UML.Association) 
     780                head_end = UML.create(UML.Property) 
     781                head_end.lowerValue = UML.create(UML.LiteralSpecification) 
     782                tail_end = UML.create(UML.Property) 
     783                tail_end.lowerValue = UML.create(UML.LiteralSpecification) 
     784                relation.package = element.canvas.diagram.namespace 
     785                relation.memberEnd = head_end 
     786                relation.memberEnd = tail_end 
     787                head_end.type = head_type 
     788                tail_end.type = tail_type 
     789                head_type.ownedAttribute = tail_end 
     790                tail_type.ownedAttribute = head_end 
     791 
     792                line.subject = relation 
     793                line.head_end.subject = head_end 
     794                line.tail_end.subject = tail_end 
    777795 
    778796    def disconnect(self, handle): 
  • gaphor/branches/new-canvas/gaphor/adapters/tests/test_connector.py

    r1085 r1087  
    150150        assert assoc.subject in comment.subject.annotatedElement, comment.subject.annotatedElement 
    151151 
    152         # Disconnect actor
     152        # Disconnect comment
    153153 
    154154        adapter.disconnect(handle) 
     
    158158        assert len(comment.subject.annotatedElement) == 0, comment.subject.annotatedElement 
    159159        assert not assoc.subject in comment.subject.annotatedElement, comment.subject.annotatedElement 
     160 
     161        # Connect again: 
     162 
     163        adapter.connect(handle, handle.x, handle.y) 
     164        assert handle.connected_to is not None, handle.connected_to 
     165 
     166 
     167    def test_connector_association_connect(self): 
     168        """ 
     169        Test behaviour when the CommentLine's subject (association) is 
     170        connected after the comment line is connected. 
     171        """ 
     172        diagram = UML.create(UML.Diagram) 
     173        comment = diagram.create(items.CommentItem, subject=UML.create(UML.Comment)) 
     174        line = diagram.create(items.CommentLineItem) 
     175        line.head.pos = 100, 100 
     176        line.tail.pos = 100, 100 
     177        c1 = diagram.create(items.ClassItem, subject=UML.create(UML.Class)) 
     178        c2 = diagram.create(items.ClassItem, subject=UML.create(UML.Class)) 
     179        assoc = diagram.create(items.AssociationItem) 
     180 
     181        # connect the comment 
     182 
     183        adapter = component.queryMultiAdapter((comment, line), IConnect) 
     184 
     185        handle = line.tail 
     186        adapter.connect(handle, handle.x, handle.y) 
     187 
     188        assert handle.connected_to is comment 
     189        assert handle._connect_constraint is not None 
     190        assert len(comment.subject.annotatedElement) == 0, comment.subject.annotatedElement 
     191 
     192        # connect opposite end to the association: 
     193 
     194        adapter = component.queryMultiAdapter((assoc, line), IConnect) 
     195        handle = line.head 
     196        adapter.connect(handle, handle.x, handle.y) 
     197 
     198        assert handle.connected_to is assoc 
     199        assert handle._connect_constraint is not None 
     200        assert len(comment.subject.annotatedElement) == 0, comment.subject.annotatedElement 
     201        assert assoc.subject is None 
     202 
     203        # Now connect the association to the classes: 
     204 
     205        adapter = component.queryMultiAdapter((c1, assoc), IConnect) 
     206        handle = assoc.head 
     207        adapter.connect(handle, handle.x, handle.y) 
     208 
     209        assert handle.connected_to is c1 
     210        assert handle._connect_constraint is not None 
     211        assert len(comment.subject.annotatedElement) == 0, comment.subject.annotatedElement 
     212        assert assoc.subject is None 
     213 
     214        adapter = component.queryMultiAdapter((c2, assoc), IConnect) 
     215        handle = assoc.tail 
     216        adapter.connect(handle, handle.x, handle.y) 
     217 
     218        assert assoc.head.connected_to is c1 
     219        assert assoc.tail.connected_to is c2 
     220        assert assoc.subject 
     221        assert len(comment.subject.annotatedElement) == 1, comment.subject.annotatedElement 
     222        assert assoc.subject in comment.subject.annotatedElement 
     223 
     224        # And now disconnect again: 
     225 
     226        adapter.disconnect(handle) 
     227        assert assoc.tail.connected_to is None 
     228        assert assoc.subject is None 
     229        assert comment.subject is not None 
     230        assert len(comment.subject.annotatedElement) == 0, comment.subject.annotatedElement 
     231 
     232        # TODO: add test 
     233        # What happens when an association is displayed in two diagrams and 
     234        # the comment is connected in one diagram. That assoc. is broken. 
    160235 
    161236 
  • gaphor/branches/new-canvas/gaphor/diagram/association.py

    r1077 r1087  
    2424from gaphor.undomanager import undoable 
    2525#from gaphor.diagram import Relationship 
    26 from gaphor.diagram.diagramitem import DiagramItem 
     26from gaphor.diagram.diagramitem import SubjectSupport 
    2727from gaphor.diagram.diagramline import DiagramLine 
    2828 
     
    7474        'AssociationInvertDirection', 
    7575        'separator', 
    76 #        'Side _A', ( 
    77 #            'Head_isNavigable', 
    78 #            'separator', 
    79 #            'Head_AggregationNone', 
    80 #            'Head_AggregationShared', 
    81 #            'Head_AggregationComposite'), 
    82 #        'Side _B', ( 
    83 #            'Tail_isNavigable', 
    84 #            'separator', 
    85 #            'Tail_AggregationNone', 
    86 #            'Tail_AggregationShared', 
    87 #            'Tail_AggregationComposite') 
     76        'Head', ( 
     77            'Head_unknownNavigation', 
     78            'Head_isNotNavigable', 
     79            'Head_isNavigable', 
     80            'separator', 
     81            'Head_AggregationNone', 
     82            'Head_AggregationShared', 
     83            'Head_AggregationComposite'), 
     84        'Tail', ( 
     85            'Tail_unknownNavigation', 
     86            'Tail_isNotNavigable', 
     87            'Tail_isNavigable', 
     88            'separator', 
     89            'Tail_AggregationNone', 
     90            'Tail_AggregationShared', 
     91            'Tail_AggregationComposite'), 
    8892    ) 
    8993 
     
    141145        self._tail_end.postload() 
    142146 
    143 #    def do_set_property(self, pspec, value): 
    144 #        if pspec.name == 'head-subject': 
    145 #            self._head_end.subject = value 
    146 #        elif pspec.name == 'tail-subject': 
    147 #            self._tail_end.subject = value 
    148 #        elif pspec.name == 'show-direction': 
    149 #            self.preserve_property('show-direction') 
    150 #            self._show_direction = value 
    151 #            self.request_update() 
    152 #        else: 
    153 #            DiagramLine.do_set_property(self, pspec, value) 
    154  
    155 #    def do_get_property(self, pspec): 
    156 #        if pspec.name == 'head': 
    157 #            return self._head_end 
    158 #        if pspec.name == 'tail': 
    159 #            return self._tail_end 
    160 #        elif pspec.name == 'head-subject': 
    161 #            return self._head_end.subject 
    162 #        elif pspec.name == 'tail-subject': 
    163 #            return self._tail_end.subject 
    164 #        elif pspec.name == 'show-direction': 
    165 #            return self._show_direction 
    166 #        else: 
    167 #            return DiagramLine.do_get_property(self, pspec) 
    168  
    169147    head_end = property(lambda self: self._head_end) 
    170148 
     
    224202 
    225203    def update(self, context): 
    226         """Update the shapes and sub-items of the association.""" 
     204        """ 
     205        Update the shapes and sub-items of the association. 
     206        """ 
    227207 
    228208        handles = self.handles() 
     
    240220            elif self._head_end.get_navigability(): 
    241221                self.draw_head = self.draw_head_navigable 
    242             if self._head_end.get_navigability() == False: 
     222            elif self._head_end.get_navigability() == False: 
    243223                self.draw_head = self.draw_head_none 
    244224            else: 
     
    250230                self.draw_tail = self.draw_tail_shared 
    251231            elif self._tail_end.get_navigability(): 
    252                 # This side is navigable: 
    253                 self.draw_tail = draw_tail_navigable 
     232                self.draw_tail = self.draw_tail_navigable 
    254233            elif self._tail_end.get_navigability() == False: 
    255                 self.draw_tail = draw_tail_none 
     234                self.draw_tail = self.draw_tail_none 
    256235            else: 
    257236                self.draw_tail = self.draw_tail_undefined 
     
    305284        cr = context.cairo 
    306285        cr.line_to(0, 0) 
    307         cr.move_to(-14, -4) 
     286        cr.move_to(6, -4) 
    308287        cr.rel_line_to(8, 8) 
    309288        cr.rel_move_to(0, -8) 
     
    321300        """ 
    322301        self.draw_tail_shared(context) 
    323         context.cairo.fill_preserve() 
     302        cr = context.cairo 
     303        cr.fill_preserve() 
    324304        cr.stroke() 
    325305 
     
    338318        """ 
    339319        cr = context.cairo 
    340         cr.line_to(-20, 0) 
    341         cr.stroke() 
    342         cr.line_to(-10, -6) 
     320        cr.line_to(20, 0) 
     321        #cr.stroke() 
     322        cr.line_to(10, -6) 
    343323        cr.line_to(0, 0) 
    344         cr.line_to(-10, 6) 
    345         cr.line_to(-20, 0) 
     324        cr.line_to(10, 6) 
     325        cr.line_to(20, 0) 
    346326 
    347327    def draw_head_navigable(self, context): 
     
    360340        cr = context.cairo 
    361341        cr.line_to(0, 0) 
    362         cr.move_to(-15, -6) 
     342        cr.move_to(15, -6) 
    363343        cr.line_to(0, 0) 
    364         cr.line_to(-15, 6) 
     344        cr.line_to(15, 6) 
    365345        cr.stroke() 
    366346 
     
    397377 
    398378 
    399 class AssociationEnd(DiagramItem): 
    400     """An association end represents one end of an association. An association 
     379class AssociationEnd(SubjectSupport): 
     380    """ 
     381    An association end represents one end of an association. An association 
    401382    has two ends. An association end has two labels: one for the name and 
    402383    one for the multiplicity (and maybe one for tagged values in the future). 
     
    409390      the first 20-30 units of the line, for association end popup menu. 
    410391    """ 
    411 #    __gproperties__ = { 
    412 #        'name': (gobject.TYPE_STRING, 'name', '', '', gobject.PARAM_READWRITE), 
    413 #        'mult': (gobject.TYPE_STRING, 'mult', '', '', gobject.PARAM_READWRITE) 
    414 #    } 
    415 #    __gproperties__.update(DiagramItem.__gproperties__) 
    416392 
    417393    head_popup_menu = ( 
     
    436412 
    437413    def __init__(self, owner, id=None, end=None): 
    438         DiagramItem.__init__(self, id
     414        SubjectSupport.__init__(self
    439415        self._owner = owner 
    440416        self._end = end 
     
    447423        self._mult_bounds = Rectangle() 
    448424        self._point1 = self._point2 = (0, 0) 
    449  
    450     def postload(self): 
    451         DiagramItem.postload(self) 
    452         #self.set_text() 
    453425 
    454426    def get_popup_menu(self): 
     
    478450                self._mult = m 
    479451                self.request_update() 
    480  
    481452 
    482453    def get_navigability(self): 
     
    660631 
    661632    def on_subject_notify(self, pspec, notifiers=()): 
    662         DiagramItem.on_subject_notify(self, pspec, 
     633        SubjectSupport.on_subject_notify(self, pspec, 
    663634                        notifiers + ('aggregation', 'visibility', 
    664635                        'name', 'lowerValue.value', 
     
    684655 
    685656    def on_subject_notify__upperValue_value(self, upper_value, pspec): 
    686         log.debug('New value for upperValue.value: %s' %  upper_value and upper_value.value) 
     657        #log.debug('New value for upperValue.value: %s' %  upper_value and upper_value.value) 
    687658        self.set_text() 
    688659        self.request_update() 
  • gaphor/branches/new-canvas/gaphor/diagram/diagramitem.py

    r1085 r1087  
    1313STEREOTYPE_CLOSE = '\xc2\xbb' # '>>' 
    1414 
    15 class DiagramItem(Presentation, Element): 
     15class SubjectSupport(Presentation, Element): 
    1616    """ 
    17     Basic functionality for all model elements (lines and elements!). 
    18  
    19     This class contains common functionallity for model elements and 
    20     relationships. 
    21     It provides an interface similar to UML.Element for connecting and 
    22     disconnecting signals. 
    23  
    24     This class is not very useful on its own. It contains some glue-code for 
    25     diacanvas.DiaCanvasItem and gaphor.UML.Element. 
    26  
    27     Example: 
    28         class ElementItem(dia