This commit is contained in:
TheShadowOfHassen 2023-06-27 21:05:17 -04:00
commit 684f854f78
32 changed files with 1840 additions and 147 deletions

View file

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

View file

@ -20,6 +20,11 @@ class AbstractData:
self.dataPath = path
self.dataStatus = DataStatus.UNDEFINED
def changePath(self, path: str):
print("{} -> {}".format(self.dataPath, path))
self.dataPath = path
def complete(self, statusCompletion: bool = True):
if self.dataStatus == DataStatus.LOADING:
self.dataStatus = DataStatus.LOADED if statusCompletion else DataStatus.UNDEFINED

View file

@ -37,6 +37,10 @@ class Character(AbstractData):
self.color = None
self.details = dict()
def changePath(self, path: str):
AbstractData.changePath(self, path)
self.file = MmdFile(self.dataPath, 21)
def allowPOV(self) -> bool:
return True if self.POV is None else self.POV
@ -119,6 +123,15 @@ class Characters(AbstractData):
self.host = UniqueIDHost()
self.data = dict()
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "characters"))
for character in self.data.values():
filename = safeFilename("%s-%s" % (str(character.UID), character.name), "txt")
path_ = os.path.join(self.dataPath, filename)
character.changePath(path_)
def __iter__(self):
return self.data.values().__iter__()

View file

@ -22,6 +22,10 @@ class Info(AbstractData):
self.author = None
self.email = None
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "infos.txt"))
self.file = MmdFile(self.dataPath, 16)
def load(self):
AbstractData.load(self)

View file

@ -35,6 +35,10 @@ class LabelHost(AbstractData):
self.file = MmdFile(self.dataPath, 21)
self.labels = collections.OrderedDict()
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "labels.txt"))
self.file = MmdFile(self.dataPath, 21)
def addLabel(self, name: str = None, color: Color = None) -> Label:
if name is None:
name = "New Label"

View file

@ -13,7 +13,7 @@ from manuskript.data.plots import Plots
from manuskript.data.status import StatusHost
from manuskript.data.unique_id import UniqueIDHost
from manuskript.io.mmdFile import MmdFile
from manuskript.util import CounterKind, countText, safeInt
from manuskript.util import CounterKind, countText, safeInt, safeFilename
@unique
@ -43,6 +43,10 @@ class OutlineItem(AbstractData):
self.compile = True
self.goal = None
def changePath(self, path: str):
AbstractData.changePath(self, path)
self.file = MmdFile(self.dataPath)
def parentItem(self):
for item in self.outline.all():
if item.contains(self):
@ -94,8 +98,8 @@ class OutlineItem(AbstractData):
metadata["summaryFull"] = item.summaryFull
metadata["POV"] = item.POV
metadata["notes"] = item.notes
metadata["label"] = None if item is None else item.label.ID
metadata["status"] = None if item is None else item.status.ID
metadata["label"] = None if item.label is None else item.label.ID
metadata["status"] = None if item.status is None else item.status.ID
metadata["compile"] = item.compile
metadata["setGoal"] = item.goal
@ -152,8 +156,9 @@ class OutlineText(OutlineItem):
metadata, body = self.file.loadMMD(optimized)
OutlineItem.loadMetadata(self, metadata)
if not optimized:
if body is not None:
self.text = body
optimized = False
self.complete(optimized=optimized)
@ -177,6 +182,19 @@ class OutlineFolder(OutlineItem):
self.folderPath = path
self.items = list()
def changePath(self, path: str):
OutlineItem.changePath(self, os.path.join(path, "folder.txt"))
self.folderPath = path
index = 0
for item in self.items:
filename = safeFilename("%s-%s" % (str(index), item.title), None if type(item) is OutlineFolder else "md")
path_ = os.path.join(self.folderPath, filename)
item.changePath(path_)
index += 1
def __iter__(self):
return self.items.__iter__()
@ -250,6 +268,7 @@ class OutlineFolder(OutlineItem):
self.type = "folder"
OutlineItem.save(self)
os.makedirs(self.folderPath, exist_ok=True)
metadata = OutlineItem.saveMetadata(self)
self.file.save((metadata, "\n"))
@ -267,6 +286,17 @@ class Outline(AbstractData):
self.items = list()
self.cache = dict()
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "outline"))
index = 0
for item in self.items:
filename = safeFilename("%s-%s" % (str(index), item.title), None if type(item) is OutlineFolder else "md")
path_ = os.path.join(self.dataPath, filename)
item.changePath(path_)
index += 1
def __iter__(self):
return self.items.__iter__()
@ -317,6 +347,10 @@ class Outline(AbstractData):
AbstractData.load(self)
if not os.path.isdir(self.dataPath):
self.complete(False)
return
names = os.listdir(self.dataPath)
names.sort()

View file

@ -113,6 +113,10 @@ class Plots(AbstractData):
self.characters = characters
self.lines = dict()
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "plots.xml"))
self.file = XmlFile(self.dataPath)
def addLine(self, name: str = None, importance: Importance = Importance.MINOR):
line = PlotLine(self, self.host.newID(), name, importance)
self.lines[line.UID.value] = line

View file

@ -29,7 +29,8 @@ from manuskript.util import profileTime
class Project(AbstractData):
def __init__(self, path):
def __init__(self, path: str):
AbstractData.__init__(self, path)
self.file = MskFile(self.dataPath)
@ -68,6 +69,25 @@ class Project(AbstractData):
def upgradeVersion(self):
self.version.value = CURRENT_MSK_VERSION
def changePath(self, path: str):
AbstractData.changePath(self, path)
saveToZip = self.settings.isEnabled("saveToZip")
self.file = MskFile(self.dataPath, ignorePath=True, forceZip=saveToZip)
os.makedirs(self.file.directoryPath, exist_ok=True)
self.version.changePath(self.file.directoryPath)
self.info.changePath(self.file.directoryPath)
self.summary.changePath(self.file.directoryPath)
self.labels.changePath(self.file.directoryPath)
self.statuses.changePath(self.file.directoryPath)
self.settings.changePath(self.file.directoryPath)
self.characters.changePath(self.file.directoryPath)
self.plots.changePath(self.file.directoryPath)
self.world.changePath(self.file.directoryPath)
self.outline.changePath(self.file.directoryPath)
self.revisions.changePath(self.file.directoryPath)
def load(self):
AbstractData.load(self)

View file

@ -43,6 +43,10 @@ class Revisions(AbstractData):
self.file = XmlFile(self.dataPath)
self.outline = dict()
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "revisions.xml"))
self.file = XmlFile(self.dataPath)
def __iter__(self):
return self.outline.values().__iter__()

View file

@ -17,6 +17,10 @@ class Settings(AbstractData):
if initDefault:
Settings.loadDefaultSettings(self)
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "settings.txt"))
self.file = JsonFile(self.dataPath)
def get(self, key: str):
props = self.properties
path = key.split(".")

View file

@ -33,6 +33,10 @@ class StatusHost(AbstractData):
self.file = TextFile(self.dataPath)
self.statuses = collections.OrderedDict()
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "status.txt"))
self.file = TextFile(self.dataPath)
def addStatus(self, name: str = None) -> Status:
if name is None:
name = "New Status"

View file

@ -19,6 +19,10 @@ class Summary(AbstractData):
self.page = None
self.full = None
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "summary.txt"))
self.file = MmdFile(self.dataPath, 13)
def load(self):
AbstractData.load(self)

View file

@ -19,6 +19,11 @@ class Version(AbstractData):
self.value = LEGACY_MSK_VERSION
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "MANUSKRIPT"))
self.file = TextFile(self.dataPath)
self.legacy_file = TextFile(os.path.join(path, "VERSION"))
def loadLegacy(self):
try:
return int(self.legacy_file.load())

View file

@ -45,6 +45,10 @@ class World(AbstractData):
self.items = dict()
self.top = list()
def changePath(self, path: str):
AbstractData.changePath(self, os.path.join(path, "world.opml"))
self.file = OpmlFile(self.dataPath)
def addItem(self, name: str = None, parent: WorldItem = None) -> WorldItem:
item = WorldItem(self, self.host.newID(), name)

View file

@ -24,7 +24,8 @@ class MmdFile(AbstractFile):
metaValue = None
with open(self.path, 'rt', encoding='utf-8') as file:
for line in file:
line = file.readline()
while line:
m = metaPattern.match(line)
if not (m is None):
@ -33,14 +34,15 @@ class MmdFile(AbstractFile):
metaKey = m.group(1)
metaValue = m.group(2)
continue
else:
m = metaValuePattern.match(line)
m = metaValuePattern.match(line)
if not (m is None):
metaValue += "\n" + m.group(2)
elif line == "\n":
break
if not (m is None):
metaValue += "\n" + m.group(2)
elif line == "\n":
break
line = file.readline()
if not (metaKey is None):
metadata[metaKey] = metaValue
@ -50,6 +52,14 @@ class MmdFile(AbstractFile):
if (len(body) > 0) and (body[0] == "\n"):
body = body[1:]
elif file.seekable():
currentPosition = file.tell()
file.seek(0, 2)
endPosition = file.tell()
if endPosition - currentPosition == 1:
body = ""
return metadata, body

View file

@ -13,14 +13,16 @@ from manuskript.data.version import LEGACY_MSK_VERSION
class MskFile(TextFile, ZipFile):
def __init__(self, path):
def __init__(self, path, ignorePath: bool = False, forceZip: bool = False):
try:
_ZipFile(path)
if not forceZip:
_ZipFile(path)
directoryPath = None
except BadZipFile:
except (BadZipFile, FileNotFoundError):
directoryPath = os.path.splitext(path)[0]
if not os.path.isdir(directoryPath):
if (not ignorePath) and (not os.path.isdir(directoryPath)):
directoryPath = None
self.zipFile = directoryPath is None
@ -47,7 +49,8 @@ class MskFile(TextFile, ZipFile):
if not os.path.isdir(self.directoryPath):
os.mkdir(self.directoryPath)
ZipFile.load(self)
if os.path.exists(self.path):
ZipFile.load(self)
self.zipFile = zipFile

View file

@ -4,6 +4,8 @@
from manuskript.ui.util import *
from manuskript.ui.aboutDialog import AboutDialog
from manuskript.ui.compileWindow import CompileWindow
from manuskript.ui.importWindow import ImportWindow
from manuskript.ui.mainWindow import MainWindow
from manuskript.ui.settingsWindow import SettingsWindow
from manuskript.ui.startupWindow import StartupWindow

View file

@ -0,0 +1,68 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gdk', '3.0')
from gi.repository import GObject, Gtk
from manuskript.ui.chooser.fileFilter import FileFilter
def openFileDialog(window, fileFilter_: FileFilter = None, appendAllFilter: bool = True) -> str | None:
dialog = Gtk.FileChooserDialog(
"Please choose a file",
window,
Gtk.FileChooserAction.OPEN,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
)
dialog.set_default_response(Gtk.ResponseType.OK)
if fileFilter_ is not None:
fileFilter_.addToChooser(dialog)
if appendAllFilter:
FileFilter("All files").addToChooser(dialog)
response = dialog.run()
result = None
if response == Gtk.ResponseType.OK:
result = dialog.get_filename()
dialog.destroy()
return result
def saveFileDialog(window, fileFilter_: FileFilter = None, appendAllFilter: bool = True) -> str | None:
dialog = Gtk.FileChooserDialog(
"Please choose a file",
window,
Gtk.FileChooserAction.SAVE,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
)
dialog.set_default_response(Gtk.ResponseType.OK)
if fileFilter_ is not None:
fileFilter_.addToChooser(dialog)
if appendAllFilter:
FileFilter("All files").addToChooser(dialog)
response = dialog.run()
result = None
if response == Gtk.ResponseType.OK:
result = dialog.get_filename()
if ((fileFilter_ is not None) and (fileFilter_.name == dialog.get_filter().get_name()) and
(not result.endswith("." + fileFilter_.extension))):
result += "." + fileFilter_.extension
dialog.destroy()
return result

View file

@ -0,0 +1,22 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gdk', '3.0')
from gi.repository import GObject, Gtk
class FileFilter:
def __init__(self, name: str, extension: str = ""):
self.name = name
self.extension = extension
def addToChooser(self, chooser: Gtk.FileChooser):
fileFilter = Gtk.FileFilter()
fileFilter.set_name(self.name)
fileFilter.add_pattern("*.{}".format(self.extension) if len(self.extension) > 0 else "*")
chooser.add_filter(fileFilter)

View file

@ -0,0 +1,53 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GObject, Gtk, Handy
Handy.init()
from manuskript.ui.abstractDialog import AbstractDialog
from manuskript.data import Project
class CompileWindow(AbstractDialog):
def __init__(self, mainWindow):
AbstractDialog.__init__(self, mainWindow, "ui/compile.glade", "compile_window")
self.headerBar = None
self.back = None
self.forward = None
self.previewLeaflet = None
self.manageExportersButton = None
def initWindow(self, builder, window):
self.headerBar = builder.get_object("header_bar")
self.back = builder.get_object("back")
self.forward = builder.get_object("forward")
self.previewLeaflet = builder.get_object("preview_leaflet")
self.manageExportersButton = builder.get_object("manage_exporters")
self.previewLeaflet.bind_property("folded", self.back, "visible",
GObject.BindingFlags.SYNC_CREATE)
self.previewLeaflet.bind_property("folded", self.forward, "visible",
GObject.BindingFlags.SYNC_CREATE)
self.previewLeaflet.bind_property("folded", self.headerBar, "show-close-button",
GObject.BindingFlags.SYNC_CREATE |
GObject.BindingFlags.INVERT_BOOLEAN)
self.back.connect("clicked", self._backClicked)
self.forward.connect("clicked", self._forwardClicked)
def _backClicked(self, button: Gtk.Button):
if self.previewLeaflet.get_visible_child_name() == "preview_box":
self.previewLeaflet.set_visible_child_name("settings_box")
else:
self.hide()
def _forwardClicked(self, button: Gtk.Button):
if self.previewLeaflet.get_visible_child_name() == "settings_box":
self.previewLeaflet.set_visible_child_name("preview_box")

View file

@ -0,0 +1,51 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GObject, Gtk, Handy
Handy.init()
from manuskript.ui.abstractDialog import AbstractDialog
from manuskript.data import Project
class ImportWindow(AbstractDialog):
def __init__(self, mainWindow):
AbstractDialog.__init__(self, mainWindow, "ui/import.glade", "import_window")
self.headerBar = None
self.back = None
self.forward = None
self.previewLeaflet = None
def initWindow(self, builder, window):
self.headerBar = builder.get_object("header_bar")
self.back = builder.get_object("back")
self.forward = builder.get_object("forward")
self.previewLeaflet = builder.get_object("preview_leaflet")
self.previewLeaflet.bind_property("folded", self.back, "visible",
GObject.BindingFlags.SYNC_CREATE)
self.previewLeaflet.bind_property("folded", self.forward, "visible",
GObject.BindingFlags.SYNC_CREATE)
self.previewLeaflet.bind_property("folded", self.headerBar, "show-close-button",
GObject.BindingFlags.SYNC_CREATE |
GObject.BindingFlags.INVERT_BOOLEAN)
self.back.connect("clicked", self._backClicked)
self.forward.connect("clicked", self._forwardClicked)
def _backClicked(self, button: Gtk.Button):
if self.previewLeaflet.get_visible_child_name() == "preview_box":
self.previewLeaflet.set_visible_child_name("settings_box")
else:
self.hide()
def _forwardClicked(self, button: Gtk.Button):
if self.previewLeaflet.get_visible_child_name() == "settings_box":
self.previewLeaflet.set_visible_child_name("preview_box")

View file

@ -13,40 +13,21 @@ Handy.init()
from manuskript.data import Project
from manuskript.ui.views import *
from manuskript.ui.chooser import openFileDialog, saveFileDialog, FileFilter
from manuskript.ui.tools import *
from manuskript.ui.aboutDialog import AboutDialog
from manuskript.ui.compileWindow import CompileWindow
from manuskript.ui.importWindow import ImportWindow
from manuskript.ui.settingsWindow import SettingsWindow
from manuskript.ui.startupWindow import StartupWindow
from manuskript.ui.util import bindMenuItem
from manuskript.util import profileTime
from manuskript.ui.util import bindMenuItem, packViewIntoSlot, unpackFromSlot
from manuskript.util import parseFilenameFromURL
class MainWindow:
@classmethod
def packViewIntoSlot(cls, builder, id, view_cls, data=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()
def __init__(self):
self.project = None
builder = Gtk.Builder()
builder.add_from_file("ui/main.glade")
@ -58,24 +39,32 @@ class MainWindow:
self.leaflet = builder.get_object("leaflet")
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.headerBar, "show-close-button", GObject.BindingFlags.SYNC_CREATE |
GObject.BindingFlags.INVERT_BOOLEAN)
self.generalView = MainWindow.packViewIntoSlot(builder, "general_slot", GeneralView, self.project.info)
self.summaryView = MainWindow.packViewIntoSlot(builder, "summary_slot", SummaryView, self.project.summary)
self.charactersView = MainWindow.packViewIntoSlot(builder, "characters_slot", CharactersView, self.project)
self.plotView = MainWindow.packViewIntoSlot(builder, "plot_slot", PlotView, self.project.plots)
self.worldView = MainWindow.packViewIntoSlot(builder, "world_slot", WorldView, self.project.world)
self.outlineView = MainWindow.packViewIntoSlot(builder, "outline_slot", OutlineView, self.project.outline)
self.editorView = MainWindow.packViewIntoSlot(builder, "editor_slot", EditorView, self.project)
self.generalSlot = builder.get_object("general_slot")
self.summarySlot = builder.get_object("summary_slot")
self.charactersSlot = builder.get_object("characters_slot")
self.plotSlot = builder.get_object("plot_slot")
self.worldSlot = builder.get_object("world_slot")
self.outlineSlot = builder.get_object("outline_slot")
self.editorSlot = builder.get_object("editor_slot")
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.aboutDialog = AboutDialog(self)
self.frequencyWindow = FrequencyWindow(self)
self.settingsWindow = SettingsWindow(self)
self.importWindow = ImportWindow(self)
self.compileWindow = CompileWindow(self)
self.windows = [
self.startupWindow,
@ -84,9 +73,15 @@ class MainWindow:
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, "save_menu_item", self._saveAction)
bindMenuItem(builder, "saveas_menu_item", self._saveAsAction)
bindMenuItem(builder, "close_menu_item", self._closeAction)
bindMenuItem(builder, "import_menu_item", self._importAction)
bindMenuItem(builder, "compile_menu_item", self._compileAction)
bindMenuItem(builder, "quit_menu_item", self._quitAction)
bindMenuItem(builder, "settings_menu_item", self._settingsAction)
@ -94,30 +89,93 @@ class MainWindow:
bindMenuItem(builder, "character_details_template_editor", self._characterDetailsTemplateEditorAction)
bindMenuItem(builder, "about_menu_item", self._aboutAction)
self.hide()
def getProject(self):
return self.project
def openProject(self):
pass
def openProject(self, path=None):
if self.project is not None:
self.closeProject()
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)
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):
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.startupWindow.show()
def _openAction(self, menuItem: Gtk.MenuItem):
self.openProject()
path = openFileDialog(self.window, FileFilter("Manuskript project", "msk"))
if path is None:
return
self.openProject(path)
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):
self.getProject().save()
self.project.save()
def _saveAsAction(self, menuItem: Gtk.MenuItem):
path = saveFileDialog(self.window, FileFilter("Manuskript project", "msk"))
if path is None:
return
self.project.changePath(path)
self.project.save()
def _closeAction(self, menuItem: Gtk.MenuItem):
self.closeProject()
def _importAction(self, menuItem: Gtk.MenuItem):
self.importWindow.show()
def _compileAction(self, menuItem: Gtk.MenuItem):
self.compileWindow.show()
def _quitAction(self, menuItem: Gtk.MenuItem):
self.exit(True)
def getSettings(self):
return self.getProject().settings
return self.project.settings
def _settingsAction(self, menuItem: Gtk.MenuItem):
self.settingsWindow.show()

View file

@ -6,10 +6,11 @@ import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GObject, Gtk, Handy
from manuskript.data import Template, TemplateLevel, TemplateKind
from manuskript.util import validInt, validString
from manuskript.data import Project, Template, TemplateKind
from manuskript.util import validInt, validString, parseFilenameFromURL
from manuskript.ui.abstractDialog import AbstractDialog
from manuskript.ui.chooser import openFileDialog, saveFileDialog, FileFilter
from manuskript.ui.startup import TemplateEntry
from manuskript.ui.util import bindMenuItem
@ -25,6 +26,9 @@ class StartupWindow(AbstractDialog):
self.headerBar = None
self.templatesLeaflet = None
self.recentChooserMenu = None
self.recentChooserMenuBtn = None
self.templatesStore = None
self.fictionTemplatesStore = None
self.nonfictionTemplatesStore = None
@ -37,6 +41,10 @@ class StartupWindow(AbstractDialog):
self.addLevelButton = None
self.addGoalButton = None
self.openButton = None
self.recentButton = None
self.createButton = None
def initWindow(self, builder, window):
self.headerBar = builder.get_object("header_bar")
self.templatesLeaflet = builder.get_object("templates_leaflet")
@ -45,6 +53,11 @@ class StartupWindow(AbstractDialog):
GObject.BindingFlags.SYNC_CREATE |
GObject.BindingFlags.INVERT_BOOLEAN)
self.recentChooserMenu = builder.get_object("recent_chooser_menu")
self.recentChooserMenuBtn = builder.get_object("recent_chooser_menu_btn")
self.recentChooserMenu.connect("item-activated", self._recentAction)
self.recentChooserMenuBtn.connect("item-activated", self._recentAction)
bindMenuItem(builder, "open_menu_item", self._openAction)
bindMenuItem(builder, "quit_menu_item", self._quitAction)
@ -98,6 +111,13 @@ class StartupWindow(AbstractDialog):
self.addLevelButton.connect("clicked", self._addLevelClicked)
self.addGoalButton.connect("clicked", self._addGoalClicked)
self.openButton = builder.get_object("open_button")
self.recentButton = builder.get_object("recent_button")
self.createButton = builder.get_object("create_button")
self.openButton.connect("clicked", self._openClicked)
self.createButton.connect("clicked", self._createClicked)
def loadTemplate(self, template: Template):
self.template = template
self.templateLevelsListbox.foreach(lambda child: self.templateLevelsListbox.remove(child))
@ -152,8 +172,40 @@ class StartupWindow(AbstractDialog):
self.template.addGoal()
self.loadTemplate(self.template)
def openProject(self):
path = openFileDialog(self.window, FileFilter("Manuskript project", "msk"))
if path is None:
return
self.mainWindow.openProject(path)
def _openClicked(self, button: Gtk.Button):
self.openProject()
def _createClicked(self, button: Gtk.Button):
path = saveFileDialog(self.window, FileFilter("Manuskript project", "msk"), appendAllFilter=False)
if path is None:
return
project = Project(path)
# TODO: apply project template!
project.save()
self.mainWindow.openProject(path)
def _openAction(self, menuItem: Gtk.MenuItem):
self.mainWindow.openProject()
self.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):
self.mainWindow.exit(True)

View file

@ -4,9 +4,22 @@
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GObject, Gtk, Handy
from gi.repository import GObject, Gtk
import re
from enum import Enum, unique
from manuskript.data import OutlineFolder, OutlineText, OutlineState, Project
from manuskript.ui.abstractDialog import AbstractDialog
from manuskript.util import validString, validInt
@unique
class AnalyzeStatus(Enum):
NONE = 0
WORDS = 1
PHRASES = 2
class FrequencyWindow(AbstractDialog):
@ -14,18 +27,56 @@ class FrequencyWindow(AbstractDialog):
def __init__(self, mainWindow):
AbstractDialog.__init__(self, mainWindow, "ui/frequency.glade", "frequency_window")
self.analyzeStatus = AnalyzeStatus.NONE
self.analyzeTexts = list()
self.outlineCompletion = list()
self.analyzeCompleted = 0
self.headerBar = None
self.back = None
self.wordLeaflet = None
self.wordsProgress = None
self.analyzeWords = None
self.phrasesProgress = None
self.analyzePhrases = None
self.wordEntry = None
self.removeWord = None
self.addWord = None
self.excludeWordSelection = None
self.excludeWordsStore = None
self.wordsFrequencyStore = None
self.phrasesFrequencyStore = None
self.phraseMinimum = None
self.phraseMaximum = None
self.wordSize = None
def initWindow(self, builder, window):
self.headerBar = builder.get_object("header_bar")
self.back = builder.get_object("back")
self.wordLeaflet = builder.get_object("word_leaflet")
self.wordsProgress = builder.get_object("words_progress")
self.analyzeWords = builder.get_object("analyze_words")
self.phrasesProgress = builder.get_object("phrases_progress")
self.analyzePhrases = builder.get_object("analyze_phrases")
self.wordEntry = builder.get_object("word_entry")
self.removeWord = builder.get_object("remove_word")
self.addWord = builder.get_object("add_word")
self.excludeWordSelection = builder.get_object("exclude_word_selection")
self.excludeWordsStore = builder.get_object("exclude_words_store")
self.wordsFrequencyStore = builder.get_object("words_frequency_store")
self.phrasesFrequencyStore = builder.get_object("phrases_frequency_store")
self.filteredFrequencyStore = builder.get_object("filtered_frequency_store")
self.filteredFrequencyStore.set_visible_func(self._filterFrequencies)
self.filteredFrequencyStore.refilter()
self.phraseMinimum = builder.get_object("phrase_minimum")
self.phraseMaximum = builder.get_object("phrase_maximum")
self.wordSize = builder.get_object("word_size")
self.wordLeaflet.bind_property("folded", self.back, "visible",
GObject.BindingFlags.SYNC_CREATE)
@ -35,12 +86,182 @@ class FrequencyWindow(AbstractDialog):
self.back.connect("clicked", self._backClicked)
self.analyzeWords.connect("clicked", self._analyzeWordsClicked)
self.analyzePhrases.connect("clicked", self._analyzePhrasesClicked)
self.wordSize.connect("value-changed", self._wordSizeChanged)
self.excludeWordSelection.connect("changed", self._excludeWordSelectionChanged)
self.removeWord.connect("clicked", self._removeWordClicked)
self.addWord.connect("clicked", self._addWordClicked)
def getProject(self) -> Project:
return self.mainWindow.getProject()
def _filterFrequencies(self, model, iterator, userdata):
word = model[iterator][0]
if word is None:
return False
word_size = validInt(self.wordSize.get_value())
if len(word) < word_size:
return False
iter = self.excludeWordsStore.get_iter_first()
while iter is not None:
excluded = self.excludeWordsStore.get_value(iter, 0)
if word == excluded:
return False
iter = self.excludeWordsStore.iter_next(iter)
return True
def _backClicked(self, button: Gtk.Button):
if self.wordLeaflet.get_visible_child_name() == "wordlist_view":
self.wordLeaflet.set_visible_child_name("wordfilter_view")
else:
self.hide()
def __completeOutlineItem(self):
outline_item = self.outlineCompletion.pop(0)
if isinstance(outline_item, OutlineFolder):
for item in outline_item:
self.outlineCompletion.append(item)
elif isinstance(outline_item, OutlineText):
if outline_item.state != OutlineState.COMPLETE:
outline_item.load(False)
self.analyzeTexts.append(outline_item.text)
self.analyzeCompleted = self.analyzeCompleted + 1
incomplete = len(self.outlineCompletion)
complete = self.analyzeCompleted
fraction = 1.0 * complete / (complete + incomplete)
if self.analyzeStatus == AnalyzeStatus.WORDS:
self.wordsProgress.set_fraction(fraction)
elif self.analyzeStatus == AnalyzeStatus.PHRASES:
self.phrasesProgress.set_fraction(fraction)
if incomplete > 0:
return True
patterns = list()
if self.analyzeStatus == AnalyzeStatus.WORDS:
word_size = validInt(self.wordSize.get_value())
patterns.append(re.compile(r"\w{" + str(word_size) + r",}"))
elif self.analyzeStatus == AnalyzeStatus.PHRASES:
phrase_minimum = validInt(self.phraseMinimum.get_value())
phrase_maximum = validInt(self.phraseMaximum.get_value())
for n in range(phrase_minimum, phrase_maximum + 1):
patterns.append(re.compile(r"\w+" + r"\s+\w+" * (n - 1)))
frequencies = dict()
text = "\n".join(self.analyzeTexts)
for pattern in patterns:
for match in pattern.findall(text):
if match is None:
continue
if match in frequencies:
frequencies[match] = frequencies[match] + 1
else:
frequencies[match] = 1
if self.analyzeStatus == AnalyzeStatus.WORDS:
self.wordsFrequencyStore.clear()
for word, frequency in frequencies.items():
tree_iter = self.wordsFrequencyStore.append()
if tree_iter is None:
continue
self.wordsFrequencyStore.set_value(tree_iter, 0, validString(word))
self.wordsFrequencyStore.set_value(tree_iter, 1, validInt(frequency))
self.wordLeaflet.set_visible_child_name("wordlist_view")
elif self.analyzeStatus == AnalyzeStatus.PHRASES:
self.phrasesFrequencyStore.clear()
for phrase, frequency in frequencies.items():
tree_iter = self.phrasesFrequencyStore.append()
if tree_iter is None:
continue
self.phrasesFrequencyStore.set_value(tree_iter, 0, validString(phrase))
self.phrasesFrequencyStore.set_value(tree_iter, 1, validInt(frequency))
self.analyzeStatus = AnalyzeStatus.NONE
self.analyzeTexts = list()
self.analyzeWords.set_sensitive(True)
self.analyzePhrases.set_sensitive(True)
return False
def analyze(self, status: AnalyzeStatus):
if self.analyzeStatus != AnalyzeStatus.NONE:
return
project = self.getProject()
if project is None:
return
self.analyzeWords.set_sensitive(False)
self.analyzePhrases.set_sensitive(False)
self.analyzeStatus = status
if len(self.outlineCompletion) == 0:
self.analyzeTexts = list()
self.analyzeCompleted = 0
if self.analyzeStatus == AnalyzeStatus.WORDS:
self.wordsProgress.set_fraction(0.0)
elif self.analyzeStatus == AnalyzeStatus.PHRASES:
self.phrasesProgress.set_fraction(0.0)
GObject.idle_add(self.__completeOutlineItem)
for outline_item in project.outline:
self.outlineCompletion.append(outline_item)
def _analyzeWordsClicked(self, button: Gtk.Button):
self.wordLeaflet.set_visible_child_name("wordlist_view")
self.analyze(AnalyzeStatus.WORDS)
def _analyzePhrasesClicked(self, button: Gtk.Button):
self.analyze(AnalyzeStatus.PHRASES)
def _wordSizeChanged(self, adjustment: Gtk.Adjustment):
self.filteredFrequencyStore.refilter()
def _excludeWordSelectionChanged(self, selection: Gtk.TreeSelection):
model, tree_iter = selection.get_selected()
self.removeWord.set_sensitive(tree_iter is not None)
def _removeWordClicked(self, button: Gtk.Button):
model, tree_iter = self.excludeWordSelection.get_selected()
if tree_iter is None:
return
self.excludeWordsStore.remove(tree_iter)
self.filteredFrequencyStore.refilter()
def _addWordClicked(self, button: Gtk.Button):
tree_iter = self.excludeWordsStore.append()
if tree_iter is None:
return
word = self.wordEntry.get_buffer().get_text()
self.excludeWordsStore.set_value(tree_iter, 0, word)
self.filteredFrequencyStore.refilter()

View file

@ -8,6 +8,7 @@ gi.require_version('GdkPixbuf', '2.0')
from gi.repository import GdkPixbuf, Gdk
from manuskript.data import Color, OutlineItem, OutlineText, OutlineFolder
from manuskript.util import profileTime
def rgbaFromColor(color: Color) -> Gdk.RGBA:
@ -34,6 +35,36 @@ def bindMenuItem(builder, id, 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:
if type(outlineItem) is OutlineFolder:
return "folder-symbolic"

View file

@ -270,8 +270,6 @@ class EditorView:
self.editorItems = self.project.outline.items
elif type(outlineItem) is OutlineFolder:
self.editorItems = outlineItem.items
elif type(outlineItem) is OutlineText:
self.__appendOutlineItemText(outlineItem)
if outlineItem is None:
for item in self.editorItems:

View file

@ -4,6 +4,7 @@
import re
import time
import traceback
import urllib.parse
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)
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):
if text is None:
return 0

875
ui/compile.glade Normal file
View file

@ -0,0 +1,875 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.40.0
Copyright (C) 2015-2021 Olivier Keshavjee et al.
This file is part of Manuskript.
Manuskript is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Manuskript is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
-->
<interface>
<requires lib="gtk+" version="3.24"/>
<requires lib="libhandy" version="0.0"/>
<!-- interface-local-resource-path ../ -->
<!-- interface-license-type gplv3 -->
<!-- interface-name Manuskript -->
<!-- interface-description Manuskript is an open-source tool for writers. -->
<!-- interface-copyright 2015-2021 Olivier Keshavjee et al. -->
<object class="GtkListStore" id="file_format_store">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name mimeType -->
<column type="gchararray"/>
<!-- column-name icon -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">Markdown</col>
<col id="1" translatable="yes">text/markdown</col>
<col id="2" translatable="yes">text-x-generic</col>
</row>
<row>
<col id="0" translatable="yes">Folder</col>
<col id="1" translatable="yes">directory</col>
<col id="2" translatable="yes">folder</col>
</row>
<row>
<col id="0" translatable="yes">OPML</col>
<col id="1" translatable="yes">text/opml</col>
<col id="2" translatable="yes">text-x-generic-template</col>
</row>
<row>
<col id="0" translatable="yes">Mind Map</col>
<col id="1" translatable="yes">text/mind-map</col>
<col id="2" translatable="yes">text-x-generic-template</col>
</row>
</data>
</object>
<object class="HdyWindow" id="compile_window">
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyTitleBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="HdyHeaderBar" id="header_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Export</property>
<child>
<object class="GtkButton" id="back">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="forward">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-next-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="HdyLeaflet" id="preview_leaflet">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="width-request">300</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">4</property>
<property name="margin-end">4</property>
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Format:</property>
<attributes>
<attribute name="weight" value="semibold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="model">file_format_store</property>
<property name="active">0</property>
<child>
<object class="GtkCellRendererPixbuf"/>
<attributes>
<attribute name="icon-name">2</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="manage_exporters">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">preferences-other-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Manage Exporters</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">8</property>
<property name="margin-end">8</property>
<property name="margin-top">8</property>
<property name="margin-bottom">8</property>
<property name="orientation">vertical</property>
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="label" translatable="yes">Settings</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="semibold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkExpander">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">8</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Decide here what will be included in the final export.</property>
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<!-- n-columns=3 n-rows=3 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">4</property>
<property name="column-homogeneous">True</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Type</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Title</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Text</property>
</object>
<packing>
<property name="left-attach">2</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton">
<property name="label" translatable="yes"> </property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkCheckButton">
<property name="label" translatable="yes"> </property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">2</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkCheckButton">
<property name="label" translatable="yes"> </property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">folder-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Folder</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">text-x-generic-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Folder</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkCheckButton">
<property name="label" translatable="yes">I need more granularity</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">4</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkExpander">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Filters what items will be included in the final export.
(Not fully implemented yet.)</property>
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton">
<property name="label" translatable="yes">Ignore compile status (include all items)</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkCheckButton">
<property name="label" translatable="yes">Subitems of:</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkCheckButton">
<property name="label" translatable="yes">Labels</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkCheckButton">
<property name="label" translatable="yes">Status</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Filters</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Content</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkExpander">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Separations</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkExpander">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Transformations</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkExpander">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Preview</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
</object>
<packing>
<property name="name">settings_box</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="width-request">250</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">8</property>
<property name="margin-end">8</property>
<property name="margin-top">8</property>
<property name="margin-bottom">8</property>
<property name="orientation">vertical</property>
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="label" translatable="yes">Preview</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="semibold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="has-subtitle">False</property>
<property name="spacing">8</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">4</property>
<property name="margin-end">4</property>
<property name="spacing">8</property>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">emblem-synchronizing-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Preview</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">document-revert-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Export</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">preview_box</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkTreeStore" id="file_store">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name icon -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkTreeStore" id="under_store">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name icon -->
<column type="gchararray"/>
</columns>
</object>
</interface>

View file

@ -65,16 +65,6 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<property name="editable">False</property>
</object>
</child>
<child type="tag">
<object class="GtkTextTag">
<property name="font">Normal</property>
</object>
</child>
<child type="tag">
<object class="GtkTextTag">
<property name="font">Normal</property>
</object>
</child>
<child type="tag">
<object class="GtkTextTag" id="h2_tag">
<property name="name">h2</property>
@ -173,7 +163,21 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<object class="GtkTextTag" id="p_tag">
<property name="name">p</property>
<property name="font">Normal</property>
<property name="pixels-above-lines">4</property>
<property name="pixels-below-lines">4</property>
<property name="left-margin">8</property>
<property name="indent">20</property>
<property name="right-margin">8</property>
</object>
</child>
<child type="tag">
<object class="GtkTextTag" id="line_tag">
<property name="name">line</property>
<property name="font">Normal</property>
<property name="editable">False</property>
<property name="left-margin">4</property>
<property name="strikethrough">True</property>
<property name="right-margin">4</property>
</object>
</child>
</object>
@ -397,6 +401,11 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="wrap-mode">word-char</property>
<property name="left-margin">8</property>
<property name="right-margin">8</property>
<property name="top-margin">4</property>
<property name="bottom-margin">4</property>
<property name="indent">4</property>
<property name="buffer">editor_text</property>
<property name="input-hints">GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_WORD_COMPLETION | GTK_INPUT_HINT_NONE</property>
</object>

View file

@ -27,6 +27,12 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<!-- interface-name Manuskript -->
<!-- interface-description Manuskript is an open-source tool for writers. -->
<!-- interface-copyright 2015-2021 Olivier Keshavjee et al. -->
<object class="GtkListStore" id="exclude_words_store">
<columns>
<!-- column-name word -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkAdjustment" id="phrase_maximum">
<property name="lower">2</property>
<property name="upper">99</property>
@ -41,6 +47,14 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkListStore" id="phrases_frequency_store">
<columns>
<!-- column-name phrase -->
<column type="gchararray"/>
<!-- column-name frequency -->
<column type="guint"/>
</columns>
</object>
<object class="GtkAdjustment" id="word_size">
<property name="lower">1</property>
<property name="upper">99</property>
@ -48,6 +62,17 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkListStore" id="words_frequency_store">
<columns>
<!-- column-name word -->
<column type="gchararray"/>
<!-- column-name frequency -->
<column type="guint"/>
</columns>
</object>
<object class="GtkTreeModelFilter" id="filtered_frequency_store">
<property name="child-model">words_frequency_store</property>
</object>
<object class="HdyWindow" id="frequency_window">
<property name="can-focus">False</property>
<child>
@ -181,9 +206,26 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkListBox">
<object class="GtkTreeView">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="can-focus">True</property>
<property name="model">exclude_words_store</property>
<property name="headers-visible">False</property>
<property name="headers-clickable">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="exclude_word_selection"/>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Word</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
@ -201,8 +243,9 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<property name="can-focus">False</property>
<property name="spacing">8</property>
<child>
<object class="GtkButton">
<object class="GtkButton" id="remove_word">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
@ -220,7 +263,7 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
</packing>
</child>
<child>
<object class="GtkEntry">
<object class="GtkEntry" id="word_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
@ -231,7 +274,7 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
</packing>
</child>
<child>
<object class="GtkButton">
<object class="GtkButton" id="add_word">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
@ -274,10 +317,9 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
</packing>
</child>
<child>
<object class="GtkLevelBar">
<object class="GtkProgressBar" id="words_progress">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-top">12</property>
</object>
<packing>
<property name="expand">False</property>
@ -316,9 +358,43 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkListBox">
<object class="GtkTreeView">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="can-focus">True</property>
<property name="model">filtered_frequency_store</property>
<property name="search-column">0</property>
<property name="show-expanders">False</property>
<property name="tooltip-column">0</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Word</property>
<property name="expand">True</property>
<property name="sort-column-id">0</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Frequency</property>
<property name="expand">True</property>
<property name="sort-indicator">True</property>
<property name="sort-column-id">1</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
@ -484,9 +560,43 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkListBox">
<object class="GtkTreeView">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="can-focus">True</property>
<property name="model">phrases_frequency_store</property>
<property name="search-column">0</property>
<property name="show-expanders">False</property>
<property name="tooltip-column">0</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Phrase</property>
<property name="expand">True</property>
<property name="sort-column-id">0</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Frequency</property>
<property name="expand">True</property>
<property name="sort-indicator">True</property>
<property name="sort-column-id">1</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
@ -500,7 +610,7 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
</packing>
</child>
<child>
<object class="GtkProgressBar">
<object class="GtkProgressBar" id="phrases_progress">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2
<!-- Generated with glade 3.40.0
Copyright (C) 2015-2021 Olivier Keshavjee et al.
@ -27,7 +27,55 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<!-- interface-name Manuskript -->
<!-- interface-description Manuskript is an open-source tool for writers. -->
<!-- interface-copyright 2015-2021 Olivier Keshavjee et al. -->
<object class="HdyWindow">
<object class="GtkListStore" id="file_format_store">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name mimeType -->
<column type="gchararray"/>
<!-- column-name icon -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">Markdown</col>
<col id="1" translatable="yes">text/markdown</col>
<col id="2" translatable="yes">text-x-generic</col>
</row>
<row>
<col id="0" translatable="yes">Folder</col>
<col id="1" translatable="yes">directory</col>
<col id="2" translatable="yes">folder</col>
</row>
<row>
<col id="0" translatable="yes">OPML</col>
<col id="1" translatable="yes">text/opml</col>
<col id="2" translatable="yes">text-x-generic-template</col>
</row>
<row>
<col id="0" translatable="yes">Mind Map</col>
<col id="1" translatable="yes">text/mind-map</col>
<col id="2" translatable="yes">text-x-generic-template</col>
</row>
</data>
</object>
<object class="GtkTreeStore" id="file_store">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name icon -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkTreeStore" id="under_store">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name icon -->
<column type="gchararray"/>
</columns>
</object>
<object class="HdyWindow" id="import_window">
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
@ -39,12 +87,12 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="HdyHeaderBar">
<object class="HdyHeaderBar" id="header_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Import</property>
<child>
<object class="GtkButton">
<object class="GtkButton" id="back">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
@ -58,7 +106,7 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
</object>
</child>
<child>
<object class="GtkButton">
<object class="GtkButton" id="forward">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
@ -85,7 +133,7 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
</packing>
</child>
<child>
<object class="HdyLeaflet">
<object class="HdyLeaflet" id="preview_leaflet">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
@ -366,6 +414,9 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
</packing>
</child>
</object>
<packing>
<property name="name">settings_box</property>
</packing>
</child>
<child>
<object class="GtkBox">
@ -609,6 +660,9 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
</packing>
</child>
</object>
<packing>
<property name="name">preview_box</property>
</packing>
</child>
</object>
<packing>
@ -620,52 +674,4 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
</object>
</child>
</object>
<object class="GtkListStore" id="file_format_store">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name mimeType -->
<column type="gchararray"/>
<!-- column-name icon -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">Markdown</col>
<col id="1" translatable="yes">text/markdown</col>
<col id="2" translatable="yes">text-x-generic</col>
</row>
<row>
<col id="0" translatable="yes">Folder</col>
<col id="1" translatable="yes">directory</col>
<col id="2" translatable="yes">folder</col>
</row>
<row>
<col id="0" translatable="yes">OPML</col>
<col id="1" translatable="yes">text/opml</col>
<col id="2" translatable="yes">text-x-generic-template</col>
</row>
<row>
<col id="0" translatable="yes">Mind Map</col>
<col id="1" translatable="yes">text/mind-map</col>
<col id="2" translatable="yes">text-x-generic-template</col>
</row>
</data>
</object>
<object class="GtkTreeStore" id="file_store">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name icon -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkTreeStore" id="under_store">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name icon -->
<column type="gchararray"/>
</columns>
</object>
</interface>

View file

@ -8,7 +8,7 @@
<pattern>*.msk</pattern>
</patterns>
</object>
<object class="GtkRecentChooserMenu" id="recent_chooser_menu">
<object class="GtkRecentChooserMenu" id="recent_chooser_menu_btn">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="filter">recent_filter</property>
@ -91,9 +91,10 @@
<property name="label" translatable="yes">_Recent</property>
<property name="use-underline">True</property>
<child type="submenu">
<object class="GtkRecentChooserMenu" id="recent_chooser_menu1">
<object class="GtkRecentChooserMenu" id="recent_chooser_menu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="filter">recent_filter</property>
<property name="limit">10</property>
<property name="sort-type">mru</property>
</object>
@ -457,7 +458,7 @@
<property name="halign">end</property>
<property name="spacing">9</property>
<child>
<object class="GtkButton">
<object class="GtkButton" id="open_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
@ -500,12 +501,12 @@
</packing>
</child>
<child>
<object class="GtkMenuButton">
<object class="GtkMenuButton" id="recent_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<property name="popup">recent_chooser_menu</property>
<property name="popup">recent_chooser_menu_btn</property>
<property name="use-popover">False</property>
<child>
<object class="GtkBox">
@ -546,7 +547,7 @@
</packing>
</child>
<child>
<object class="GtkButton">
<object class="GtkButton" id="create_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>