manuskript/manuskript/ui/views/outlineView.py
TheJackiMonster 3481e40b4f
Implement basic outline overview
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
2022-10-30 17:48:02 +01:00

275 lines
9.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from manuskript.data import Outline, OutlineFolder, OutlineText, OutlineItem, OutlineState, Plots, PlotLine, Characters, Character, Importance, Goal
from manuskript.ui.util import rgbaFromColor, pixbufFromColor
from manuskript.util import validString, invalidString, validInt, invalidInt, CounterKind, countText
class OutlineView:
def __init__(self, outline: Outline):
self.outline = outline
self.outlineItem = None
builder = Gtk.Builder()
builder.add_from_file("ui/outline.glade")
self.widget = builder.get_object("outline_view")
self.plotsStore = builder.get_object("plots_store")
self.refreshPlotsStore()
self.charactersStore = builder.get_object("characters_store")
self.refreshCharactersStore()
self.outlineStore = builder.get_object("outline_store")
self.refreshOutlineStore()
self.mainPlotsStore = builder.get_object("main_plots_store")
self.secondaryPlotsStore = builder.get_object("secondary_plots_store")
self.minorPlotsStore = builder.get_object("minor_plots_store")
self.mainPlotsStore.set_visible_func(
lambda model, iter, userdata: model[iter][2] == Importance.MAIN.value)
self.secondaryPlotsStore.set_visible_func(
lambda model, iter, userdata: model[iter][2] == Importance.SECONDARY.value)
self.minorPlotsStore.set_visible_func(
lambda model, iter, userdata: model[iter][2] == Importance.MINOR.value)
self.mainPlotsStore.refilter()
self.secondaryPlotsStore.refilter()
self.minorPlotsStore.refilter()
self.plotSelections = [
builder.get_object("minor_plot_selection"),
builder.get_object("secondary_plot_selection"),
builder.get_object("main_plot_selection")
]
for selection in self.plotSelections:
selection.connect("changed", self.plotSelectionChanged)
self.filterOutlineBuffer = builder.get_object("filter_outline")
self.filterOutlineBuffer.connect("deleted-text", self.filterOutlineDeletedText)
self.filterOutlineBuffer.connect("inserted-text", self.filterOutlineInsertedText)
self.filteredOutlineStore = builder.get_object("filtered_outline_store")
self.filteredOutlineStore.set_visible_func(self.filterOutline)
self.filteredOutlineStore.refilter()
self.outlineSelection = builder.get_object("outline_selection")
self.outlineSelection.connect("changed", self.outlineSelectionChanged)
self.goalBuffer = builder.get_object("goal")
self.oneLineSummaryBuffer = builder.get_object("one_line_summary")
self.fewSentencesSummaryBuffer = builder.get_object("few_sentences_summary")
self.goalBuffer.connect("deleted-text", self.goalDeletedText)
self.goalBuffer.connect("inserted-text", self.goalInsertedText)
self.oneLineSummaryBuffer.connect("deleted-text", self.oneLineSummaryDeletedText)
self.oneLineSummaryBuffer.connect("inserted-text", self.oneLineSummaryInsertedText)
self.fewSentencesSummaryBuffer.connect("changed", self.fewSentencesSummaryChanged)
self.unloadOutlineData()
def refreshPlotsStore(self):
self.plotsStore.clear()
for plotLine in self.outline.plots:
tree_iter = self.plotsStore.append()
if tree_iter is None:
continue
self.plotsStore.set_value(tree_iter, 0, plotLine.UID.value)
self.plotsStore.set_value(tree_iter, 1, validString(plotLine.name))
self.plotsStore.set_value(tree_iter, 2, Importance.asValue(plotLine.importance))
def refreshCharactersStore(self):
self.charactersStore.clear()
for character in self.outline.plots.characters:
tree_iter = self.charactersStore.append()
if tree_iter is None:
continue
self.charactersStore.set_value(tree_iter, 0, character.UID.value)
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)
if type(outlineItem) is OutlineFolder:
for item in outlineItem:
self.__appendOutlineItem(item, tree_iter)
wordCount = validInt(outlineItem.textCount())
goal = validInt(outlineItem.goalCount())
progress = 0
if goal > wordCount:
progress = 100 * wordCount / goal
elif goal > 0:
progress = 100
self.outlineStore.set_value(tree_iter, 0, outlineItem.UID.value)
self.outlineStore.set_value(tree_iter, 1, validString(outlineItem.title))
self.outlineStore.set_value(tree_iter, 2, validString(outlineItem.label))
self.outlineStore.set_value(tree_iter, 3, validString(outlineItem.status))
self.outlineStore.set_value(tree_iter, 4, outlineItem.compile)
self.outlineStore.set_value(tree_iter, 5, wordCount)
self.outlineStore.set_value(tree_iter, 6, goal)
self.outlineStore.set_value(tree_iter, 7, progress)
def refreshOutlineStore(self):
self.outlineStore.clear()
for item in self.outline.items:
self.__appendOutlineItem(item)
def plotSelectionChanged(self, selection: Gtk.TreeSelection):
model, tree_iter = selection.get_selected()
if tree_iter is None:
return
for other in self.plotSelections:
if other != selection:
other.unselect_all()
def loadOutlineData(self, outlineItem: OutlineItem):
self.outlineItem = None
self.goalBuffer.set_text(validString(outlineItem.goal), -1)
self.oneLineSummaryBuffer.set_text(validString(outlineItem.summarySentence), -1)
self.fewSentencesSummaryBuffer.set_text(validString(outlineItem.summaryFull), -1)
self.outlineItem = outlineItem
def unloadOutlineData(self):
self.outlineItem = None
self.goalBuffer.set_text("", -1)
self.oneLineSummaryBuffer.set_text("", -1)
self.fewSentencesSummaryBuffer.set_text("", -1)
def outlineSelectionChanged(self, selection: Gtk.TreeSelection):
model, tree_iter = selection.get_selected()
if tree_iter is None:
self.unloadOutlineData()
return
outlineItem = self.outline.getItemByID(model[tree_iter][0])
if outlineItem is None:
self.unloadOutlineData()
else:
self.loadOutlineData(outlineItem)
def __matchOutlineItemByText(self, outlineItem: OutlineItem, text: str):
if type(outlineItem) is OutlineFolder:
for item in outlineItem:
if self.__matchOutlineItemByText(item, text):
return True
title = validString(outlineItem.title)
return text in title.lower()
def filterOutline(self, model, iter, userdata):
outlineItem = self.outline.getItemByID(model[iter][0])
if outlineItem is None:
return False
text = validString(self.filterOutlineBuffer.get_text())
return self.__matchOutlineItemByText(outlineItem, text.lower())
def filterOutlineChanged(self, buffer: Gtk.EntryBuffer):
self.filteredOutlineStore.refilter()
def filterOutlineDeletedText(self, buffer: Gtk.EntryBuffer, position: int, n_chars: int):
self.filterOutlineChanged(buffer)
def filterOutlineInsertedText(self, buffer: Gtk.EntryBuffer, position: int, chars: str, n_chars: int):
self.filterOutlineChanged(buffer)
def goalChanged(self, buffer: Gtk.EntryBuffer):
if self.outlineItem is None:
return
text = buffer.get_text()
self.outlineItem.goal = Goal.parse(text)
outline_id = self.outlineItem.UID.value
wordCount = validInt(self.outlineItem.textCount())
goal = validInt(self.outlineItem.goalCount())
progress = 0
if goal > wordCount:
progress = 100 * wordCount / goal
elif goal > 0:
progress = 100
for row in self.outlineStore:
if row[0] == outline_id:
row[6] = goal
row[7] = progress
break
def goalDeletedText(self, buffer: Gtk.EntryBuffer, position: int, n_chars: int):
self.goalChanged(buffer)
def goalInsertedText(self, buffer: Gtk.EntryBuffer, position: int, chars: str, n_chars: int):
self.goalChanged(buffer)
def oneLineSummaryChanged(self, buffer: Gtk.EntryBuffer):
if self.outlineItem is None:
return
text = buffer.get_text()
summary = invalidString(text)
self.outlineItem.summarySentence = summary
def oneLineSummaryDeletedText(self, buffer: Gtk.EntryBuffer, position: int, n_chars: int):
self.oneLineSummaryChanged(buffer)
def oneLineSummaryInsertedText(self, buffer: Gtk.EntryBuffer, position: int, chars: str, n_chars: int):
self.oneLineSummaryChanged(buffer)
def fewSentencesSummaryChanged(self, buffer: Gtk.TextBuffer):
if self.outlineItem is None:
return
start_iter = buffer.get_start_iter()
end_iter = buffer.get_end_iter()
text = buffer.get_text(start_iter, end_iter, False)
self.outlineItem.summaryFull = invalidString(text)
def show(self):
self.widget.show_all()