From 1007b663770e58722f62068131652d53f0886287 Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Sun, 6 Jan 2019 09:55:01 -0500 Subject: [PATCH 01/15] Fix TypeError: can't concatenate list to tuple Signed-off-by: Dan Yeaw --- gaphor/ui/namespace.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gaphor/ui/namespace.py b/gaphor/ui/namespace.py index ff8430440d..f6207f7880 100644 --- a/gaphor/ui/namespace.py +++ b/gaphor/ui/namespace.py @@ -290,9 +290,9 @@ def _on_association_set(self, event): # Remove entry from old place if old_value in self._nodes: try: - path = self.path_from_element(old_value) + [ - self._nodes[old_value].index(element) - ] + path = self.path_from_element(old_value) + ( + self._nodes[old_value].index(element), + ) except ValueError: log.error( "Unable to create path for element %s and old_value %s" From 30242e0da2c093b6129d351526ab329ce954625a Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Sun, 6 Jan 2019 13:16:45 -0500 Subject: [PATCH 02/15] Create diagram tab only if diagram isn't currently open Signed-off-by: Dan Yeaw --- gaphor/ui/{diagramtab.py => diagrampage.py} | 8 +- gaphor/ui/diagramtoolbox.py | 2 +- gaphor/ui/mainwindow.py | 190 ++++-------------- ...test_diagramtab.py => test_diagrampage.py} | 4 +- gaphor/ui/tests/test_diagramtoolbox.py | 4 +- 5 files changed, 44 insertions(+), 164 deletions(-) rename gaphor/ui/{diagramtab.py => diagrampage.py} (98%) rename gaphor/ui/tests/{test_diagramtab.py => test_diagrampage.py} (94%) diff --git a/gaphor/ui/diagramtab.py b/gaphor/ui/diagrampage.py similarity index 98% rename from gaphor/ui/diagramtab.py rename to gaphor/ui/diagrampage.py index b6043a5965..98cd94f150 100644 --- a/gaphor/ui/diagramtab.py +++ b/gaphor/ui/diagrampage.py @@ -34,7 +34,7 @@ log = logging.getLogger(__name__) -class DiagramTab(object): +class DiagramPage(object): component_registry = inject("component_registry") element_factory = inject("element_factory") @@ -112,7 +112,7 @@ def construct(self): view = GtkView(canvas=self.diagram.canvas) view.drag_dest_set( Gtk.DestDefaults.MOTION, - DiagramTab.VIEW_DND_TARGETS, + DiagramPage.VIEW_DND_TARGETS, Gdk.DragAction.MOVE | Gdk.DragAction.COPY | Gdk.DragAction.LINK, ) @@ -325,7 +325,7 @@ def _on_drag_data_received(self, view, context, x, y, data, info, time): if ( data and data.get_format() == 8 - and info == DiagramTab.VIEW_TARGET_TOOLBOX_ACTION + and info == DiagramPage.VIEW_TARGET_TOOLBOX_ACTION ): tool = self.toolbox.get_tool(data.get_data().decode()) tool.create_item((x, y)) @@ -333,7 +333,7 @@ def _on_drag_data_received(self, view, context, x, y, data, info, time): elif ( data and data.get_format() == 8 - and info == DiagramTab.VIEW_TARGET_ELEMENT_ID + and info == DiagramPage.VIEW_TARGET_ELEMENT_ID ): # print('drag_data_received:', data.data, info) n, p = data.data.split("#") diff --git a/gaphor/ui/diagramtoolbox.py b/gaphor/ui/diagramtoolbox.py index b50af4d23c..fcf998975b 100644 --- a/gaphor/ui/diagramtoolbox.py +++ b/gaphor/ui/diagramtoolbox.py @@ -172,7 +172,7 @@ def itemiter(toolbox_actions): class DiagramToolbox(object): """ - Composite class for DiagramTab (diagramtab.py). + Composite class for DiagramPage (diagrampage.py). """ element_factory = inject("element_factory") diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index 91bf036928..805b541c92 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -30,7 +30,7 @@ from gaphor.services.filemanager import FileManagerStateChanged from gaphor.services.undomanager import UndoManagerStateChanged from gaphor.ui.accelmap import load_accel_map, save_accel_map -from gaphor.ui.diagramtab import DiagramTab +from gaphor.ui.diagrampage import DiagramPage from gaphor.ui.diagramtoolbox import TOOLBOX_ACTIONS from gaphor.ui.event import DiagramTabChange, DiagramSelectionChange, DiagramShow from gaphor.ui.interfaces import IDiagramTabChange @@ -132,10 +132,6 @@ class MainWindow(object): def __init__(self): self.window = None self.model_changed = False - - # Map tab contents to DiagramTab - # self.notebook_map = {} - self._current_diagram_tab = None self.layout = None def init(self, app=None): @@ -174,7 +170,6 @@ def shutdown(self): cr.unregister_handler(self._on_file_manager_state_changed) cr.unregister_handler(self._on_undo_manager_state_changed) cr.unregister_handler(self._new_model_content) - # self.ui_manager.remove_action_group(self.action_group) def init_action_group(self): self.action_group = build_action_group(self) @@ -204,30 +199,6 @@ def get_filename(self): """ return self.file_manager.filename - def get_current_diagram_tab(self): - """ - Get the currently opened and viewed DiagramTab, shown on the right - side of the main window. - See also: get_current_diagram(), get_current_diagram_view(). - """ - return self._current_diagram_tab - - def get_current_diagram(self): - """ - Return the Diagram associated with the viewed DiagramTab. - See also: get_current_diagram_tab(), get_current_diagram_view(). - """ - tab = self._current_diagram_tab - return tab and tab.get_diagram() - - def get_current_diagram_view(self): - """ - Return the DiagramView associated with the viewed DiagramTab. - See also: get_current_diagram_tab(), get_current_diagram(). - """ - tab = self._current_diagram_tab - return tab and tab.get_view() - def ask_to_close(self): """ Ask user to close window if the model has changed. @@ -310,9 +281,6 @@ def _factory(name): with open(filename) as f: deserialize(self.layout, vbox, f.read(), _factory) - # self.layout.connect('item-closed', self._on_item_closed) - # self.layout.connect('item-selected', self._on_item_selected) - vbox.show() # TODO: add statusbar @@ -324,7 +292,6 @@ def _factory(name): self.window.set_resizable(True) self.window.connect("size-allocate", self._on_window_size_allocate) self.window.connect("destroy", self._on_window_destroy) - # self.window.connect_after('key-press-event', self._on_key_press_event) cr = self.component_registry cr.register_handler(self._on_file_manager_state_changed) @@ -353,41 +320,6 @@ def set_title(self): title += " *" self.window.set_title(title) - # Notebook methods: - - def add_tab(self, item): - """ - Create a new tab on the notebook with window as its contents. - Returns: The page number of the tab. - """ - diagrams = self.get_widgets("diagrams") - if len(diagrams): - group = diagrams[0] - group.insert_item(item) - item.show_all() - # item.diagram_tab = tab - # self.notebook_map[item] = tab - - def set_current_page(self, tab): - """ - Force a specific tab (DiagramTab) to the foreground. - """ - for i in self.get_widgets("diagram-tab"): - if i.diagram_tab is tab: - g = i.get_parent() - g.set_current_item(g.item_num(i)) - return - # for p, t in self.notebook_map.iteritems(): - # if tab is t: - # num = self.notebook.page_num(p) - # self.notebook.set_current_page(num) - # return - pass - - def get_tabs(self): - tabs = [i.diagram_tab for i in self.get_widgets("diagram-tab")] - return tabs - # Signal callbacks: @component.adapter(ModelFactoryEvent) @@ -400,7 +332,6 @@ def _new_model_content(self, event): lambda e: e.isKindOf(UML.Diagram) and not (e.namespace and e.namespace.namespace) ): - # self.show_diagram(diagram) self.component_registry.handle(DiagramShow(diagram)) @component.adapter(FileManagerStateChanged) @@ -446,51 +377,6 @@ def _clear_ui_settings(self): self.ui_manager.remove_ui(ui_id) self._tab_ui_settings = None - def _on_item_closed(self, layout, page_num, item): - self._clear_ui_settings() - try: - ui_component = item.ui_component - except AttributeError: - log.warning("No ui component defined on item") - else: - ui_component.close() - item.destroy() - - def _on_item_selected(self, layout, page_num, item): - """ - Another page (tab) is put on the front of the diagram notebook. - A dummy action is executed. - """ - # TODO: Here the magic happens! - # TODO: Need to see what the active view is, or make toolbox actions global - self._clear_ui_settings() - - # Is it a diagram view? - try: - tab = item.diagram_tab - except AttributeError: - # Not a diagram tab - return - - self._current_diagram_tab = tab - - content = self.notebook.get_nth_page(page_num) - tab = self.notebook_map.get(content) - # assert isinstance(tab, DiagramTab), str(tab) - - self.ui_manager.insert_action_group(tab.action_group, -1) - ui_id = self.ui_manager.add_ui_from_string(tab.menu_xml) - self._tab_ui_settings = tab.action_group, ui_id - log.debug("Menus updated with %s, %d" % self._tab_ui_settings) - - # Make sure everyone knows the selection has changed. - self.component_registry.handle( - DiagramTabChange(item), - DiagramSelectionChange( - tab.view, tab.view.focused_item, tab.view.selected_items - ), - ) - def _on_window_size_allocate(self, window, allocation): """ Store the window size in a property. @@ -582,7 +468,6 @@ def __init__(self): @open_action(name="open-namespace", label=_("_Namespace")) def open_namespace(self): if not self._namespace: - # self.main_window.create_item(self) #self.open(), self.title, self.placement) return self else: self._namespace.set_property("has-focus", True) @@ -777,7 +662,7 @@ def tree_view_create_package(self): @action( name="tree-view-delete-package", - label=_("Delete pac_kage"), + label=_("Delete package"), stock_id="gtk-delete", ) @transactional @@ -823,30 +708,23 @@ def __init__(self): self.properties.get("reset-tool-after-create", True) ) - @open_action(name="open-toolbox", label=_("T_oolbox")) + @open_action(name="open-toolbox", label=_("Toolbox")) def open_toolbox(self): if not self._toolbox: - # self.main_window.create_item(self) #.open(), self.title, self.placement) return self else: self._toolbox.set_property("has-focus", True) def open(self): + print("open toolbox") widget = self.construct() self.main_window.window.connect_after( "key-press-event", self._on_key_press_event ) - - self.component_registry.register_handler(self._on_diagram_tab_change) - if self.main_window.get_current_diagram_tab(): - self.update_toolbox( - self.main_window.get_current_diagram_tab().toolbox.action_group - ) return widget def close(self): if self._toolbox: - self.component_registry.unregister_handler(self._on_diagram_tab_change) self._toolbox.destroy() self._toolbox = None @@ -875,10 +753,6 @@ def _on_toolbox_destroyed(self, widget): def reset_tool_after_create(self, active): self.properties.set("reset-tool-after-create", active) - # def _insensivate_toolbox(self): - # for button in self._toolbox.buttons: - # button.set_property('sensitive', False) - @component.adapter(IDiagramTabChange) def _on_diagram_tab_change(self, event): self.update_toolbox(event.diagram_tab.toolbox.action_group) @@ -911,12 +785,8 @@ def set_active_tool(self, action_name=None, shortcut=None): if not action_name: return - self.main_window.get_current_diagram_tab().toolbox.action_group.get_action( - action_name - ).activate() - -@implementer(IUIComponent) # , IActionProvider) +@implementer(IUIComponent) class Diagrams(object): title = _("Diagrams") @@ -927,10 +797,10 @@ class Diagrams(object): def __init__(self): self._notebook = None - # self.action_group = build_action_group(self) - # self.action_group.get_action('reset-tool-after-create').set_active(self.properties.get('reset-tool-after-create', True)) + self._current_diagram_tab = None def open(self): + print("open diagram") self._notebook = Gtk.Notebook() self._notebook.show() self.component_registry.register_handler(self._on_show_diagram) @@ -975,28 +845,38 @@ def create_tab(self, title, widget): @component.adapter(DiagramShow) def _on_show_diagram(self, event): - """ - Show a Diagram element in a new tab. - If a tab is already open, show that one instead. - """ - diagram = event.diagram + """Show a Diagram element in the Notebook. - # Try to find an existing window/tab and let it get focus: - # for tab in self.get_tabs(): - # if tab.get_diagram() is diagram: - # self.set_current_page(tab) - # return tab + If a diagram is already open on a Notebook page, show that one, + otherwise create a new Notebook page. - tab = DiagramTab(diagram) - widget = tab.construct() - widget.set_name("diagram-tab") - widget.diagram_tab = tab - assert widget.get_name() == "diagram-tab" - tab.set_drawing_style(self.properties("diagram.sloppiness", 0)) + Args: + event: The service event that is calling the method. - self.create_tab(diagram.name, widget) + """ + diagram = event.diagram - return tab + # Try to find an existing window/tab and let it get focus: + num_pages = self._notebook.get_n_pages() + found_page = False + for page in range(0, num_pages): + child_widget = self._notebook.get_nth_page(page) + if child_widget.diagram_tab.get_diagram() is diagram: + self._notebook.set_current_page(page) + found_page = True + break + + if not found_page: + print("Show diagram") + + page = DiagramPage(diagram) + widget = page.construct() + widget.set_name("diagram-tab") + widget.diagram_tab = page + assert widget.get_name() == "diagram-tab" + page.set_drawing_style(self.properties("diagram.sloppiness", 0)) + + self.create_tab(diagram.name, widget) # vim:sw=4:et:ai diff --git a/gaphor/ui/tests/test_diagramtab.py b/gaphor/ui/tests/test_diagrampage.py similarity index 94% rename from gaphor/ui/tests/test_diagramtab.py rename to gaphor/ui/tests/test_diagrampage.py index 9d529c0f90..8060594477 100644 --- a/gaphor/ui/tests/test_diagramtab.py +++ b/gaphor/ui/tests/test_diagrampage.py @@ -2,11 +2,11 @@ from gaphor import UML from gaphor.application import Application -from gaphor.ui.diagramtab import DiagramTab +from gaphor.ui.diagrampage import DiagramPage from gaphor.ui.mainwindow import MainWindow -class DiagramTabTestCase(unittest.TestCase): +class DiagramPageTestCase(unittest.TestCase): def setUp(self): Application.init( services=[ diff --git a/gaphor/ui/tests/test_diagramtoolbox.py b/gaphor/ui/tests/test_diagramtoolbox.py index 12053486bd..91fc6110cc 100644 --- a/gaphor/ui/tests/test_diagramtoolbox.py +++ b/gaphor/ui/tests/test_diagramtoolbox.py @@ -2,7 +2,7 @@ from gi.repository import Gtk from gaphor.tests.testcase import TestCase from gaphor.application import Application -from gaphor.ui.diagramtab import DiagramTab +from gaphor.ui.diagrampage import DiagramPage from gaphor.ui.diagramtoolbox import DiagramToolbox, TOOLBOX_ACTIONS from gaphor import UML @@ -24,7 +24,7 @@ class DiagramToolboxTestCase(TestCase): def setUp(self): TestCase.setUp(self) diagram = self.diagram - tab = DiagramTab(WindowOwner()) + tab = DiagramPage(WindowOwner()) tab.diagram = diagram tab.construct() self.tab = tab From 9a7d064cd91c9e252a632bd0c5ce30f8cd251221 Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Sun, 6 Jan 2019 14:24:35 -0500 Subject: [PATCH 03/15] Allow diagram tabs to be reordered via drag and drop Signed-off-by: Dan Yeaw --- gaphor/ui/mainwindow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index 805b541c92..6594577743 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -839,6 +839,7 @@ def create_tab(self, title, widget): page_num = self._notebook.append_page(child=widget, tab_label=tab_box) self._notebook.set_current_page(page_num) + self._notebook.set_tab_reorderable(widget, True) button.connect("clicked", self.on_close_tab, widget) self.component_registry.handle(DiagramTabChange(widget)) From c9bf299952705938a03a60269ff3e5ce10b7277c Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Sun, 6 Jan 2019 21:24:07 -0500 Subject: [PATCH 04/15] Fix gtk_notebook_get_tab_label: assertion 'list != NULL' failed error When closing a tab or exiting the app, it was throwing the above GTK-CRITICAL error. This error was resolved by unshowing the tabs prior to removing a page, and then showing them again after the page is removed. I need to look in to more why this is necessary. Signed-off-by: Dan Yeaw --- gaphor/ui/mainwindow.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index 6594577743..971fb01661 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -716,7 +716,6 @@ def open_toolbox(self): self._toolbox.set_property("has-focus", True) def open(self): - print("open toolbox") widget = self.construct() self.main_window.window.connect_after( "key-press-event", self._on_key_press_event @@ -797,23 +796,43 @@ class Diagrams(object): def __init__(self): self._notebook = None - self._current_diagram_tab = None def open(self): - print("open diagram") + """Open the diagrams component. + + Returns: + The Gtk.Notebook. + + """ self._notebook = Gtk.Notebook() self._notebook.show() self.component_registry.register_handler(self._on_show_diagram) return self._notebook def close(self): + """Close the diagrams component. + + """ self.component_registry.unregister_handler(self._on_show_diagram) self._notebook.destroy() self._notebook = None - def on_close_tab(self, button, widget): + def cb_close_tab(self, button, widget): + """Callback to close the tab and remove the notebook page. + + Args: + button (Gtk.Button): The button the callback is from. + widget (Gtk.Widget): The child widget of the tab. + + """ page_num = self._notebook.page_num(widget) + # TODO why does Gtk.Notebook give a GTK-CRITICAL if you remove a page + # with set_show_tabs(True)? + self._notebook.set_show_tabs(False) self._notebook.remove_page(page_num) + if self._notebook.get_n_pages() > 0: + self._notebook.set_show_tabs(True) + widget.destroy() def create_tab(self, title, widget): """Creates a new Notebook tab with a label and close button. @@ -841,8 +860,9 @@ def create_tab(self, title, widget): self._notebook.set_current_page(page_num) self._notebook.set_tab_reorderable(widget, True) - button.connect("clicked", self.on_close_tab, widget) + button.connect("clicked", self.cb_close_tab, widget) self.component_registry.handle(DiagramTabChange(widget)) + self._notebook.set_show_tabs(True) @component.adapter(DiagramShow) def _on_show_diagram(self, event): @@ -868,8 +888,6 @@ def _on_show_diagram(self, event): break if not found_page: - print("Show diagram") - page = DiagramPage(diagram) widget = page.construct() widget.set_name("diagram-tab") From 66987a78243606b3f269c384cc736699d390b11c Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Mon, 7 Jan 2019 22:09:48 -0500 Subject: [PATCH 05/15] Rename diagram tab to diagram page to match Gtk Notebook terminology Signed-off-by: Dan Yeaw --- .../plugins/checkmetamodel/checkmodelgui.py | 4 +- gaphor/services/diagramexportmanager.py | 2 +- gaphor/ui/diagrampage.py | 10 ++--- gaphor/ui/event.py | 8 ++-- gaphor/ui/interfaces.py | 4 +- gaphor/ui/mainwindow.py | 42 +++++++++---------- 6 files changed, 33 insertions(+), 37 deletions(-) diff --git a/gaphor/plugins/checkmetamodel/checkmodelgui.py b/gaphor/plugins/checkmetamodel/checkmodelgui.py index d22e7d89bc..47b365ddfd 100644 --- a/gaphor/plugins/checkmetamodel/checkmodelgui.py +++ b/gaphor/plugins/checkmetamodel/checkmodelgui.py @@ -117,8 +117,8 @@ def on_row_activated(self, treeview, row, column): except AttributeError: presentation = element.namespace.presentation[0] diagram = presentation.canvas.diagram - diagram_tab = main_window.show_diagram(diagram) - diagram_tab.view.focused_item = presentation + diagram_page = main_window.show_diagram(diagram) + diagram_page.view.focused_item = presentation def on_destroy(self, window): self.window = None diff --git a/gaphor/services/diagramexportmanager.py b/gaphor/services/diagramexportmanager.py index 3d65ee6b48..23c0568b3c 100644 --- a/gaphor/services/diagramexportmanager.py +++ b/gaphor/services/diagramexportmanager.py @@ -56,7 +56,7 @@ def update(self): self.logger.info("Updating") - tab = self.get_window().get_current_diagram_tab() + tab = self.get_window().get_current_diagram_page() self.sensitive = tab and True or False def save_dialog(self, diagram, title, ext): diff --git a/gaphor/ui/diagrampage.py b/gaphor/ui/diagrampage.py index 98cd94f150..dc919b1a16 100644 --- a/gaphor/ui/diagrampage.py +++ b/gaphor/ui/diagrampage.py @@ -84,7 +84,7 @@ class DiagramPage(object): def __init__(self, diagram): self.diagram = diagram self.view = None - # self.owning_window = owning_window + self.widget = None self.action_group = build_action_group(self) self.toolbox = None self.component_registry.register_handler(self._on_element_change) @@ -121,6 +121,7 @@ def construct(self): scrolled_window.set_shadow_type(Gtk.ShadowType.IN) scrolled_window.add(view) scrolled_window.show_all() + self.widget = scrolled_window view.connect("focus-changed", self._on_view_selection_changed) view.connect("selection-changed", self._on_view_selection_changed) @@ -132,12 +133,7 @@ def construct(self): self.toolbox = DiagramToolbox(self.diagram, view) - # item = DockItem(title=self.title, stock_id='gaphor-diagram') - # item.add(scrolled_window) - item = scrolled_window - self.widget = item - - return item + return self.widget @component.adapter(IAttributeChangeEvent) def _on_element_change(self, event): diff --git a/gaphor/ui/event.py b/gaphor/ui/event.py index 8eb476f461..4be61731bf 100644 --- a/gaphor/ui/event.py +++ b/gaphor/ui/event.py @@ -4,7 +4,7 @@ from gaphor.ui.interfaces import ( IDiagramSelectionChange, - IDiagramTabChange, + IDiagramPageChange, IDiagramShow, ) @@ -15,11 +15,11 @@ def __init__(self, diagram): self.diagram = diagram -@implementer(IDiagramTabChange) -class DiagramTabChange(object): +@implementer(IDiagramPageChange) +class DiagramPageChange(object): def __init__(self, item): self.item = item - self.diagram_tab = item.diagram_tab + self.diagram_page = item.diagram_page @implementer(IDiagramSelectionChange) diff --git a/gaphor/ui/interfaces.py b/gaphor/ui/interfaces.py index dce0481d39..d02466a056 100644 --- a/gaphor/ui/interfaces.py +++ b/gaphor/ui/interfaces.py @@ -13,14 +13,14 @@ class IDiagramShow(interface.Interface): diagram = interface.Attribute("The newly selected Diagram") -class IDiagramTabChange(interface.Interface): +class IDiagramPageChange(interface.Interface): """ The selected diagram changes. """ item = interface.Attribute("The newly selected Notebook pane") - diagram_tab = interface.Attribute("The newly selected diagram tab") + diagram_page = interface.Attribute("The newly selected diagram page") class IDiagramSelectionChange(interface.Interface): diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index 971fb01661..9f4a694511 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -32,8 +32,8 @@ from gaphor.ui.accelmap import load_accel_map, save_accel_map from gaphor.ui.diagrampage import DiagramPage from gaphor.ui.diagramtoolbox import TOOLBOX_ACTIONS -from gaphor.ui.event import DiagramTabChange, DiagramSelectionChange, DiagramShow -from gaphor.ui.interfaces import IDiagramTabChange +from gaphor.ui.event import DiagramPageChange, DiagramShow +from gaphor.ui.interfaces import IDiagramPageChange from gaphor.ui.interfaces import IUIComponent from gaphor.ui.layout import deserialize from gaphor.ui.namespace import NamespaceModel, NamespaceView @@ -752,9 +752,9 @@ def _on_toolbox_destroyed(self, widget): def reset_tool_after_create(self, active): self.properties.set("reset-tool-after-create", active) - @component.adapter(IDiagramTabChange) - def _on_diagram_tab_change(self, event): - self.update_toolbox(event.diagram_tab.toolbox.action_group) + @component.adapter(IDiagramPageChange) + def _on_diagram_page_change(self, event): + self.update_toolbox(event.diagram_page.toolbox.action_group) def update_toolbox(self, action_group): """ @@ -832,6 +832,7 @@ def cb_close_tab(self, button, widget): self._notebook.remove_page(page_num) if self._notebook.get_n_pages() > 0: self._notebook.set_show_tabs(True) + widget.diagram_page.close() widget.destroy() def create_tab(self, title, widget): @@ -861,7 +862,7 @@ def create_tab(self, title, widget): self._notebook.set_tab_reorderable(widget, True) button.connect("clicked", self.cb_close_tab, widget) - self.component_registry.handle(DiagramTabChange(widget)) + self.component_registry.handle(DiagramPageChange(widget)) self._notebook.set_show_tabs(True) @component.adapter(DiagramShow) @@ -877,25 +878,24 @@ def _on_show_diagram(self, event): """ diagram = event.diagram - # Try to find an existing window/tab and let it get focus: + # Try to find an existing diagram page and give it focus num_pages = self._notebook.get_n_pages() - found_page = False for page in range(0, num_pages): child_widget = self._notebook.get_nth_page(page) - if child_widget.diagram_tab.get_diagram() is diagram: + if child_widget.diagram_page.get_diagram() is diagram: self._notebook.set_current_page(page) - found_page = True - break - - if not found_page: - page = DiagramPage(diagram) - widget = page.construct() - widget.set_name("diagram-tab") - widget.diagram_tab = page - assert widget.get_name() == "diagram-tab" - page.set_drawing_style(self.properties("diagram.sloppiness", 0)) - - self.create_tab(diagram.name, widget) + return child_widget.diagram_page + + # No existing diagram page found, creating one + page = DiagramPage(diagram) + widget = page.construct() + widget.set_name("diagram-tab") + widget.diagram_page = page + assert widget.get_name() == "diagram-tab" + page.set_drawing_style(self.properties("diagram.sloppiness", 0)) + + self.create_tab(diagram.name, widget) + return page # vim:sw=4:et:ai From b697a60495d61260ba091f212b0f7d4275a7b7c8 Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Tue, 8 Jan 2019 21:21:07 -0500 Subject: [PATCH 06/15] Update tests to support diagram Gtk.Notebook and DiagramPage Signed-off-by: Dan Yeaw --- gaphor/ui/tests/test_diagrampage.py | 39 +++++++++++++---------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/gaphor/ui/tests/test_diagrampage.py b/gaphor/ui/tests/test_diagrampage.py index 8060594477..befb10a8ec 100644 --- a/gaphor/ui/tests/test_diagrampage.py +++ b/gaphor/ui/tests/test_diagrampage.py @@ -1,9 +1,11 @@ import unittest +from gaphas.examples import Box + from gaphor import UML from gaphor.application import Application -from gaphor.ui.diagrampage import DiagramPage -from gaphor.ui.mainwindow import MainWindow +from gaphor.diagram.comment import CommentItem +from gaphor.ui.mainwindow import DiagramPage class DiagramPageTestCase(unittest.TestCase): @@ -20,37 +22,30 @@ def setUp(self): ) main_window = Application.get_service("main_window") main_window.open() - element_factory = Application.get_service("element_factory") - self.element_factory = element_factory - self.diagram = element_factory.create(UML.Diagram) - self.tab = main_window.show_diagram(self.diagram) - self.assertEqual(self.tab.diagram, self.diagram) - self.assertEqual(self.tab.view.canvas, self.diagram.canvas) - self.assertEqual(len(element_factory.lselect()), 1) + self.element_factory = Application.get_service("element_factory") + self.diagram = self.element_factory.create(UML.Diagram) + self.page = DiagramPage(self.diagram) + self.page.construct() + self.assertEqual(self.page.diagram, self.diagram) + self.assertEqual(self.page.view.canvas, self.diagram.canvas) + self.assertEqual(len(self.element_factory.lselect()), 1) def tearDown(self): - self.tab.close() - del self.tab + self.page.close() + del self.page self.diagram.unlink() del self.diagram Application.shutdown() - # assert len(self.element_factory.lselect()) == 0 + assert len(self.element_factory.lselect()) == 0 def test_creation(self): pass def test_placement(self): - tab = self.tab - diagram = self.diagram - from gaphas import Element - from gaphas.examples import Box - box = Box() - diagram.canvas.add(box) - diagram.canvas.update_now() - tab.view.request_update([box]) - - from gaphor.diagram.comment import CommentItem + self.diagram.canvas.add(box) + self.diagram.canvas.update_now() + self.page.view.request_update([box]) comment = self.diagram.create( CommentItem, subject=self.element_factory.create(UML.Comment) From d58daf014ab2c0f57bf4484da89c654e4dd24a8c Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Tue, 8 Jan 2019 21:41:27 -0500 Subject: [PATCH 07/15] Update checkmetamodel plugin to be compatible with new Gtk.Notebook Signed-off-by: Dan Yeaw --- gaphor/plugins/checkmetamodel/checkmodelgui.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/gaphor/plugins/checkmetamodel/checkmodelgui.py b/gaphor/plugins/checkmetamodel/checkmodelgui.py index 47b365ddfd..b46e25f153 100644 --- a/gaphor/plugins/checkmetamodel/checkmodelgui.py +++ b/gaphor/plugins/checkmetamodel/checkmodelgui.py @@ -3,13 +3,18 @@ """ from __future__ import print_function +import logging from builtins import object +import gi + +gi.require_version("Gtk", "3.0") from gi.repository import GObject from gi.repository import Gtk from zope.interface import implementer from gaphor.core import inject, action, build_action_group +from gaphor.ui.diagrampage import DiagramPage from gaphor.interfaces import IService, IActionProvider from gaphor.plugins.checkmetamodel import checkmodel @@ -17,6 +22,8 @@ ELEMENT_COLUMN = 1 REASON_COLUMN = 2 +log = logging.getLogger(__name__) + @implementer(IService, IActionProvider) class CheckModelWindow(object): @@ -110,14 +117,13 @@ def on_row_activated(self, treeview, row, column): element = self.model.get_value(iter, PYELEMENT_COLUMN) print("Looking for element", element) if element.presentation: - main_window = self.main_window presentation = element.presentation[0] try: diagram = presentation.canvas.diagram except AttributeError: presentation = element.namespace.presentation[0] diagram = presentation.canvas.diagram - diagram_page = main_window.show_diagram(diagram) + diagram_page = DiagramPage(diagram) diagram_page.view.focused_item = presentation def on_destroy(self, window): From 5149842246e7e2e30d0b78bc2d652c1eb30ee6dd Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Wed, 9 Jan 2019 22:04:07 -0500 Subject: [PATCH 08/15] Remove open Toolbox and Namespace from Window drop down on menu bar The updated main window always displays the Toolbox and Namespace, so an option to show them is not needed. Signed-off-by: Dan Yeaw --- gaphor/plugins/diagramlayout/__init__.py | 10 ++++--- gaphor/ui/mainwindow.py | 34 +++++++----------------- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/gaphor/plugins/diagramlayout/__init__.py b/gaphor/plugins/diagramlayout/__init__.py index 589716eb30..eda31d6678 100644 --- a/gaphor/plugins/diagramlayout/__init__.py +++ b/gaphor/plugins/diagramlayout/__init__.py @@ -1,15 +1,17 @@ """ -This module provides a means to automatocally layout diagrams. +This module provides a means to automatically layout diagrams. The layout is done like this: - - First all nodes (Classes, packages, comments) on a digram are determined + - First all nodes (Classes, packages, comments) on a diagram are determined - A vertical ordering is determined based on the inheritance - A horizontal ordering is determined based on associations and dependencies - The nodes are moved to their place - Lines are reconnected to the nodes, so everything looks pretty. + """ from __future__ import division +import logging import random from builtins import object @@ -21,6 +23,8 @@ from gaphor.interfaces import IService, IActionProvider from gaphor.plugins.diagramlayout import toposort +log = logging.getLogger(__name__) + @implementer(IService, IActionProvider) class DiagramLayout(object): @@ -52,7 +56,7 @@ def update(self): name="diagram-layout", label="Layout diagram", tooltip="simple diagram layout" ) def execute(self): - d = self.main_window.get_current_diagram() + d = self.diagram.get_current_diagram() self.layout_diagram(d) @transactional diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index 9f4a694511..7a21222544 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -110,11 +110,6 @@ class MainWindow(object): - - - - - @@ -430,8 +425,6 @@ class Namespace(object): ui_manager = inject("ui_manager") action_manager = inject("action_manager") - menu_xml = STATIC_MENU_XML % ("window", "open-namespace") - _menu_xml = """ @@ -465,13 +458,6 @@ def __init__(self): self._ui_id = None self.action_group = build_action_group(self) - @open_action(name="open-namespace", label=_("_Namespace")) - def open_namespace(self): - if not self._namespace: - return self - else: - self._namespace.set_property("has-focus", True) - def open(self): widget = self.construct() self.component_registry.register_handler(self.expand_root_nodes) @@ -694,9 +680,6 @@ class Toolbox(object): - - - """ @@ -708,13 +691,6 @@ def __init__(self): self.properties.get("reset-tool-after-create", True) ) - @open_action(name="open-toolbox", label=_("Toolbox")) - def open_toolbox(self): - if not self._toolbox: - return self - else: - self._toolbox.set_property("has-focus", True) - def open(self): widget = self.construct() self.main_window.window.connect_after( @@ -817,6 +793,16 @@ def close(self): self._notebook.destroy() self._notebook = None + def get_current_diagram(self): + """Returns the current page of the notebook. + + Returns (DiagramPage): The current diagram page. + + """ + page_num = self._notebook.get_current_page() + child_widget = self._notebook.get_nth_page(page_num) + return child_widget.diagram_page + def cb_close_tab(self, button, widget): """Callback to close the tab and remove the notebook page. From 512c8a91c4219b648894ec5c63c416cbf0952d1f Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Wed, 9 Jan 2019 22:22:42 -0500 Subject: [PATCH 09/15] Update copyright, license, and contributors in about dialog Signed-off-by: Dan Yeaw --- gaphor/services/helpservice.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/gaphor/services/helpservice.py b/gaphor/services/helpservice.py index d0bc0840ed..ccbfb90399 100644 --- a/gaphor/services/helpservice.py +++ b/gaphor/services/helpservice.py @@ -81,9 +81,15 @@ def add_label(text, padding_x=0, padding_y=0): tab_vbox.pack_start(label, True, True, 0) add_label('version %s' % version) - add_label('UML Modeling tool for GNOME', 8, 8) add_label( - 'Copyright (c) 2001-2007 Arjan J. Molenaar', 8, 8 + 'Gaphor is the simple modeling tool written in Python', + 8, + 8, + ) + add_label( + 'Copyright (c) 2001-2019 Arjan J. Molenaar and Dan Yeaw', + 8, + 8, ) notebook.append_page(tab_vbox, Gtk.Label(label=_("About"))) @@ -93,8 +99,8 @@ def add_label(text, padding_x=0, padding_y=0): add_label( "This software is published\n" "under the terms of the\n" - 'GNU General Public License v2.\n' - "See the COPYING file for details.", + 'GNU Library General Public License v2.\n' + "See the LICENSE.txt file for details.", 0, 8, ) @@ -103,13 +109,21 @@ def add_label(text, padding_x=0, padding_y=0): tab_vbox = Gtk.VBox() add_label( - "Gaphor is written by:\n" + "Thanks to all the wonderful people that have contributed:\n\n" "Arjan Molenaar\n" "Artur Wroblewski\n" - "Jeroen Vloothuis" + "Jeroen Vloothuis\n" + "Dan Yeaw\n" + "Enno Groeper\n" + "Adam Boduch\n" + "Jordi Mallach\n" + "Ygor Mutti\n" + "Alexis Howells\n" + "Encolpe Degoute\n" + "Melis Dogan" ) add_label("") - notebook.append_page(tab_vbox, Gtk.Label(label=_("Authors"))) + notebook.append_page(tab_vbox, Gtk.Label(label=_("Contributors"))) vbox.show_all() about.run() From 779850f9223a06b9951456dca5e28c4562234eaf Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Sat, 12 Jan 2019 14:38:03 -0500 Subject: [PATCH 10/15] Restore alt key menu shortcuts Signed-off-by: Dan Yeaw --- gaphor/plugins/diagramlayout/__init__.py | 2 +- gaphor/ui/elementeditor.py | 2 +- gaphor/ui/mainwindow.py | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/gaphor/plugins/diagramlayout/__init__.py b/gaphor/plugins/diagramlayout/__init__.py index eda31d6678..1c8b27432f 100644 --- a/gaphor/plugins/diagramlayout/__init__.py +++ b/gaphor/plugins/diagramlayout/__init__.py @@ -53,7 +53,7 @@ def update(self): self.sensitive = bool(self.get_window().get_current_diagram()) @action( - name="diagram-layout", label="Layout diagram", tooltip="simple diagram layout" + name="diagram-layout", label="La_yout diagram", tooltip="simple diagram layout" ) def execute(self): d = self.diagram.get_current_diagram() diff --git a/gaphor/ui/elementeditor.py b/gaphor/ui/elementeditor.py index 0f8a3fd21c..af64058e35 100644 --- a/gaphor/ui/elementeditor.py +++ b/gaphor/ui/elementeditor.py @@ -48,7 +48,7 @@ def __init__(self): @open_action( name="ElementEditor:open", - label=_("Editor"), + label=_("_Editor"), stock_id="gtk-edit", accel="e", ) diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index 7a21222544..f346aa354d 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -175,7 +175,6 @@ def init_action_group(self): ("edit", "_Edit"), ("diagram", "_Diagram"), ("tools", "_Tools"), - ("window", "_Window"), ("help", "_Help"), ): a = Gtk.Action.new(name, label, None, None) @@ -648,7 +647,7 @@ def tree_view_create_package(self): @action( name="tree-view-delete-package", - label=_("Delete package"), + label=_("Delete pac_kage"), stock_id="gtk-delete", ) @transactional From f3ef0193abf87eb1c4b6714c69c11b9e8342fd50 Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Sat, 12 Jan 2019 22:23:42 -0500 Subject: [PATCH 11/15] Fix console window opens small by adding minimum size Signed-off-by: Dan Yeaw --- gaphor/misc/console.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gaphor/misc/console.py b/gaphor/misc/console.py index 58fc64f1f6..f7d667049c 100644 --- a/gaphor/misc/console.py +++ b/gaphor/misc/console.py @@ -149,6 +149,8 @@ class GTKInterpreterConsole(Gtk.ScrolledWindow): def __init__(self, locals=None): Gtk.ScrolledWindow.__init__(self) + self.set_min_content_width(640) + self.set_min_content_height(480) self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.text = Gtk.TextView() @@ -360,7 +362,6 @@ def do_unrealize(self): def main(): w = Gtk.Window() console = GTKInterpreterConsole() - console.set_size_request(640, 480) w.add(console) def destroy(arg=None): From 893df4369fb65b295cdcc02ede37f660a10a9e8d Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Sun, 27 Jan 2019 20:05:50 -0500 Subject: [PATCH 12/15] Allow main window to be resizable Signed-off-by: Dan Yeaw --- gaphor/ui/mainwindow.py | 3 +-- gaphor/ui/toolbox.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index f346aa354d..ba93f836d5 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -237,8 +237,7 @@ def open(self): self.window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL) self.window.set_title(self.title) - self.window.set_size_request(*self.size) - self.window.set_resizable(self.resizable) + self.window.set_default_size(*self.size) # set default icons of gaphor windows icon_dir = os.path.abspath( diff --git a/gaphor/ui/toolbox.py b/gaphor/ui/toolbox.py index f109d6df77..c2b4a11af7 100644 --- a/gaphor/ui/toolbox.py +++ b/gaphor/ui/toolbox.py @@ -16,7 +16,7 @@ class Toolbox(Gtk.VBox): with a name above it. When the user clicks on the name the box's content shows/hides. - The 'toggled' signal is emited everytime a box shows/hides. + The 'toggled' signal is emitted every time a box shows/hides. The toolbox is generated based on a definition with the form: ('name', ('boxAction1', 'boxAction2',...), 'name2', ('BoxActionN',...)) From 35ea26b9a0ccccff8e6379d47261cc1a1c00f9f6 Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Tue, 29 Jan 2019 22:18:54 -0500 Subject: [PATCH 13/15] Replace Toolbox wrapbox with Gtk.ToolPalette The toolbox was using a custom wrapbox that provided similar functionality to the Gtk ToolPalette widget. Switched to the base Gtk+ widget to improve Gtk compatibility and fix the wrapbox not wrapping the buttons down to the next row when shrinking the toolbox. Signed-off-by: Dan Yeaw --- gaphor/ui/layout.py | 4 +- gaphor/ui/mainwindow.py | 2 + gaphor/ui/toolbox.py | 81 ++++++++-------------------------- gaphor/ui/wrapbox.py | 98 ----------------------------------------- 4 files changed, 23 insertions(+), 162 deletions(-) delete mode 100644 gaphor/ui/wrapbox.py diff --git a/gaphor/ui/layout.py b/gaphor/ui/layout.py index 48f2cbe893..51ede0694b 100644 --- a/gaphor/ui/layout.py +++ b/gaphor/ui/layout.py @@ -73,9 +73,9 @@ def _des(element, index, parent_widget=None): def add(widget, index, parent_widget): if isinstance(parent_widget, Gtk.Paned): if index == 0: - parent_widget.add1(widget) + parent_widget.pack1(child=widget, resize=False, shrink=False) elif index == 1: - parent_widget.add2(widget) + parent_widget.pack2(child=widget, resize=True, shrink=False) else: parent_widget.add(widget) diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index ba93f836d5..ce76351a4d 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -478,6 +478,8 @@ def construct(self): scrolled_window = Gtk.ScrolledWindow() scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scrolled_window.set_shadow_type(Gtk.ShadowType.IN) + scrolled_window.set_min_content_height(150) + scrolled_window.set_placement(Gtk.CornerType.TOP_RIGHT) scrolled_window.add(view) scrolled_window.show() view.show() diff --git a/gaphor/ui/toolbox.py b/gaphor/ui/toolbox.py index c2b4a11af7..d6db2fc442 100644 --- a/gaphor/ui/toolbox.py +++ b/gaphor/ui/toolbox.py @@ -7,23 +7,18 @@ from gi.repository import Gtk from gaphor.core import inject -from gaphor.ui.wrapbox import Wrapbox -class Toolbox(Gtk.VBox): +class Toolbox(Gtk.ToolPalette): """ - A toolbox is a widget that contains a set of buttons (a Wrapbox widget) - with a name above it. When the user clicks on the name the box's content - shows/hides. - - The 'toggled' signal is emitted every time a box shows/hides. + A toolbox is a ToolPalette widget that contains a ToolItems (buttons) that + are added to a ToolItemGroup. Each group has a label above the buttons. + When the user clicks on the name the group's content toggles to show or + hide the buttons. The toolbox is generated based on a definition with the form: ('name', ('boxAction1', 'boxAction2',...), 'name2', ('BoxActionN',...)) - 1 Create action pool for placement actions - 2 Create Gtk.RadioButtons for each item. - 3 connect to action """ TARGET_STRING = 0 @@ -47,57 +42,23 @@ class Toolbox(Gtk.VBox): properties = inject("properties") def __init__(self, toolboxdef): - """ - Create a new Toolbox instance. Wrapbox objects are generated - using the menu_factory and based on the toolboxdef definition. + """Create a new Toolbox instance. + + ToolItemGroups and ToolItems are created using the menu_factory and + based on the toolboxdef definition. + """ GObject.GObject.__init__(self) self.buttons = [] self.shortcuts = {} self._construct(toolboxdef) - def make_wrapbox_decorator(self, title, content): - """ - Create a Gtk.VBox with in the top compartment a label that can be - clicked to show/hide the lower compartment. - """ - expander = Gtk.Expander() - - expander.set_label(title) - - prop = "ui.toolbox.%s" % title.replace(" ", "-").lower() - - expanded = self.properties.get(prop, False) - expander.set_expanded(expanded) - - expander.connect("activate", self.on_expander_toggled, prop) - - expander.add(content) - - expander.show_all() - - return expander - - def on_expander_toggled(self, widget, prop): - # Save the property (inverse value as handler is called before the - # action takes place): - self.properties.set(prop, not widget.get_expanded()) - - def toolbox_button( - self, action_name, stock_id, icon_size=Gtk.IconSize.LARGE_TOOLBAR - ): - button = Gtk.ToggleButton() - button.set_relief(Gtk.ReliefStyle.NONE) - if stock_id: - icon = Gtk.Image() - icon.set_from_stock(stock_id, icon_size) - button.add(icon) - icon.show() - else: - button.props.label = action_name + def toolbox_button(self, action_name, stock_id): + button = Gtk.ToolButton.new_from_stock(stock_id) button.action_name = action_name + button.set_use_drag_window(True) - # Enable DND (behaviour like tree view) + # Enable Drag and Drop button.drag_source_set( Gdk.ModifierType.BUTTON1_MASK, self.DND_TARGETS, @@ -111,21 +72,17 @@ def toolbox_button( def _construct(self, toolboxdef): shortcuts = self.shortcuts for title, items in toolboxdef: - wrapbox = Wrapbox() + tool_item_group = Gtk.ToolItemGroup.new(title) for action_name, label, stock_id, shortcut in items: button = self.toolbox_button(action_name, stock_id) if label: button.set_tooltip_text("%s (%s)" % (label, shortcut)) self.buttons.append(button) - wrapbox.add(button) + tool_item_group.insert(button, -1) button.show() shortcuts[shortcut] = action_name - if title: - wrapbox_dec = self.make_wrapbox_decorator(title, wrapbox) - self.pack_start(wrapbox_dec, False, True, 0) - else: - self.pack_start(wrapbox, False, True, 0) - wrapbox.show() + self.add(tool_item_group) + tool_item_group.show() def _button_drag_data_get(self, button, context, data, info, time): """The drag-data-get event signal handler. @@ -143,7 +100,7 @@ def _button_drag_data_get(self, button, context, data, info, time): time (int): The timestamp at which the data was received. """ - data.set(data.get_target(), 8, button.action_name.encode()) + data.set(type=data.get_target(), format=8, data=button.action_name.encode()) # vim:sw=4:et:ai diff --git a/gaphor/ui/wrapbox.py b/gaphor/ui/wrapbox.py deleted file mode 100644 index 7726082d32..0000000000 --- a/gaphor/ui/wrapbox.py +++ /dev/null @@ -1,98 +0,0 @@ -from __future__ import division - -from past.utils import old_div -from gi.repository import GLib -from gi.repository import GObject -from gi.repository import Gtk - - -class Wrapbox(Gtk.Table): - """ - A Wrapbox contains a set of items. A wrap box tries to optimize it's - content by moving elements to a second row if the do not fit on the first. - And a third and a fourth, depending on the given space. - - The width is given, the height is changed in order to fit all contained - objects. - """ - - def __init__(self): - GObject.GObject.__init__(self) - self.resize_idle_id = 0 - self.rows = 1 - self.cols = 1 - self.resize(self.rows, self.cols) - self.connect("size_allocate", self.on_size_allocate) - self.children = [] - - def calculate_size(self, allocation): - children = self.children - max_width = 0 - for c in children: - size_request = c.size_request() - # print size_request - max_width = max(max_width, size_request[0]) - cols = old_div(allocation.width, (max_width or 1)) - if cols == 0: - cols = 1 - rows = old_div(len(children), cols) - if len(children) % cols: - rows += 1 - return cols, rows - - def set_new_size(self): - # table = self.table - table = self - children = self.children - if not children: - return - rows = self.rows - cols = self.cols - for c in children: - table.remove(c) - table.resize(rows, cols) - x = y = 0 - for c in children: - table.attach( - c, left_attach=x, right_attach=x + 1, top_attach=y, bottom_attach=y + 1 - ) - x += 1 - if x == rows: - x = 0 - y += 1 - - def _idle_handler(self): - try: - self.set_new_size() - finally: - self.resize_idle_id = 0 - - def on_size_allocate(self, table, allocation): - rows, cols = self.calculate_size(allocation) - # print 'size_allocate', rows, cols - if not self.resize_idle_id and (rows != self.rows or cols != self.cols): - # print 'size_allocate', 'setting idle handler' - self.resize_idle_id = GLib.idle_add(self._idle_handler) - self.rows = rows - self.cols = cols - - def add(self, widget): - assert widget, "No widget supplied: %s" % widget - self.cols += 1 - row = self.rows - col = self.cols - # self.table.attach(widget, left_attach=col-1, right_attach=col, - self.attach( - widget, - left_attach=col - 1, - right_attach=col, - top_attach=row - 1, - bottom_attach=row, - ) - self.children.append(widget) - - -GObject.type_register(Wrapbox) - - -# vim:sw=4:et From c7d16571f149a280741c17275a6acb12f3a86ce0 Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Wed, 30 Jan 2019 20:47:18 -0500 Subject: [PATCH 14/15] Apply default position layout to Gtk Paned on main window Signed-off-by: Dan Yeaw --- gaphor/ui/layout.py | 4 +++- gaphor/ui/layout.xml | 6 +++--- gaphor/ui/mainwindow.py | 1 - 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/gaphor/ui/layout.py b/gaphor/ui/layout.py index 51ede0694b..2965ef708e 100644 --- a/gaphor/ui/layout.py +++ b/gaphor/ui/layout.py @@ -93,12 +93,14 @@ def _factory(func): @factory("paned") -def paned(parent, index, orientation, weight=None): +def paned(parent, index, orientation, position=None): paned = Gtk.Paned.new( Gtk.Orientation.HORIZONTAL if orientation == "horizontal" else Gtk.Orientation.VERTICAL ) add(paned, index, parent) + if position: + paned.set_position(int(position)) paned.show() return paned diff --git a/gaphor/ui/layout.xml b/gaphor/ui/layout.xml index f55599481d..8940a36f21 100644 --- a/gaphor/ui/layout.xml +++ b/gaphor/ui/layout.xml @@ -1,10 +1,10 @@ - - + + - + diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index ce76351a4d..d455f84cb1 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -478,7 +478,6 @@ def construct(self): scrolled_window = Gtk.ScrolledWindow() scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scrolled_window.set_shadow_type(Gtk.ShadowType.IN) - scrolled_window.set_min_content_height(150) scrolled_window.set_placement(Gtk.CornerType.TOP_RIGHT) scrolled_window.add(view) scrolled_window.show() From 833934fdceada50827aecc51d5d18e0422b67d4c Mon Sep 17 00:00:00 2001 From: Dan Yeaw Date: Thu, 31 Jan 2019 22:11:47 -0500 Subject: [PATCH 15/15] Fix hand drawn style option on diagram pages Refactored the hand draw style action from the MainWindow to the Diagram class, since the action was unable to get the list of tabs from the MainWindow. Signed-off-by: Dan Yeaw --- gaphor/ui/mainwindow.py | 74 ++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/gaphor/ui/mainwindow.py b/gaphor/ui/mainwindow.py index d455f84cb1..d1bfd6533b 100644 --- a/gaphor/ui/mainwindow.py +++ b/gaphor/ui/mainwindow.py @@ -99,8 +99,6 @@ class MainWindow(object): - - @@ -181,9 +179,6 @@ def init_action_group(self): a.set_property("hide-if-empty", False) self.action_group.add_action(a) self._tab_ui_settings = None - self.action_group.get_action("diagram-drawing-style").set_active( - self.properties("diagram.sloppiness", 0) != 0 - ) self.action_manager.register_action_provider(self) @@ -384,19 +379,6 @@ def quit(self): self.ask_to_close() and Gtk.main_quit() self.shutdown() - @toggle_action(name="diagram-drawing-style", label="Hand drawn style", active=False) - def hand_drawn_style(self, active): - """ - Toggle between straight diagrams and "hand drawn" diagram style. - """ - if active: - sloppiness = 0.5 - else: - sloppiness = 0.0 - for tab in self.get_tabs(): - tab.set_drawing_style(sloppiness) - self.properties.set("diagram.sloppiness", sloppiness) - def create_item(self, ui_component): """ Create an item for a ui component. This method can be called from UIComponents. @@ -760,7 +742,7 @@ def set_active_tool(self, action_name=None, shortcut=None): return -@implementer(IUIComponent) +@implementer(IUIComponent, IActionProvider) class Diagrams(object): title = _("Diagrams") @@ -769,8 +751,24 @@ class Diagrams(object): component_registry = inject("component_registry") properties = inject("properties") + menu_xml = """ + + + + + + + + + + """ + def __init__(self): self._notebook = None + self.action_group = build_action_group(self) + self.action_group.get_action("diagram-drawing-style").set_active( + self.properties("diagram.sloppiness", 0) != 0 + ) def open(self): """Open the diagrams component. @@ -850,6 +848,23 @@ def create_tab(self, title, widget): self.component_registry.handle(DiagramPageChange(widget)) self._notebook.set_show_tabs(True) + def get_widgets_on_pages(self): + """Gets the widget on each open page Notebook page. + + The page is the page number in the Notebook (0 indexed) and the widget + is the child widget on each page. + + Returns: + List of tuples (page, widget) of the currently open Notebook pages. + + """ + widgets_on_pages = [] + num_pages = self._notebook.get_n_pages() + for page in range(0, num_pages): + widget = self._notebook.get_nth_page(page) + widgets_on_pages.append((page, widget)) + return widgets_on_pages + @component.adapter(DiagramShow) def _on_show_diagram(self, event): """Show a Diagram element in the Notebook. @@ -864,12 +879,10 @@ def _on_show_diagram(self, event): diagram = event.diagram # Try to find an existing diagram page and give it focus - num_pages = self._notebook.get_n_pages() - for page in range(0, num_pages): - child_widget = self._notebook.get_nth_page(page) - if child_widget.diagram_page.get_diagram() is diagram: + for page, widget in self.get_widgets_on_pages(): + if widget.diagram_page.get_diagram() is diagram: self._notebook.set_current_page(page) - return child_widget.diagram_page + return widget.diagram_page # No existing diagram page found, creating one page = DiagramPage(diagram) @@ -882,5 +895,18 @@ def _on_show_diagram(self, event): self.create_tab(diagram.name, widget) return page + @toggle_action(name="diagram-drawing-style", label="Hand drawn style", active=False) + def hand_drawn_style(self, active): + """ + Toggle between straight diagrams and "hand drawn" diagram style. + """ + if active: + sloppiness = 0.5 + else: + sloppiness = 0.0 + for page, widget in self.get_widgets_on_pages(): + widget.diagram_page.set_drawing_style(sloppiness) + self.properties.set("diagram.sloppiness", sloppiness) + # vim:sw=4:et:ai