Create a webpage version of a lesson

This commit is contained in:
Christopher T. Johnson
2023-11-20 13:23:05 -05:00
parent 217e31ee7a
commit d3c77f5569
17 changed files with 187 additions and 69 deletions

View File

@@ -1,16 +1,29 @@
import json
import os
import re
from typing import cast
import requests
from PyQt6.QtCore import QPoint, QRect, Qt, QTimer, pyqtSlot
from PyQt6.QtCore import (
QFile,
QIODeviceBase,
QPoint,
QRect,
QResource,
Qt,
QTimer,
pyqtSlot,
)
from PyQt6.QtGui import (
QBrush,
QColor,
QFont,
QKeyEvent,
QMouseEvent,
QPainter,
QPainterPath,
QPaintEvent,
QTextBlockFormat,
QTextCharFormat,
QTextCursor,
QTextDocument,
@@ -29,21 +42,28 @@ class EditDialog(QDialog, Ui_Dialog):
def __init__(self, person_id: int) -> None:
super(EditDialog, self).__init__()
self.person_id = person_id
if not QResource.registerResource(
os.path.join(os.path.dirname(__file__), "../ui/resources.rcc"), "/"
):
raise Exception("Unable to register resources.rcc")
styleSheet = QResource(":/display.css").data().decode("utf-8")
self.setupUi(self)
#
# Override UI
#
font = QFont()
font.setFamily("OpenDyslexic")
font.setPointSize(14)
self.paraEdit.setFont(font)
self.printBtn = QPushButton()
self.printBtn.setText("Print")
self.printBtn.setObjectName("printBtn")
self.verticalLayout.addWidget(self.printBtn)
#
# End overrides
#
self.load_book(self.person_id)
blockNumber = self.block
self.paraEdit.setReadOnly(True)
self.paraEdit.document().setDefaultStyleSheet(styleSheet)
self.defEdit.setReadOnly(True)
self.defEdit.document().setDefaultStyleSheet(styleSheet)
self.show_section(self.section_id)
self.block = blockNumber
self.savePosition()
@@ -54,10 +74,72 @@ class EditDialog(QDialog, Ui_Dialog):
self.prevBtn.clicked.connect(self.prevAction)
self.nextParaBtn.clicked.connect(self.nextParaAction)
self.prevParaBtn.clicked.connect(self.prevParaAction)
self.printBtn.clicked.connect(self.printAction)
self.paraEdit.verticalScrollBar().valueChanged.connect(self.scrollSlot)
self.scrollBtn.clicked.connect(self.scrollAction)
return
def defToHtml(self, word: str, definition) -> str:
html = f'<h1 class="def-word">{word}</h1>' + "\n"
try:
html += f"<p class=\"phonetic\">{definition['phonetic']}</p>" + "\n"
except Exception:
pass
html += '<ul class="outer">' + "\n"
for meaning in definition["meanings"]:
html += f"<li>{meaning['partOfSpeech']}"
html += '<ul class="inner">'
for a_def in meaning["definitions"]:
html += f"<li>{a_def['definition']}</li>\n"
html += "</ul>\n"
html += "</ul>\n<p/>\n"
return html
@pyqtSlot()
def printAction(self) -> None:
html = "<!DOCTYPE html>\n<html>\n<head>\n"
html += (
'<link href="https://fonts.cdnfonts.com/css/open-dyslexic" rel="stylesheet">'
+ "\n"
)
html += (
'<link href="https://fonts.cdnfonts.com/css/tex-gyre-heros" rel="stylesheet">'
+ "\n"
)
html += '<style type="text/css">\n'
style = QResource(":/print.css").data().decode("utf-8")
html += style
html += "</style>\n</head>\n<body>\n"
query = QSqlQuery()
query.prepare(
"SELECT w.* FROM word_block wb "
"LEFT JOIN words w "
"ON (w.word_id = wb.word_id) "
"WHERE wb.section_id = :section_id "
"ORDER BY w.word"
)
query.bindValue(":section_id", self.section_id)
if not query.exec():
query_error(query)
while query.next():
word = query.value("word")
definition = json.loads(query.value("definition"))
html += self.defToHtml(word, definition)
html += "\n"
html += "<hr/>\n"
html += '<div class="text">' + "\n"
text = self.sections[self.section_map[self.section_id]]
text = re.sub(r"</?body>", "", text)
html += text
html += "\n</div>\n"
html += "\n</body>\n</html>\n"
qf = QFile("out.html")
if qf.open(QIODeviceBase.OpenModeFlag.WriteOnly):
qf.write(html.encode("utf-8"))
qf.close()
print("Printed!")
return
@pyqtSlot()
def scrollAction(self) -> None:
position = (
@@ -200,18 +282,26 @@ class EditDialog(QDialog, Ui_Dialog):
definition = json.loads(query.value("definition"))
try:
phonetic = definition["phonetic"]
def_format.setToolTip(
f'<font size="24">{word}:<br/><font family="Tex Gyre Heros">{phonetic}</font></font>'
)
cursor.mergeCharFormat(def_format)
except:
phonetic = ""
def_format.setToolTip(
f'<font size="24">{word}:<br/><font family="Tex Gyre Heros">{phonetic}</font></font>'
)
cursor.setCharFormat(def_format)
pass
return
#
# Event handlers
#
def mousePressEvent(self, event: QMouseEvent | None) -> None:
return
def keyPressEvent(self, event: QKeyEvent) -> None:
print(event)
super().keyPressEvent(event)
return
def paintEvent(self, e: QPaintEvent | None) -> None:
idx = self.stackedWidget.currentIndex()
if idx > 0:
@@ -328,19 +418,19 @@ class EditDialog(QDialog, Ui_Dialog):
query.bindValue(":end", end)
if not query.exec():
query_error(query)
if query.next():
return
query.prepare(
"INSERT INTO word_block VALUES "
"( :word_id, :section_id, :block, :start, :end)"
)
query.bindValue(":word_id", word_id)
query.bindValue(":section_id", self.section_id)
query.bindValue(":block", blockNum)
query.bindValue(":start", start)
query.bindValue(":end", end)
if not query.exec():
query_error(query)
if not query.next():
query.prepare(
"INSERT INTO word_block VALUES "
"( :word_id, :section_id, :block, :start, :end)"
)
query.bindValue(":word_id", word_id)
query.bindValue(":section_id", self.section_id)
query.bindValue(":block", blockNum)
query.bindValue(":start", start)
query.bindValue(":end", end)
if not query.exec():
query_error(query)
def_format = QTextCharFormat()
def_format.setFontUnderline(True)
cursor = QTextCursor(self.paraEdit.document())
@@ -351,7 +441,7 @@ class EditDialog(QDialog, Ui_Dialog):
cursor.setPosition(
end + textBlock.position(), QTextCursor.MoveMode.KeepAnchor
)
cursor.setCharFormat(def_format)
cursor.mergeCharFormat(def_format)
return
def display_definition(self) -> None:
@@ -377,47 +467,10 @@ class EditDialog(QDialog, Ui_Dialog):
definition = json.loads(query.value("definition"))
self.defEdit.document().clear()
cursor = self.defEdit.textCursor()
h1_size = 48
h1_weight = QFont.Weight.Bold
p_size = 16
p_weight = QFont.Weight.Normal
word_format = QTextCharFormat()
word_format.setFontPointSize(h1_size)
word_format.setFontWeight(h1_weight)
cursor.insertText(word, word_format)
typeFormat = QTextListFormat()
typeFormat.setStyle(QTextListFormat.Style.ListDisc)
typeFormat.setIndent(1)
defFormat = QTextListFormat()
defFormat.setStyle(QTextListFormat.Style.ListCircle)
defFormat.setIndent(2)
word_format.setFontWeight(p_weight)
word_format.setFontPointSize(p_size)
phonetic_format = QTextCharFormat()
phonetic_format.setFontPointSize(32)
phonetic_format.setFontFamily("TeX Gyre Heros")
try:
cursor.insertBlock()
cursor.insertText(definition["phonetic"], phonetic_format)
except Exception:
pass
cursor.setCharFormat(word_format)
for meaning in definition["meanings"]:
cursor.insertList(typeFormat)
cursor.insertText(meaning["partOfSpeech"])
cursor.insertList(defFormat)
first = True
for a_def in meaning["definitions"]:
if not first:
cursor.insertBlock()
cursor.insertText(a_def["definition"])
# TODO: synonyms
# TODO: antonyms
first = False
cursor.insertHtml(self.defToHtml(word,definition))
cursor.setPosition(0)
self.defEdit.setTextCursor(cursor)
print(self.defEdit.document().toHtml())
return
@pyqtSlot()