Create a webpage version of a lesson
This commit is contained in:
179
lib/read.py
179
lib/read.py
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user