What if UI components are just services
Management of services can be arranged centrally and DI works without a hassle.
This commit is contained in:
@ -1,7 +1,8 @@
|
||||
import abc
|
||||
from gaphor.abc import Service
|
||||
|
||||
|
||||
class UIComponent(metaclass=abc.ABCMeta):
|
||||
class UIComponent(Service):
|
||||
"""
|
||||
A user interface component.
|
||||
"""
|
||||
@ -26,3 +27,9 @@ class UIComponent(metaclass=abc.ABCMeta):
|
||||
Close the UI component. The component can decide to hide or destroy the UI
|
||||
components.
|
||||
"""
|
||||
|
||||
def shutdown(self):
|
||||
"""
|
||||
Shut down this component. It's not supposed to be opened again.
|
||||
"""
|
||||
self.close()
|
||||
|
@ -18,9 +18,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class ConsoleWindow(UIComponent, ActionProvider):
|
||||
|
||||
component_registry = inject("component_registry")
|
||||
main_window = inject("main_window")
|
||||
|
||||
menu_xml = """
|
||||
<ui>
|
||||
<menubar name="mainwindow">
|
||||
@ -35,7 +32,9 @@ class ConsoleWindow(UIComponent, ActionProvider):
|
||||
size = (400, 400)
|
||||
placement = "floating"
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, component_registry, main_window):
|
||||
self.component_registry = component_registry
|
||||
self.main_window = main_window
|
||||
self.action_group = build_action_group(self)
|
||||
self.window = None
|
||||
|
||||
@ -63,8 +62,9 @@ class ConsoleWindow(UIComponent, ActionProvider):
|
||||
|
||||
@action(name="ConsoleWindow:close", stock_id="gtk-close", accel="<Primary><Shift>w")
|
||||
def close(self, widget=None):
|
||||
self.window.destroy()
|
||||
self.window = None
|
||||
if self.window:
|
||||
self.window.destroy()
|
||||
self.window = None
|
||||
|
||||
def construct(self):
|
||||
window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
|
||||
@ -93,6 +93,3 @@ class ConsoleWindow(UIComponent, ActionProvider):
|
||||
window.connect("destroy", self.close)
|
||||
|
||||
return console
|
||||
|
||||
|
||||
# vim:sw=4:et:ai
|
||||
|
@ -20,10 +20,6 @@ class ElementEditor(UIComponent, ActionProvider):
|
||||
It will display the properties of the currently selected element in the
|
||||
diagram."""
|
||||
|
||||
element_factory = inject("element_factory")
|
||||
main_window = inject("main_window")
|
||||
event_manager = inject("event_manager")
|
||||
|
||||
title = _("Element Editor")
|
||||
size = (275, -1)
|
||||
resizable = True
|
||||
@ -39,11 +35,13 @@ class ElementEditor(UIComponent, ActionProvider):
|
||||
</ui>
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, event_manager, element_factory, main_window):
|
||||
"""Constructor. Build the action group for the element editor window.
|
||||
This will place a button for opening the window in the toolbar.
|
||||
The widget attribute is a PropertyEditor."""
|
||||
|
||||
self.event_manager = event_manager
|
||||
self.element_factory = element_factory
|
||||
self.main_window = main_window
|
||||
self.action_group = build_action_group(self)
|
||||
self.window = None
|
||||
self.vbox = None
|
||||
@ -90,7 +88,7 @@ class ElementEditor(UIComponent, ActionProvider):
|
||||
|
||||
window.connect("destroy", self.close)
|
||||
|
||||
def close(self, _widget=None):
|
||||
def close(self):
|
||||
"""Hide the element editor window and deactivate the toolbar button.
|
||||
Both the widget and event parameters default to None and are
|
||||
idempotent if set."""
|
||||
|
@ -91,19 +91,6 @@ class MainWindow(Service, ActionProvider):
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
)
|
||||
|
||||
def init_ui_components(self):
|
||||
component_registry = self.component_registry
|
||||
for ep in pkg_resources.iter_entry_points("gaphor.uicomponents"):
|
||||
log.debug("found entry point uicomponent.%s" % ep.name)
|
||||
cls = ep.load()
|
||||
if not issubclass(cls, UIComponent):
|
||||
raise NameError("Entry point %s doesn't provide UIComponent" % ep.name)
|
||||
uicomp = cls()
|
||||
uicomp.ui_name = ep.name
|
||||
component_registry.register(uicomp, ep.name)
|
||||
if isinstance(uicomp, ActionProvider):
|
||||
self.action_manager.register_action_provider(uicomp)
|
||||
|
||||
def shutdown(self):
|
||||
log.info("Shutting down")
|
||||
if self.window:
|
||||
@ -140,7 +127,6 @@ class MainWindow(Service, ActionProvider):
|
||||
"""Open the main window.
|
||||
"""
|
||||
load_accel_map()
|
||||
self.init_ui_components()
|
||||
|
||||
self.window = (
|
||||
Gtk.ApplicationWindow.new(gtk_app)
|
||||
@ -284,11 +270,6 @@ class Diagrams(UIComponent, ActionProvider):
|
||||
title = _("Diagrams")
|
||||
placement = ("left", "diagrams")
|
||||
|
||||
event_manager = inject("event_manager")
|
||||
element_factory = inject("element_factory")
|
||||
properties = inject("properties")
|
||||
action_manager = inject("action_manager")
|
||||
|
||||
menu_xml = """
|
||||
<ui>
|
||||
<menubar name="mainwindow">
|
||||
@ -301,7 +282,11 @@ class Diagrams(UIComponent, ActionProvider):
|
||||
</ui>
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, event_manager, element_factory, action_manager, properties):
|
||||
self.event_manager = event_manager
|
||||
self.element_factory = element_factory
|
||||
self.action_manager = action_manager
|
||||
self.properties = properties
|
||||
self._notebook = None
|
||||
self.action_group = build_action_group(self)
|
||||
self.action_group.get_action("diagram-drawing-style").set_active(
|
||||
@ -330,8 +315,9 @@ class Diagrams(UIComponent, ActionProvider):
|
||||
self.event_manager.unsubscribe(self._on_flush_model)
|
||||
self.event_manager.unsubscribe(self._on_name_change)
|
||||
self.event_manager.unsubscribe(self._on_show_diagram)
|
||||
self._notebook.destroy()
|
||||
self._notebook = None
|
||||
if self._notebook:
|
||||
self._notebook.destroy()
|
||||
self._notebook = None
|
||||
|
||||
def get_current_diagram(self):
|
||||
"""Returns the current page of the notebook.
|
||||
|
@ -278,10 +278,6 @@ class Namespace(UIComponent, ActionProvider):
|
||||
title = _("Namespace")
|
||||
placement = ("left", "diagrams")
|
||||
|
||||
event_manager = inject("event_manager")
|
||||
element_factory = inject("element_factory")
|
||||
action_manager = inject("action_manager")
|
||||
|
||||
menu_xml = """
|
||||
<ui>
|
||||
<menubar name="mainwindow">
|
||||
@ -308,7 +304,10 @@ class Namespace(UIComponent, ActionProvider):
|
||||
</ui>
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, event_manager, element_factory, action_manager):
|
||||
self.event_manager = event_manager
|
||||
self.element_factory = element_factory
|
||||
self.action_manager = action_manager
|
||||
self._namespace = None
|
||||
self.action_group = build_action_group(self)
|
||||
self.model = Gtk.TreeStore.new([object])
|
||||
|
@ -1,17 +1,30 @@
|
||||
import pytest
|
||||
|
||||
from gaphor.ui.consolewindow import ConsoleWindow
|
||||
from gaphor.tests.testcase import TestCase
|
||||
import gaphor.services.componentregistry
|
||||
|
||||
|
||||
class ConsoleWindowTestCase(TestCase):
|
||||
class MainWindowStub:
|
||||
def __init__(self):
|
||||
self.window = None
|
||||
|
||||
services = TestCase.services + ["main_window", "action_manager", "properties"]
|
||||
|
||||
def test1(self):
|
||||
from gi.repository import Gtk
|
||||
@pytest.fixture
|
||||
def component_registry():
|
||||
return gaphor.services.componentregistry.ComponentRegistry()
|
||||
|
||||
window = ConsoleWindow()
|
||||
assert (
|
||||
len(window.action_group.list_actions()) == 2
|
||||
), window.action_group.list_actions()
|
||||
window.open()
|
||||
window.close()
|
||||
|
||||
@pytest.fixture
|
||||
def main_window():
|
||||
return MainWindowStub()
|
||||
|
||||
|
||||
def test_open_close(component_registry, main_window):
|
||||
window = ConsoleWindow(component_registry, main_window)
|
||||
|
||||
window.open()
|
||||
window.close()
|
||||
|
||||
assert (
|
||||
len(window.action_group.list_actions()) == 2
|
||||
), window.action_group.list_actions()
|
||||
|
@ -11,7 +11,15 @@ from gaphor.ui.mainwindow import DiagramPage
|
||||
class DiagramPageTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
Application.init(
|
||||
services=["element_factory", "main_window", "action_manager", "properties"]
|
||||
services=[
|
||||
"element_factory",
|
||||
"main_window",
|
||||
"action_manager",
|
||||
"properties",
|
||||
"namespace",
|
||||
"diagrams",
|
||||
"toolbox",
|
||||
]
|
||||
)
|
||||
main_window = Application.get_service("main_window")
|
||||
main_window.open()
|
||||
|
@ -13,7 +13,14 @@ logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
||||
class DiagramItemConnectorTestCase(TestCase):
|
||||
services = TestCase.services + ["main_window", "action_manager", "properties"]
|
||||
services = TestCase.services + [
|
||||
"main_window",
|
||||
"action_manager",
|
||||
"properties",
|
||||
"namespace",
|
||||
"diagrams",
|
||||
"toolbox",
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(DiagramItemConnectorTestCase, self).setUp()
|
||||
|
@ -28,6 +28,9 @@ class DiagramItemConnectorTestCase(unittest.TestCase):
|
||||
"properties_manager",
|
||||
"action_manager",
|
||||
"properties",
|
||||
"namespace",
|
||||
"diagrams",
|
||||
"toolbox",
|
||||
]
|
||||
)
|
||||
self.main_window = Application.get_service("main_window")
|
||||
@ -76,6 +79,9 @@ class HandleToolTestCase(unittest.TestCase):
|
||||
"properties_manager",
|
||||
"action_manager",
|
||||
"properties",
|
||||
"namespace",
|
||||
"diagrams",
|
||||
"toolbox",
|
||||
]
|
||||
)
|
||||
self.component_registry = Application.get_service("component_registry")
|
||||
|
@ -10,7 +10,15 @@ from gaphor.ui.abc import UIComponent
|
||||
class MainWindowTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
Application.init(
|
||||
services=["element_factory", "properties", "main_window", "action_manager"]
|
||||
services=[
|
||||
"element_factory",
|
||||
"properties",
|
||||
"main_window",
|
||||
"action_manager",
|
||||
"namespace",
|
||||
"diagrams",
|
||||
"toolbox",
|
||||
]
|
||||
)
|
||||
|
||||
self.component_registry = Application.get_service("component_registry")
|
||||
|
@ -1,29 +1,36 @@
|
||||
import pytest
|
||||
import gaphor.UML as UML
|
||||
from gaphor.ui.namespace import Namespace
|
||||
from gaphor.application import Application
|
||||
import gaphor.services.eventmanager
|
||||
import gaphor.services.componentregistry
|
||||
import gaphor.services.actionmanager
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def application(services=["element_factory", "action_manager"]):
|
||||
Application.init(services=services)
|
||||
yield Application
|
||||
Application.shutdown()
|
||||
def event_manager():
|
||||
return gaphor.services.eventmanager.EventManager()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def element_factory(application):
|
||||
return application.get_service("element_factory")
|
||||
def element_factory(event_manager):
|
||||
return UML.elementfactory.ElementFactory(event_manager)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def component_registry(application):
|
||||
return application.get_service("component_registry")
|
||||
def component_registry():
|
||||
return gaphor.services.componentregistry.ComponentRegistry()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def namespace(application):
|
||||
namespace = Namespace()
|
||||
def action_manager(event_manager, component_registry):
|
||||
return gaphor.services.actionmanager.ActionManager(
|
||||
event_manager, component_registry
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def namespace(event_manager, element_factory, action_manager):
|
||||
namespace = Namespace(event_manager, element_factory, action_manager)
|
||||
namespace.init()
|
||||
yield namespace
|
||||
namespace.close()
|
||||
|
@ -32,10 +32,6 @@ class Toolbox(UIComponent, ActionProvider):
|
||||
title = _("Toolbox")
|
||||
placement = ("left", "diagrams")
|
||||
|
||||
event_manager = inject("event_manager")
|
||||
main_window = inject("main_window")
|
||||
properties = inject("properties")
|
||||
|
||||
menu_xml = """
|
||||
<ui>
|
||||
<menubar name="mainwindow">
|
||||
@ -48,7 +44,12 @@ class Toolbox(UIComponent, ActionProvider):
|
||||
</ui>
|
||||
"""
|
||||
|
||||
def __init__(self, toolbox_actions=TOOLBOX_ACTIONS):
|
||||
def __init__(
|
||||
self, event_manager, main_window, properties, toolbox_actions=TOOLBOX_ACTIONS
|
||||
):
|
||||
self.event_manager = event_manager
|
||||
self.main_window = main_window
|
||||
self.properties = properties
|
||||
self._toolbox = None
|
||||
self._toolbox_actions = toolbox_actions
|
||||
self.action_group = build_action_group(self)
|
||||
|
@ -67,8 +67,6 @@ gaphorconvert = 'gaphor.tools.gaphorconvert:main'
|
||||
"pynsource" = "gaphor.plugins.pynsource:PyNSource"
|
||||
"alignment" = "gaphor.plugins.alignment:Alignment"
|
||||
"help" = "gaphor.services.helpservice:HelpService"
|
||||
|
||||
[tool.poetry.plugins."gaphor.uicomponents"]
|
||||
"namespace" = "gaphor.ui.mainwindow:Namespace"
|
||||
"toolbox" = "gaphor.ui.mainwindow:Toolbox"
|
||||
"diagrams" = "gaphor.ui.mainwindow:Diagrams"
|
||||
|
2
setup.py
2
setup.py
@ -118,8 +118,6 @@ setup(
|
||||
"pynsource = gaphor.plugins.pynsource:PyNSource",
|
||||
"alignment = gaphor.plugins.alignment:Alignment",
|
||||
"help = gaphor.services.helpservice:HelpService",
|
||||
],
|
||||
"gaphor.uicomponents": [
|
||||
"namespace = gaphor.ui.mainwindow:Namespace",
|
||||
"toolbox = gaphor.ui.mainwindow:Toolbox",
|
||||
"diagrams = gaphor.ui.mainwindow:Diagrams",
|
||||
|
Reference in New Issue
Block a user