Create menu extension points for import, export and tools.
Let's see if we need more.
This commit is contained in:
@ -11,6 +11,9 @@ class DiagramLayoutTestCase(TestCase):
|
||||
"properties",
|
||||
"action_manager",
|
||||
"diagram_layout",
|
||||
"import_menu",
|
||||
"export_menu",
|
||||
"tools_menu",
|
||||
]
|
||||
|
||||
def testDiagramLayout(self):
|
||||
|
@ -26,36 +26,14 @@ class DiagramExportManager(Service, ActionProvider):
|
||||
Service for exporting diagrams as images (SVG, PNG, PDF).
|
||||
"""
|
||||
|
||||
menu_xml = """
|
||||
<ui>
|
||||
<menubar action="mainwindow">
|
||||
<menu action="file">
|
||||
<menu action="file-export">
|
||||
<menuitem action="file-export-svg" />
|
||||
<menuitem action="file-export-png" />
|
||||
<menuitem action="file-export-pdf" />
|
||||
<separator />
|
||||
</menu>
|
||||
</menu>
|
||||
</menubar>
|
||||
</ui>
|
||||
"""
|
||||
|
||||
def __init__(self, component_registry, properties):
|
||||
self.component_registry = component_registry
|
||||
def __init__(self, diagrams, properties, export_menu):
|
||||
self.diagrams = diagrams
|
||||
self.properties = properties
|
||||
self.action_group = build_action_group(self)
|
||||
self.export_menu = export_menu
|
||||
export_menu.add_actions(self)
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
def get_current_diagram(self):
|
||||
return self.component_registry.get(
|
||||
UIComponent, "diagrams"
|
||||
).get_current_diagram()
|
||||
self.export_menu.remove_actions(self)
|
||||
|
||||
def save_dialog(self, diagram, title, ext):
|
||||
|
||||
@ -142,42 +120,39 @@ class DiagramExportManager(Service, ActionProvider):
|
||||
|
||||
@action(
|
||||
name="file-export-svg",
|
||||
label="Export to SVG",
|
||||
tooltip="Export the diagram to SVG",
|
||||
label=_("Export to SVG"),
|
||||
tooltip=_("Export the diagram to SVG"),
|
||||
)
|
||||
def save_svg_action(self):
|
||||
title = "Export diagram to SVG"
|
||||
title = _("Export diagram to SVG")
|
||||
ext = ".svg"
|
||||
diagram = self.get_current_diagram()
|
||||
diagram = self.diagrams.get_current_diagram()
|
||||
filename = self.save_dialog(diagram, title, ext)
|
||||
if filename:
|
||||
self.save_svg(filename, diagram.canvas)
|
||||
|
||||
@action(
|
||||
name="file-export-png",
|
||||
label="Export to PNG",
|
||||
tooltip="Export the diagram to PNG",
|
||||
label=_("Export to PNG"),
|
||||
tooltip=_("Export the diagram to PNG"),
|
||||
)
|
||||
def save_png_action(self):
|
||||
title = "Export diagram to PNG"
|
||||
title = _("Export diagram to PNG")
|
||||
ext = ".png"
|
||||
diagram = self.get_current_diagram()
|
||||
diagram = self.diagrams.get_current_diagram()
|
||||
filename = self.save_dialog(diagram, title, ext)
|
||||
if filename:
|
||||
self.save_png(filename, diagram.canvas)
|
||||
|
||||
@action(
|
||||
name="file-export-pdf",
|
||||
label="Export to PDF",
|
||||
tooltip="Export the diagram to PDF",
|
||||
label=_("Export to PDF"),
|
||||
tooltip=_("Export the diagram to PDF"),
|
||||
)
|
||||
def save_pdf_action(self):
|
||||
title = "Export diagram to PDF"
|
||||
title = _("Export diagram to PDF")
|
||||
ext = ".pdf"
|
||||
diagram = self.get_current_diagram()
|
||||
diagram = self.diagrams.get_current_diagram()
|
||||
filename = self.save_dialog(diagram, title, ext)
|
||||
if filename:
|
||||
self.save_pdf(filename, diagram.canvas)
|
||||
|
||||
|
||||
# vim:sw=4:et:
|
||||
|
@ -14,6 +14,9 @@ class CopyServiceTestCase(TestCase):
|
||||
"action_manager",
|
||||
"properties",
|
||||
"undo_manager",
|
||||
"import_menu",
|
||||
"export_menu",
|
||||
"tools_menu",
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
|
@ -2,13 +2,17 @@ import pytest
|
||||
|
||||
import gaphas, gaphas.examples
|
||||
from gaphor.services.diagramexportmanager import DiagramExportManager
|
||||
import gaphor.ui.menufragment
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def diagram_export_manager():
|
||||
properties = {}
|
||||
export_menu = gaphor.ui.menufragment.MenuFragment()
|
||||
|
||||
return DiagramExportManager(component_registry=None, properties=properties)
|
||||
return DiagramExportManager(
|
||||
diagrams=None, properties=properties, export_menu=export_menu
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -19,13 +19,7 @@ def window_action_group(component_registry):
|
||||
def add_actions_to_group(
|
||||
action_group: Gio.ActionMap, provider, scope: str
|
||||
) -> Gio.ActionMap:
|
||||
provider_class = type(provider)
|
||||
for attrname in dir(provider_class):
|
||||
method = getattr(provider_class, attrname)
|
||||
act = getattr(method, "__action__", None)
|
||||
if not act or act.scope != scope:
|
||||
continue
|
||||
|
||||
for attrname, act in iter_actions(provider, scope):
|
||||
if isinstance(act, radio_action):
|
||||
a = Gio.SimpleAction.new_stateful(
|
||||
act.name, None, GLib.Variant.new_int16(act.active)
|
||||
@ -45,6 +39,15 @@ def add_actions_to_group(
|
||||
return action_group
|
||||
|
||||
|
||||
def iter_actions(provider, scope):
|
||||
provider_class = type(provider)
|
||||
for attrname in dir(provider_class):
|
||||
method = getattr(provider_class, attrname)
|
||||
act = getattr(method, "__action__", None)
|
||||
if act and act.scope == scope:
|
||||
yield (attrname, act)
|
||||
|
||||
|
||||
def _action_activate(_action, _param, obj, name):
|
||||
method = getattr(obj, name)
|
||||
method()
|
||||
|
@ -63,16 +63,16 @@ class RecentFilesMenu(Gio.Menu):
|
||||
self.append_item(Gio.MenuItem.new(_("No recently opened models"), None))
|
||||
|
||||
|
||||
def hamburger_menu():
|
||||
def hamburger_menu(hamburger_model):
|
||||
button = Gtk.MenuButton()
|
||||
image = Gtk.Image.new_from_icon_name("open-menu-symbolic", Gtk.IconSize.MENU)
|
||||
button.add(image)
|
||||
button.set_popover(create_hamburger_popover(button))
|
||||
button.set_popover(Gtk.Popover.new_from_model(button, hamburger_model))
|
||||
button.show_all()
|
||||
return button
|
||||
|
||||
|
||||
def create_hamburger_popover(parent):
|
||||
def create_hamburger_model(import_menu, export_menu, tools_menu):
|
||||
model = Gio.Menu.new()
|
||||
|
||||
part = Gio.Menu.new()
|
||||
@ -85,8 +85,6 @@ def create_hamburger_popover(parent):
|
||||
model.append_section(None, part)
|
||||
|
||||
part = Gio.Menu.new()
|
||||
import_menu = Gio.Menu.new()
|
||||
export_menu = Gio.Menu.new()
|
||||
part.append_submenu(_("Import"), import_menu)
|
||||
part.append_submenu(_("Export"), export_menu)
|
||||
model.append_section(None, part)
|
||||
@ -96,7 +94,6 @@ def create_hamburger_popover(parent):
|
||||
model.append_section(None, part)
|
||||
|
||||
part = Gio.Menu.new()
|
||||
tools_menu = Gio.Menu.new()
|
||||
part.append_submenu(_("Tools"), tools_menu)
|
||||
model.append_section(None, part)
|
||||
|
||||
@ -105,7 +102,7 @@ def create_hamburger_popover(parent):
|
||||
part.append(_("About Gaphor"), "app.about")
|
||||
model.append_section(None, part)
|
||||
|
||||
return Gtk.Popover.new_from_model(parent, model)
|
||||
return model
|
||||
|
||||
|
||||
def create_recent_files_button(recent_manager=None):
|
||||
@ -141,12 +138,18 @@ class MainWindow(Service, ActionProvider):
|
||||
element_factory,
|
||||
action_manager,
|
||||
properties,
|
||||
import_menu,
|
||||
export_menu,
|
||||
tools_menu,
|
||||
):
|
||||
self.event_manager = event_manager
|
||||
self.component_registry = component_registry
|
||||
self.element_factory = element_factory
|
||||
self.action_manager = action_manager
|
||||
self.properties = properties
|
||||
self.import_menu = import_menu
|
||||
self.export_menu = export_menu
|
||||
self.tools_menu = tools_menu
|
||||
|
||||
self.title = "Gaphor"
|
||||
self.window = None
|
||||
@ -235,7 +238,13 @@ class MainWindow(Service, ActionProvider):
|
||||
b.show_all()
|
||||
header.pack_start(b)
|
||||
|
||||
header.pack_end(hamburger_menu())
|
||||
header.pack_end(
|
||||
hamburger_menu(
|
||||
create_hamburger_model(
|
||||
self.import_menu.menu, self.export_menu.menu, self.tools_menu.menu
|
||||
)
|
||||
)
|
||||
)
|
||||
header.pack_end(button(_("Save"), "win.file-save"))
|
||||
|
||||
self.set_title()
|
||||
|
31
gaphor/ui/menufragment.py
Normal file
31
gaphor/ui/menufragment.py
Normal file
@ -0,0 +1,31 @@
|
||||
from gi.repository import Gio
|
||||
from gaphor.abc import Service
|
||||
from gaphor.ui.actiongroup import iter_actions
|
||||
|
||||
|
||||
class MenuFragment(Service):
|
||||
"""
|
||||
Menu fragments are used as extension points for
|
||||
plugins. Now they have some place to make themselves
|
||||
accessible to the user.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._menu = Gio.Menu.new()
|
||||
|
||||
def shutdown(self):
|
||||
self._menu.remove_all()
|
||||
|
||||
@property
|
||||
def menu(self):
|
||||
return self._menu
|
||||
|
||||
def add_actions(self, action_provider):
|
||||
section = Gio.Menu.new()
|
||||
for method_name, action in iter_actions(action_provider, "win"):
|
||||
section.append(action.label, f"{action.scope}.{action.name}")
|
||||
if section.get_n_items():
|
||||
self._menu.append_section(None, section)
|
||||
|
||||
def remove_actions(self, action_provider):
|
||||
pass
|
@ -21,6 +21,9 @@ class DiagramPageTestCase(unittest.TestCase):
|
||||
"namespace",
|
||||
"diagrams",
|
||||
"toolbox",
|
||||
"import_menu",
|
||||
"export_menu",
|
||||
"tools_menu",
|
||||
]
|
||||
)
|
||||
main_window = Application.get_service("main_window")
|
||||
|
@ -24,6 +24,9 @@ class DiagramToolboxTestCase(TestCase):
|
||||
"properties",
|
||||
"action_manager",
|
||||
"main_window",
|
||||
"import_menu",
|
||||
"export_menu",
|
||||
"tools_menu",
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
|
@ -19,6 +19,9 @@ class DiagramItemConnectorTestCase(TestCase):
|
||||
"namespace",
|
||||
"diagrams",
|
||||
"toolbox",
|
||||
"import_menu",
|
||||
"export_menu",
|
||||
"tools_menu",
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
|
@ -33,6 +33,9 @@ def application():
|
||||
"namespace",
|
||||
"diagrams",
|
||||
"toolbox",
|
||||
"import_menu",
|
||||
"export_menu",
|
||||
"tools_menu",
|
||||
]
|
||||
)
|
||||
main_window = Application.get_service("main_window")
|
||||
@ -111,6 +114,9 @@ class HandleToolTestCase(unittest.TestCase):
|
||||
"namespace",
|
||||
"diagrams",
|
||||
"toolbox",
|
||||
"import_menu",
|
||||
"export_menu",
|
||||
"tools_menu",
|
||||
]
|
||||
)
|
||||
self.component_registry = Application.get_service("component_registry")
|
||||
|
@ -19,6 +19,9 @@ def application():
|
||||
"namespace",
|
||||
"diagrams",
|
||||
"toolbox",
|
||||
"import_menu",
|
||||
"export_menu",
|
||||
"tools_menu",
|
||||
]
|
||||
)
|
||||
yield Application
|
||||
|
22
gaphor/ui/tests/test_menufragment.py
Normal file
22
gaphor/ui/tests/test_menufragment.py
Normal file
@ -0,0 +1,22 @@
|
||||
import pytest
|
||||
|
||||
from gaphor.core import action
|
||||
from gaphor.ui.menufragment import MenuFragment
|
||||
|
||||
|
||||
class MockService:
|
||||
@action(name="action-one", label="Action One")
|
||||
def action_one(self):
|
||||
pass
|
||||
|
||||
@action(name="action-two", label="Action Two")
|
||||
def action_one(self):
|
||||
pass
|
||||
|
||||
|
||||
def test_adding_actions():
|
||||
menu_fragment = MenuFragment()
|
||||
|
||||
menu_fragment.add_actions(MockService())
|
||||
|
||||
assert menu_fragment.menu.get_n_items() == 1
|
@ -63,6 +63,9 @@ gaphorconvert = 'gaphor.tools.gaphorconvert:main'
|
||||
"diagram_export_manager" = "gaphor.services.diagramexportmanager:DiagramExportManager"
|
||||
"action_manager" = "gaphor.services.actionmanager:ActionManager"
|
||||
"main_window" = "gaphor.ui.mainwindow:MainWindow"
|
||||
"export_menu" = "gaphor.ui.menufragment:MenuFragment"
|
||||
"import_menu" = "gaphor.ui.menufragment:MenuFragment"
|
||||
"tools_menu" = "gaphor.ui.menufragment:MenuFragment"
|
||||
"copy" = "gaphor.services.copyservice:CopyService"
|
||||
"sanitizer" = "gaphor.services.sanitizerservice:SanitizerService"
|
||||
"xmi_export" = "gaphor.plugins.xmiexport:XMIExport"
|
||||
|
5
setup.py
5
setup.py
@ -109,9 +109,11 @@ setup(
|
||||
"element_factory = gaphor.UML.elementfactory:ElementFactory",
|
||||
"file_manager = gaphor.ui.filemanager:FileManager",
|
||||
"recent_files = gaphor.ui.recentfiles:RecentFiles",
|
||||
"diagram_export_manager = gaphor.services.diagramexportmanager:DiagramExportManager",
|
||||
"action_manager = gaphor.services.actionmanager:ActionManager",
|
||||
"main_window = gaphor.ui.mainwindow:MainWindow",
|
||||
"export_menu = gaphor.ui.menufragment:MenuFragment",
|
||||
"import_menu = gaphor.ui.menufragment:MenuFragment",
|
||||
"tools_menu = gaphor.ui.menufragment:MenuFragment",
|
||||
"copy = gaphor.services.copyservice:CopyService",
|
||||
"sanitizer = gaphor.services.sanitizerservice:SanitizerService",
|
||||
"xmi_export = gaphor.plugins.xmiexport:XMIExport",
|
||||
@ -124,6 +126,7 @@ setup(
|
||||
"diagrams = gaphor.ui.mainwindow:Diagrams",
|
||||
"consolewindow = gaphor.ui.consolewindow:ConsoleWindow",
|
||||
"elementeditor = gaphor.ui.elementeditor:ElementEditor",
|
||||
"diagram_export_manager = gaphor.services.diagramexportmanager:DiagramExportManager",
|
||||
],
|
||||
},
|
||||
cmdclass={
|
||||
|
Reference in New Issue
Block a user