diff --git a/manuskript/data/outline.py b/manuskript/data/outline.py index c98af2d9..b4d409d9 100644 --- a/manuskript/data/outline.py +++ b/manuskript/data/outline.py @@ -212,10 +212,18 @@ class OutlineFolder(OutlineItem): return count - def load(self, _: bool = True): + def load(self, optimized: bool = True): metadata, _ = self.file.loadMMD(True) OutlineItem.loadMetadata(self, metadata) - self.state = OutlineState.COMPLETE + + if optimized: + self.state = OutlineState.OPTIMIZED + else: + for item in self.items: + if item.state != OutlineState.COMPLETE: + return + + self.state = OutlineState.COMPLETE @classmethod def saveItems(cls, folder, recursive: bool = True): diff --git a/manuskript/data/project.py b/manuskript/data/project.py index ebce4e42..2b80bc77 100644 --- a/manuskript/data/project.py +++ b/manuskript/data/project.py @@ -16,6 +16,7 @@ from manuskript.data.world import World from manuskript.data.outline import Outline from manuskript.data.revisions import Revisions from manuskript.io.mskFile import MskFile +from manuskript.util import profileTime class Project: @@ -62,17 +63,17 @@ class Project: except BadZipFile or FileNotFoundError: return - self.version.load() - self.info.load() - self.summary.load() - self.labels.load() - self.statuses.load() - self.settings.load() - self.characters.load() - self.plots.load() - self.world.load() - self.outline.load() - self.revisions.load() + profileTime(self.version.load) + profileTime(self.info.load) + profileTime(self.summary.load) + profileTime(self.labels.load) + profileTime(self.statuses.load) + profileTime(self.settings.load) + profileTime(self.characters.load) + profileTime(self.plots.load) + profileTime(self.world.load) + profileTime(self.outline.load) + profileTime(self.revisions.load) self.file.setZipFile(self.settings.isEnabled("saveToZip")) diff --git a/manuskript/ui/mainWindow.py b/manuskript/ui/mainWindow.py index 541e93f1..84fe8004 100644 --- a/manuskript/ui/mainWindow.py +++ b/manuskript/ui/mainWindow.py @@ -18,6 +18,7 @@ from manuskript.ui.aboutDialog import AboutDialog from manuskript.ui.settingsWindow import SettingsWindow from manuskript.ui.startupWindow import StartupWindow from manuskript.ui.util import bindMenuItem +from manuskript.util import profileTime class MainWindow: @@ -31,9 +32,9 @@ class MainWindow: try: if data is None: - view = view_cls() + view = profileTime(view_cls) else: - view = view_cls(data) + view = profileTime(view_cls, data) except Exception: return None diff --git a/manuskript/ui/views/editorView.py b/manuskript/ui/views/editorView.py index f6006ba6..7df400ec 100644 --- a/manuskript/ui/views/editorView.py +++ b/manuskript/ui/views/editorView.py @@ -4,7 +4,7 @@ import gi gi.require_version("Gtk", "3.0") -from gi.repository import Gtk, Pango +from gi.repository import GObject, Gtk, Pango from manuskript.data import Project, OutlineFolder, OutlineText, OutlineItem, OutlineState, Goal from manuskript.ui.editor import GridItem @@ -17,6 +17,7 @@ class EditorView: def __init__(self, project: Project): self.project = project self.outlineItem = None + self.outlineCompletion = [] self.editorItems = list() builder = Gtk.Builder() @@ -76,21 +77,9 @@ class EditorView: self.statusStore.set_value(tree_iter, 0, validString(status.name)) - def __appendOutlineItem(self, outlineItem: OutlineItem, parent_iter=None): - tree_iter = self.outlineStore.append(parent_iter) - - if tree_iter is None: - return - - if outlineItem.state != OutlineState.COMPLETE: - outlineItem.load(False) - + def __updateOutlineItem(self, tree_iter, outlineItem: OutlineItem): icon = iconByOutlineItemType(outlineItem) - if type(outlineItem) is OutlineFolder: - for item in outlineItem: - self.__appendOutlineItem(item, tree_iter) - wordCount = validInt(outlineItem.textCount()) goal = validInt(outlineItem.goalCount()) progress = 100 * safeFraction(wordCount, 0, goal) @@ -105,6 +94,34 @@ class EditorView: self.outlineStore.set_value(tree_iter, 7, progress) self.outlineStore.set_value(tree_iter, 8, icon) + def __completeOutlineItem(self): + (tree_iter, outlineItem) = self.outlineCompletion.pop(0) + + if outlineItem.state != OutlineState.COMPLETE: + outlineItem.load(False) + + self.__updateOutlineItem(tree_iter, outlineItem) + + return len(self.outlineCompletion) > 0 + + def __appendOutlineItem(self, outlineItem: OutlineItem, parent_iter=None): + tree_iter = self.outlineStore.append(parent_iter) + + if tree_iter is None: + return + + if type(outlineItem) is OutlineFolder: + for item in outlineItem: + self.__appendOutlineItem(item, tree_iter) + + if outlineItem.state != OutlineState.COMPLETE: + if len(self.outlineCompletion) == 0: + GObject.idle_add(self.__completeOutlineItem) + + self.outlineCompletion.append((tree_iter, outlineItem)) + + self.__updateOutlineItem(tree_iter, outlineItem) + def refreshOutlineStore(self): self.outlineStore.clear() diff --git a/manuskript/ui/views/outlineView.py b/manuskript/ui/views/outlineView.py index 002591fb..d1019261 100644 --- a/manuskript/ui/views/outlineView.py +++ b/manuskript/ui/views/outlineView.py @@ -4,7 +4,7 @@ import gi gi.require_version("Gtk", "3.0") -from gi.repository import Gtk +from gi.repository import GObject, Gtk from manuskript.data import Outline, OutlineFolder, OutlineText, OutlineItem, OutlineState, Plots, PlotLine, Characters, Character, Importance, Goal from manuskript.ui.util import rgbaFromColor, pixbufFromColor @@ -16,6 +16,7 @@ class OutlineView: def __init__(self, outline: Outline): self.outline = outline self.outlineItem = None + self.outlineCompletion = [] builder = Gtk.Builder() builder.add_from_file("ui/outline.glade") @@ -138,20 +139,9 @@ class OutlineView: self.charactersStore.set_value(tree_iter, 1, validString(character.name)) self.charactersStore.set_value(tree_iter, 2, pixbufFromColor(character.color)) - def __appendOutlineItem(self, outlineItem: OutlineItem, parent_iter=None): - tree_iter = self.outlineStore.append(parent_iter) - - if tree_iter is None: - return - - if outlineItem.state != OutlineState.COMPLETE: - outlineItem.load(False) - + def __updateOutlineItem(self, tree_iter, outlineItem: OutlineItem): if type(outlineItem) is OutlineFolder: icon = "folder-symbolic" - - for item in outlineItem: - self.__appendOutlineItem(item, tree_iter) elif type(outlineItem) is OutlineText: icon = "emblem-documents-symbolic" else: @@ -176,6 +166,34 @@ class OutlineView: self.outlineStore.set_value(tree_iter, 7, progress) self.outlineStore.set_value(tree_iter, 8, icon) + def __completeOutlineItem(self): + (tree_iter, outlineItem) = self.outlineCompletion.pop(0) + + if outlineItem.state != OutlineState.COMPLETE: + outlineItem.load(False) + + self.__updateOutlineItem(tree_iter, outlineItem) + + return len(self.outlineCompletion) > 0 + + def __appendOutlineItem(self, outlineItem: OutlineItem, parent_iter=None): + tree_iter = self.outlineStore.append(parent_iter) + + if tree_iter is None: + return + + if type(outlineItem) is OutlineFolder: + for item in outlineItem: + self.__appendOutlineItem(item, tree_iter) + + if outlineItem.state != OutlineState.COMPLETE: + if len(self.outlineCompletion) == 0: + GObject.idle_add(self.__completeOutlineItem) + + self.outlineCompletion.append((tree_iter, outlineItem)) + + self.__updateOutlineItem(tree_iter, outlineItem) + def refreshOutlineStore(self): self.outlineStore.clear() diff --git a/manuskript/util/__init__.py b/manuskript/util/__init__.py index 78fd9c4a..01acf0bc 100644 --- a/manuskript/util/__init__.py +++ b/manuskript/util/__init__.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- import re +import time from manuskript.util.counter import CounterKind, CharCounter, WordCounter, PageCounter @@ -70,3 +71,11 @@ def safeFraction(value, low, high) -> float: return 1.0 else: return 1.0 * (value - low) / (high - low) + + +def profileTime(func, *args): + start = time.perf_counter() + result = func(*args) + end = time.perf_counter() + print("{}.{}: {}".format(func.__module__, func.__name__, end - start)) + return result diff --git a/manuskript/util/counter.py b/manuskript/util/counter.py index 53667e81..05a7d482 100644 --- a/manuskript/util/counter.py +++ b/manuskript/util/counter.py @@ -9,6 +9,8 @@ _char_pattern_with_spaces = re.compile(r"[\S ]") _char_pattern_without_spaces = re.compile(r"\S") _word_pattern = re.compile(r"\S+") +_whitespace = " \t\r\n" + @unique class CounterKind(Enum):