Changeset 1170
- Timestamp:
- 03/21/07 00:45:08 (1 year ago)
- Files:
-
- gaphor/trunk/doc/services.txt (added)
- gaphor/trunk/gaphor/UML/elementfactory.py (modified) (8 diffs)
- gaphor/trunk/gaphor/UML/event.py (modified) (4 diffs)
- gaphor/trunk/gaphor/UML/interfaces.py (modified) (2 diffs)
- gaphor/trunk/gaphor/UML/tests/test_elementfactory.py (modified) (2 diffs)
- gaphor/trunk/gaphor/__init__.py (modified) (2 diffs)
- gaphor/trunk/gaphor/actions/diagramactions.py (modified) (1 diff)
- gaphor/trunk/gaphor/actions/mainactions.py (modified) (2 diffs)
- gaphor/trunk/gaphor/diagram/__init__.py (modified) (1 diff)
- gaphor/trunk/gaphor/event.py (modified) (1 diff)
- gaphor/trunk/gaphor/interfaces.py (modified) (1 diff)
- gaphor/trunk/gaphor/services (added)
- gaphor/trunk/gaphor/services/__init__.py (added)
- gaphor/trunk/gaphor/services/pluginmanager.py (moved) (moved from gaphor/trunk/gaphor/pluginmanager.py) (3 diffs)
- gaphor/trunk/gaphor/services/tests (added)
- gaphor/trunk/gaphor/services/tests/test_undomanager.py (moved) (moved from gaphor/trunk/gaphor/tests/test_undomanager.py)
- gaphor/trunk/gaphor/services/undomanager.py (moved) (moved from gaphor/trunk/gaphor/undomanager.py) (13 diffs)
- gaphor/trunk/gaphor/ui/diagramtab.py (modified) (1 diff)
- gaphor/trunk/gaphor/ui/event.py (added)
- gaphor/trunk/gaphor/ui/interfaces.py (added)
- gaphor/trunk/gaphor/ui/mainwindow.py (modified) (3 diffs)
- gaphor/trunk/gaphor/ui/objectinspector.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
gaphor/trunk/gaphor/UML/elementfactory.py
r1121 r1170 3 3 """ 4 4 5 from zope import interface 5 6 from zope import component 6 7 from gaphor.misc import uniqueid, odict … … 8 9 from gaphor.UML.element import Element 9 10 from gaphor.UML.diagram import Diagram 11 from gaphor.UML.interfaces import ICreateElementEvent, IRemoveElementEvent, \ 12 IFlushFactoryEvent, IModelFactoryEvent, \ 13 IService 10 14 from gaphor.UML.event import CreateElementEvent, RemoveElementEvent, \ 11 15 FlushFactoryEvent, ModelFactoryEvent 12 16 13 17 14 class _ UndoCreateAction(object):18 class _xxUndoCreateAction(object): 15 19 16 20 def __init__(self, factory, element): … … 32 36 33 37 34 class _ UndoRemoveAction(object):38 class _xxUndoRemoveAction(object): 35 39 36 40 def __init__(self, factory, element): … … 61 65 (element is None) 62 66 """ 67 interface.implements(IService) 63 68 64 69 def __init__(self): … … 78 83 obj = type(id, self) 79 84 self._elements[id] = obj 80 get_undo_manager().add_undo_action(_UndoCreateAction(self, obj))81 obj.connect('__unlink__', self._ _element_signal)85 #get_undo_manager().add_undo_action(_UndoCreateAction(self, obj)) 86 obj.connect('__unlink__', self._element_signal) 82 87 self.notify(obj, 'create') 83 88 component.handle(CreateElementEvent(self, obj)) … … 197 202 component.handle(ModelFactoryEvent(self)) 198 203 199 def _ _element_signal(self, element, pspec):204 def _element_signal(self, element, pspec): 200 205 """Remove an element from the factory """ 201 206 #log.debug('element %s send signal %s' % (element, name)) … … 204 209 # TODO: make undo action 205 210 del self._elements[element.id] 206 get_undo_manager().add_undo_action(_UndoRemoveAction(self, element))211 #get_undo_manager().add_undo_action(_UndoRemoveAction(self, element)) 207 212 self.notify(element, 'remove') 208 213 component.handle(RemoveElementEvent(self, element)) … … 212 217 # self.notify(element, 'create') 213 218 219 component.provideUtility(ElementFactory(), IService, "element_factory") 220 221 222 @component.adapter(ICreateElementEvent) 223 def undo_create_event(event): 224 factory = event.service 225 element = event.element 226 def _undo_create_event(): 227 try: 228 del factory._elements[element.id] 229 except KeyError: 230 pass # Key was probably already removed in an unlink call 231 factory.notify(element, 'remove') 232 component.handle(RemoveElementEvent(factory, element)) 233 get_undo_manager().add_undo_action(_undo_create_event) 234 235 component.provideHandler(undo_create_event) 236 237 238 @component.adapter(IRemoveElementEvent) 239 def undo_remove_event(event): 240 factory = event.service 241 element = event.element 242 def _undo_remove_event(): 243 factory._elements[element.id] = element 244 factory.notify(element, 'create') 245 component.handle(CreateElementEvent(factory, element)) 246 get_undo_manager().add_undo_action(_undo_remove_event) 247 248 component.provideHandler(undo_remove_event) 249 250 251 # vim:sw=4:et gaphor/trunk/gaphor/UML/event.py
r1121 r1170 26 26 interface.implements(ICreateElementEvent) 27 27 28 def __init__(self, factory, element):29 self. factory = factory28 def __init__(self, service, element): 29 self.service = service 30 30 self.element = element 31 31 … … 34 34 interface.implements(IRemoveElementEvent) 35 35 36 def __init__(self, factory, element):37 self. factory = factory36 def __init__(self, service, element): 37 self.service = service 38 38 self.element = element 39 39 … … 42 42 interface.implements(IModelFactoryEvent) 43 43 44 def __init__(self, factory):45 self. factory = factory44 def __init__(self, service): 45 self.service = service 46 46 47 47 … … 49 49 interface.implements(IFlushFactoryEvent) 50 50 51 def __init__(self, factory):52 self. factory = factory51 def __init__(self, service): 52 self.service = service 53 53 gaphor/trunk/gaphor/UML/interfaces.py
r1121 r1170 4 4 5 5 from zope import interface 6 6 from gaphor.interfaces import IService, IServiceEvent 7 7 8 8 class IElementChangedEvent(interface.Interface): … … 25 25 26 26 27 class IFactoryEvent(interface.Interface): 28 """Events related to creation/deletion of model elements. 29 """ 30 factory = interface.Attribute("The ElementFactory emiting the event") 31 32 33 class IModelFactoryEvent(IFactoryEvent): 27 class IModelFactoryEvent(IServiceEvent): 34 28 """A new model is loaded into the ElementFactory. 35 29 """ 36 30 37 31 38 class IFlushFactoryEvent(I FactoryEvent):32 class IFlushFactoryEvent(IServiceEvent): 39 33 """All elements are removed from the ElementFactory. 40 34 """ 41 35 42 36 43 class IFactoryElementEvent(I FactoryEvent):37 class IFactoryElementEvent(IServiceEvent): 44 38 """Events related to individual model elements. 45 39 """ gaphor/trunk/gaphor/UML/tests/test_elementfactory.py
r1121 r1170 14 14 last_event = None 15 15 16 @component.adapter(I FactoryEvent)16 @component.adapter(IServiceEvent) 17 17 def handler(event): 18 18 global handled, events, last_event … … 111 111 self.assertTrue(IFlushFactoryEvent.providedBy(last_event) ) 112 112 113 def testUndo(self): 114 pass 115 # TODO: implement 116 from gaphor.services.undomanager import get_undo_manager 117 get_undo_manager().begin_transaction() 118 ef = self.factory 119 p = ef.create(Parameter) 120 121 assert get_undo_manager().can_undo() 122 get_undo_manager().commit_transaction() 123 assert get_undo_manager().can_undo() 124 assert ef.size() == 1 125 get_undo_manager().undo_transaction() 126 assert not get_undo_manager().can_undo() 127 assert get_undo_manager().can_redo() 128 gaphor/trunk/gaphor/__init__.py
r1135 r1170 31 31 }) 32 32 33 33 34 class GaphorError(Exception): 34 35 """ … … 50 51 import actions 51 52 # Load plugin definitions: 52 import pluginmanager 53 import services.pluginmanager 54 import services.undomanager 55 53 56 from ui.mainwindow import MainWindow 54 57 gaphor/trunk/gaphor/actions/diagramactions.py
r1132 r1170 35 35 36 36 register_action(CloseTabAction) 37 38 39 class UndoStackAction(Action):40 """Dummy action that triggers the undo and redo actions to update41 themselves.42 """43 id = 'EditUndoStack'44 45 def init(self, window):46 pass47 48 register_action(UndoStackAction)49 50 51 class UndoAction(Action):52 id = 'EditUndo'53 stock_id = 'gtk-undo'54 label = '_Undo'55 tooltip = 'Undo the most recent changes'56 accel = 'C-z'57 58 # TODO: check if the diagram can undo.59 60 def init(self, window):61 self._window = window62 63 def update(self):64 diagram_tab = self._window.get_current_diagram_tab()65 self.sensitive = diagram_tab and get_undo_manager().can_undo()66 67 def execute(self):68 get_undo_manager().undo_transaction()69 self.update()70 self._window.execute_action('EditUndoStack')71 72 register_action(UndoAction, 'EditUndoStack')73 74 75 class RedoAction(Action):76 id = 'EditRedo'77 stock_id = 'gtk-redo'78 tooltip = 'Redo the undone changes'79 accel = 'C-r'80 81 def init(self, window):82 self._window = window83 84 def update(self):85 diagram_tab = self._window.get_current_diagram_tab()86 self.sensitive = diagram_tab and get_undo_manager().can_redo()87 88 def execute(self):89 get_undo_manager().redo_transaction()90 self.update()91 self._window.execute_action('EditUndoStack')92 93 register_action(RedoAction, 'EditUndoStack')94 95 37 96 38 class ToolChangeAction(Action): gaphor/trunk/gaphor/actions/mainactions.py
r1121 r1170 600 600 601 601 class UndoStackAction(Action): 602 """Dummy action that triggers the undo and redo actions to update 602 """ 603 Dummy action that triggers the undo and redo actions to update 603 604 themselves. 604 605 """ … … 627 628 def execute(self): 628 629 get_undo_manager().undo_transaction() 629 #self.update()630 self.update() 630 631 self._window.execute_action('UndoStack') 631 632 gaphor/trunk/gaphor/diagram/__init__.py
r1135 r1170 90 90 91 91 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 print 'state', state 100 state.observers.add(state.revert_handler) 101 102 def _undo_handler(event): 103 get_undo_manager().add_undo_action(lambda: state.saveapply(*event)); 104 105 state.subscribers.add(_undo_handler) 106 92 107 # vim:sw=4:et gaphor/trunk/gaphor/event.py
r610 r1170 2 2 from gaphor.interfaces import * 3 3 4 class DiagramItemFocused(object):5 interface.implements(IDiagramElementReceivedFocus)6 7 def __init__(self, diagramItem):8 self.diagramItem = diagramItemgaphor/trunk/gaphor/interfaces.py
r1121 r1170 1 """ 2 Top level interface definitions for Gaphor. 3 """ 4 1 5 from zope import interface 2 from zope import component3 class IGaphorAction(interface.Interface):4 """Action interface for use in Gaphor"""5 6 6 class IMenuAction(interface.Interface):7 """An interface to hook up items to."""8 9 7 10 class TestAdapter(object): 11 def __init__(self, context): 12 self.context = context 8 class IService(interface.Interface): 9 """ 10 Base interface for all services in Gaphor. 11 """ 13 12 14 #component.provideAdapter( 15 #factory=TestAdapter,16 #adapts=[IGaphorAction],17 #provides=IZopeMenu,18 #name="Test adapter name")13 def init(self, application): 14 """ 15 Initialize the service, this method is called after all services 16 are instantiated. 17 """ 19 18 20 #class TestAdapter2(object):21 #def __init__(self, context):22 #self.context = context23 19 24 #component.provideAdapter( 25 #factory=TestAdapter2,26 #adapts=[IGaphorAction],27 #provides=IZopeMenu,28 #name="Test adapter 2 name")20 class IServiceEvent(interface.Interface): 21 """ 22 An event emitted by a service. 23 """ 24 service = interface.Attribute("The service that emits the event") 29 25 30 #class TestAction(object): 31 #interface.implements(IGaphorAction) 32 33 class IDiagramElementReceivedFocus(interface.Interface): 34 """A diagram item received focus""" 35 diagramItem = interface.Attribute("The diagram item that received focus") 36 37 38 class IWidget(interface.Interface): 39 """A GTK widget""" 40 41 class IDetailsPage(IWidget): 42 """A property page which can display itself in a notebook""" 43 26 27 # vim:sw=4:et gaphor/trunk/gaphor/services/pluginmanager.py
r1135 r1170 22 22 User provided plugins overrule the system provided plugins. 23 23 """ 24 import imp 24 25 import os 25 import imp26 26 import os.path 27 27 import glob 28 28 import sys 29 29 from xml.sax import handler, make_parser 30 31 from zope import interface 32 from gaphor.interfaces import IService 33 30 34 from gaphor import resource 31 32 35 from gaphor.parser import ParserException 33 36 from gaphor.misc.action import register_action_for_slot 34 37 from gaphor.misc.odict import odict 38 35 39 36 40 XMLNS='http://gaphor.sourceforge.net/gaphor/plugin' … … 49 53 A plugin represents one plugin loaded from the file system. 50 54 """ 55 interface.implements(IService) 51 56 52 57 def __init__(self): … … 60 65 self.module = None 61 66 self.status = '' 67 68 def init(self, app): 69 self._app = app 62 70 63 71 def requirements_met(self, manager): gaphor/trunk/gaphor/services/undomanager.py
r1135 r1170 15 15 """ 16 16 17 from zope import interface 18 from zope import component 19 from gaphor.interfaces import IService, IServiceEvent 17 20 18 21 def get_undo_manager(): … … 41 44 42 45 43 class undoableproperty(object):44 """45 Property with state preservation.46 Set and del statements preserve the original value before the operation47 is performed48 """49 50 def __init__(self, fget=None, fset=None, fdel=None, doc=None,51 property=None, undo_manager=None):52 if property:53 self.fget = property.fget54 self.fset = property.fset55 self.fdel = property.fdel56 self.__doc__ = property.__doc__57 else:58 self.fget = fget59 self.fset = fset60 self.fdel = fdel61 self.__doc__ = doc62 self._undo_manager = undo_manager or get_undo_manager()63 64 def _preserve_state(self, obj):65 try:66 val = self.__get__(obj)67 except AttributeError:68 def _del_action():69 action = self._preserve_state(obj)70 self.__delete__(obj)71 return action72 return _del_action73 else:74 def _set_action():75 action = self._preserve_state(obj)76 self.__set__(obj, val)77 return action78 return _set_action79 80 def __get__(self, obj, class_=None):81 if obj:82 return self.fget(obj)83 return self.fget84 85 def __set__(self, obj, value):86 self._undo_manager.add_undo_action(self._preserve_state(obj))87 return self.fset(obj, value)88 89 def __delete__(self, obj):90 self._undo_manager.add_undo_action(self._preserve_state(obj))91 return self.fdel(obj)92 93 94 46 class TransactionError(Exception): 95 47 … … 116 68 return self._actions and True or False 117 69 70 @transactional 118 71 def execute(self): 119 72 self._actions.reverse() 120 contra_transaction = Transaction()121 73 for action in self._actions: 122 74 try: 123 contra_action = action() 124 contra_transaction.add(contra_action or action) 75 action() 125 76 except Exception, e: 126 77 log.error('Error while undoing action %s' % action, e) 127 return contra_transaction 78 79 80 class UndoManagerStateChanged(object): 81 """ 82 Event class used to send state changes on the ndo Manager. 83 """ 84 interface.implements(IServiceEvent) 85 86 def __init__(self, service): 87 self.service = service 88 128 89 129 90 class UndoManager(object): … … 138 99 """ 139 100 101 interface.implements(IService) 102 140 103 def __init__(self): 141 self._in_undo = False142 104 self._undo_stack = [] 143 105 self._redo_stack = [] … … 146 108 self._transaction_depth = 0 147 109 110 def init(self, app): 111 self._app = app 112 148 113 def clear_undo_stack(self): 149 114 self._undo_stack = [] … … 157 122 Add an action to the current transaction 158 123 """ 159 if self._in_undo:160 return161 162 #log.debug('begin_transaction')163 124 if self._current_transaction: 164 125 self._transaction_depth += 1 … … 182 143 183 144 self._current_transaction.add(action) 145 component.handle(UndoManagerStateChanged(self)) 184 146 185 147 def commit_transaction(self): 186 if self._in_undo:187 return188 189 148 #log.debug('commit_transaction') 190 149 if not self._current_transaction: … … 204 163 Roll back the transaction we're in. 205 164 """ 206 if self._in_undo:207 return208 209 165 if not self._current_transaction: 210 166 raise TransactionError, 'No transaction to rollback' … … 215 171 self._current_transaction = None 216 172 # else: mark for rollback? 173 component.handle(UndoManagerStateChanged(self)) 217 174 218 175 def discard_transaction(self): 219 if self._in_undo:220 return221 176 222 177 if not self._current_transaction: … … 226 181 if self._transaction_depth == 0: 227 182 self._current_transaction = None 183 component.handle(UndoManagerStateChanged(self)) 228 184 229 185 def undo_transaction(self): … … 235 191 self.commit_transaction() 236 192 transaction = self._undo_stack.pop() 237 try: 238 self._in_undo = True 239 redo_transaction = transaction.execute() 240 finally: 241 self._in_undo = False 242 self._redo_stack.append(redo_transaction) 193 194 transaction.execute() 195 component.handle(UndoManagerStateChanged(self)) 243 196 244 197 def redo_transaction(self): … … 247 200 248 201 transaction = self._redo_stack.pop() 249 try: 250 self._in_undo = True 251 undo_transaction = transaction.execute() 252 finally: 253 self._in_undo = False 254 self._undo_stack.append(undo_transaction) 202 203 transaction.execute() 204 component.handle(UndoManagerStateChanged(self)) 255 205 256 206 def in_transaction(self): … … 264 214 265 215 266 # Register as resource: 267 import gaphor 268 _default_undo_manager = gaphor.resource(UndoManager) 269 del gaphor 270 216 from gaphor import resource 217 _default_undo_manager = resource(UndoManager) 218 gaphor/trunk/gaphor/ui/diagramtab.py
r1121 r1170 13 13 from gaphor.ui.abstractwindow import AbstractWindow 14 14 15 from gaphor.event import DiagramItemFocused15 from event import DiagramItemFocused 16 16 from zope import component 17 17 gaphor/trunk/gaphor/ui/mainwindow.py
r1121 r1170 17 17 18 18 19 from gaphor.interfaces import * 19 from interfaces import IDiagramElementReceivedFocus 20 from gaphor.interfaces import IServiceEvent 20 21 from zope import component 21 22 … … 457 458 # #resource.set('ui.toolbox.%s' % box_name, visible, persistent=True) 458 459 459 def on_undo(self, *args):460 self.execute_action('UndoStack')461 462 460 # def on_transient_window_closed(self, window): 463 461 # assert window in self._transient_windows … … 474 472 475 473 gtk.accel_map_add_filter('gaphor') 474 475 @component.adapter(IServiceEvent) 476 def on_undo(*args): 477 resource(MainWindow).execute_action('UndoStack') 478 479 component.provideHandler(on_undo) 480 gaphor/trunk/gaphor/ui/objectinspector.py
r1121 r1170 1 1 import gtk 2 from gaphor.interfaces import *2 from interfaces import * 3 3 from gaphor.diagram import items 4 4 from zope import component
