Handle recent files through the GTK facility
This saves me some headaches synching files with GUI and it's done GNOME wide.
This commit is contained in:
parent
da7a063f33
commit
e95e3a7241
@ -15,7 +15,7 @@ from gaphor.misc.gidlethread import GIdleThread, Queue
|
||||
from gaphor.misc.xmlwriter import XMLWriter
|
||||
from gaphor.storage import storage, verify
|
||||
import gaphor.ui
|
||||
from gaphor.ui.event import FilenameChanged, RecentFilesUpdated, WindowClose
|
||||
from gaphor.ui.event import FilenameChanged, WindowClose
|
||||
from gaphor.ui.filedialog import FileDialog
|
||||
from gaphor.ui.questiondialog import QuestionDialog
|
||||
from gaphor.ui.statuswindow import StatusWindow
|
||||
@ -110,6 +110,8 @@ class FileManager(Service, ActionProvider):
|
||||
|
||||
if filename != self._filename:
|
||||
self._filename = filename
|
||||
if self.event_manager:
|
||||
self.event_manager.handle(FilenameChanged(self, filename))
|
||||
self.update_recent_files(filename)
|
||||
|
||||
filename = property(get_filename, set_filename)
|
||||
@ -136,11 +138,12 @@ class FileManager(Service, ActionProvider):
|
||||
|
||||
recent_files = self.recent_files
|
||||
|
||||
if new_filename and new_filename not in recent_files:
|
||||
if new_filename:
|
||||
if new_filename in recent_files:
|
||||
recent_files.remove(new_filename)
|
||||
recent_files.insert(0, new_filename)
|
||||
recent_files = recent_files[0 : (MAX_RECENT - 1)]
|
||||
self.recent_files = recent_files
|
||||
self.event_manager.handle(RecentFilesUpdated(self, recent_files))
|
||||
|
||||
# TODO: Old code, remove.
|
||||
for i in range(0, (MAX_RECENT - 1)):
|
||||
@ -162,7 +165,6 @@ class FileManager(Service, ActionProvider):
|
||||
filename = self.recent_files[index]
|
||||
|
||||
self.load(filename)
|
||||
self.event_manager.handle(FilenameChanged(self, filename))
|
||||
|
||||
def load(self, filename):
|
||||
"""Load the Gaphor model from the supplied file name. A status window
|
||||
@ -358,8 +360,6 @@ class FileManager(Service, ActionProvider):
|
||||
# main_window.select_element(diagram)
|
||||
# main_window.show_diagram(diagram)
|
||||
|
||||
self.event_manager.handle(FilenameChanged(self))
|
||||
|
||||
@action(name="file-new-template", label=_("New from template"))
|
||||
def action_new_from_template(self):
|
||||
"""This menu action opens the new model from template dialog."""
|
||||
@ -380,7 +380,6 @@ class FileManager(Service, ActionProvider):
|
||||
if filename:
|
||||
self.load(filename)
|
||||
self.filename = None
|
||||
self.event_manager.handle(FilenameChanged(self))
|
||||
|
||||
@action(
|
||||
name="file-open",
|
||||
@ -406,7 +405,6 @@ class FileManager(Service, ActionProvider):
|
||||
|
||||
if filename:
|
||||
self.load(filename)
|
||||
self.event_manager.handle(FilenameChanged(self, filename))
|
||||
|
||||
@action(
|
||||
name="file-save",
|
||||
@ -426,7 +424,6 @@ class FileManager(Service, ActionProvider):
|
||||
|
||||
if filename:
|
||||
self.save(filename)
|
||||
self.event_manager.handle(FilenameChanged(self, filename))
|
||||
return True
|
||||
else:
|
||||
return self.action_save_as()
|
||||
@ -455,7 +452,6 @@ class FileManager(Service, ActionProvider):
|
||||
|
||||
if filename:
|
||||
self.save(filename)
|
||||
self.event_manager.handle(FilenameChanged(self, filename))
|
||||
return True
|
||||
|
||||
return False
|
||||
|
@ -14,6 +14,9 @@ import os.path
|
||||
from gaphor.ui.actiongroup import apply_application_actions
|
||||
|
||||
|
||||
APPLICATION_ID = "org.gaphor.Gaphor"
|
||||
|
||||
|
||||
icon_theme = Gtk.IconTheme.get_default()
|
||||
with importlib.resources.path("gaphor.ui", "pixmaps") as path:
|
||||
icon_theme.append_search_path(str(path))
|
||||
@ -31,7 +34,7 @@ css_provider.load_from_data(b"#diagram-tab { background: white }")
|
||||
|
||||
def run(application, model):
|
||||
gtk_app = Gtk.Application(
|
||||
application_id="org.gaphor.Gaphor", flags=Gio.ApplicationFlags.FLAGS_NONE
|
||||
application_id=APPLICATION_ID, flags=Gio.ApplicationFlags.FLAGS_NONE
|
||||
)
|
||||
|
||||
def app_startup(app):
|
||||
|
@ -38,13 +38,3 @@ class FilenameChanged:
|
||||
def __init__(self, service, filename=None):
|
||||
self.service = service
|
||||
self.filename = filename
|
||||
|
||||
|
||||
class RecentFilesUpdated:
|
||||
"""
|
||||
Event class used to send state changes on the Undo Manager.
|
||||
"""
|
||||
|
||||
def __init__(self, service, recent_files=[]):
|
||||
self.service = service
|
||||
self.recent_files = recent_files
|
||||
|
@ -6,6 +6,7 @@ from typing import List, Tuple
|
||||
|
||||
import logging
|
||||
import os.path
|
||||
from pathlib import Path
|
||||
|
||||
import importlib.resources
|
||||
from gi.repository import Gio, Gdk, Gtk, GLib
|
||||
@ -23,6 +24,7 @@ from gaphor.core import (
|
||||
from gaphor.abc import Service, ActionProvider
|
||||
from gaphor.UML.event import AttributeChangeEvent, FlushFactoryEvent
|
||||
from gaphor.services.undomanager import UndoManagerStateChanged
|
||||
from gaphor.ui import APPLICATION_ID
|
||||
from gaphor.ui.abc import UIComponent
|
||||
from gaphor.ui.actiongroup import window_action_group
|
||||
from gaphor.ui.accelmap import load_accel_map, save_accel_map
|
||||
@ -43,6 +45,28 @@ ICONS = (
|
||||
)
|
||||
|
||||
|
||||
class RecentFilesMenu(Gio.Menu):
|
||||
def __init__(self, recent_manager):
|
||||
super().__init__()
|
||||
|
||||
self._on_recent_manager_changed(recent_manager)
|
||||
recent_manager.connect("changed", self._on_recent_manager_changed)
|
||||
|
||||
def _on_recent_manager_changed(self, recent_manager):
|
||||
self.remove_all()
|
||||
home = str(Path.home())
|
||||
for item in recent_manager.get_items():
|
||||
if APPLICATION_ID in item.get_applications():
|
||||
menu_item = Gio.MenuItem.new(
|
||||
item.get_uri_display().replace(home, "~"), None
|
||||
)
|
||||
self.append_item(menu_item)
|
||||
if self.get_n_items() > 9:
|
||||
break
|
||||
if self.get_n_items() == 0:
|
||||
self.append_item(Gio.MenuItem.new(_("No recently opened models"), None))
|
||||
|
||||
|
||||
def hamburger_menu():
|
||||
button = Gtk.MenuButton()
|
||||
image = Gtk.Image.new_from_icon_name("open-menu-symbolic", Gtk.IconSize.MENU)
|
||||
@ -56,40 +80,30 @@ def create_dummy_popover(parent):
|
||||
model = Gio.Menu.new()
|
||||
|
||||
part = Gio.Menu.new()
|
||||
part.append_item(Gio.MenuItem.new(_("Save As..."), "win.file-save-as"))
|
||||
part.append(_("New"), "win.file-new")
|
||||
part.append(_("New from Template"), "win.file-new-template")
|
||||
model.append_section(None, part)
|
||||
|
||||
part = Gio.Menu.new()
|
||||
part.append_item(
|
||||
Gio.MenuItem.new(_("Hand-Drawn Style"), "win.diagram-drawing-style")
|
||||
)
|
||||
part.append(_("Save As..."), "win.file-save-as")
|
||||
model.append_section(None, part)
|
||||
|
||||
part = Gio.Menu.new()
|
||||
part.append_item(Gio.MenuItem.new(_("Preferences"), "app.preferences"))
|
||||
part.append_item(Gio.MenuItem.new(_("About Gaphor"), "app.about"))
|
||||
part.append(_("Hand-Drawn Style"), "win.diagram-drawing-style")
|
||||
model.append_section(None, part)
|
||||
|
||||
part = Gio.Menu.new()
|
||||
part.append(_("Preferences"), "app.preferences")
|
||||
part.append(_("About Gaphor"), "app.about")
|
||||
model.append_section(None, part)
|
||||
|
||||
return Gtk.Popover.new_from_model(parent, model)
|
||||
|
||||
|
||||
def create_recent_files_popover(parent):
|
||||
model = Gio.Menu.new()
|
||||
|
||||
part = Gio.Menu.new()
|
||||
menu_item = Gio.MenuItem.new(_("New"), "win.file-new")
|
||||
menu_item.set_attribute_value("iconic", GLib.Variant.new_boolean(True))
|
||||
part.append_item(menu_item)
|
||||
part.append_item(Gio.MenuItem.new(_("New from Template"), "win.file-new-template"))
|
||||
model.append_section(None, part)
|
||||
|
||||
part = Gio.Menu.new()
|
||||
part.append_item(
|
||||
Gio.MenuItem.new("~/gaphor/UML/uml2.gaphor", "recent.file-open-recent-1")
|
||||
return Gtk.Popover.new_from_model(
|
||||
parent, RecentFilesMenu(Gtk.RecentManager.get_default())
|
||||
)
|
||||
model.append_section(None, part)
|
||||
|
||||
return Gtk.Popover.new_from_model(parent, model)
|
||||
|
||||
|
||||
class MainWindow(Service, ActionProvider):
|
||||
|
31
gaphor/ui/recentfiles.py
Normal file
31
gaphor/ui/recentfiles.py
Normal file
@ -0,0 +1,31 @@
|
||||
import os
|
||||
from gi.repository import GLib, Gtk
|
||||
|
||||
from gaphor.abc import Service
|
||||
from gaphor.core import event_handler
|
||||
from gaphor.ui import APPLICATION_ID
|
||||
from gaphor.ui.event import FilenameChanged
|
||||
|
||||
|
||||
class RecentFiles(Service):
|
||||
def __init__(self, event_manager, recent_manager=None):
|
||||
print("Recent files initated")
|
||||
self.event_manager = event_manager
|
||||
self.recent_manager = recent_manager or Gtk.RecentManager.get_default()
|
||||
|
||||
self.event_manager.subscribe(self._on_filename_changed)
|
||||
|
||||
def shutdown(self):
|
||||
self.event_manager.unsubscribe(self._on_filename_changed)
|
||||
|
||||
@event_handler(FilenameChanged)
|
||||
def _on_filename_changed(self, event):
|
||||
filename = event.filename
|
||||
if not filename:
|
||||
return
|
||||
uri = GLib.filename_to_uri(os.path.abspath(filename))
|
||||
meta = Gtk.RecentData()
|
||||
meta.app_name = APPLICATION_ID
|
||||
meta.app_exec = f"{GLib.get_prgname()} %u"
|
||||
meta.mime_type = "application/x-gaphor"
|
||||
self.recent_manager.add_full(uri, meta)
|
27
gaphor/ui/tests/test_recentfiles.py
Normal file
27
gaphor/ui/tests/test_recentfiles.py
Normal file
@ -0,0 +1,27 @@
|
||||
import pytest
|
||||
from gaphor.services.eventmanager import EventManager
|
||||
from gaphor.ui.event import FilenameChanged
|
||||
from gaphor.ui.recentfiles import RecentFiles
|
||||
|
||||
|
||||
class RecentManagerStub:
|
||||
def __init__(self):
|
||||
self.items = []
|
||||
|
||||
def add_full(self, uri, meta):
|
||||
self.items.append(uri)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def event_manager():
|
||||
return EventManager()
|
||||
|
||||
|
||||
def test_add_new_recent_file(event_manager):
|
||||
recent_manager = RecentManagerStub()
|
||||
recent_files = RecentFiles(event_manager, recent_manager)
|
||||
|
||||
event_manager.handle(FilenameChanged(None, "testfile.gaphor"))
|
||||
|
||||
assert len(recent_manager.items) == 1
|
||||
assert recent_manager.items[0].startswith("file:///"), recent_manager.items[0]
|
@ -59,6 +59,7 @@ gaphorconvert = 'gaphor.tools.gaphorconvert:main'
|
||||
"undo_manager" = "gaphor.services.undomanager:UndoManager"
|
||||
"element_factory" = "gaphor.UML.elementfactory:ElementFactory"
|
||||
"file_manager" = "gaphor.services.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"
|
||||
|
1
setup.py
1
setup.py
@ -108,6 +108,7 @@ setup(
|
||||
"undo_manager = gaphor.services.undomanager:UndoManager",
|
||||
"element_factory = gaphor.UML.elementfactory:ElementFactory",
|
||||
"file_manager = gaphor.services.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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user