Changeset 1171

Show
Ignore:
Timestamp:
03/22/07 02:05:12 (2 years ago)
Author:
arjanmol
Message:

updated UML properties to use zope.component.handle

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • gaphor/trunk/gaphor/UML/elementfactory.py

    r1170 r1171  
    99from gaphor.UML.element import Element 
    1010from gaphor.UML.diagram import Diagram 
    11 from gaphor.UML.interfaces import ICreateElementEvent, IRemoveElementEvent, \ 
     11from gaphor.UML.interfaces import IElementCreateEvent, IElementDeleteEvent, \ 
    1212                                  IFlushFactoryEvent, IModelFactoryEvent, \ 
    1313                                  IService 
    14 from gaphor.UML.event import CreateElementEvent, RemoveElementEvent, \ 
     14from gaphor.UML.event import ElementCreateEvent, ElementDeleteEvent, \ 
    1515                             FlushFactoryEvent, ModelFactoryEvent 
    16  
    17  
    18 class _xxUndoCreateAction(object): 
    19  
    20     def __init__(self, factory, element): 
    21         self.factory = factory 
    22         self.element = element 
    23  
    24     def undo(self): 
    25         try: 
    26             del self.factory._elements[self.element.id] 
    27         except KeyError: 
    28             pass # Key was probably already removed in an unlink call 
    29         self.factory.notify(self.element, 'remove') 
    30         component.handle(RemoveElementEvent(self.factory, self.element)) 
    31  
    32     def redo(self): 
    33         self.factory._elements[self.element.id] = self.element 
    34         self.factory.notify(self.element, 'create') 
    35         component.handle(CreateElementEvent(self.factory, self.element)) 
    36  
    37  
    38 class _xxUndoRemoveAction(object): 
    39  
    40     def __init__(self, factory, element): 
    41         self.factory = factory 
    42         self.element = element 
    43  
    44     def undo(self): 
    45         self.factory._elements[self.element.id] = self.element 
    46         self.factory.notify(self.element, 'create') 
    47         component.handle(CreateElementEvent(self.factory, self.element)) 
    48  
    49     def redo(self): 
    50         del self.factory._elements[self.element.id] 
    51         self.factory.notify(self.element, 'remove') 
    52         component.handle(RemoveElementEvent(self.factory, self.element)) 
    5316 
    5417 
     
    8649        obj.connect('__unlink__', self._element_signal) 
    8750        self.notify(obj, 'create') 
    88         component.handle(CreateElementEvent(self, obj)) 
     51        component.handle(ElementCreateEvent(self, obj)) 
    8952        return obj 
    9053 
     
    211174            #get_undo_manager().add_undo_action(_UndoRemoveAction(self, element)) 
    212175            self.notify(element, 'remove') 
    213             component.handle(RemoveElementEvent(self, element)) 
     176            component.handle(ElementDeleteEvent(self, element)) 
    214177#        elif pspec == '__relink__' and not self._elements.has_key(element.id): 
    215178#            log.debug('Relinking element: %s' % element) 
     
    217180#            self.notify(element, 'create') 
    218181 
    219 component.provideUtility(ElementFactory(), IService, "element_factory") 
    220  
    221  
    222 @component.adapter(ICreateElementEvent) 
     182component.provideUtility(ElementFactory(), IService, "ElementFactory") 
     183 
     184 
     185@component.adapter(IElementCreateEvent) 
    223186def undo_create_event(event): 
    224187    factory = event.service 
     
    230193            pass # Key was probably already removed in an unlink call 
    231194        factory.notify(element, 'remove') 
    232         component.handle(RemoveElementEvent(factory, element)) 
     195        component.handle(ElementDeleteEvent(factory, element)) 
    233196    get_undo_manager().add_undo_action(_undo_create_event) 
    234197 
     
    236199 
    237200 
    238 @component.adapter(IRemoveElementEvent) 
     201@component.adapter(IElementDeleteEvent) 
    239202def undo_remove_event(event): 
    240203    factory = event.service 
     
    243206        factory._elements[element.id] = element 
    244207        factory.notify(element, 'create') 
    245         component.handle(CreateElementEvent(factory, element)) 
     208        component.handle(ElementCreateEvent(factory, element)) 
    246209    get_undo_manager().add_undo_action(_undo_remove_event) 
    247210 
  • gaphor/trunk/gaphor/UML/event.py

    r1170 r1171  
    77 
    88 
    9 class AttributeChangedEvent(object): 
    10     interface.implements(IAttributeChangedEvent) 
     9class AttributeChangeEvent(object): 
     10    interface.implements(IAttributeChangeEvent) 
    1111 
    12     def __init__(self, element, attribute): 
     12    def __init__(self, element, attribute, old_value, new_value): 
    1313        self.element = element 
    14         self.attribute = attribute 
     14        self.property = attribute 
     15        self.old_value = old_value 
     16        self.new_value = new_value 
    1517 
    1618 
    17 class AssociationChangedEvent(object): 
    18     interface.implements(IAssociationChangedEvent) 
     19class AssociationChangeEvent(object): 
     20    interface.implements(IAssociationChangeEvent) 
    1921 
    2022    def __init__(self, element, associaton): 
    2123        self.element = element 
    22         self.associaton = associaton 
     24        self.property = associaton 
    2325 
    2426 
    25 class CreateElementEvent(object): 
    26     interface.implements(ICreateElementEvent) 
     27class AssociationSetEvent(AssociationChangeEvent): 
     28 
     29    def __init__(self, element, associaton, old_value, new_value): 
     30        AssociationChangeEvent.__init__(self, element, associaton) 
     31        self.old_value = old_value 
     32        self.new_value = new_value 
     33 
     34 
     35class AssociationAddEvent(AssociationChangeEvent): 
     36 
     37    def __init__(self, element, associaton, new_value): 
     38        AssociationChangeEvent.__init__(self, element, associaton) 
     39        self.new_value = new_value 
     40 
     41 
     42class AssociationDeleteEvent(AssociationChangeEvent): 
     43 
     44    def __init__(self, element, associaton, old_value): 
     45        AssociationChangeEvent.__init__(self, element, associaton) 
     46        self.old_value = old_value 
     47 
     48 
     49class ElementCreateEvent(object): 
     50    interface.implements(IElementCreateEvent, IElementFactoryEvent) 
    2751 
    2852    def __init__(self, service, element): 
     
    3155 
    3256 
    33 class RemoveElementEvent(object): 
    34     interface.implements(IRemoveElementEvent) 
     57class ElementDeleteEvent(object): 
     58    interface.implements(IElementDeleteEvent, IElementFactoryEvent) 
    3559 
    3660    def __init__(self, service, element): 
  • gaphor/trunk/gaphor/UML/interfaces.py

    r1170 r1171  
    66from gaphor.interfaces import IService, IServiceEvent 
    77 
    8 class IElementChangedEvent(interface.Interface): 
     8class IElementEvent(interface.Interface): 
    99    """Generic event fired when element state changes. 
    1010    """ 
     
    1212 
    1313 
    14 class IAttributeChangedEvent(IElementChangedEvent): 
    15     """An attribute has changed. 
    16     """ 
    17     attribute = interface.Attribute("The attribute") 
    18  
    19  
    20 class IAssociationChangedEvent(IElementChangedEvent): 
    21     """An association hs changed. 
    22     This event may be fired for both ends of the association. 
    23     """ 
    24     association = interface.Attribute("The association") 
    25  
    26  
    27 class IModelFactoryEvent(IServiceEvent): 
    28     """A new model is loaded into the ElementFactory. 
    29     """ 
    30  
    31  
    32 class IFlushFactoryEvent(IServiceEvent): 
    33     """All elements are removed from the ElementFactory. 
    34     """ 
    35  
    36  
    37 class IFactoryElementEvent(IServiceEvent): 
    38     """Events related to individual model elements. 
    39     """ 
    40     element = interface.Attribute("The element") 
    41  
    42  
    43 class ICreateElementEvent(IFactoryElementEvent): 
     14class IElementCreateEvent(IElementEvent): 
    4415    """A new element has been created. 
    4516    """ 
    4617 
    4718 
    48 class IRemoveElementEvent(IFactoryElementEvent): 
     19class IElementDeleteEvent(IElementEvent): 
    4920    """An element is deleted from the model. 
    5021    """ 
    5122 
    5223 
     24class IElementChangeEvent(IElementEvent): 
     25    """Generic event fired when element state changes. 
     26    """ 
     27    property = interface.Attribute("The property that changed") 
     28    old_value = interface.Attribute("The property value before the change") 
     29    new_value = interface.Attribute("The property value after the change") 
     30 
     31 
     32class IAttributeChangeEvent(IElementChangeEvent): 
     33    """ 
     34    An attribute has changed. 
     35    """ 
     36 
     37 
     38class IAssociationChangeEvent(IElementChangeEvent): 
     39    """ 
     40    An association hs changed. 
     41    This event may be fired for both ends of the association. 
     42    """ 
     43 
     44class IElementFactoryEvent(IServiceEvent): 
     45    """ 
     46    Events related to individual model elements. 
     47    """ 
     48 
     49class IModelFactoryEvent(IElementFactoryEvent): 
     50    """ 
     51    A new model is loaded into the ElementFactory. 
     52    """ 
     53 
     54 
     55class IFlushFactoryEvent(IElementFactoryEvent): 
     56    """ 
     57    All elements are removed from the ElementFactory. 
     58    """ 
     59 
     60 
    5361# vim: sw=4:et 
  • gaphor/trunk/gaphor/UML/properties.py

    r1135 r1171  
    11#!/usr/bin/env python 
    22# vim:sw=4:et 
    3 """Properties used to create the UML 2.0 data model. 
     3""" 
     4Properties used to create the UML 2.0 data model. 
    45 
    56The logic for creating and destroying connections between UML objects is 
     
    2425    load(value):      load 'value' as the current value for this property 
    2526    save(save_func):  send the value of the property to save_func(name, value) 
    26     #unlink():         remove references to other elements. 
    2727""" 
    2828 
    2929__all__ = [ 'attribute', 'enumeration', 'association', 'derivedunion', 'redefine' ] 
    3030 
     31from zope import component 
    3132from collection import collection 
     33from event import AttributeChangeEvent, AssociationSetEvent, \ 
     34                  AssociationAddEvent, AssociationDeleteEvent 
    3235import operator 
    3336from gaphor.undomanager import get_undo_manager 
    3437 
    35 #infinite = 100000 
    3638 
    3739class undoaction(object): 
     
    5355        get_undo_manager().add_undo_action(self.undo) 
    5456 
     57 
    5558class umlproperty(object): 
    56     """Superclass for attribute, enumeration and association. 
     59    """ 
     60    Superclass for attribute, enumeration and association. 
    5761    The subclasses should define a 'name' attribute that contains the name 
    5862    of the property. Derived properties (derivedunion and redefine) can be 
     
    8791        pass 
    8892 
    89 #    def unlink(self, obj): 
    90 #        if hasattr(obj, self._name): 
    91 #            self.__delete__(obj) 
    92  
    9393    def notify(self, obj): 
    94         """Notify obj that the property's value has been changed. 
     94        """ 
     95        Notify obj that the property's value has been changed. 
    9596        Deriviates are also triggered to send a notify signal. 
    9697        """ 
     
    120121 
    121122class undoattributeaction(undoaction): 
    122     """This undo action contains one undo action for an attribute 
     123    """ 
     124    This undo action contains one undo action for an attribute 
    123125    property. 
    124126    """ 
     
    175177            return 
    176178 
    177         undoattributeaction(self, obj, self._get(obj)) 
    178  
     179        #undoattributeaction(self, obj, self._get(obj)) 
     180 
     181        old = self._get(obj) 
    179182        if value == self.default and hasattr(obj, self._name): 
    180183            delattr(obj, self._name) 
    181184        else: 
    182185            setattr(obj, self._name, value) 
     186        component.handle(AttributeChangeEvent(obj, self, old, value)) 
    183187        self.notify(obj) 
    184188 
    185189    def _del(self, obj, value=None): 
    186         #self.old = self._get(obj) 
    187         try: 
    188             undoattributeaction(self, obj, self._get(obj)) 
     190        old = self._get(obj) 
     191        try: 
     192            #undoattributeaction(self, obj, self._get(obj)) 
    189193            delattr(obj, self._name) 
    190194        except AttributeError: 
    191195            pass 
    192196        else: 
     197            component.handle(AttributeChangeEvent(obj, self, old, self.default)) 
    193198            self.notify(obj) 
    194199 
    195200 
    196201class enumeration(umlproperty): 
    197     """Enumeration. 
    198     Element.enum = enumeration('enum', ('one', 'two', 'three'), 'one')""" 
     202    """ 
     203    Enumeration. 
     204    Element.enum = enumeration('enum', ('one', 'two', 'three'), 'one') 
     205    """ 
    199206 
    200207    def __init__(self, name, values, default): 
     
    221228        if not value in self.values: 
    222229            raise AttributeError, 'Value should be one of %s' % str(self.values) 
    223         if value != self._get(obj): 
    224             undoattributeaction(self, obj, self._get(obj)) 
    225             if value == self.default: 
    226                 delattr(obj, self._name) 
    227             else: 
    228                 setattr(obj, self._name, value) 
    229             self.notify(obj) 
     230        if value == self._get(obj): 
     231            return 
     232 
     233        #undoattributeaction(self, obj, self._get(obj)) 
     234        old = self._get(obj) 
     235        if value == self.default: 
     236            delattr(obj, self._name) 
     237        else: 
     238            setattr(obj, self._name, value) 
     239        component.handle(AttributeChangeEvent(obj, self, old, value)) 
     240        self.notify(obj) 
    230241 
    231242    def _del(self, obj, value=None): 
    232         try: 
    233             undoattributeaction(self, obj, self._get(obj)) 
     243        old = self._get(obj) 
     244        try: 
     245            #undoattributeaction(self, obj, self._get(obj)) 
    234246            delattr(obj, self._name) 
    235247        except AttributeError: 
    236248            pass 
    237249        else: 
     250            component.handle(AttributeChangeEvent(obj, self, old, self.default)) 
    238251            self.notify(obj) 
    239252 
    240253 
    241254class undosetassociationaction(undoaction): 
    242     """Undo a 'set' action in an association. 
     255    """ 
     256    Undo a 'set' action in an association. 
    243257    """ 
    244258 
     
    270284 
    271285class association(umlproperty): 
    272     """Association, both uni- and bi-directional. 
     286    """ 
     287    Association, both uni- and bi-directional. 
     288 
    273289    Element.assoc = association('assoc', Element, opposite='other') 
    274290     
     
    276292    will cause the association to be ended if the element on the other end 
    277293    of the association is unlinked. 
     294 
    278295    If the association is a composite relationship, the value is connected to 
    279296    the elements __unlink__ signal too. This will cause the value to be 
     
    293310        if not isinstance(value, self.type): 
    294311            raise AttributeError, 'Value for %s should be of type %s (%s)' % (self.name, self.type.__name__, type(value).__name__) 
    295         # TODO: avoid sending notifications: 
    296312        self._set(obj, value, do_notify=False) 
    297313 
     
    327343                # Create the empty collection here since it might be used to 
    328344                # add  
    329                 #c = collection(self, obj, self.type) 
    330                 #setattr(obj, self._name, c) 
    331345                c = collection(self, obj, self.type) 
    332346                setattr(obj, self._name, c) 
     
    336350 
    337351    def _set(self, obj, value, from_opposite=False, do_notify=True): 
    338         """Set a new value for our attribute. If this is a collection, append 
     352        """ 
     353        Set a new value for our attribute. If this is a collection, append 
    339354        to the existing collection. 
    340355 
     
    348363        if self.upper == 1: 
    349364            old = self._get(obj) 
     365 
    350366            # do nothing if we are assigned our current value: 
    351367            if value is old: 
    352368                return 
    353369 
    354             # is done is _del(): undoassociationaction(self, obj, old) 
     370            # is done in _del(): undoassociationaction(self, obj, old) 
    355371            if old: 
    356372                self._del(obj, old) 
     373 
    357374            if value is None: 
    358375                return 
    359             if value is self._get(obj): 
    360                 #log.debug('association: value already in obj: %s' % value) 
    361                 return 
    362  
    363             if not from_opposite: 
    364                 undosetassociationaction(self, obj, value) 
     376 
     377            #if value is self._get(obj): 
     378            #    #log.debug('association: value already in obj: %s' % value) 
     379            #    return 
     380 
     381            #if not from_opposite: 
     382            #    undosetassociationaction(self, obj, value) 
    365383            setattr(obj, self._name, value) 
     384            if do_notify: 
     385                component.handle(AssociationSetEvent(obj, self, old, value)) 
    366386        else: 
    367387            # Set the actual value 
     
    374394                return 
    375395 
    376             if not from_opposite: 
    377                 undosetassociationaction(self, obj, value) 
     396            #if not from_opposite: 
     397            #    undosetassociationaction(self, obj, value) 
    378398            c.items.append(value) 
     399            if do_notify: 
     400                component.handle(AssociationAddEvent(obj, self, value)) 
    379401 
    380402        # Callbacks are only connected if a new relationship has 
     
    391413 
    392414    def _del(self, obj, value, from_opposite=False): 
    393         # TODO: move code to _del 
    394         """Delete is used for element deletion and for removal of 
     415        """ 
     416        Delete is used for element deletion and for removal of 
    395417        elements from a list. 
    396418        """ 
     
    400422            if self.upper > 1: 
    401423                raise Exception, 'Can not delete collections' 
    402             value = self._get(obj) 
     424            old = value = self._get(obj) 
    403425            if value is None: 
    404426                return 
    405427 
    406         if not from_opposite: 
    407             undodelassociationaction(self, obj, value) 
     428        #if not from_opposite: 
     429        #    undodelassociationaction(self, obj, value) 
    408430 
    409431        if not from_opposite and self.opposite: 
     
    418440                except: 
    419441                    pass 
     442                else: 
     443                    component.handle(AssociationDeleteEvent(obj, self, value)) 
     444                # Remove items collection if empty 
    420445                if not items: 
    421446                    delattr(obj, self._name) 
     
    426451                pass 
    427452                #print 'association._del: delattr failed for %s' % self.name 
     453            else: 
     454                component.handle(AssociationSetEvent(obj, self, value, None)) 
    428455 
    429456        value.disconnect(self.__on_unlink, obj) 
     
    432459        self.notify(obj) 
    433460 
    434 #    def unlink(self, obj): 
    435 #        #print 'unlink', self, obj 
    436 #        lst = getattr(obj, self._name) 
    437 #        while lst: 
    438 #            self.__delete__(obj, lst[0]) 
    439 #            # re-establish unlink handler: 
    440 #            value.connect('__unlink__', self.__on_unlink, obj) 
    441  
    442461    def __on_unlink(self, value, pspec, obj): 
    443         """Disconnect when the element on the other end of the association 
     462        """ 
     463        Disconnect when the element on the other end of the association 
    444464        (value) sends the '__unlink__' signal. This is especially important 
    445465        for uni-directional associations. 
     
    452472 
    453473    def __on_composite_unlink(self, obj, pspec, value): 
    454         """Unlink value if we have a part-whole (composite) relationship 
     474        """ 
     475        Unlink value if we have a part-whole (composite) relationship 
    455476        (value is a composite of obj). 
    456477        The implementation of value.unlink() should ensure that no deadlocks 
     
    489510    def save(self, obj, save_func): 
    490511        pass 
    491  
    492 #    def unlink(self, obj): 
    493 #        pass 
    494512 
    495513    def __str__(self): 
     
    528546 
    529547class redefine(umlproperty): 
    530     """Redefined association 
     548    """ 
     549    Redefined association 
    531550    Element.x = redefine('x', Class, Element.assoc) 
    532551    If the redefine eclipses the original property (it has the same name) 
     
    553572        if self.original.name == self.name: 
    554573            self.original.save(obj, save_func) 
    555  
    556 #    def unlink(self, obj): 
    557 #        self.original.unlink(obj) 
    558574 
    559575    def __str__(self): 
  • gaphor/trunk/gaphor/UML/tests/test_elementfactory.py

    r1170 r1171  
    8686        global handled 
    8787        p = ef.create(Parameter) 
    88         self.assertTrue(ICreateElementEvent.providedBy(last_event) ) 
     88        self.assertTrue(IElementCreateEvent.providedBy(last_event) ) 
    8989        self.assertTrue(handled) 
    9090 
     
    9393        global handled 
    9494        p = ef.create(Parameter) 
    95         self.assertTrue(ICreateElementEvent.providedBy(last_event) ) 
     95        self.assertTrue(IElementCreateEvent.providedBy(last_event) ) 
    9696        self.assertTrue(handled) 
    9797        self.clearEvents() 
    9898        p.unlink() 
    99         self.assertTrue(IRemoveElementEvent.providedBy(last_event) ) 
     99        self.assertTrue(IElementDeleteEvent.providedBy(last_event) ) 
    100100 
    101101    def testModelEvent(self): 
     
    112112 
    113113    def testUndo(self): 
    114         pass 
    115         # TODO: implement 
    116114        from gaphor.services.undomanager import get_undo_manager 
    117115        get_undo_manager().begin_transaction() 
     
    120118 
    121119        assert get_undo_manager().can_undo() 
     120 
    122121        get_undo_manager().commit_transaction() 
    123122        assert get_undo_manager().can_undo() 
    124123        assert ef.size() == 1 
     124 
    125125        get_undo_manager().undo_transaction() 
    126126        assert not get_undo_manager().can_undo() 
    127127        assert get_undo_manager().can_redo() 
     128        assert ef.size() == 0 
    128129 
     130        get_undo_manager().redo_transaction() 
     131        assert get_undo_manager().can_undo() 
     132        assert not get_undo_manager().can_redo() 
     133        assert ef.size() == 1 
     134        assert ef.lselect()[0] is p 
     135         
     136 
     137# vim:sw=4:et 
  • gaphor/trunk/gaphor/services/tests/test_undomanager.py

    r1170 r1171  
    44 
    55import unittest 
    6 from gaphor.undomanager import UndoManager, undoableproperty 
     6from gaphor.services.undomanager import UndoManager 
    77 
    88class TestUndoManager(unittest.TestCase): 
     
    4848        undone = [ 0 ] 
    4949        def undo_action(undone=undone): 
    50             assert undo_manager._in_undo 
     50            #print 'undo_action called' 
    5151            undone[0] = 1 
    52             return undo_action 
     52            undo_manager.add_undo_action(redo_action) 
     53 
     54        def redo_action(undone=undone): 
     55            #print 'redo_action called' 
     56            undone[0] = -1 
     57            undo_manager.add_undo_action(undo_action) 
    5358 
    5459        undo_manager = UndoManager() 
     
    6368 
    6469        undo_manager.undo_transaction() 
    65         assert not undo_manager.can_undo() 
    66         assert undone[0] == 1 
     70        assert not undo_manager.can_undo(), undo_manager._undo_stack 
     71        assert undone[0] == 1, undone 
    6772         
    6873        undone[0] = 0 
    6974 
    70         assert undo_manager.can_redo() 
     75        assert undo_manager.can_redo(), undo_manager._redo_stack 
    7176 
    7277        undo_manager.redo_transaction() 
    7378        assert not undo_manager.can_redo() 
    7479        assert undo_manager.can_undo() 
    75         assert undone[0] == 1 
     80        assert undone[0] == -1, undone 
    7681 
    7782 
    78     def test_undoableproperty(self): 
    79         class A(object): 
    80             def _set_x(self, value): 
    81                 self._x = value 
    82             def _del_x(self): 
    83                 del self._x 
    84             x = undoableproperty(lambda s: s._x, _set_x, _del_x) 
    85  
    86         a = A() 
    87         assert A.x 
    88  
    89         a.x = 3 
    90         assert a.x == 3 
    91         assert a._x == 3 
    92  
    93         a.x = 9 
    94         assert a.x == 9 
    95         assert a._x == 9 
    96  
    97         del a.x 
    98         assert not hasattr(a, 'x') 
    99         assert not hasattr(a, '_x') 
    100  
    101         a.x = 3 
    102         assert hasattr(a, 'x') 
    103         assert hasattr(a, '_x') 
    104          
    105     def test_undoableproperty_property(self): 
    106         undo_manager = UndoManager() 
    107         class A(object): 
    108             def _set_x(self, value): 
    109                 self._x = value 
    110             def _del_x(self): 
    111                 del self._x 
    112             x = undoableproperty(property=property(lambda s: s._x, _set_x, _del_x), 
    113                                  undo_manager=undo_manager) 
    114  
    115         a = A() 
    116         a.x = 3 
    117         assert a.x == 3 
    118  
    119     def test_undoableproperty_in_transaction(self): 
    120         undo_manager = UndoManager() 
    121         class A(object): 
    122             def _set_x(self, value): 
    123                 self._x = value 
    124             def _del_x(self): 
    125                 del self._x 
    126             x = undoableproperty(lambda s: s._x, _set_x, _del_x, 
    127                                  undo_manager=undo_manager) 
    128  
    129         a = A() 
    130         a.x = 3 
    131         undo_manager.begin_transaction() 
    132         assert undo_manager._current_transaction 
    133         a.x = 2 
    134  
    135         undo_manager.commit_transaction() 
    136         assert undo_manager._undo_stack 
    137         assert a.x == 2 
    138  
    139         undo_manager.undo_transaction() 
    140         assert not undo_manager._undo_stack 
    141         assert undo_manager._redo_stack 
    142         assert a.x == 3 
    143  
    144         undo_manager.redo_transaction() 
    145         assert undo_manager._undo_stack 
    146         assert not undo_manager._redo_stack 
    147          
    148         assert a.x == 2 
    149  
    15083# vim:sw=4:et 
  • gaphor/trunk/gaphor/services/undomanager.py

    r1170 r1171  
    3939        except: 
    4040            undo_manager.rollback_transaction() 
     41            raise 
    4142        else: 
    4243            undo_manager.commit_transaction() 
     
    116117 
    117118    def clear_redo_stack(self): 
    118         self._redo_stack = [
     119        del self._redo_stack[:
    119120 
    120121    def begin_transaction(self): 
     
    128129 
    129130        self._current_transaction = Transaction() 
    130         self.clear_redo_stack() 
    131131        self._transaction_depth += 1 
    132132 
     
    138138        if not self._current_transaction: 
    139139            return 
    140  
    141         if self._redo_stack: 
    142             self.clear_redo_stack() 
    143140 
    144141        self._current_transaction.add(action) 
     
    153150        if self._transaction_depth == 0: 
    154151            if self._current_transaction.can_execute(): 
     152                self.clear_redo_stack() 
    155153                self._undo_stack.append(self._current_transaction) 
    156154            else: 
     
    192190        transaction = self._undo_stack.pop() 
    193191 
     192        self._current_transaction = Transaction() 
     193        self._transaction_depth += 1 
     194 
    194195        transaction.execute() 
     196 
     197        assert self._transaction_depth == 1 
     198        self._redo_stack.append(self._current_transaction) 
     199        self._current_transaction = None 
     200        self._transaction_depth = 0 
    195201        component.handle(UndoManagerStateChanged(self)) 
    196202 
     
    201207        transaction = self._redo_stack.pop() 
    202208 
     209        self._current_transaction = Transaction() 
     210        self._transaction_depth += 1 
     211 
    203212        transaction.execute() 
     213 
     214        assert self._transaction_depth == 1 
     215        self._undo_stack.append(self._current_transaction) 
     216        self._current_transaction = None 
     217        self._transaction_depth = 0 
     218 
    204219        component.handle(UndoManagerStateChanged(self)) 
    205220