Implement recent projects menu

Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
This commit is contained in:
TheJackiMonster 2023-03-21 20:51:05 +01:00
parent 988fa62d61
commit 9287e85b7e
No known key found for this signature in database
GPG key ID: D850A5F772E880F9
6 changed files with 137 additions and 56 deletions

View file

@ -14,5 +14,6 @@ from manuskript.ui import MainWindow
path = os.path.join(os.getcwd(), "sample-projects/book-of-acts") path = os.path.join(os.getcwd(), "sample-projects/book-of-acts")
window = MainWindow(path + ".msk") window = MainWindow()
window.openProject(path + ".msk")
window.run() window.run()

View file

@ -17,36 +17,14 @@ from manuskript.ui.tools import *
from manuskript.ui.aboutDialog import AboutDialog from manuskript.ui.aboutDialog import AboutDialog
from manuskript.ui.settingsWindow import SettingsWindow from manuskript.ui.settingsWindow import SettingsWindow
from manuskript.ui.startupWindow import StartupWindow from manuskript.ui.startupWindow import StartupWindow
from manuskript.ui.util import bindMenuItem from manuskript.ui.util import bindMenuItem, packViewIntoSlot, unpackFromSlot
from manuskript.util import profileTime from manuskript.util import parseFilenameFromURL
class MainWindow: class MainWindow:
@classmethod def __init__(self):
def packViewIntoSlot(cls, builder, id, view_cls, data=None): self.project = None
slot = builder.get_object(id)
if slot is None:
return None
try:
if data is None:
view = profileTime(view_cls)
else:
view = profileTime(view_cls, data)
except Exception:
return None
if view.widget is None:
return None
slot.pack_start(view.widget, True, True, 0)
return view
def __init__(self, path):
self.project = Project(path)
self.project.load()
builder = Gtk.Builder() builder = Gtk.Builder()
builder.add_from_file("ui/main.glade") builder.add_from_file("ui/main.glade")
@ -58,20 +36,25 @@ class MainWindow:
self.leaflet = builder.get_object("leaflet") self.leaflet = builder.get_object("leaflet")
self.viewSwitcherBar = builder.get_object("view_switcher_bar") self.viewSwitcherBar = builder.get_object("view_switcher_bar")
self.headerBar.set_subtitle(self.project.info.title)
self.leaflet.bind_property("folded", self.viewSwitcherBar, "reveal", GObject.BindingFlags.SYNC_CREATE) self.leaflet.bind_property("folded", self.viewSwitcherBar, "reveal", GObject.BindingFlags.SYNC_CREATE)
self.leaflet.bind_property("folded", self.headerBar, "show-close-button", GObject.BindingFlags.SYNC_CREATE | self.leaflet.bind_property("folded", self.headerBar, "show-close-button", GObject.BindingFlags.SYNC_CREATE |
GObject.BindingFlags.INVERT_BOOLEAN) GObject.BindingFlags.INVERT_BOOLEAN)
self.generalView = MainWindow.packViewIntoSlot(builder, "general_slot", GeneralView, self.project.info) self.generalSlot = builder.get_object("general_slot")
self.summaryView = MainWindow.packViewIntoSlot(builder, "summary_slot", SummaryView, self.project.summary) self.summarySlot = builder.get_object("summary_slot")
self.charactersView = MainWindow.packViewIntoSlot(builder, "characters_slot", CharactersView, self.charactersSlot = builder.get_object("characters_slot")
self.project.characters) self.plotSlot = builder.get_object("plot_slot")
self.plotView = MainWindow.packViewIntoSlot(builder, "plot_slot", PlotView, self.project.plots) self.worldSlot = builder.get_object("world_slot")
self.worldView = MainWindow.packViewIntoSlot(builder, "world_slot", WorldView, self.project.world) self.outlineSlot = builder.get_object("outline_slot")
self.outlineView = MainWindow.packViewIntoSlot(builder, "outline_slot", OutlineView, self.project.outline) self.editorSlot = builder.get_object("editor_slot")
self.editorView = MainWindow.packViewIntoSlot(builder, "editor_slot", EditorView, self.project)
self.generalView = None
self.summaryView = None
self.charactersView = None
self.plotView = None
self.worldView = None
self.outlineView = None
self.editorView = None
self.startupWindow = StartupWindow(self) self.startupWindow = StartupWindow(self)
self.aboutDialog = AboutDialog(self) self.aboutDialog = AboutDialog(self)
@ -85,6 +68,9 @@ class MainWindow:
self.settingsWindow self.settingsWindow
] ]
self.recentChooserMenu = builder.get_object("recent_chooser_menu")
self.recentChooserMenu.connect("item-activated", self._recentAction)
bindMenuItem(builder, "open_menu_item", self._openAction) bindMenuItem(builder, "open_menu_item", self._openAction)
bindMenuItem(builder, "save_menu_item", self._saveAction) bindMenuItem(builder, "save_menu_item", self._saveAction)
bindMenuItem(builder, "close_menu_item", self._closeAction) bindMenuItem(builder, "close_menu_item", self._closeAction)
@ -94,18 +80,66 @@ class MainWindow:
bindMenuItem(builder, "frequency_menu_item", self._frequencyAction) bindMenuItem(builder, "frequency_menu_item", self._frequencyAction)
bindMenuItem(builder, "about_menu_item", self._aboutAction) bindMenuItem(builder, "about_menu_item", self._aboutAction)
self.hide()
def getProject(self): def getProject(self):
return self.project return self.project
def openProject(self): def openProject(self, path=None, dialog=False):
pass if self.project is not None:
self.closeProject()
if dialog:
return
if path is None:
return
self.project = Project(path)
self.project.load()
self.headerBar.set_subtitle(self.project.info.title)
self.generalView = packViewIntoSlot(self.generalSlot, GeneralView, self.project.info)
self.summaryView = packViewIntoSlot(self.summarySlot, SummaryView, self.project.summary)
self.charactersView = packViewIntoSlot(self.charactersSlot, CharactersView, self.project.characters)
self.plotView = packViewIntoSlot(self.plotSlot, PlotView, self.project.plots)
self.worldView = packViewIntoSlot(self.worldSlot, WorldView, self.project.world)
self.outlineView = packViewIntoSlot(self.outlineSlot, OutlineView, self.project.outline)
self.editorView = packViewIntoSlot(self.editorSlot, EditorView, self.project)
self.startupWindow.hide()
self.show()
def closeProject(self): def closeProject(self):
if self.project is not None:
self.generalView = unpackFromSlot(self.generalSlot, self.generalView)
self.summaryView = unpackFromSlot(self.summarySlot, self.summaryView)
self.charactersView = unpackFromSlot(self.charactersSlot, self.charactersView)
self.plotView = unpackFromSlot(self.plotSlot, self.plotView)
self.worldView = unpackFromSlot(self.worldSlot, self.worldView)
self.outlineView = unpackFromSlot(self.outlineSlot, self.outlineView)
self.editorView = unpackFromSlot(self.editorSlot, self.editorView)
del self.project
self.project = None
self.hide() self.hide()
self.startupWindow.show() self.startupWindow.show()
def _openAction(self, menuItem: Gtk.MenuItem): def _openAction(self, menuItem: Gtk.MenuItem):
self.openProject() self.openProject(dialog=True)
def _recentAction(self, recentChooser: Gtk.RecentChooser):
uri = recentChooser.get_current_uri()
if uri is None:
return
path = parseFilenameFromURL(uri)
if path is None:
return
self.openProject(path)
def _saveAction(self, menuItem: Gtk.MenuItem): def _saveAction(self, menuItem: Gtk.MenuItem):
self.getProject().save() self.getProject().save()

View file

@ -6,8 +6,8 @@ import gi
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
from gi.repository import GObject, Gtk, Handy from gi.repository import GObject, Gtk, Handy
from manuskript.data import Template, TemplateLevel, TemplateKind from manuskript.data import Template, TemplateKind
from manuskript.util import validInt, validString from manuskript.util import validInt, validString, parseFilenameFromURL
from manuskript.ui.abstractDialog import AbstractDialog from manuskript.ui.abstractDialog import AbstractDialog
from manuskript.ui.startup import TemplateEntry from manuskript.ui.startup import TemplateEntry
@ -25,6 +25,8 @@ class StartupWindow(AbstractDialog):
self.headerBar = None self.headerBar = None
self.templatesLeaflet = None self.templatesLeaflet = None
self.recentChooserMenu = None
self.templatesStore = None self.templatesStore = None
self.fictionTemplatesStore = None self.fictionTemplatesStore = None
self.nonfictionTemplatesStore = None self.nonfictionTemplatesStore = None
@ -45,6 +47,9 @@ class StartupWindow(AbstractDialog):
GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.SYNC_CREATE |
GObject.BindingFlags.INVERT_BOOLEAN) GObject.BindingFlags.INVERT_BOOLEAN)
self.recentChooserMenu = builder.get_object("recent_chooser_menu")
self.recentChooserMenu.connect("item-activated", self._recentAction)
bindMenuItem(builder, "open_menu_item", self._openAction) bindMenuItem(builder, "open_menu_item", self._openAction)
bindMenuItem(builder, "quit_menu_item", self._quitAction) bindMenuItem(builder, "quit_menu_item", self._quitAction)
@ -154,6 +159,17 @@ class StartupWindow(AbstractDialog):
def _openAction(self, menuItem: Gtk.MenuItem): def _openAction(self, menuItem: Gtk.MenuItem):
self.mainWindow.openProject() self.mainWindow.openProject()
def _recentAction(self, recentChooser: Gtk.RecentChooser):
uri = recentChooser.get_current_uri()
if uri is None:
return
path = parseFilenameFromURL(uri)
if path is None:
return
self.mainWindow.openProject(path)
def _quitAction(self, menuItem: Gtk.MenuItem): def _quitAction(self, menuItem: Gtk.MenuItem):
self.mainWindow.exit(True) self.mainWindow.exit(True)

View file

@ -8,6 +8,7 @@ gi.require_version('GdkPixbuf', '2.0')
from gi.repository import GdkPixbuf, Gdk from gi.repository import GdkPixbuf, Gdk
from manuskript.data import Color, OutlineItem, OutlineText, OutlineFolder from manuskript.data import Color, OutlineItem, OutlineText, OutlineFolder
from manuskript.util import profileTime
def rgbaFromColor(color: Color) -> Gdk.RGBA: def rgbaFromColor(color: Color) -> Gdk.RGBA:
@ -34,6 +35,36 @@ def bindMenuItem(builder, id, action):
menuItem.connect("activate", action) menuItem.connect("activate", action)
def packViewIntoSlot(slot, view_cls, data=None):
if slot is None:
return None
for child in slot.get_children():
slot.remove(child)
try:
if data is None:
view = profileTime(view_cls)
else:
view = profileTime(view_cls, data)
except Exception:
return None
if view.widget is None:
return None
slot.pack_start(view.widget, True, True, 0)
return view
def unpackFromSlot(slot, view):
if (slot is not None) and (view.widget is not None):
slot.remove(view.widget)
del view
return None
def iconByOutlineItemType(outlineItem: OutlineItem) -> str: def iconByOutlineItemType(outlineItem: OutlineItem) -> str:
if type(outlineItem) is OutlineFolder: if type(outlineItem) is OutlineFolder:
return "folder-symbolic" return "folder-symbolic"

View file

@ -4,6 +4,7 @@
import re import re
import time import time
import traceback import traceback
import urllib.parse
from manuskript.util.counter import CounterKind, CharCounter, WordCounter, PageCounter from manuskript.util.counter import CounterKind, CharCounter, WordCounter, PageCounter
@ -51,6 +52,18 @@ def safeFilename(filename: str, extension: str = None) -> str:
return re.sub(r"[^a-zA-Z0-9._\-+()]", "_", name) return re.sub(r"[^a-zA-Z0-9._\-+()]", "_", name)
def parseFilenameFromURL(url: str) -> str | None:
result = urllib.parse.urlparse(url)
if result is None:
return None
if result.scheme != "file":
return None
return result.path
def countText(text: str, kind: CounterKind = CounterKind.WORDS): def countText(text: str, kind: CounterKind = CounterKind.WORDS):
if text is None: if text is None:
return 0 return 0

View file

@ -923,20 +923,6 @@ summary</property>
<property name="position">2</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Next</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">3</property>
</packing>
</child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>