Changeset 1262
- Timestamp:
- 05/09/07 21:10:43 (1 year ago)
- Files:
-
- gaphor/trunk/TODO (modified) (1 diff)
- gaphor/trunk/gaphor/actions/mainactions.py (modified) (6 diffs)
- gaphor/trunk/gaphor/actions/placementactions.py (modified) (1 diff)
- gaphor/trunk/gaphor/application.py (modified) (3 diffs)
- gaphor/trunk/gaphor/services/guimanager.py (modified) (3 diffs)
- gaphor/trunk/gaphor/ui/consolewindow.py (modified) (3 diffs)
- gaphor/trunk/gaphor/ui/mainwindow.py (modified) (23 diffs)
- gaphor/trunk/gaphor/ui/tests/test_mainwindow.py (modified) (1 diff)
- gaphor/trunk/gaphor/ui/toolbox.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
gaphor/trunk/TODO
r1250 r1262 6 6 - bug in zope.component package: in zope.component.globalregistry.py zope.testing is included. This package is only a dependency for the [test] setting. zope.testing is not mandatory. 7 7 Use a more recent version 8 9 - Placement actions should be instantiated on a per-view basis. the view's 10 action_group should be added/removed when visible/hidden. 11 12 - Toolbox should proxy gtk.Action in stead of using the Menu Factory. 13 14 - fix settings for new actions (PlacementEvent?) by using subscribtions or handlers. 8 15 9 16 - filename should not be part of the main window gaphor/trunk/gaphor/actions/mainactions.py
r1244 r1262 1 # vim: sw=4:et2 1 """ 3 2 Main window actions. … … 105 104 #stereotypes.name = 'Stereotypes' 106 105 self._window.set_filename(None) 107 self._window.set_message(_('Created a new model'))106 #self._window.set_message(_('Created a new model')) 108 107 element_factory.notify_model() 109 108 … … 155 154 error_handler(message='Error while loading model from file %s' % filename, exc_info=worker.exc_info) 156 155 157 self._window.set_message('Model loaded successfully')156 #self._window.set_message('Model loaded successfully') 158 157 model = self._window.get_model() 159 158 view = self._window.get_tree_view() … … 347 346 ew.construct() 348 347 self._window.add_transient_window(ew) 349 self._window.set_message('Editor launched')348 #self._window.set_message('Editor launched') 350 349 351 350 register_action(OpenEditorWindowAction) … … 366 365 ew.construct() 367 366 self._window.add_transient_window(ew) 368 self._window.set_message('Console launched')367 #self._window.set_message('Console launched') 369 368 370 369 register_action(OpenConsoleWindowAction) … … 723 722 register_slot('RecentFiles', RecentFilesSlot) 724 723 724 # vim: sw=4:et gaphor/trunk/gaphor/actions/placementactions.py
r1239 r1262 89 89 90 90 def item_factory(self): 91 """Create a new instance of the item and return it.""" 91 """ 92 Create a new instance of the item and return it. 93 """ 92 94 subject = None 93 95 if self.subject_type: gaphor/trunk/gaphor/application.py
r1256 r1262 24 24 self._uninitialized_services = {} 25 25 26 def init(self ):26 def init(self, services=None): 27 27 """ 28 28 Initialize the application. 29 29 """ 30 self.load_services( )30 self.load_services(services) 31 31 self.init_all_services() 32 32 33 def load_services(self ):33 def load_services(self, services=None): 34 34 """ 35 35 Load services from resources. … … 44 44 if not IService.implementedBy(cls): 45 45 raise 'MisConfigurationException', 'Entry point %s doesn''t provide IService' % ep.name 46 srv = cls() 47 self._uninitialized_services[ep.name] = srv 46 if services is None or ep.name in services: 47 srv = cls() 48 self._uninitialized_services[ep.name] = srv 48 49 49 50 def init_all_services(self): … … 92 93 93 94 def restart(): 95 global Application 94 96 Application.shutdown() 95 97 Application = _Application() gaphor/trunk/gaphor/services/guimanager.py
r1261 r1262 4 4 import pkg_resources 5 5 from zope import interface 6 from gaphor.interfaces import IService 6 from gaphor.interfaces import IService, IActionProvider 7 7 8 8 … … 53 53 uicomp.ui_manager = self.ui_manager 54 54 self._ui_components[ep.name] = uicomp 55 55 if IActionProvider.providedBy(uicomp): 56 uicomp.__ui_merge_id = self.ui_manager.add_ui_from_string(uicomp.menu_xml) 57 self.ui_manager.insert_action_group(uicomp.action_group, -1) 58 56 59 def init_main_window(self): 57 60 from gaphor.ui.accelmap import load_accel_map … … 60 63 61 64 load_accel_map() 62 self._main_window = MainWindow() 63 # Backwards compat 64 # TODO: remove 65 #from gaphor import resource 66 #resource.set(MainWindow, self._main_window) 67 #resource.set('MainWindow', self._main_window) 65 self._main_window = self._ui_components['mainwindow'] 68 66 self._main_window.construct() 69 67 70 68 # When the state changes to CLOSED, quit the application 71 self._main_window.connect(lambda win: win.get_state() == MainWindow.STATE_CLOSED and gtk.main_quit()) 72 69 #self._main_window.connect(lambda win: win.get_state() == MainWindow.STATE_CLOSED and gtk.main_quit()) 73 70 def init_actions(self): 74 71 from gaphor.actions import diagramactions, editoractions, mainactions gaphor/trunk/gaphor/ui/consolewindow.py
r1260 r1262 4 4 import sys 5 5 import gtk 6 from zope import interface 6 7 import gaphor 7 8 from gaphor.interfaces import IActionProvider … … 9 10 from gaphor.action import action, build_action_group 10 11 from gaphor.misc.console import GTKInterpreterConsole 11 from zope import interface12 from toplevelwindow import ToplevelWindow 12 13 13 class ConsoleWindow(object): 14 15 class ConsoleWindow(ToplevelWindow): 14 16 15 interface.implements(IActionProvider , IUIComponent)17 interface.implements(IActionProvider) 16 18 17 19 menu_xml = """ 18 20 <ui> 19 <menubar action="mainwindow">20 <menu name=" _Window" action="Menu">21 <menubar name="mainwindow"> 22 <menu name="WindowMenu"> 21 23 <menuitem name='_Console' action="ConsoleWindow:open" /> 22 24 </menu> 23 25 </menubar> 24 <menubar action="consolewindow">25 <menu name="_File" action=" Menu">26 <menubar name="consolewindow"> 27 <menu name="_File" action="FileMenu"> 26 28 <menuitem name='_Close' action="ConsoleWindow:close" /> 27 29 </menu> … … 45 47 return console 46 48 47 def construct(self):48 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)49 self.window.set_title(self.title)50 self.window.set_size_request(*self.size)51 self.window.set_resizable(True)52 53 vbox = gtk.VBox()54 self.window.add(vbox)55 vbox.show()56 57 self.ui_manager.insert_action_group(self.action_group, 0)58 self.ui_manager.add_ui_from_string(self.menu_xml)59 60 self.window.add_accel_group(self.ui_manager.get_accel_group())61 62 menubar = self.ui_manager.get_widget(self.menubar_path)63 vbox.pack_start(menubar, expand=False)64 65 if self.toolbar_path:66 toolbar = self.ui_manager.get_widget(self.toolbar_path)67 vbox.pack_start(toolbar, expand=False)68 69 vbox.pack_end(self.ui_component(), expand=True)70 71 # TODO: add statusbar72 self.window.show_all()73 74 @action(name='Menu', label='_File')75 def dummy(self): pass76 77 49 @action(name='ConsoleWindow:open', label='Console') 78 50 def open(self): gaphor/trunk/gaphor/ui/mainwindow.py
r1261 r1262 1 2 # vim:sw=4:et 1 """ 2 The main application window. 3 """ 3 4 4 5 import gtk 5 6 6 from zope import interface 7 from gaphor.interfaces import IService, IActionProvider 7 from zope import interface, component 8 from gaphor.interfaces import IActionProvider 9 from interfaces import IUIComponent 8 10 9 11 from gaphor import UML 10 12 from gaphor.core import inject 13 from gaphor.action import action, build_action_group 11 14 from gaphor.i18n import _ 12 15 from gaphor.ui import namespace 13 from gaphor.ui.abstractwindow import AbstractWindow16 #from gaphor.ui.abstractwindow import AbstractWindow 14 17 from gaphor.ui.diagramtab import DiagramTab 15 18 from gaphor.ui.toolbox import Toolbox 16 19 from gaphor.ui.menufactory import toolbox_to_menu 20 from toplevelwindow import ToplevelWindow 17 21 18 22 from gaphor.ui.objectinspector import ObjectInspector … … 21 25 from interfaces import IUIComponent, IDiagramElementReceivedFocus 22 26 from gaphor.interfaces import IServiceEvent 23 from zope import component 24 25 class MainWindow( AbstractWindow):27 28 29 class MainWindow(ToplevelWindow): 26 30 """ 27 31 The main window for the application. … … 32 36 properties = inject('properties') 33 37 element_factory = inject('element_factory') 34 38 action_manager = inject('action_manager') 39 40 # <old> 35 41 toolbox = ( 36 42 ('', ( … … 158 164 'RefreshNamespaceModel', 159 165 '<NamespacePopupSlot>') 166 # </old> 167 168 title = 'Gaphor' 169 size = property(lambda s: s.properties.get('ui.window-size', (760, 580))) 170 menubar_path = '/mainwindow' 171 toolbar_path = '/mainwindow_toolbar' 160 172 161 173 menu_xml = """ 162 174 <ui> 163 <menubar action="main menu">175 <menubar action="mainwindow"> 164 176 <menu name="FileMenu" action="FileMenu"> 165 <menuitem name="New" action="FileNew" />166 <menuitem name="Open" action="FileOpen" />167 <menuitem name="Revert" action="FileRevert" />168 <menu name="Recent files" action="FileRecent">169 <placeholder action="RecentFiles" />170 </menu>171 <separator />172 <menuitem action="FileSave" />173 <menuitem action="FileSaveAs" />174 <placeholder action="SaveSlot" />175 <separator />176 <menu action="Import">177 <placeholder action="FileImportSlot" />178 </menu>179 <menu action="Export">180 <placeholder action="FileExportSlot" />181 </menu>182 <separator />183 <menuitem action="FileCloseTab" />184 <placeholder action="FileSlot" />185 <separator>186 177 <menuitem action="FileQuit" /> 187 178 </menu> 179 <menu name="EditMenu" action="EditMenu"/> 180 <menu name="DiagramMenu" action="DiagramMenu"/> 181 <menu name="WindowMenu" action="WindowMenu"/> 188 182 </menubar> 189 <toolbar> 190 <toolitem action="FileOpen" /> 191 <toolitem action="separator" /> 192 <toolitem action="FileSave" /> 193 <toolitem action="FileSaveAs" /> 194 <separator /> 195 <toolitem action="Undo" /> 196 <toolitem action="Redo" /> 197 <separator /> 198 <toolitem action="ViewZoomIn" /> 199 <toolitem action="ViewZoomOut" /> 200 <toolitem action="ViewZoom100" /> 183 <toolbar name='mainwindow_toolbar'> 201 184 </toolbar> 202 185 <toolbar action="tools"> … … 214 197 </ui> 215 198 """ 216 199 # <menuitem name="New" action="FileNew" /> 200 # <menuitem name="Open" action="FileOpen" /> 201 # <menuitem name="Revert" action="FileRevert" /> 202 # <menu name="Recent files" action="FileRecent"> 203 # <placeholder action="RecentFiles" /> 204 # </menu> 205 # <separator /> 206 # <menuitem action="FileSave" /> 207 # <menuitem action="FileSaveAs" /> 208 # <placeholder action="SaveSlot" /> 209 # <separator /> 210 # <menu action="Import"> 211 # <placeholder action="FileImportSlot" /> 212 # </menu> 213 # <menu action="Export"> 214 # <placeholder action="FileExportSlot" /> 215 # </menu> 216 # <separator /> 217 # <menuitem action="FileCloseTab" /> 218 # <placeholder action="FileSlot" /> 219 # <separator /> 220 221 # <toolitem action="FileOpen" /> 222 # <toolitem action="separator" /> 223 # <toolitem action="FileSave" /> 224 # <toolitem action="FileSaveAs" /> 225 # <separator /> 226 # <toolitem action="Undo" /> 227 # <toolitem action="Redo" /> 228 # <separator /> 229 # <toolitem action="ViewZoomIn" /> 230 # <toolitem action="ViewZoomOut" /> 231 # <toolitem action="ViewZoom100" /> 217 232 def __init__(self): 218 AbstractWindow.__init__(self)233 ToplevelWindow.__init__(self) 219 234 self._filename = None 220 #self._transient_windows = []221 235 self.notebook_map = {} 236 # Tree view: 237 self._model = None 238 self._view = None 239 240 self.action_group = build_action_group(self) 241 for name, label in (('FileMenu', '_File'), 242 ('EditMenu', '_Edit'), 243 ('DiagramMenu', '_Diagram'), 244 ('WindowMenu', '_Window')): 245 self.action_group.add_action(gtk.Action(name, label, None, None)) 222 246 223 247 def get_model(self): … … 226 250 (shown on the left side in a TreeView). 227 251 """ 228 self._check_state(AbstractWindow.STATE_ACTIVE) 229 return self.model 252 return self._model 253 254 tree_model = property(lambda s: s._model) 230 255 231 256 def get_tree_view(self): … … 234 259 See also get_model(). 235 260 """ 236 return self.view 261 return self._view 262 263 tree_view = property(lambda s: s._view) 237 264 238 265 def set_filename(self, filename): … … 248 275 recent_files = [filename] + recent_files[:8] 249 276 self.properties.set('recent-files', recent_files) 250 self.action_manager.get_slot('RecentFiles').rebuild() 277 # TODO: notify recent files manager 278 #self.action_manager.get_slot('RecentFiles').rebuild() 251 279 252 280 def get_filename(self): … … 255 283 """ 256 284 return self._filename 257 258 # def get_transient_windows(self):259 # """Get the windows that act as child windows of the main window.260 # """261 # return self._transient_windows262 285 263 286 def get_current_diagram_tab(self): … … 278 301 279 302 def get_current_diagram_view(self): 280 """Return the DiagramView associated with the viewed DiagramTab. 303 """ 304 Return the DiagramView associated with the viewed DiagramTab. 281 305 See also: get_current_diagram_tab(), get_current_diagram(). 282 306 """ … … 288 312 Ask user to close window. 289 313 """ 290 dialog = gtk.MessageDialog(self. get_window(),314 dialog = gtk.MessageDialog(self.window, 291 315 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, 292 316 gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, … … 297 321 298 322 def show_diagram(self, diagram): 299 """Show a Diagram element in a new tab. 323 """ 324 Show a Diagram element in a new tab. 300 325 If a tab is already open, show that one instead. 301 326 """ … … 311 336 return tab 312 337 313 def construct(self): 314 """Create the widgets that make up the main window. 338 def ui_component(self): 339 """ 340 Create the widgets that make up the main window. 315 341 """ 316 342 model = namespace.NamespaceModel(self.element_factory) … … 347 373 component.provideHandler(diagramReceivedFocus) 348 374 349 second Paned = gtk.VPaned()350 second Paned.set_property('position',375 second_paned = gtk.VPaned() 376 second_paned.set_property('position', 351 377 int(self.properties.get('ui.object-inspector-position', 600))) 352 second Paned.pack1(notebook)353 second Paned.pack2(self.objectInspector)354 second Paned.show_all()355 paned.pack2(second Paned)378 second_paned.pack1(notebook) 379 second_paned.pack2(self.objectInspector) 380 second_paned.show_all() 381 paned.pack2(second_paned) 356 382 paned.show_all() 357 383 358 second Paned.connect('notify::position',384 second_paned.connect('notify::position', 359 385 self.on_object_inspector_notify_position) 360 386 361 387 self.notebook = notebook 362 self.model = model 363 self.view = view 364 365 window_size = self.properties.get('ui.window-size', (760, 580)) 366 self._construct_window(name='main', 367 title='Gaphor', 368 size=window_size, 369 contents=paned) 388 self._model = model 389 self._view = view 390 391 vbox.set_border_width(3) 392 393 #toolbox = Toolbox(self.menu_factory, self.toolbox) 394 #toolbox.construct() 395 #vbox.pack_start(toolbox, expand=False) 396 #toolbox.show() 397 398 #self._toolbox = toolbox 399 400 return paned 401 402 def construct(self): 403 super(MainWindow, self).construct() 370 404 371 405 self.window.connect('delete-event', self._on_window_delete) 372 373 vbox.set_border_width(3)374 375 toolbox = Toolbox(self.menu_factory, self.toolbox)376 toolbox.construct()377 #toolbox.connect('toggled', self.on_toolbox_toggled)378 vbox.pack_start(toolbox, expand=False)379 toolbox.show()380 381 self._toolbox = toolbox382 406 383 407 # We want to store the window size, so it can be reloaded on startup 384 408 self.window.set_property('allow-shrink', True) 385 409 self.window.connect('size-allocate', self.on_window_size_allocate) 386 387 def add_transient_window(self, window): 388 """Add a window as a sub-window of the main application. 389 """ 390 # Assign the window the accelerators od the main window too 391 pass #window.get_window().add_accel_group(self.accel_group) 392 #self._transient_windows.append(window) 393 #window.connect(self.on_transient_window_closed) 410 self.window.connect('destroy', self.on_window_destroy) 411 412 # TODO: add action_groups and menu_xml from NamespaceView 413 414 # def add_transient_window(self, window): 415 # """Add a window as a sub-window of the main application. 416 # """ 417 # # Assign the window the accelerators od the main window too 418 # pass #window.get_window().add_accel_group(self.accel_group) 419 # #self._transient_windows.append(window) 420 # #window.connect(self.on_transient_window_closed) 394 421 395 422 # Notebook methods: 396 423 397 424 def new_tab(self, window, contents, label): 398 """Create a new tab on the notebook with window as its contents. 425 """ 426 Create a new tab on the notebook with window as its contents. 399 427 Returns: The page number of the tab. 400 428 """ 401 #contents = tab.get_contents()402 429 l = gtk.Label(label) 403 #img = gtk.Image()404 #img.set_from_stock('gtk-close', gtk.ICON_SIZE_MENU)405 #b = gtk.Button()406 #b.set_border_width(0)407 #b.add(img)408 #h = gtk.HBox()409 #h.set_spacing(4)410 #h.pack_start(l, expand=False)411 #h.pack_start(b, expand=False)412 #h.show_all()413 430 self.notebook.append_page(contents, l) 414 431 page_num = self.notebook.page_num(contents) … … 419 436 420 437 def get_current_tab(self): 421 """Return the window (DiagramTab) that is currently visible on the 438 """ 439 Return the window (DiagramTab) that is currently visible on the 422 440 notebook. 423 441 """ … … 427 445 428 446 def set_current_page(self, tab): 429 """Force a specific tab (DiagramTab) to the foreground. 447 """ 448 Force a specific tab (DiagramTab) to the foreground. 430 449 """ 431 450 for p, t in self.notebook_map.iteritems(): … … 459 478 460 479 def select_element(self, element): 461 """Select an element from the Namespace view. 480 """ 481 Select an element from the Namespace view. 462 482 The element is selected. After this an action may be executed, 463 483 such as OpenModelElement, which will try to open the element (if it's … … 476 496 477 497 def _on_window_destroy(self, window): 478 """Window is destroyed... Quit the application. 479 """ 480 AbstractWindow._on_window_destroy(self, window) 481 del self.model 482 del self.view 498 """ 499 Window is destroyed... Quit the application. 500 """ 501 self._model = None 502 self._view = None 503 self.window = None 504 gtk.main_quit() 483 505 484 506 def _on_window_delete(self, window = None, event = None): … … 486 508 487 509 def on_view_event(self, view, event): 488 """Show a popup menu if button3 was pressed on the TreeView. 489 """ 490 self._check_state(AbstractWindow.STATE_ACTIVE) 491 510 """ 511 Show a popup menu if button3 was pressed on the TreeView. 512 """ 492 513 # handle mouse button 3: 493 514 if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3: … … 495 516 496 517 def on_view_row_activated(self, view, path, column): 497 """ Double click on an element in the tree view.498 """499 self._check_state(AbstractWindow.STATE_ACTIVE)518 """ 519 Double click on an element in the tree view. 520 """ 500 521 self.action_manager.execute('OpenModelElement') 501 522 # Set the pointer tool as default tool. … … 503 524 504 525 def on_view_cursor_changed(self, view): 505 """Another row is selected, execute a dummy action. 526 """ 527 Another row is selected, execute a dummy action. 506 528 """ 507 529 self.action_manager.execute('SelectRow') 508 530 509 531 def on_notebook_switch_page(self, notebook, tab, page_num): 510 """Another page (tab) is put on the front of the diagram notebook. 532 """ 533 Another page (tab) is put on the front of the diagram notebook. 511 534 A dummy action is executed. 512 535 """ … … 515 538 def on_window_size_allocate(self, window, allocation): 516 539 self.properties.set('ui.window-size', (allocation.width, allocation.height)) 540 541 def on_window_destroy(self, window): 542 self.quit() 517 543 518 544 def on_object_inspector_notify_position(self, paned, arg): … … 525 551 # self._transient_windows.remove(window) 526 552 527 def _on_transient_window_notify_title(self, window): 528 pass 553 # Actions: 554 555 @action(name='FileQuit', stock_id='gtk-quit') 556 def quit(self): 557 gtk.main_quit() 529 558 530 559 gtk.accel_map_add_filter('gaphor') 531 560 532 @component.adapter(IServiceEvent) 533 def on_undo(*args): 534 from gaphor.application import Application 535 Application.get_service('action_manager').execute('UndoStack') 536 537 component.provideHandler(on_undo) 538 561 #@component.adapter(IServiceEvent) 562 #def on_undo(*args): 563 # from gaphor.application import Application 564 # Application.get_service('action_manager').execute('UndoStack') 565 # 566 #component.provideHandler(on_undo) 567 568 # vim:sw=4:et:ai gaphor/trunk/gaphor/ui/tests/test_mainwindow.py
r1121 r1262 1 1 2 import gtk 2 3 import unittest 3 4 4 5 from gaphor.ui.mainwindow import MainWindow 5 from gaphor import resource 6 6 7 7 8 class MainWindowTestCase(unittest.TestCase): 8 9 10 def setUp(self): 11 from gaphor.application import restart, Application 12 restart() 13 Application.init(services=['element_factory', 'properties', 'action_manager']) 14 9 15 def test_creation(self): 10 16 # MainWindow should be created as resource 11 main_w = resource(MainWindow) 12 try: 13 main_w.construct() 14 except: 15 pass 17 main_w = MainWindow() 18 ui_manager = gtk.UIManager() 19 main_w.ui_manager = ui_manager 20 main_w.construct() 16 21 self.assertEqual(main_w.get_current_diagram(), None) 17 22 gaphor/trunk/gaphor/ui/toolbox.py
r1229 r1262 7 7 8 8 from gaphor.core import inject 9 10 #from gaphor.ui.wrapbox import WrapBox 11 9 12 10 13 class Toolbox(gtk.VBox): … … 18 21 The toolbox is generated based on a definition with the form: 19 22 ('name', ('boxAction1', 'boxAction2',...), 'name2', ('BoxActionN',...)) 23 24 1 Create action pool for placement actions 25 2 Create gtk.RadioButtons for each item. 26 3 connect to action 20 27 """ 21 28 … … 87 94 button.connect('clicked', self.on_wrapbox_decorator_toggled, content) 88 95 89 #AJM: vbox.pack_start(content, True, True)90 91 96 vbox.label = label 92 97 vbox.content = content … … 140 145 self.boxes.append(wrapbox) 141 146 147 142 148 # vim:sw=4:et:ai
