From 8029522563e2073be87d6f2bef2f265f17780f1b Mon Sep 17 00:00:00 2001 From: TheJackiMonster Date: Tue, 21 Mar 2023 23:37:17 +0100 Subject: [PATCH] Implement save as functionality moving data paths Signed-off-by: TheJackiMonster --- manuskript/data/abstractData.py | 5 +++++ manuskript/data/characters.py | 13 +++++++++++++ manuskript/data/info.py | 4 ++++ manuskript/data/labels.py | 4 ++++ manuskript/data/outline.py | 31 ++++++++++++++++++++++++++++++- manuskript/data/plots.py | 4 ++++ manuskript/data/project.py | 21 ++++++++++++++++++++- manuskript/data/revisions.py | 4 ++++ manuskript/data/settings.py | 4 ++++ manuskript/data/status.py | 4 ++++ manuskript/data/summary.py | 4 ++++ manuskript/data/version.py | 5 +++++ manuskript/data/world.py | 4 ++++ manuskript/io/mskFile.py | 8 +++++--- manuskript/ui/mainWindow.py | 15 ++++++++++++--- 15 files changed, 122 insertions(+), 8 deletions(-) diff --git a/manuskript/data/abstractData.py b/manuskript/data/abstractData.py index 00faad2..bb34f7e 100644 --- a/manuskript/data/abstractData.py +++ b/manuskript/data/abstractData.py @@ -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 diff --git a/manuskript/data/characters.py b/manuskript/data/characters.py index b416a8c..e6f55ea 100644 --- a/manuskript/data/characters.py +++ b/manuskript/data/characters.py @@ -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__() diff --git a/manuskript/data/info.py b/manuskript/data/info.py index 32c29a8..612c85d 100644 --- a/manuskript/data/info.py +++ b/manuskript/data/info.py @@ -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) diff --git a/manuskript/data/labels.py b/manuskript/data/labels.py index bdeae33..1522615 100644 --- a/manuskript/data/labels.py +++ b/manuskript/data/labels.py @@ -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" diff --git a/manuskript/data/outline.py b/manuskript/data/outline.py index 3f2d23b..fafa097 100644 --- a/manuskript/data/outline.py +++ b/manuskript/data/outline.py @@ -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): @@ -177,6 +181,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 +267,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 +285,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__() diff --git a/manuskript/data/plots.py b/manuskript/data/plots.py index fb8e833..9399f15 100644 --- a/manuskript/data/plots.py +++ b/manuskript/data/plots.py @@ -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 diff --git a/manuskript/data/project.py b/manuskript/data/project.py index 6e9b7d0..ff72655 100644 --- a/manuskript/data/project.py +++ b/manuskript/data/project.py @@ -23,7 +23,7 @@ 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) @@ -60,6 +60,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) diff --git a/manuskript/data/revisions.py b/manuskript/data/revisions.py index b39264a..9ce1944 100644 --- a/manuskript/data/revisions.py +++ b/manuskript/data/revisions.py @@ -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__() diff --git a/manuskript/data/settings.py b/manuskript/data/settings.py index f1e0c80..625c4bb 100644 --- a/manuskript/data/settings.py +++ b/manuskript/data/settings.py @@ -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(".") diff --git a/manuskript/data/status.py b/manuskript/data/status.py index c972acd..061de80 100644 --- a/manuskript/data/status.py +++ b/manuskript/data/status.py @@ -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" diff --git a/manuskript/data/summary.py b/manuskript/data/summary.py index 5bf0da6..f79a8c4 100644 --- a/manuskript/data/summary.py +++ b/manuskript/data/summary.py @@ -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) diff --git a/manuskript/data/version.py b/manuskript/data/version.py index 7f8c2dc..ffc5fae 100644 --- a/manuskript/data/version.py +++ b/manuskript/data/version.py @@ -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()) diff --git a/manuskript/data/world.py b/manuskript/data/world.py index 17c9bc4..e04e44a 100644 --- a/manuskript/data/world.py +++ b/manuskript/data/world.py @@ -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) diff --git a/manuskript/io/mskFile.py b/manuskript/io/mskFile.py index ec0e40d..46ffdad 100644 --- a/manuskript/io/mskFile.py +++ b/manuskript/io/mskFile.py @@ -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, 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 diff --git a/manuskript/ui/mainWindow.py b/manuskript/ui/mainWindow.py index 59e0942..9efbf75 100644 --- a/manuskript/ui/mainWindow.py +++ b/manuskript/ui/mainWindow.py @@ -13,7 +13,7 @@ Handy.init() from manuskript.data import Project from manuskript.ui.views import * -from manuskript.ui.chooser import openFileDialog, FileFilter +from manuskript.ui.chooser import openFileDialog, saveFileDialog, FileFilter from manuskript.ui.tools import * from manuskript.ui.aboutDialog import AboutDialog from manuskript.ui.settingsWindow import SettingsWindow @@ -74,6 +74,7 @@ class MainWindow: 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, "quit_menu_item", self._quitAction) @@ -144,7 +145,15 @@ class MainWindow: 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() @@ -153,7 +162,7 @@ class MainWindow: self.exit(True) def getSettings(self): - return self.getProject().settings + return self.project.settings def _settingsAction(self, menuItem: Gtk.MenuItem): self.settingsWindow.show()