Working checkpoint
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
venv
|
venv
|
||||||
*~
|
*~
|
||||||
\#*
|
\#*
|
||||||
|
__pycache__
|
||||||
|
*.db
|
||||||
|
|||||||
5
clean.sh
Executable file
5
clean.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
isort --profile black *.py lib/*.py
|
||||||
|
black *.py lib/*.py
|
||||||
|
flynt *.py lib/*.py
|
||||||
|
|
||||||
2
lib/__init__.py
Normal file
2
lib/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from .books import Book
|
||||||
|
from .read import EditDialog
|
||||||
67
lib/books.py
Normal file
67
lib/books.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import xml.dom.minidom
|
||||||
|
|
||||||
|
|
||||||
|
class Book:
|
||||||
|
sections = []
|
||||||
|
metadata = {}
|
||||||
|
|
||||||
|
def __init__(self, src: str) -> None:
|
||||||
|
super(Book, self).__init__()
|
||||||
|
self.parse_book(src)
|
||||||
|
return
|
||||||
|
|
||||||
|
def parse_book(self, src: str) -> None:
|
||||||
|
with open(f"{src}/content.opf", "r") as f:
|
||||||
|
dom = xml.dom.minidom.parse(f)
|
||||||
|
metadata = dom.getElementsByTagName("metadata")[0]
|
||||||
|
for meta in metadata.childNodes:
|
||||||
|
if meta.nodeType != xml.dom.Node.ELEMENT_NODE:
|
||||||
|
continue
|
||||||
|
if meta.prefix == "dc":
|
||||||
|
self.metadata[meta.localName] = meta.firstChild.data
|
||||||
|
#
|
||||||
|
# The manifest contains a list of all the files contained in this
|
||||||
|
# EPUB
|
||||||
|
#
|
||||||
|
manifest = dom.getElementsByTagName("manifest")[0]
|
||||||
|
#
|
||||||
|
# The spine contains the documents in order they are read
|
||||||
|
#
|
||||||
|
spine = dom.getElementsByTagName("spine")[0]
|
||||||
|
for itemref in spine.childNodes:
|
||||||
|
if itemref.nodeType != xml.dom.Node.ELEMENT_NODE:
|
||||||
|
continue
|
||||||
|
# If linear == "no" skip
|
||||||
|
if (
|
||||||
|
itemref.hasAttribute("linear")
|
||||||
|
and itemref.getAttribute("linear") == "no"
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
idref = itemref.getAttribute("idref")
|
||||||
|
for item in manifest.childNodes:
|
||||||
|
if item.nodeType != xml.dom.Node.ELEMENT_NODE:
|
||||||
|
continue
|
||||||
|
id = item.getAttribute("id")
|
||||||
|
if id == idref:
|
||||||
|
break
|
||||||
|
#
|
||||||
|
# A properly created *.opf will always have a correct
|
||||||
|
# spin/manifest.
|
||||||
|
#
|
||||||
|
href = item.getAttribute("href")
|
||||||
|
print(f"{idref}: {href}")
|
||||||
|
self.parse_section(src, href)
|
||||||
|
return
|
||||||
|
|
||||||
|
def parse_section(self, src: str, href: str) -> None:
|
||||||
|
with open(f"{src}/{href}") as f:
|
||||||
|
dom = xml.dom.minidom.parse(f)
|
||||||
|
title = dom.getElementsByTagName("title")[0].firstChild.data
|
||||||
|
body = dom.getElementsByTagName("body")[0]
|
||||||
|
paragraphs = []
|
||||||
|
for p in body.getElementsByTagName("p"):
|
||||||
|
paragraphs.append(p.toxml())
|
||||||
|
self.sections.append({"title": title, "paragraphs": paragraphs})
|
||||||
|
return
|
||||||
277
lib/read.py
Normal file
277
lib/read.py
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from PyDictionary import PyDictionary # type: ignore[import-untyped]
|
||||||
|
from PyQt6.QtCore import Qt, pyqtSlot
|
||||||
|
from PyQt6.QtGui import (
|
||||||
|
QFont,
|
||||||
|
QTextCharFormat,
|
||||||
|
QTextCursor,
|
||||||
|
QTextDocument,
|
||||||
|
QTextListFormat,
|
||||||
|
)
|
||||||
|
from PyQt6.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
|
||||||
|
from PyQt6.QtWidgets import QDialog
|
||||||
|
|
||||||
|
from main import query_error
|
||||||
|
from ui.EditDialog import Ui_Dialog
|
||||||
|
|
||||||
|
|
||||||
|
class EditDialog(QDialog, Ui_Dialog):
|
||||||
|
def __init__(self, book_id: int, person_id: int) -> None:
|
||||||
|
super(EditDialog, self).__init__()
|
||||||
|
self.book_id = book_id
|
||||||
|
self.person_id = person_id
|
||||||
|
self.setupUi(self)
|
||||||
|
self.current_paragraph(self.person_id)
|
||||||
|
self.paraEdit.setReadOnly(True)
|
||||||
|
self.defEdit.setReadOnly(True)
|
||||||
|
self.stackedWidget.setCurrentIndex(0)
|
||||||
|
self.defineBtn.clicked.connect(self.defineAction)
|
||||||
|
self.showBtn.clicked.connect(self.showAction)
|
||||||
|
self.nextBtn.clicked.connect(self.nextAction)
|
||||||
|
self.prevBtn.clicked.connect(self.prevAction)
|
||||||
|
return
|
||||||
|
|
||||||
|
def current_paragraph(self, person_id: int) -> None:
|
||||||
|
query = QSqlQuery()
|
||||||
|
query.prepare("SELECT * FROM people WHERE person_id = :person_id")
|
||||||
|
query.bindValue(":person_id", person_id)
|
||||||
|
query.exec()
|
||||||
|
query.next()
|
||||||
|
paragraph_id = query.value("paragraph_id")
|
||||||
|
self.display_paragraph(paragraph_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
def display_paragraph(self, paragraph_id: int) -> None:
|
||||||
|
self.paragraph_id = paragraph_id
|
||||||
|
query = QSqlQuery()
|
||||||
|
query.prepare("SELECT * FROM paragraphs WHERE paragraph_id = :paragraph_id")
|
||||||
|
query.bindValue(":paragraph_id", paragraph_id)
|
||||||
|
query.exec()
|
||||||
|
query.next()
|
||||||
|
self.section_id = query.value("section_id")
|
||||||
|
self.paraSequence = query.value("sequence")
|
||||||
|
cursor = self.paraEdit.textCursor()
|
||||||
|
cursor.movePosition(QTextCursor.MoveOperation.Start)
|
||||||
|
cursor.movePosition(
|
||||||
|
QTextCursor.MoveOperation.End, QTextCursor.MoveMode.KeepAnchor
|
||||||
|
)
|
||||||
|
cursor.removeSelectedText()
|
||||||
|
cursor.insertHtml(query.value("content"))
|
||||||
|
query.prepare(
|
||||||
|
"SELECT * FROM word_paragraph " "WHERE paragraph_id = :paragraph_id"
|
||||||
|
)
|
||||||
|
query.bindValue(":paragraph_id", self.paragraph_id)
|
||||||
|
if not query.exec():
|
||||||
|
query_error(query)
|
||||||
|
def_format = QTextCharFormat()
|
||||||
|
def_format.setFontUnderline(True)
|
||||||
|
cursor = QTextCursor(self.paraEdit.document())
|
||||||
|
while query.next():
|
||||||
|
start = query.value("start")
|
||||||
|
end = query.value("end")
|
||||||
|
cursor.setPosition(start, QTextCursor.MoveMode.MoveAnchor)
|
||||||
|
cursor.setPosition(end, QTextCursor.MoveMode.KeepAnchor)
|
||||||
|
cursor.setCharFormat(def_format)
|
||||||
|
cursor.setPosition(0)
|
||||||
|
self.paraEdit.setTextCursor(cursor)
|
||||||
|
return
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def defineAction(self) -> None:
|
||||||
|
cursor = self.paraEdit.textCursor()
|
||||||
|
word = cursor.selectedText()
|
||||||
|
start = cursor.selectionStart()
|
||||||
|
end = cursor.selectionEnd()
|
||||||
|
if start != end:
|
||||||
|
word = word.strip()
|
||||||
|
if len(word) == 0 or word.find(" ") >= 0:
|
||||||
|
return
|
||||||
|
if start > end:
|
||||||
|
tmp = start
|
||||||
|
start = end
|
||||||
|
end = tmp
|
||||||
|
|
||||||
|
query = QSqlQuery()
|
||||||
|
query.prepare("SELECT * FROM words WHERE word = :word")
|
||||||
|
query.bindValue(":word", word)
|
||||||
|
if not query.exec():
|
||||||
|
query_error(query)
|
||||||
|
if query.next(): # we have something
|
||||||
|
self.defined(query.value("word_id"), start, end)
|
||||||
|
return
|
||||||
|
dictionary = PyDictionary()
|
||||||
|
meaning = json.dumps(dictionary.meaning(word))
|
||||||
|
por = dictionary.translate(word, "pt")
|
||||||
|
query.prepare(
|
||||||
|
"INSERT INTO words (word, definition, translation) "
|
||||||
|
"VALUES (:word, :definition, :translation)"
|
||||||
|
)
|
||||||
|
query.bindValue(":word", word)
|
||||||
|
query.bindValue(":definition", meaning)
|
||||||
|
query.bindValue(":translation", por)
|
||||||
|
if not query.exec():
|
||||||
|
query_error(query)
|
||||||
|
self.defined(query.lastInsertId(), start, end)
|
||||||
|
return
|
||||||
|
|
||||||
|
def defined(self, word_id: int, start: int, end: int) -> None:
|
||||||
|
query = QSqlQuery()
|
||||||
|
query.prepare(
|
||||||
|
"SELECT * FROM word_paragraph "
|
||||||
|
"WHERE word_id = :word_id "
|
||||||
|
"AND paragraph_id = :paragraph_id "
|
||||||
|
"AND start = :start "
|
||||||
|
"AND end = :end"
|
||||||
|
)
|
||||||
|
query.bindValue(":word_id", word_id)
|
||||||
|
query.bindValue(":paragraph_id", self.paragraph_id)
|
||||||
|
query.bindValue(":start", start)
|
||||||
|
query.bindValue(":end", end)
|
||||||
|
if not query.exec():
|
||||||
|
query_error(query)
|
||||||
|
if query.next():
|
||||||
|
return
|
||||||
|
query.prepare(
|
||||||
|
"INSERT INTO word_paragraph VALUES "
|
||||||
|
"( :word_id, :paragraph_id, :start, :end)"
|
||||||
|
)
|
||||||
|
query.bindValue(":word_id", word_id)
|
||||||
|
query.bindValue(":paragraph_id", self.paragraph_id)
|
||||||
|
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())
|
||||||
|
cursor.setPosition(start, QTextCursor.MoveMode.MoveAnchor)
|
||||||
|
cursor.setPosition(end, QTextCursor.MoveMode.KeepAnchor)
|
||||||
|
cursor.setCharFormat(def_format)
|
||||||
|
return
|
||||||
|
|
||||||
|
def display_definition(self) -> None:
|
||||||
|
cursor = self.paraEdit.textCursor()
|
||||||
|
query = QSqlQuery()
|
||||||
|
query.prepare(
|
||||||
|
"SELECT w.* FROM word_paragraph wp "
|
||||||
|
"LEFT JOIN words w "
|
||||||
|
"ON (w.word_id = wp.word_id) "
|
||||||
|
"WHERE :position BETWEEN wp.start AND wp.end "
|
||||||
|
"AND wp.paragraph_id = :paragraph_id"
|
||||||
|
)
|
||||||
|
query.bindValue(":position", cursor.position())
|
||||||
|
query.bindValue(":paragraph_id", self.paragraph_id)
|
||||||
|
print("display_definition()", cursor.position())
|
||||||
|
if not query.exec():
|
||||||
|
query_error(query)
|
||||||
|
if not query.next():
|
||||||
|
return
|
||||||
|
word = query.value("word")
|
||||||
|
definition = json.loads(query.value("definition"))
|
||||||
|
self.defEdit.document().clear()
|
||||||
|
cursor = self.defEdit.textCursor()
|
||||||
|
word_format = QTextCharFormat()
|
||||||
|
word_format.setFontPointSize(48)
|
||||||
|
word_format.setFontWeight(QFont.Weight.Bold)
|
||||||
|
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(QFont.Weight.Normal)
|
||||||
|
word_format.setFontPointSize(16)
|
||||||
|
cursor.setCharFormat(word_format)
|
||||||
|
for key in definition.keys():
|
||||||
|
cursor.insertList(typeFormat)
|
||||||
|
cursor.insertText(key)
|
||||||
|
cursor.insertList(defFormat)
|
||||||
|
first = True
|
||||||
|
for a_def in definition[key]:
|
||||||
|
if not first:
|
||||||
|
cursor.insertBlock()
|
||||||
|
cursor.insertText(a_def)
|
||||||
|
first = False
|
||||||
|
return
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def showAction(self) -> None:
|
||||||
|
idx = self.stackedWidget.currentIndex()
|
||||||
|
if idx == 0:
|
||||||
|
self.display_definition()
|
||||||
|
self.stackedWidget.setCurrentIndex(1 - idx)
|
||||||
|
return
|
||||||
|
|
||||||
|
def nextDefinition(self):
|
||||||
|
cursor = self.paraEdit.textCursor()
|
||||||
|
position = cursor.position()
|
||||||
|
print(position)
|
||||||
|
formats = cursor.block().textFormats()
|
||||||
|
found = None
|
||||||
|
for f in formats:
|
||||||
|
wc = QTextCursor(cursor)
|
||||||
|
wc.setPosition(f.start)
|
||||||
|
wc.movePosition(
|
||||||
|
QTextCursor.MoveOperation.Right,
|
||||||
|
QTextCursor.MoveMode.KeepAnchor,
|
||||||
|
f.length,
|
||||||
|
)
|
||||||
|
word = wc.selectedText()
|
||||||
|
cf = wc.charFormat()
|
||||||
|
if f.start <= position:
|
||||||
|
continue
|
||||||
|
if not cf.fontUnderline():
|
||||||
|
continue
|
||||||
|
if not found:
|
||||||
|
found = f
|
||||||
|
elif f.start < found.start:
|
||||||
|
found = f
|
||||||
|
if found:
|
||||||
|
cursor.setPosition(found.start)
|
||||||
|
self.paraEdit.setTextCursor(cursor)
|
||||||
|
self.display_definition()
|
||||||
|
return
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def nextAction(self) -> None:
|
||||||
|
if self.stackedWidget.currentIndex() == 1:
|
||||||
|
self.nextDefinition()
|
||||||
|
return
|
||||||
|
paraQuery = QSqlQuery()
|
||||||
|
paraQuery.prepare(
|
||||||
|
"SELECT * FROM paragraphs WHERE "
|
||||||
|
"section_id=:section_id AND sequence = :sequence"
|
||||||
|
)
|
||||||
|
paraQuery.bindValue(":section_id", self.section_id)
|
||||||
|
paraQuery.bindValue(":sequence", self.paraSequence + 1)
|
||||||
|
if not paraQuery.exec():
|
||||||
|
query_error(paraQuery)
|
||||||
|
if not paraQuery.next():
|
||||||
|
secQuery = QSqlQuery()
|
||||||
|
secQuery.prepare(
|
||||||
|
"SELECT * FROM sections WHERE book_id=:book_id "
|
||||||
|
"AND sequence = "
|
||||||
|
"(SELECT sequence FROM sections WHERE "
|
||||||
|
"section_id = :section_id)+1"
|
||||||
|
)
|
||||||
|
secQuery.bindValue(":book_id", self.book_id)
|
||||||
|
secQuery.bindValue(":section_id", self.section_id)
|
||||||
|
if not secQuery.exec():
|
||||||
|
query_error(secQuery)
|
||||||
|
if not secQuery.next():
|
||||||
|
return
|
||||||
|
self.paraSequence = 0
|
||||||
|
self.section_id = secQuery.value("section_id")
|
||||||
|
paraQuery.bindValue(":section_id", self.section_id)
|
||||||
|
paraQuery.bindValue(":sequence", self.paraSequence)
|
||||||
|
if not paraQuery.exec():
|
||||||
|
query_error(paraQuery)
|
||||||
|
paraQuery.next()
|
||||||
|
self.display_paragraph(paraQuery.value("paragraph_id"))
|
||||||
|
return
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def prevAction(self) -> None:
|
||||||
|
return
|
||||||
286
main.py
Executable file
286
main.py
Executable file
@@ -0,0 +1,286 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtCore import Qt, pyqtSlot
|
||||||
|
from PyQt6.QtGui import (
|
||||||
|
QFont,
|
||||||
|
QTextCharFormat,
|
||||||
|
QTextCursor,
|
||||||
|
QTextDocument,
|
||||||
|
QTextListFormat,
|
||||||
|
)
|
||||||
|
from PyQt6.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
|
||||||
|
from PyQt6.QtWidgets import QApplication, QFileDialog, QMainWindow
|
||||||
|
|
||||||
|
from lib import *
|
||||||
|
from ui.MainWindow import Ui_MainWindow
|
||||||
|
|
||||||
|
# from ui.testWindow import Ui_MainWindow
|
||||||
|
|
||||||
|
|
||||||
|
def query_error(query: QSqlQuery) -> None:
|
||||||
|
print(
|
||||||
|
"SQL Error:\n{}\n{}\n{}:{}".format(
|
||||||
|
query.executedQuery(),
|
||||||
|
query.boundValues(),
|
||||||
|
query.lastError().type(),
|
||||||
|
query.lastError().text(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
raise Exception("SQL Error")
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
|
book_id = 0
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super(MainWindow, self).__init__()
|
||||||
|
self.setupUi(self)
|
||||||
|
model = QSqlQueryModel()
|
||||||
|
query = QSqlQuery("SELECT * FROM people ORDER BY name")
|
||||||
|
model.setQuery(query)
|
||||||
|
self.peopleView.setModel(model)
|
||||||
|
self.peopleView.setModelColumn(1)
|
||||||
|
# self.load_definition(word, PyDictionary.meaning(word))
|
||||||
|
# self.wordButton.clicked.connect(self.wordAction)
|
||||||
|
self.ReadButton.clicked.connect(self.readAction)
|
||||||
|
self.bookBtn.clicked.connect(self.bookAction)
|
||||||
|
self.show()
|
||||||
|
return
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def bookAction(self) -> None:
|
||||||
|
directory = QFileDialog.getExistingDirectory()
|
||||||
|
book = Book(directory)
|
||||||
|
self.book_id = self.store_book(book)
|
||||||
|
return
|
||||||
|
|
||||||
|
def store_book(self, book: Book) -> int:
|
||||||
|
uuid = book.metadata["identifier"]
|
||||||
|
query = QSqlQuery()
|
||||||
|
query.prepare(
|
||||||
|
"SELECT COUNT(*) AS number, book_id FROM books b " "WHERE b.uuid = :uuid"
|
||||||
|
)
|
||||||
|
query.bindValue(":uuid", uuid)
|
||||||
|
if not query.exec():
|
||||||
|
query_error(query)
|
||||||
|
query.next()
|
||||||
|
if query.value("number") > 0:
|
||||||
|
book_id: int = query.value("book_id")
|
||||||
|
return book_id
|
||||||
|
query.prepare(
|
||||||
|
"INSERT INTO books (title, author, uuid, level) VALUES ("
|
||||||
|
":title, :author, :uuid, 0)"
|
||||||
|
)
|
||||||
|
query.bindValue(":title", book.metadata["title"])
|
||||||
|
query.bindValue(":author", book.metadata["creator"])
|
||||||
|
query.bindValue(":uuid", uuid)
|
||||||
|
if not query.exec():
|
||||||
|
query_error(query)
|
||||||
|
book_id = query.lastInsertId()
|
||||||
|
section_query = QSqlQuery()
|
||||||
|
section_query.prepare(
|
||||||
|
"INSERT INTO sections (title, sequence, book_id) "
|
||||||
|
"VALUES (:title, :sequence, :book_id)"
|
||||||
|
)
|
||||||
|
section_query.bindValue(":book_id", book_id)
|
||||||
|
para_query = QSqlQuery()
|
||||||
|
para_query.prepare(
|
||||||
|
"INSERT INTO paragraphs (section_id, sequence, content) "
|
||||||
|
"VALUES (:section_id, :sequence, :content)"
|
||||||
|
)
|
||||||
|
for seq, section in enumerate(book.sections):
|
||||||
|
section_query.bindValue(":title", section["title"])
|
||||||
|
section_query.bindValue(":sequence", seq)
|
||||||
|
if not section_query.exec():
|
||||||
|
query_error(section_query)
|
||||||
|
section_id = query.lastInsertId()
|
||||||
|
para_query.bindValue(":section_id", section_id)
|
||||||
|
for ps, paragraph in enumerate(section["paragraphs"]):
|
||||||
|
para_query.bindValue(":sequence", ps)
|
||||||
|
para_query.bindValue(":content", paragraph)
|
||||||
|
if not para_query.exec():
|
||||||
|
query_error(para_query)
|
||||||
|
return book_id
|
||||||
|
|
||||||
|
def load_definition(self, word: str, definition: dict) -> None:
|
||||||
|
document = None # self.textEdit.document()
|
||||||
|
myCursor = QTextCursor(document)
|
||||||
|
myCursor.movePosition(QTextCursor.MoveOperation.Start)
|
||||||
|
myCursor.movePosition(
|
||||||
|
QTextCursor.MoveOperation.End, QTextCursor.MoveMode.KeepAnchor
|
||||||
|
)
|
||||||
|
myCursor.removeSelectedText()
|
||||||
|
word_format = QTextCharFormat()
|
||||||
|
# word_format.setFontFamily("Caveat")
|
||||||
|
word_format.setFontPointSize(48)
|
||||||
|
word_format.setFontWeight(QFont.Weight.Bold)
|
||||||
|
myCursor.insertText(word, word_format)
|
||||||
|
# word_format.setFont(document.defaultFont())
|
||||||
|
typeFormat = QTextListFormat()
|
||||||
|
typeFormat.setStyle(QTextListFormat.Style.ListDisc)
|
||||||
|
typeFormat.setIndent(1)
|
||||||
|
defFormat = QTextListFormat()
|
||||||
|
defFormat.setStyle(QTextListFormat.Style.ListCircle)
|
||||||
|
defFormat.setIndent(2)
|
||||||
|
myCursor.setCharFormat(word_format)
|
||||||
|
for key in definition.keys():
|
||||||
|
myCursor.insertList(typeFormat)
|
||||||
|
myCursor.insertText(key)
|
||||||
|
myCursor.insertList(defFormat)
|
||||||
|
first = True
|
||||||
|
for a_def in definition[key]:
|
||||||
|
if not first:
|
||||||
|
myCursor.insertBlock()
|
||||||
|
myCursor.insertText(a_def)
|
||||||
|
first = False
|
||||||
|
return
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def readAction(self) -> None:
|
||||||
|
indexes = self.peopleView.selectedIndexes()
|
||||||
|
if len(indexes) < 1:
|
||||||
|
return
|
||||||
|
person_id = indexes[0].siblingAtColumn(0).data()
|
||||||
|
name = indexes[0].data()
|
||||||
|
print(person_id, name)
|
||||||
|
dlg = EditDialog(self.book_id, person_id)
|
||||||
|
dlg.exec()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
SQL_CMDS = [
|
||||||
|
"PRAGMA foreign_keys=ON",
|
||||||
|
"CREATE TABLE IF NOT EXISTS words "
|
||||||
|
"(word_id INTEGER PRIMARY KEY AUTOINCREMENT, word TEXT, definition TEXT, "
|
||||||
|
"translation TEXT)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS books "
|
||||||
|
"(book_id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, author TEXT, "
|
||||||
|
"uuid TEXT, level INTEGER)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS sections "
|
||||||
|
"(section_id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||||
|
"title TEXT, sequence INTEGER, "
|
||||||
|
"book_id INTEGER REFERENCES books ON DELETE CASCADE) ",
|
||||||
|
"CREATE TABLE IF NOT EXISTS paragraphs "
|
||||||
|
"(paragraph_id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||||
|
"section_id INTEGER REFERENCES sections ON DELETE CASCADE, "
|
||||||
|
"sequence INTEGER NOT NULL DEFAULT 0, "
|
||||||
|
"content TEXT)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS people "
|
||||||
|
"(person_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, "
|
||||||
|
"organization TEXT, "
|
||||||
|
"paragraph_id INTEGER REFERENCES paragraphs ON DELETE CASCADE)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS person_book "
|
||||||
|
"(person_id INTEGER REFERENCES people ON DELETE CASCADE, "
|
||||||
|
"book_id INTEGER REFERENCES books ON DELETE CASCADE)",
|
||||||
|
"CREATE TABLE IF NOT EXISTS word_paragraph "
|
||||||
|
"(word_id INTEGER REFERENCES words ON DELETE CASCADE, "
|
||||||
|
"paragraph_id INTEGER REFERENCES paragraphs ON DELETE CASCADE, "
|
||||||
|
"start INTEGER NOT NULL, end INTEGER NOT NULL)",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def schema_update(db: QSqlDatabase) -> None:
|
||||||
|
query = QSqlQuery()
|
||||||
|
|
||||||
|
for sql in SQL_CMDS:
|
||||||
|
print(sql)
|
||||||
|
inlower = sql.lower()
|
||||||
|
if not inlower.startswith("create table "):
|
||||||
|
if not query.exec(sql):
|
||||||
|
query_error(query)
|
||||||
|
continue
|
||||||
|
create_cmd = re.sub(r"IF NOT EXISTS ", "", sql)
|
||||||
|
create_cmd = re.sub(r"\s\s*", " ", create_cmd)
|
||||||
|
matches = re.search(r"^(CREATE TABLE )([^ ]+)( \(.+)$", create_cmd)
|
||||||
|
if matches:
|
||||||
|
table_name = matches.group(2)
|
||||||
|
create_cmd = (
|
||||||
|
matches.group(1) + '"' + matches.group(2) + '"' + matches.group(3)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise AttributeError(f"No match found: {create_cmd}")
|
||||||
|
|
||||||
|
query.prepare("SELECT sql FROM sqlite_schema WHERE tbl_name = :tbl")
|
||||||
|
query.bindValue(":tbl", table_name)
|
||||||
|
if not query.exec():
|
||||||
|
query_error(query)
|
||||||
|
query.next()
|
||||||
|
old = query.value(0)
|
||||||
|
if not old:
|
||||||
|
if not query.exec(sql):
|
||||||
|
query_error(query)
|
||||||
|
continue
|
||||||
|
if old.lower() == create_cmd.lower():
|
||||||
|
continue
|
||||||
|
print(old.lower())
|
||||||
|
print(create_cmd.lower())
|
||||||
|
print(f"Updating: {table_name}")
|
||||||
|
|
||||||
|
# Step 1 turn off foreign key constraints
|
||||||
|
if not query.exec("PRAGMA foreign_keys=OFF"):
|
||||||
|
query_error(query)
|
||||||
|
# Step 2 start a transaction
|
||||||
|
db.transaction()
|
||||||
|
# Step 3 remember old indexes, triggers, and views
|
||||||
|
# Step 4 create new table
|
||||||
|
new_table_name = table_name + "_new"
|
||||||
|
if not query.exec(matches.group(1) + new_table_name + matches.group(3)):
|
||||||
|
query_error(query)
|
||||||
|
# step 5 transfer content
|
||||||
|
coldefs = re.search(r"\((.+)\)", old).group(1).split(", ")
|
||||||
|
cols = [x.split(" ")[0] for x in coldefs]
|
||||||
|
if not query.exec(
|
||||||
|
"INSERT INTO "
|
||||||
|
+ new_table_name
|
||||||
|
+ "("
|
||||||
|
+ ", ".join(cols)
|
||||||
|
+ ") SELECT "
|
||||||
|
+ ", ".join(cols)
|
||||||
|
+ " FROM "
|
||||||
|
+ table_name
|
||||||
|
):
|
||||||
|
query_error(query)
|
||||||
|
|
||||||
|
# step 6 Drop old table
|
||||||
|
if not query.exec("DROP TABLE " + table_name):
|
||||||
|
query_error(query)
|
||||||
|
# step 6 rename new table to old table
|
||||||
|
if not query.exec("ALTER TABLE " + new_table_name + " RENAME TO " + table_name):
|
||||||
|
query_error(query)
|
||||||
|
|
||||||
|
# step 8 create indexes, triggers, and views
|
||||||
|
# step 9 rebuild affected views
|
||||||
|
# step 10 turn foreign key constrants back on
|
||||||
|
if not query.exec("PRAGMA foreign_keys=ON"):
|
||||||
|
query_error(query)
|
||||||
|
# step 11 commit the changes
|
||||||
|
db.commit()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
db = QSqlDatabase()
|
||||||
|
db = db.addDatabase("QSQLITE")
|
||||||
|
db.setDatabaseName("twel.db")
|
||||||
|
db.open()
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
schema_update(db)
|
||||||
|
window: QMainWindow = MainWindow()
|
||||||
|
return app.exec()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
outOfDate = []
|
||||||
|
for fileName in os.listdir("ui"):
|
||||||
|
if not fileName.endswith(".py"):
|
||||||
|
continue
|
||||||
|
uiName = fileName[:-3] + ".ui"
|
||||||
|
if os.path.getmtime("ui/" + uiName) > os.path.getmtime("ui/" + fileName):
|
||||||
|
outOfDate.append(fileName)
|
||||||
|
if len(outOfDate) > 0:
|
||||||
|
print(f"UI out of date: {', '.join(outOfDate)}")
|
||||||
|
sys.exit(1)
|
||||||
|
sys.exit(main())
|
||||||
8
mypy.ini
Normal file
8
mypy.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[mypy]
|
||||||
|
warn_redundant_casts = True
|
||||||
|
disallow_untyped_defs = True
|
||||||
|
warn_return_any = True
|
||||||
|
warn_unused_configs = True
|
||||||
|
|
||||||
|
[mypy-ui.*]
|
||||||
|
disallow_untyped_defs = False
|
||||||
78
ui/EditDialog.py
Normal file
78
ui/EditDialog.py
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# Form implementation generated from reading ui file 'ui/EditDialog.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt6 UI code generator 6.6.0
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_Dialog(object):
|
||||||
|
def setupUi(self, Dialog):
|
||||||
|
Dialog.setObjectName("Dialog")
|
||||||
|
Dialog.resize(761, 427)
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(Dialog)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.stackedWidget = QtWidgets.QStackedWidget(parent=Dialog)
|
||||||
|
self.stackedWidget.setObjectName("stackedWidget")
|
||||||
|
self.page = QtWidgets.QWidget()
|
||||||
|
self.page.setObjectName("page")
|
||||||
|
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.page)
|
||||||
|
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||||
|
self.paraEdit = QtWidgets.QTextEdit(parent=self.page)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("OpenDyslexic")
|
||||||
|
font.setPointSize(16)
|
||||||
|
self.paraEdit.setFont(font)
|
||||||
|
self.paraEdit.setObjectName("paraEdit")
|
||||||
|
self.verticalLayout_2.addWidget(self.paraEdit)
|
||||||
|
self.stackedWidget.addWidget(self.page)
|
||||||
|
self.page_2 = QtWidgets.QWidget()
|
||||||
|
self.page_2.setObjectName("page_2")
|
||||||
|
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.page_2)
|
||||||
|
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||||
|
self.defEdit = QtWidgets.QTextEdit(parent=self.page_2)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("OpenDyslexic")
|
||||||
|
self.defEdit.setFont(font)
|
||||||
|
self.defEdit.setObjectName("defEdit")
|
||||||
|
self.verticalLayout_3.addWidget(self.defEdit)
|
||||||
|
self.stackedWidget.addWidget(self.page_2)
|
||||||
|
self.horizontalLayout.addWidget(self.stackedWidget)
|
||||||
|
self.widget = QtWidgets.QWidget(parent=Dialog)
|
||||||
|
self.widget.setObjectName("widget")
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.defineBtn = QtWidgets.QPushButton(parent=self.widget)
|
||||||
|
self.defineBtn.setObjectName("defineBtn")
|
||||||
|
self.verticalLayout.addWidget(self.defineBtn)
|
||||||
|
self.wordsBtn = QtWidgets.QPushButton(parent=self.widget)
|
||||||
|
self.wordsBtn.setObjectName("wordsBtn")
|
||||||
|
self.verticalLayout.addWidget(self.wordsBtn)
|
||||||
|
self.showBtn = QtWidgets.QPushButton(parent=self.widget)
|
||||||
|
self.showBtn.setObjectName("showBtn")
|
||||||
|
self.verticalLayout.addWidget(self.showBtn)
|
||||||
|
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
|
||||||
|
self.verticalLayout.addItem(spacerItem)
|
||||||
|
self.nextBtn = QtWidgets.QPushButton(parent=self.widget)
|
||||||
|
self.nextBtn.setObjectName("nextBtn")
|
||||||
|
self.verticalLayout.addWidget(self.nextBtn)
|
||||||
|
self.prevBtn = QtWidgets.QPushButton(parent=self.widget)
|
||||||
|
self.prevBtn.setObjectName("prevBtn")
|
||||||
|
self.verticalLayout.addWidget(self.prevBtn)
|
||||||
|
self.horizontalLayout.addWidget(self.widget)
|
||||||
|
|
||||||
|
self.retranslateUi(Dialog)
|
||||||
|
self.stackedWidget.setCurrentIndex(0)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||||
|
|
||||||
|
def retranslateUi(self, Dialog):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||||
|
self.defineBtn.setText(_translate("Dialog", "Define"))
|
||||||
|
self.wordsBtn.setText(_translate("Dialog", "Words"))
|
||||||
|
self.showBtn.setText(_translate("Dialog", "Show"))
|
||||||
|
self.nextBtn.setText(_translate("Dialog", "Next"))
|
||||||
|
self.prevBtn.setText(_translate("Dialog", "Previous"))
|
||||||
109
ui/EditDialog.ui
Normal file
109
ui/EditDialog.ui
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>761</width>
|
||||||
|
<height>427</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QStackedWidget" name="stackedWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="page">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="paraEdit">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>OpenDyslexic</family>
|
||||||
|
<pointsize>16</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="page_2">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="defEdit">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>OpenDyslexic</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="widget" native="true">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="defineBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Define</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="wordsBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Words</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="showBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="nextBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Next</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="prevBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Previous</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
56
ui/MainWindow.py
Normal file
56
ui/MainWindow.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Form implementation generated from reading ui file 'ui/MainWindow.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt6 UI code generator 6.6.0
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_MainWindow(object):
|
||||||
|
def setupUi(self, MainWindow):
|
||||||
|
MainWindow.setObjectName("MainWindow")
|
||||||
|
MainWindow.resize(800, 600)
|
||||||
|
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
|
||||||
|
self.centralwidget.setObjectName("centralwidget")
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.peopleView = QtWidgets.QListView(parent=self.centralwidget)
|
||||||
|
self.peopleView.setObjectName("peopleView")
|
||||||
|
self.horizontalLayout.addWidget(self.peopleView)
|
||||||
|
self.widget = QtWidgets.QWidget(parent=self.centralwidget)
|
||||||
|
self.widget.setObjectName("widget")
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.WordButton = QtWidgets.QPushButton(parent=self.widget)
|
||||||
|
self.WordButton.setObjectName("WordButton")
|
||||||
|
self.verticalLayout.addWidget(self.WordButton)
|
||||||
|
self.ReadButton = QtWidgets.QPushButton(parent=self.widget)
|
||||||
|
self.ReadButton.setObjectName("ReadButton")
|
||||||
|
self.verticalLayout.addWidget(self.ReadButton)
|
||||||
|
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
|
||||||
|
self.verticalLayout.addItem(spacerItem)
|
||||||
|
self.bookBtn = QtWidgets.QPushButton(parent=self.widget)
|
||||||
|
self.bookBtn.setObjectName("bookBtn")
|
||||||
|
self.verticalLayout.addWidget(self.bookBtn)
|
||||||
|
self.horizontalLayout.addWidget(self.widget)
|
||||||
|
MainWindow.setCentralWidget(self.centralwidget)
|
||||||
|
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
|
||||||
|
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
|
||||||
|
self.menubar.setObjectName("menubar")
|
||||||
|
MainWindow.setMenuBar(self.menubar)
|
||||||
|
self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
|
||||||
|
self.statusbar.setObjectName("statusbar")
|
||||||
|
MainWindow.setStatusBar(self.statusbar)
|
||||||
|
|
||||||
|
self.retranslateUi(MainWindow)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||||
|
|
||||||
|
def retranslateUi(self, MainWindow):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
|
||||||
|
self.WordButton.setText(_translate("MainWindow", "Words"))
|
||||||
|
self.ReadButton.setText(_translate("MainWindow", "Read"))
|
||||||
|
self.bookBtn.setText(_translate("MainWindow", "Add Book"))
|
||||||
77
ui/MainWindow.ui
Normal file
77
ui/MainWindow.ui
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QListView" name="peopleView"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="widget" native="true">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="WordButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Words</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="ReadButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Read</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="bookBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add Book</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
42
ui/WordDialog.py
Normal file
42
ui/WordDialog.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Form implementation generated from reading ui file 'ui/WordDialog.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt6 UI code generator 6.6.0
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_Dialog(object):
|
||||||
|
def setupUi(self, Dialog):
|
||||||
|
Dialog.setObjectName("Dialog")
|
||||||
|
Dialog.resize(802, 300)
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.wordList = QtWidgets.QListView(parent=Dialog)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Expanding)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.wordList.sizePolicy().hasHeightForWidth())
|
||||||
|
self.wordList.setSizePolicy(sizePolicy)
|
||||||
|
self.wordList.setObjectName("wordList")
|
||||||
|
self.horizontalLayout.addWidget(self.wordList)
|
||||||
|
self.definition = QtWidgets.QTextEdit(parent=Dialog)
|
||||||
|
self.definition.setObjectName("definition")
|
||||||
|
self.horizontalLayout.addWidget(self.definition)
|
||||||
|
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||||
|
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
|
||||||
|
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Ok)
|
||||||
|
self.buttonBox.setObjectName("buttonBox")
|
||||||
|
self.verticalLayout.addWidget(self.buttonBox)
|
||||||
|
|
||||||
|
self.retranslateUi(Dialog)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||||
|
|
||||||
|
def retranslateUi(self, Dialog):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||||
45
ui/WordDialog.ui
Normal file
45
ui/WordDialog.ui
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>802</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QListView" name="wordList">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="definition"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
37
ui/testWindow.py
Normal file
37
ui/testWindow.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Form implementation generated from reading ui file 'ui/testWindow.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt6 UI code generator 6.6.0
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_MainWindow(object):
|
||||||
|
def setupUi(self, MainWindow):
|
||||||
|
MainWindow.setObjectName("MainWindow")
|
||||||
|
MainWindow.resize(800, 600)
|
||||||
|
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
|
||||||
|
self.centralwidget.setObjectName("centralwidget")
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.textEdit = QtWidgets.QTextEdit(parent=self.centralwidget)
|
||||||
|
self.textEdit.setObjectName("textEdit")
|
||||||
|
self.verticalLayout.addWidget(self.textEdit)
|
||||||
|
MainWindow.setCentralWidget(self.centralwidget)
|
||||||
|
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
|
||||||
|
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 19))
|
||||||
|
self.menubar.setObjectName("menubar")
|
||||||
|
MainWindow.setMenuBar(self.menubar)
|
||||||
|
self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
|
||||||
|
self.statusbar.setObjectName("statusbar")
|
||||||
|
MainWindow.setStatusBar(self.statusbar)
|
||||||
|
|
||||||
|
self.retranslateUi(MainWindow)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||||
|
|
||||||
|
def retranslateUi(self, MainWindow):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
|
||||||
37
ui/testWindow.ui
Normal file
37
ui/testWindow.ui
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="textEdit"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>19</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
Reference in New Issue
Block a user