Create menu extension points for import, export and tools.

Let's see if we need more.
This commit is contained in:
Arjan Molenaar
2019-10-02 22:46:43 +02:00
parent d1e45afeff
commit 1ad4be0798
15 changed files with 133 additions and 59 deletions

View File

@ -11,6 +11,9 @@ class DiagramLayoutTestCase(TestCase):
"properties",
"action_manager",
"diagram_layout",
"import_menu",
"export_menu",
"tools_menu",
]
def testDiagramLayout(self):

View File

@ -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:

View File

@ -14,6 +14,9 @@ class CopyServiceTestCase(TestCase):
"action_manager",
"properties",
"undo_manager",
"import_menu",
"export_menu",
"tools_menu",
]
def setUp(self):

View File

@ -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

View File

@ -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()

View File

@ -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
View 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

View File

@ -21,6 +21,9 @@ class DiagramPageTestCase(unittest.TestCase):
"namespace",
"diagrams",
"toolbox",
"import_menu",
"export_menu",
"tools_menu",
]
)
main_window = Application.get_service("main_window")

View File

@ -24,6 +24,9 @@ class DiagramToolboxTestCase(TestCase):
"properties",
"action_manager",
"main_window",
"import_menu",
"export_menu",
"tools_menu",
]
def setUp(self):

View File

@ -19,6 +19,9 @@ class DiagramItemConnectorTestCase(TestCase):
"namespace",
"diagrams",
"toolbox",
"import_menu",
"export_menu",
"tools_menu",
]
def setUp(self):

View File

@ -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")

View File

@ -19,6 +19,9 @@ def application():
"namespace",
"diagrams",
"toolbox",
"import_menu",
"export_menu",
"tools_menu",
]
)
yield Application

View 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

View File

@ -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"

View File

@ -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={