Changeset 1219

Show
Ignore:
Timestamp:
04/11/07 23:00:00 (1 year ago)
Author:
arj..@yirdis.nl
Message:

Removed gaphor.undomanager. All transactions are now handled through gaphor.transaction. Moved undo action creation to undomanager service. removed all references to gaphor.undomanager.

Files:

Legend:

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

    r1173 r1219  
    66from zope import component 
    77from gaphor.misc import uniqueid, odict 
    8 from gaphor.undomanager import get_undo_manager 
    98from gaphor.UML.element import Element 
    109from gaphor.UML.diagram import Diagram 
     
    4645        obj = type(id, self) 
    4746        self._elements[id] = obj 
    48         #get_undo_manager().add_undo_action(_UndoCreateAction(self, obj)) 
    4947        obj.connect('__unlink__', self._element_signal) 
    5048        self.notify(obj, 'create') 
     
    172170            # TODO: make undo action 
    173171            del self._elements[element.id] 
    174             #get_undo_manager().add_undo_action(_UndoRemoveAction(self, element)) 
    175172            self.notify(element, 'remove') 
    176173            component.handle(ElementDeleteEvent(self, element)) 
     
    183180 
    184181 
    185 @component.adapter(IElementCreateEvent) 
    186 def undo_create_event(event): 
    187     factory = event.service 
    188     element = event.element 
    189     def _undo_create_event(): 
    190         try: 
    191             del factory._elements[element.id] 
    192         except KeyError: 
    193             pass # Key was probably already removed in an unlink call 
    194         factory.notify(element, 'remove') 
    195         component.handle(ElementDeleteEvent(factory, element)) 
    196     get_undo_manager().add_undo_action(_undo_create_event) 
    197  
    198 component.provideHandler(undo_create_event) 
    199  
    200  
    201 @component.adapter(IElementDeleteEvent) 
    202 def undo_delete_event(event): 
    203     factory = event.service 
    204     element = event.element 
    205     def _undo_delete_event(): 
    206         factory._elements[element.id] = element 
    207         factory.notify(element, 'create') 
    208         component.handle(ElementCreateEvent(factory, element)) 
    209     get_undo_manager().add_undo_action(_undo_delete_event) 
    210  
    211 component.provideHandler(undo_delete_event) 
    212  
    213182 
    214183# vim:sw=4:et 
  • gaphor/trunk/gaphor/UML/properties.py

    r1176 r1219  
    3535from interfaces import IAttributeChangeEvent, IAssociationChangeEvent 
    3636import operator 
    37 from gaphor.undomanager import get_undo_manager 
    3837 
    3938 
     
    587586 
    588587 
    589 @component.adapter(IAttributeChangeEvent) 
    590 def undo_attribute_change_event(event): 
    591     attribute = event.property 
    592     obj = event.element 
    593     value = event.old_value 
    594     def _undo_attribute_change_event(): 
    595         attribute._set(obj, value) 
    596     get_undo_manager().add_undo_action(_undo_attribute_change_event) 
    597  
    598 component.provideHandler(undo_attribute_change_event) 
    599  
    600  
    601 @component.adapter(AssociationSetEvent) 
    602 def undo_association_set_event(event): 
    603     association = event.property 
    604     obj = event.element 
    605     value = event.old_value 
    606     def _undo_association_set_event(): 
    607         #print 'undoing action', obj, value 
    608         # Tell the assoctaion it should not need to let the opposite 
    609         # side connect (it has it's own signal) 
    610         association._set(obj, value, from_opposite=True) 
    611     get_undo_manager().add_undo_action(_undo_association_set_event) 
    612  
    613 component.provideHandler(undo_association_set_event) 
    614  
    615  
    616 @component.adapter(AssociationAddEvent) 
    617 def undo_association_add_event(event): 
    618     association = event.property 
    619     obj = event.element 
    620     value = event.new_value 
    621     def _undo_association_add_event(): 
    622         #print 'undoing action', obj, value 
    623         # Tell the assoctaion it should not need to let the opposite 
    624         # side connect (it has it's own signal) 
    625         association._del(obj, value, from_opposite=True) 
    626     get_undo_manager().add_undo_action(_undo_association_add_event) 
    627  
    628 component.provideHandler(undo_association_add_event) 
    629  
    630  
    631 @component.adapter(AssociationDeleteEvent) 
    632 def undo_association_delete_event(event): 
    633     association = event.property 
    634     obj = event.element 
    635     value = event.old_value 
    636     def _undo_association_delete_event(): 
    637         #print 'undoing action', obj, value 
    638         # Tell the assoctaion it should not need to let the opposite 
    639         # side connect (it has it's own signal) 
    640         association._set(obj, value, from_opposite=True) 
    641     get_undo_manager().add_undo_action(_undo_association_delete_event) 
    642  
    643 component.provideHandler(undo_association_delete_event) 
    644  
    645  
    646588try: 
    647589    import psyco 
  • gaphor/trunk/gaphor/UML/tests/test_elementfactory.py

    r1171 r1219  
    111111        self.assertTrue(IFlushFactoryEvent.providedBy(last_event) ) 
    112112 
    113     def testUndo(self): 
    114         from gaphor.services.undomanager import get_undo_manager 
    115         get_undo_manager().begin_transaction() 
    116         ef = self.factory 
    117         p = ef.create(Parameter) 
    118  
    119         assert get_undo_manager().can_undo() 
    120  
    121         get_undo_manager().commit_transaction() 
    122         assert get_undo_manager().can_undo() 
    123         assert ef.size() == 1 
    124  
    125         get_undo_manager().undo_transaction() 
    126         assert not get_undo_manager().can_undo() 
    127         assert get_undo_manager().can_redo() 
    128         assert ef.size() == 0 
    129  
    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          
    136113 
    137114# vim:sw=4:et 
  • gaphor/trunk/gaphor/UML/tests/test_properties.py

    r1176 r1219  
    374374        assert b.is_unlinked 
    375375 
    376     def test_undo_attribute(self): 
    377         import types 
    378         from gaphor.services.undomanager import get_undo_manager 
    379         undo_manager = get_undo_manager() 
    380  
    381         class A(Element): 
    382             attr = attribute('attr', types.StringType, default='default') 
    383  
    384         a = A() 
    385         assert a.attr == 'default', a.attr 
    386         undo_manager.begin_transaction() 
    387         a.attr = 'five' 
    388  
    389         undo_manager.commit_transaction() 
    390         assert a.attr == 'five' 
    391  
    392         undo_manager.undo_transaction() 
    393         assert a.attr == 'default', a.attr 
    394  
    395         undo_manager.redo_transaction() 
    396         assert a.attr == 'five' 
    397  
    398     def test_undo_aassociation_1_x(self): 
    399         from gaphor.services.undomanager import get_undo_manager 
    400         undo_manager = get_undo_manager() 
    401  
    402         class A(Element): pass 
    403         class B(Element): pass 
    404  
    405         A.one = association('one', B, 0, 1, opposite='two') 
    406         B.two = association('two', A, 0, 1) 
    407  
    408         a = A() 
    409         b = B() 
    410  
    411         assert a.one is None 
    412         assert b.two is None 
    413  
    414         undo_manager.begin_transaction() 
    415         a.one = b 
    416  
    417         undo_manager.commit_transaction() 
    418         assert a.one is b 
    419         assert b.two is a 
    420  
    421         undo_manager.undo_transaction() 
    422         assert a.one is None 
    423         assert b.two is None 
    424  
    425         undo_manager.redo_transaction() 
    426         assert a.one is b 
    427         assert b.two is a 
    428  
    429     def test_undo_association_1_n(self): 
    430         from gaphor.services.undomanager import get_undo_manager 
    431         undo_manager = get_undo_manager() 
    432   
    433         class A(Element): pass 
    434         class B(Element): pass 
    435  
    436         A.one = association('one', B, lower=0, upper=1, opposite='two') 
    437         B.two = association('two', A, lower=0, upper='*', opposite='one') 
    438  
    439         a1 = A() 
    440         a2 = A() 
    441         b1 = B() 
    442         b2 = B() 
    443  
    444  
    445         undo_manager.begin_transaction() 
    446         b1.two = a1 
    447          
    448         undo_manager.commit_transaction() 
    449         assert a1 in b1.two 
    450         assert b1 is a1.one 
    451  
    452         undo_manager.undo_transaction() 
    453         assert len(b1.two) == 0 
    454         assert a1.one is None 
    455  
    456         undo_manager.redo_transaction() 
    457         assert a1 in b1.two 
    458         assert b1 is a1.one 
    459  
    460         undo_manager.begin_transaction() 
    461         b1.two = a2 
    462  
    463         undo_manager.commit_transaction() 
    464         assert a1 in b1.two 
    465         assert a2 in b1.two 
    466         assert b1 is a1.one 
    467         assert b1 is a2.one 
    468  
    469376 
    470377# vim:sw=4:et:ai 
  • gaphor/trunk/gaphor/__init__.py

    r1200 r1219  
    4242 
    4343 
    44 def new_main(gaphor_file=None): 
     44def main(gaphor_file=None): 
    4545    """ 
    46     Not yet used. see main() below. 
     46    Start the main application by initiating and running 
     47    gaphor.application.Application.  
    4748    """ 
     49    import pkg_resources 
     50 
     51    resource('DataDir', os.path.join(pkg_resources.get_distribution('gaphor').location, 'gaphor', 'data')) 
     52 
    4853    from gaphor.application import Application 
    4954    Application.init() 
    5055 
    51     # backwards compatible 
    52     main_window = resource("MainWindow", Application.main_window) 
    53  
     56    main_window = resource('MainWindow') 
    5457    if gaphor_file: 
    5558        main_window.set_filename(gaphor_file) 
     
    6164 
    6265 
    63 def main(gaphor_file=None): 
    64     """ 
    65     Start the interactive application. 
    66  
    67     This involves importing plugins and creating the main window. 
    68     """ 
    69     import pkg_resources 
    70  
    71     resource('Version', pkg_resources.get_distribution('gaphor').version) 
    72     resource('DataDir', os.path.join(pkg_resources.get_distribution('gaphor').location, 'gaphor', 'data')) 
    73  
    74     # Import GUI stuff here, since the user might not need all the GUI stuff 
    75     import gtk 
    76     import ui 
    77     import adapters 
    78     import actions 
    79     # Load plugin definitions: 
    80     import services.pluginmanager 
    81     import services.undomanager 
    82  
    83     from ui.mainwindow import MainWindow 
    84  
    85     resource('PluginManager').init(None) 
    86  
    87     ui.load_accel_map() 
    88  
    89     # should we set a default icon here or something? 
    90     main_window = resource(MainWindow) 
    91     main_window.construct() 
    92  
    93     # When the state changes to CLOSED, quit the application 
    94     main_window.connect(lambda win: win.get_state() == MainWindow.STATE_CLOSED and gtk.main_quit()) 
    95  
    96     if gaphor_file: 
    97         main_window.set_filename(gaphor_file) 
    98         main_window.execute_action('FileRevert') 
    99     else: 
    100         main_window.execute_action('FileNew') 
    101  
    102     gtk.main() 
    103     #gtk.threads_leave() 
    104  
    105     resource.save() 
    106  
    107     ui.save_accel_map() 
    108  
    109     log.info('Bye!') 
    110  
    111  
    11266# TODO: Remove this 
    11367import __builtin__ 
  • gaphor/trunk/gaphor/actions/__init__.py

    r1121 r1219  
    22Actions are used by the user interface to execute user events. 
    33""" 
    4  
    5 import diagramactions 
    6 import editoractions 
    7 import mainactions 
    8  
    9 import itemactions 
    10 import placementactions 
  • gaphor/trunk/gaphor/actions/diagramactions.py

    r1170 r1219  
    99from gaphor import resource 
    1010from gaphor import UML 
    11 from gaphor.undomanager import get_undo_manager, transactional 
     11from gaphor.transaction import Transaction, transactional 
    1212from gaphor.misc.action import Action, CheckAction, RadioAction 
    1313from gaphor.misc.action import register_action as _register_action 
     
    145145 
    146146        if view.is_focus(): 
    147             get_undo_manager().begin_transaction() 
     147            tx = Transaction() 
    148148            try: 
    149149                items = view.selected_items 
     
    154154                    i.unlink() 
    155155            finally: 
    156                 get_undo_manager().commit_transaction() 
     156                tx.commit() 
    157157     
    158158    def may_remove_from_model(self, view): 
  • gaphor/trunk/gaphor/actions/mainactions.py

    r1190 r1219  
    88import gtk 
    99import gc 
    10 from threading import Thread 
    11  
     10from gaphor.application import Application 
    1211from gaphor import resource 
    1312from gaphor import UML 
    1413from gaphor import diagram 
    15 from gaphor.undomanager import get_undo_manager 
    1614from gaphor.misc.action import Action, CheckAction, RadioAction, register_action 
    1715from gaphor.misc.action import DynamicMenu, ObjectAction, register_slot 
     
    2321 
    2422DEFAULT_EXT='.gaphor' 
     23 
     24def get_undo_manager(): 
     25    return Application.get_service('undo_manager') 
    2526 
    2627def show_status_window(title, message, parent=None, queue=None): 
     
    391392    def execute(self): 
    392393        logo = gtk.gdk.pixbuf_new_from_file (resource('DataDir') + '/pixmaps/logo.png') 
    393         version = resource('Version') 
     394        version = Application.distribution.version 
    394395        about = gtk.Dialog("About Gaphor", self._window.get_window(), gtk.DIALOG_MODAL, (gtk.STOCK_OK, gtk.RESPONSE_OK)) 
    395396        about.set_default_response(gtk.RESPONSE_OK) 
  • gaphor/trunk/gaphor/application.py

    r1188 r1219  
    1515from gaphor.interfaces import IService 
    1616 
    17 import gaphor.ui 
    18 from gaphor.ui import mainwindow, load_accel_map, save_accel_map 
     17import gaphor.UML 
     18 
     19# Backwards compat 
     20from gaphor import resource 
    1921 
    2022class _Application(object): 
     
    2426    def __init__(self): 
    2527        self.services = { 
    26             'main_window': mainwindow.MainWindow(), 
    2728            'element_factory': gaphor.UML.ElementFactory() 
    2829        } 
    2930     
    30     def __getattr__(self, key): 
    31         return self.services[key] 
     31#    def __getattr__(self, key): 
     32#        return self.services[key] 
    3233 
    3334    def init(self): 
     
    3536        Initialize the application. 
    3637        """ 
    37         load_accel_map() 
    38         import gaphor.adapters 
    39         import gaphor.actions 
     38        #import gaphor.adapters 
     39        #import gaphor.actions 
    4040        self.load_services() 
    41         self.main_window.construct() 
    42         main_window.connect(lambda win: win.get_state() == MainWindow.STATE_CLOSED and gtk.main_quit()) 
    4341 
    4442    def load_services(self): 
     
    4947        Service should provide an interface gaphor.interfaces.IService. 
    5048        """ 
     49        services = [] 
    5150        for ep in pkg_resources.iter_entry_points('gaphor.services'): 
    5251            #print ep, dir(ep) 
     
    5655                raise 'MisConfigurationException', 'Entry point %s doesn''t provide IService' % ep.name 
    5756            srv = cls() 
     57            services.append((ep.name, srv)) 
     58 
     59        for name, srv in services: 
     60            log.debug('initializing service.%s' % name) 
    5861            srv.init(self) 
    59             print 'service', srv 
    60             component.provideUtility(srv, IService, ep.name) 
     62            component.provideUtility(srv, IService, name) 
     63 
     64    distribution = property(lambda s: pkg_resources.get_distribution('gaphor'), 
     65                            doc='Get the PkgResources distribution for Gaphor') 
    6166 
    6267    def get_service(self, name): 
    63         component.getUtility(IService, name) 
     68        return component.getUtility(IService, name) 
    6469 
    6570    def run(self): 
     
    6772 
    6873    def shutdown(self): 
    69         save_accel_map() 
     74        pass # for each IService: shutdown 
    7075 
    7176# Make sure there is only one! 
  • gaphor/trunk/gaphor/data/plugins/plugineditor/plugineditor.py

    r399 r1219  
    88import pango 
    99import gtk 
     10from zope import component 
    1011import gaphor 
     12from gaphor.interfaces import IService 
    1113from gaphor.ui.abstractwindow import AbstractWindow 
    1214from gaphor.plugin import resource 
     
    8587 
    8688    def update(self): 
    87         manager = resource('PluginManager') 
     89        manager = component.getUtility(IService, 'plugin_manager') 
    8890        model = self.model 
    8991 
  • gaphor/trunk/gaphor/data/plugins/pynsource/engineer.py

    r543 r1219  
    3535         
    3636        try: 
    37             self._root_package = UML.select(lambda e: isinstance(e, UML.Package) and not e.namespace)[0] 
     37            self._root_package = UML.lselect(lambda e: isinstance(e, UML.Package) and not e.namespace)[0] 
    3838        except IndexError: 
    3939            pass # running as test? 
     
    9191                except KeyError, e: 
    9292                    print 'No class found named', superclassname 
    93                     others = UML.select(lambda e: isinstance(e, UML.Class) and e.name == superclassname) 
     93                    others = UML.lselect(lambda e: isinstance(e, UML.Class) and e.name == superclassname) 
    9494                    if others: 
    9595                        superclass = others[0] 
     
    127127        except KeyError, e: 
    128128            print 'No class found named', classname 
    129             others = UML.select(lambda e: isinstance(e, UML.Class) and e.name == classname) 
     129            others = UML.lselect(lambda e: isinstance(e, UML.Class) and e.name == classname) 
    130130            if others: 
    131131                superclass = others[0] 
  • gaphor/trunk/gaphor/diagram/__init__.py

    r1193 r1219  
    9090 
    9191 
    92 ## 
    93 ## Direct revert-statements from gaphas to the undomanager 
    94 ### 
    95  
    96 from gaphas import state 
    97 from gaphor.undomanager import get_undo_manager, transactional 
    98  
    99 state.observers.add(state.revert_handler) 
    100  
    101 def _undo_handler(event): 
    102     get_undo_manager().add_undo_action(lambda: state.saveapply(*event)); 
    103  
    104 state.subscribers.add(_undo_handler) 
    105  
    10692# vim:sw=4:et 
  • gaphor/trunk/gaphor/diagram/comment.py

    r1201 r1219  
    3333 
    3434    def on_subject_notify(self, pspec): 
    35         """See DiagramItem.on_subject_notify().""" 
     35        """ 
     36        See DiagramItem.on_subject_notify(). 
     37        """ 
    3638        ElementItem.on_subject_notify(self, pspec, ('body',)) 
    3739 
     
    4143 
    4244    def on_subject_notify__body(self, subject, pspec): 
    43         print 'on_subject_notify__body: %s' % self.subject.body 
    4445        #self.sbody.set_text(self.subject.body or '') 
    4546        self.request_update() 
  • gaphor/trunk/gaphor/interfaces.py

    r1201 r1219  
    1515        Initialize the service, this method is called after all services 
    1616        are instantiated. 
     17        """ 
     18 
     19    def shutdown(self): 
     20        """ 
     21        Shutdown the services, free resources. 
    1722        """ 
    1823 
  • gaphor/trunk/gaphor/services/tests/test_undomanager.py

    r1171 r1219  
    55import unittest 
    66from gaphor.services.undomanager import UndoManager 
     7from gaphor.transaction import Transaction 
     8 
    79 
    810class TestUndoManager(unittest.TestCase): 
     
    1113 
    1214        undo_manager = UndoManager() 
     15        undo_manager.init(None) 
     16 
    1317        assert undo_manager._transaction_depth == 0 
    1418        assert not undo_manager._current_transaction 
    1519 
    16         undo_manager.begin_transaction() 
     20        #undo_manager.begin_transaction() 
     21        tx = Transaction() 
     22 
    1723        assert undo_manager._transaction_depth == 1 
    1824        assert undo_manager._current_transaction 
    1925 
    2026        current = undo_manager._current_transaction 
    21         undo_manager.begin_transaction() 
    22         assert undo_manager._transaction_depth == 2 
    23         assert undo_manager._current_transaction is current 
    24  
    25         undo_manager.commit_transaction() 
     27        #undo_manager.begin_transaction() 
     28        tx2 = Transaction() 
     29        #assert undo_manager._transaction_depth == 2 
    2630        assert undo_manager._transaction_depth == 1 
    2731        assert undo_manager._current_transaction is current 
    2832 
    29         undo_manager.commit_transaction() 
     33        #undo_manager.commit_transaction() 
     34        tx2.commit() 
     35 
     36        assert undo_manager._transaction_depth == 1 
     37        assert undo_manager._current_transaction is current 
     38 
     39        #undo_manager.commit_transaction() 
     40        tx.commit() 
    3041        assert undo_manager._transaction_depth == 0 
    3142        assert undo_manager._current_transaction is None 
     
    3344    def test_not_in_transaction(self): 
    3445        undo_manager = UndoManager() 
     46        undo_manager.init(None) 
    3547 
    3648        action = object() 
     
    5870 
    5971        undo_manager = UndoManager() 
    60  
    61         undo_manager.begin_transaction() 
     72        undo_manager.init(None) 
     73 
     74        #undo_manager.begin_transaction() 
     75        tx = Transaction() 
    6276        undo_manager.add_undo_action(undo_action) 
    6377        assert undo_manager._current_transaction 
     
    6579        assert len(undo_manager._current_transaction._actions) == 1 
    6680 
    67         undo_manager.commit_transaction() 
     81        #undo_manager.commit_transaction() 
     82        tx.commit() 
    6883 
    6984        undo_manager.undo_transaction() 
     
    8095        assert undone[0] == -1, undone 
    8196 
    82  
     97    def test_undo_attribute(self): 
     98        import types 
     99        from gaphor.UML.properties import attribute 
     100        from gaphor.UML.element import Element 
     101        undo_manager = UndoManager() 
     102        undo_manager.init(None) 
     103 
     104        class A(Element): 
     105            attr = attribute('attr', types.StringType, default='default') 
     106 
     107        a = A() 
     108        assert a.attr == 'default', a.attr 
     109        undo_manager.begin_transaction() 
     110        a.attr = 'five' 
     111 
     112        undo_manager.commit_transaction() 
     113        assert a.attr == 'five' 
     114 
     115        undo_manager.undo_transaction() 
     116        assert a.attr == 'default', a.attr 
     117 
     118        undo_manager.redo_transaction() 
     119        assert a.attr == 'five' 
     120 
     121    def test_undo_aassociation_1_x(self): 
     122        from gaphor.UML.properties import association 
     123        from gaphor.UML.element import Element 
     124        undo_manager = UndoManager() 
     125        undo_manager.init(None) 
     126 
     127        class A(Element): pass 
     128        class B(Element): pass 
     129 
     130        A.one = association('one', B, 0, 1, opposite='two') 
     131        B.two = association('two', A, 0, 1) 
     132 
     133        a = A() 
     134        b = B() 
     135 
     136        assert a.one is None 
     137        assert b.two is None 
     138 
     139        undo_manager.begin_transaction() 
     140        a.one = b 
     141 
     142        undo_manager.commit_transaction() 
     143        assert a.one is b 
     144        assert b.two is a 
     145 
     146        undo_manager.undo_transaction() 
     147        assert a.one is None 
     148        assert b.two is None 
     149 
     150        undo_manager.redo_transaction() 
     151        assert a.one is b 
     152        assert b.two is a 
     153 
     154    def test_undo_association_1_n(self): 
     155        from gaphor.UML.properties import association 
     156        from gaphor.UML.element import Element 
     157        undo_manager = UndoManager() 
     158        undo_manager.init(None) 
     159  
     160        class A(Element): pass 
     161        class B(Element): pass 
     162 
     163        A.one = association('one', B, lower=0, upper=1, opposite='two') 
     164        B.two = association('two', A, lower=0, upper='*', opposite='one') 
     165 
     166        a1 = A() 
     167        a2 = A() 
     168        b1 = B() 
     169        b2 = B() 
     170 
     171 
     172        undo_manager.begin_transaction() 
     173        b1.two = a1 
     174         
     175        undo_manager.commit_transaction() 
     176        assert a1 in b1.two 
     177        assert b1 is a1.one 
     178 
     179        undo_manager.undo_transaction() 
     180        assert len(b1.two) == 0 
     181        assert a1.one is None 
     182 
     183        undo_manager.redo_transaction() 
     184        assert a1 in b1.two 
     185        assert b1 is a1.one 
     186 
     187        undo_manager.begin_transaction() 
     188        b1.two = a2 
     189 
     190        undo_manager.commit_transaction() 
     191        assert a1 in b1.two 
     192        assert a2 in b1.two 
     193        assert b1 is a1.one 
     194        assert b1 is a2.one 
     195 
     196    def test_element_factory_undo(self): 
     197        from gaphor.UML.elementfactory import ElementFactory 
     198        from gaphor.UML.element import Element 
     199        undo_manager = UndoManager() 
     200        undo_manager.init(None) 
     201        undo_manager.begin_transaction() 
     202        ef = ElementFactory() 
     203        p = ef.create(Element) 
     204 
     205        assert undo_manager.can_undo() 
     206 
     207        undo_manager.commit_transaction() 
     208        assert undo_manager.can_undo() 
     209        assert ef.size() == 1 
     210 
     211        undo_manager.undo_transaction() 
     212        assert not undo_manager.can_undo() 
     213        assert undo_manager.can_redo() 
     214        assert ef.size() == 0 
     215 
     216        undo_manager.redo_transaction() 
     217        assert undo_manager.can_undo() 
     218        assert not undo_manager.can_redo() 
     219        assert ef.size() == 1 
     220        assert ef.lselect()[0] is p 
     221         
    83222# vim:sw=4:et 
  • gaphor/trunk/gaphor/services/undomanager.py

    r1177 r1219  
    1818from zope import component 
    1919from gaphor.interfaces import IService, IServiceEvent 
    20  
    21 def get_undo_manager(): 
    22     """ 
    23     Return the default undo manager. 
    24     """ 
    25     return _default_undo_manager 
    26  
    27  
    28 def transactional(func): 
    29     """ 
    30     Descriptor. Begins a transaction around the method/function. 
    31  
    32     TODO: In casse of an exception, roll back the transaction if the transaction 
    33     level == 1. 
    34     """ 
    35     def wrapper(*args, **kwargs): 
    36         undo_manager = get_undo_manager() 
    37         undo_manager.begin_transaction() 
    38         try: 
    39             func(*args, **kwargs) 
    40         except: 
    41             undo_manager.rollback_transaction() 
    42             raise 
    43         else: 
    44             undo_manager.commit_transaction() 
    45     return wrapper 
    46  
    47  
    48 class TransactionError(Exception): 
    49  
    50     def __init__(self, msg): 
    51         self.args = msg 
     20from gaphor.event import TransactionBegin, TransactionCommit, TransactionRollback 
     21from gaphor.transaction import TransactionError, transactional 
     22 
     23from gaphor.UML.event import ElementCreateEvent, ElementDeleteEvent, \ 
     24                             FlushFactoryEvent, ModelFactoryEvent, \ 
     25                             AttributeChangeEvent, AssociationSetEvent, \ 
     26                             AssociationAddEvent, AssociationDeleteEvent 
     27from gaphor.UML.interfaces import IElementCreateEvent, IElementDeleteEvent, \ 
     28                                  IAttributeChangeEvent, IAssociationChangeEvent 
    5229 
    5330 
     
    11289    def init(self, app): 
    11390        self._app = app 
     91        component.provideHandler(self.begin_transaction) 
     92        component.provideHandler(self.commit_transaction) 
     93        component.provideHandler(self.rollback_transaction) 
     94        self._provide_undo_handlers() 
     95 
     96    def shutdown(self): 
     97        pass 
    11498 
    11599    def clear_undo_stack(self): 
     
    120104        del self._redo_stack[:] 
    121105 
    122     def begin_transaction(self): 
     106    @component.adapter(TransactionBegin) 
     107    def begin_transaction(self, event=None): 
    123108        """ 
    124109        Add an action to the current transaction 
     
    143128        component.handle(UndoManagerStateChanged(self)) 
    144129 
    145     def commit_transaction(self): 
     130    @component.adapter(TransactionCommit) 
     131    def commit_transaction(self, event=None): 
    146132        #log.debug('commit_transaction') 
    147133        if not self._current_transaction: 
     
    159145        component.handle(UndoManagerStateChanged(self)) 
    160146 
    161     def rollback_transaction(self): 
     147    @component.adapter(TransactionRollback) 
     148    def rollback_transaction(self, event=None): 
    162149        """ 
    163150        Roll back the transaction we're in. 
     
    230217        return bool(self._redo_stack) 
    231218 
    232  
    233 from gaphor import resource 
    234 _default_undo_manager = resource(UndoManager) 
    235  
     219    ## 
     220    ## Undo Handlers 
     221    ## 
     222 
     223    def _provide_undo_handlers(self): 
     224        component.provideHandler(self.undo_create_event) 
     225        component.provideHandler(self.undo_delete_event) 
     226        component.provideHandler(self.undo_attribute_change_event) 
     227        component.provideHandler(self.undo_association_set_event) 
     228        component.provideHandler(self.undo_association_add_event) 
     229        component.provideHandler(self.undo_association_delete_event) 
     230 
     231        # 
     232        # Direct revert-statements from gaphas to the undomanager 
     233        from gaphas import state 
     234        state.observers.add(state.revert_handler) 
     235 
     236        def _undo_handler(event): 
     237            self.add_undo_action(lambda: state.saveapply(*event)); 
     238 
     239        state.subscribers.add(_undo_handler) 
     240 
     241 
     242    @component.adapter(IElementCreateEvent) 
     243    def undo_create_event(self, event): 
     244        factory = event.service 
     245        element = event.element 
     246        def _undo_create_event(): 
     247            try: 
     248                del factory._elements[element.id] 
     249            except KeyError: 
     250                pass # Key was probably already removed in an unlink call 
     251            factory.notify(element, 'remove') 
     252            component.handle(ElementDeleteEvent(factory, element)) 
     253        self.add_undo_action(_undo_create_event) 
     254 
     255 
     256    @component.adapter(IElementDeleteEvent) 
     257    def undo_delete_event(self, event): 
     258        factory = event.service 
     259        element = event.element 
     260        def _undo_delete_event(): 
     261            factory._elements[element.id] = element 
     262            factory.notify(element, 'create') 
     263            component.handle(ElementCreateEvent(factory, element)) 
     264        self.add_undo_action(_undo_delete_event) 
     265 
     266 
     267    @component.adapter(IAttributeChangeEvent) 
     268    def undo_attribute_change_event(self, event): 
     269        attribute = event.property 
     270        obj = event.element 
     271        value = event.old_value 
     272        def _undo_attribute_change_event(): 
     273            attribute._set(obj, value) 
     274        self.add_undo_action(_undo_attribute_change_event) 
     275 
     276 
     277    @component.adapter(AssociationSetEvent) 
     278    def undo_association_set_event(self, event): 
     279        association = event.property 
     280        obj = event.element 
     281        value = event.old_value 
     282        def _undo_association_set_event(): 
     283            #print 'undoing action', obj, value 
     284            # Tell the assoctaion it should not need to let the opposite 
     285            # side connect (it has it's own signal) 
     286            association._set(obj, value, from_opposite=True) 
     287        self.add_undo_action(_undo_association_set_event) 
     288 
     289 
     290    @component.adapter(AssociationAddEvent) 
     291    def undo_association_add_event(self, event): 
     292        association = event.property 
     293        obj = event.element 
     294        value = event.new_value 
     295        def _undo_association_add_event(): 
     296            #print 'undoing action', obj, value 
     297            # Tell the assoctaion it should not need to let the opposite 
     298            # side connect (it has it's own signal) 
     299            association._del(obj, value, from_opposite=True) 
     300        self.add_undo_action(_undo_association_add_event) 
     301 
     302 
     303    @component.adapter(AssociationDeleteEvent) 
     304    def undo_association_delete_event(self, event): 
     305        association = event.property 
     306        obj = event.element 
     307        value = event.old_value 
     308        def _undo_association_delete_event(): 
     309            #print 'undoing action', obj, value 
     310            # Tell the assoctaion it should not need to let the opposite 
     311            # side connect (it has it's own signal) 
     312            association._set(obj, value, from_opposite=True) 
     313        self.add_undo_action(_undo_association_delete_event) 
     314 
     315 
     316# vim:sw=4:et:ai 
  • gaphor/trunk/gaphor/storage.py

    r1169 r1219  
    2626from gaphor import parser 
    2727from gaphor import diagram 
     28from gaphor.application import Application 
    2829from gaphor.diagram import items 
    2930from gaphor import resource 
     
    134135    writer.startDocument() 
    135136    writer.startElement('gaphor', { 'version': FILE_FORMAT_VERSION, 
    136                                     'gaphor-version': resource('Version') }) 
     137                                    'gaphor-version': Application.distribution.version }) 
    137138 
    138139    size = factory.size() 
  • gaphor/trunk/gaphor/ui/__init__.py