trelby_export/src/characterreport.py

149 lines
4.4 KiB
Python

import misc
import pdf
import pml
import screenplay
import util
from functools import reduce
import functools
class CharacterReport:
def __init__(self, sp):
self.sp = sp
ls = sp.lines
# key = character name, value = CharInfo
chars = {}
name = None
scene = "(NO SCENE NAME)"
# how many lines processed for current speech
curSpeechLines = 0
for i in range(len(ls)):
line = ls[i]
if (line.lt == screenplay.SCENE) and\
(line.lb == screenplay.LB_LAST):
scene = util.upper(line.text)
elif (line.lt == screenplay.CHARACTER) and\
(line.lb == screenplay.LB_LAST):
name = util.upper(line.text)
curSpeechLines = 0
elif line.lt in (screenplay.DIALOGUE, screenplay.PAREN) and name:
ci = chars.get(name)
if not ci:
ci = CharInfo(name, sp)
chars[name] = ci
if scene:
ci.scenes[scene] = ci.scenes.get(scene, 0) + 1
if curSpeechLines == 0:
ci.speechCnt += 1
curSpeechLines += 1
# PAREN lines don't count as spoken words
if line.lt == screenplay.DIALOGUE:
ci.lineCnt += 1
words = util.splitToWords(line.text)
ci.wordCnt += len(words)
ci.wordCharCnt += reduce(lambda x, y: x + len(y), words,
0)
ci.pages.addPage(sp.line2page(i))
else:
name = None
curSpeechLines = 0
# list of CharInfo objects
self.cinfo = []
for v in list(chars.values()):
self.cinfo.append(v)
self.cinfo = sorted(self.cinfo, key=functools.cmp_to_key(cmpLines))
self.totalSpeechCnt = self.sum("speechCnt")
self.totalLineCnt = self.sum("lineCnt")
self.totalWordCnt = self.sum("wordCnt")
self.totalWordCharCnt = self.sum("wordCharCnt")
# information types and what to include
self.INF_BASIC, self.INF_PAGES, self.INF_LOCATIONS = list(range(3))
self.inf = []
for s in ["Basic information", "Page list", "Location list"]:
self.inf.append(misc.CheckBoxItem(s))
# calculate total sum of self.cinfo.{name} and return it.
def sum(self, name):
return reduce(lambda tot, ci: tot + getattr(ci, name), self.cinfo, 0)
def generate(self):
tf = pml.TextFormatter(self.sp.cfg.paperWidth,
self.sp.cfg.paperHeight, 20.0, 12)
for ci in self.cinfo:
if not ci.include:
continue
tf.addText(ci.name, fs = 14,
style = pml.BOLD | pml.UNDERLINED)
if self.inf[self.INF_BASIC].selected:
tf.addText("Speeches: %d, Lines: %d (%.2f%%),"
" per speech: %.2f" % (ci.speechCnt, ci.lineCnt,
util.pctf(ci.lineCnt, self.totalLineCnt),
util.safeDiv(ci.lineCnt, ci.speechCnt)))
tf.addText("Words: %d, per speech: %.2f,"
" characters per: %.2f" % (ci.wordCnt,
util.safeDiv(ci.wordCnt, ci.speechCnt),
util.safeDiv(ci.wordCharCnt, ci.wordCnt)))
if self.inf[self.INF_PAGES].selected:
tf.addWrappedText("Pages: %d, list: %s" % (len(ci.pages),
ci.pages), " ")
if self.inf[self.INF_LOCATIONS].selected:
tf.addSpace(2.5)
for it in util.sortDict(ci.scenes):
tf.addText("%3d %s" % (it[1], it[0]),
x = tf.margin * 2.0, fs = 10)
tf.addSpace(5.0)
return pdf.generate(tf.doc)
# information about one character
class CharInfo:
def __init__(self, name, sp):
self.name = name
self.speechCnt = 0
self.lineCnt = 0
self.wordCnt = 0
self.wordCharCnt = 0
self.scenes = {}
self.include = True
self.pages = screenplay.PageList(sp.getPageNumbers())
def cmpfunc(a, b):
return (a > b) - (a < b)
def cmpLines(c1, c2):
ret = cmpfunc(c2.lineCnt, c1.lineCnt)
if ret != 0:
return ret
else:
return cmpfunc(c1.name, c2.name)