diff --git a/lib/read.py b/lib/read.py index 9b2b4c0..83dec45 100644 --- a/lib/read.py +++ b/lib/read.py @@ -12,6 +12,7 @@ from PyQt6.QtCore import ( QResource, Qt, QTimer, + pyqtSignal, pyqtSlot, ) from PyQt6.QtGui import ( @@ -39,8 +40,10 @@ from ui.EditDialog import Ui_Dialog class EditDialog(QDialog, Ui_Dialog): block: int paragraphs = True + displayedWord = pyqtSignal(int) - def __init__(self, person_id: int) -> None: + def __init__(self, session, person_id: int) -> None: + self.session = session super(EditDialog, self).__init__() self.person_id = person_id if not QResource.registerResource( @@ -65,12 +68,20 @@ class EditDialog(QDialog, Ui_Dialog): self.block = blockNumber self.savePosition() self.stackedWidget.setCurrentIndex(0) + # + # Connect widgets + # self.defineBtn.clicked.connect(self.defineAction) self.printBtn.clicked.connect(self.printAction) self.scrollBtn.clicked.connect(self.scrollAction) self.nextBtn.clicked.connect(self.nextAction) self.prevBtn.clicked.connect(self.prevAction) + self.sessionBtn.clicked.connect(self.session.timerAction) self.paraEdit.verticalScrollBar().valueChanged.connect(self.scrollSlot) + # + # Connect signals + # + self.displayedWord.connect(self.session.addWord) return # @@ -148,7 +159,6 @@ class EditDialog(QDialog, Ui_Dialog): if msPerTick < 3: msPerTick = 3 self.target = value + delta - print(f"delta: {delta}, pixels: {self.pxPerTick}, ms: {msPerTick}") timer = QTimer(self) timer.timeout.connect(self.softTick) timer.start(msPerTick) @@ -200,7 +210,6 @@ class EditDialog(QDialog, Ui_Dialog): @pyqtSlot() def defineAction(self) -> None: - print("defineAction") if self.paragraphs: self.showDefinition() else: @@ -512,6 +521,7 @@ class EditDialog(QDialog, Ui_Dialog): cursor.insertHtml(self.defToHtml(word, definition)) cursor.setPosition(0) self.defEdit.setTextCursor(cursor) + self.displayedWord.emit(query.value("word_id")) return def showDefinition(self) -> None: diff --git a/main.py b/main.py index b7b6dce..0980923 100755 --- a/main.py +++ b/main.py @@ -1,10 +1,33 @@ #!/usr/bin/env python3 +# +# TODO: +# Start/Stop Session +# Record all words examined +# Record all words defined after start session +# Record paragraph start and stop +# +# Add definition to definition +# Follow definition links +# Print subset of words, limit to words from this session's paragraphs +# plus defined during session +# Add Note per session +# Add book import dialog +# Add person create/edit dialog +# Reading scroll with speed control +# Move controls out of reading window. +# Ability to edit text with updates to word-section links +# Need to be able to place a visible cursor in text. +# Scroll to cursor +# XXX: +# Scrolling is messed up. Need a way of marking current line. +# import os import re import sys +from datetime import datetime, timedelta from typing import cast -from PyQt6.QtCore import QModelIndex, Qt, pyqtSlot +from PyQt6.QtCore import QModelIndex, Qt, QTimer, pyqtSignal, pyqtSlot from PyQt6.QtGui import ( QAction, QFont, @@ -37,181 +60,97 @@ def query_error(query: QSqlQuery) -> None: ) raise Exception("SQL Error") - -class ModelOverride(QSqlQueryModel): - enableFlag = False - - def flags(self, index: QModelIndex) -> Qt.ItemFlag: - itemFlags = super(ModelOverride, self).flags(index) - if self.enableFlag: - return itemFlags - value = index.siblingAtColumn(3).data() - if not value or value < 1: - itemFlags &= ~( - Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled - ) - return itemFlags - - @pyqtSlot() - def toggle(self) -> None: - self.enableFlag = not self.enableFlag - sender = cast(QPushButton, self.sender()) - if self.enableFlag: - sender.setText("Disable") - else: - sender.setText("Enable") - return - - class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self) -> None: super(MainWindow, self).__init__() self.setupUi(self) - model = ModelOverride() + #model = ModelOverride() + model = QSqlQueryModel() query = QSqlQuery("SELECT * FROM people ORDER BY name") model.setQuery(query) self.peopleView.setModel(model) self.peopleView.setModelColumn(1) - self.toggleBtn.clicked.connect(model.toggle) - self.bookBtn.clicked.connect(self.bookAction) - self.peopleView.doubleClicked.connect(self.readAction) - self.actionQuit.triggered.connect(self.close) - self.createActions() + self.actionEditPerson.setEnabled(False) + # + # Connections + # + # Action Connections + # + self.actionQuit.triggered.connect(self.close) # Y + self.actionAddBook.triggered.connect(self.addBook) # Y + self.actionEditBook.triggered.connect(self.editBook) # Y + self.actionRead.triggered.connect(self.readBook) # Y + self.actionRead.enabledChanged.connect(self.readBtn.setEnabled) + self.actionAddPerson.triggered.connect(self.addPerson) # Y + self.actionEditPerson.triggered.connect(self.editPerson) # Y + self.actionEditPerson.enabledChanged.connect(self.editBtn.setEnabled) # Y + self.peopleView.doubleClicked.connect(self.editPerson) # Y + self.peopleView.clicked.connect(self.selectedPerson) # Y self.show() return - def createActions(self) -> None: - query = QSqlQuery() - query.prepare("SELECT * FROM books ORDER BY title") - if not query.exec(): - query_error(query) - while query.next(): - action = QAction(query.value("title"), self) - action.setData(query.value("book_id")) - action.triggered.connect(self.setBookAction) - self.menuBooks.addAction(action) + @pyqtSlot(QModelIndex) + def selectedPerson(self, index: QModelIndex) -> None: + person_id = index.siblingAtColumn(0).data() + self.actionEditPerson.setEnabled(True) + book_id = index.siblingAtColumn(3).data() + if not book_id or book_id < 0: + self.actionRead.setEnabled(False) + else: + self.actionRead.setEnabled(True) return + + @pyqtSlot(bool) + def enablePerson(self, flag: bool) -> None: + if flag: + self.editBtn.setEnabled(False) + self.readBtn.setEnabled(False) + else: + self.editBtn.setEnabled(True) + self.readBtn.setEnabled(True) + return + @pyqtSlot() - def setBookAction(self) -> None: - action = cast(QAction, self.sender()) - book_id = action.data() - indexes = self.peopleView.selectedIndexes() - if len(indexes) < 1: - return - person_id = indexes[0].siblingAtColumn(0).data() - query = QSqlQuery() - query.prepare( - "SELECT * FROM person_book " - "WHERE person_id = :person_id " - "AND book_id = :book_id" - ) - query.bindValue(":person_id", person_id) - query.bindValue(":book_id", book_id) - if not query.exec(): - query_error(query) - if not query.next(): - query.prepare( - "SELECT * FROM sections WHERE sequence = 0 " - "AND book_id = :book_id" - ) - query.bindValue(":book_id", book_id) - if not query.exec(): - query_error(query) - if not query.next(): - raise Exception(f"book_id: {book_id} has no section 0!") - section_id = query.value("section_id") - query.prepare( - "INSERT INTO person_book " - "VALUES (:person_id, :book_id, :section_id, 0)" - ) - query.bindValue(":person_id", person_id) - query.bindValue(":book_id", book_id) - query.bindValue(":section_id", section_id) - if not query.exec(): - query_error(query) - query.prepare( - "UPDATE people SET book_id = :book_id " - "WHERE person_id = :person_id" - ) - query.bindValue(":book_id", book_id) - query.bindValue(":person_id", person_id) - if not query.exec(): - query_error(query) - query.prepare( - "SELECT p.name,b.title FROM people p " - "LEFT JOIN books b " - "ON (p.book_id = b.book_id) " - "WHERE p.person_id = :person_id" - ) - query.bindValue(":person_id", person_id) - if not query.exec(): - query_error(query) - query.next() - title = query.value("title") - name = query.value("name") - QMessageBox.information( - self, "Book Assignment", f"{title} was assigned to {name}" - ) - self.resetPeopleModel() - return - - def resetPeopleModel(self) -> None: - query = QSqlQuery("SELECT * FROM people ORDER BY name") - self.peopleView.model().setQuery(query) - return - - @pyqtSlot() - def bookAction(self) -> None: - directory = QFileDialog.getExistingDirectory() - self.book = Book(directory) - return - - 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 + def addPerson(self) -> None: + dlg = PersonDialog() + dlg.exec() return @pyqtSlot() @pyqtSlot(QModelIndex) - def readAction(self, index: QModelIndex | None = None) -> None: - if index: - person_id = index.siblingAtColumn(0).data() - else: - indexes = self.peopleView.selectedIndexes() - if len(indexes) < 1: - return - person_id = indexes[0].siblingAtColumn(0).data() - dlg = EditDialog(person_id) - dlg.exec() + def editPerson(self, index = None ) -> None: + print("Edit a person") + return + + @pyqtSlot() + def addBook(self) -> None: + directory = QFileDialog.getExistingDirectory() + self.book = Book(directory) + return + + @pyqtSlot() + def editBook(self) -> None: + print("Edit Book") + return + session = None + setPerson = pyqtSignal(int) + + @pyqtSlot() + def readBook(self) -> None: + indexes = self.peopleView.selectedIndexes() + if len(indexes) < 1: + return + person_id = indexes[0].siblingAtColumn(0).data() + if not self.session: + self.session = SessionDialog() + self.setPerson.connect(self.session.setPerson) + self.session.show() + self.session.raise_() + self.setPerson.emit(person_id) + self.dlg = EditDialog(self.session, person_id) + self.dlg.show() + self.dlg.raise_() return diff --git a/ui/EditDialog.py b/ui/EditDialog.py index 729de8c..d412b2d 100644 --- a/ui/EditDialog.py +++ b/ui/EditDialog.py @@ -62,6 +62,14 @@ class Ui_Dialog(object): self.prevBtn = QtWidgets.QPushButton(parent=self.widget) self.prevBtn.setObjectName("prevBtn") self.verticalLayout.addWidget(self.prevBtn) + self.line = QtWidgets.QFrame(parent=self.widget) + self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.line.setObjectName("line") + self.verticalLayout.addWidget(self.line) + self.sessionBtn = QtWidgets.QPushButton(parent=self.widget) + self.sessionBtn.setObjectName("sessionBtn") + self.verticalLayout.addWidget(self.sessionBtn) self.horizontalLayout.addWidget(self.widget) self.retranslateUi(Dialog) @@ -76,3 +84,4 @@ class Ui_Dialog(object): self.scrollBtn.setText(_translate("Dialog", "Scroll")) self.nextBtn.setText(_translate("Dialog", "Next Para")) self.prevBtn.setText(_translate("Dialog", "Prev Para")) + self.sessionBtn.setText(_translate("Dialog", "Start")) diff --git a/ui/EditDialog.ui b/ui/EditDialog.ui index 360d78d..dcadad8 100644 --- a/ui/EditDialog.ui +++ b/ui/EditDialog.ui @@ -99,6 +99,20 @@ + + + + Qt::Horizontal + + + + + + + Start + + + diff --git a/ui/MainWindow.py b/ui/MainWindow.py index a4c53bf..c910b0b 100644 --- a/ui/MainWindow.py +++ b/ui/MainWindow.py @@ -24,18 +24,25 @@ class Ui_MainWindow(object): self.widget.setObjectName("widget") self.verticalLayout = QtWidgets.QVBoxLayout(self.widget) self.verticalLayout.setObjectName("verticalLayout") - self.WordButton = QtWidgets.QPushButton(parent=self.widget) - self.WordButton.setEnabled(False) - self.WordButton.setObjectName("WordButton") - self.verticalLayout.addWidget(self.WordButton) - self.toggleBtn = QtWidgets.QPushButton(parent=self.widget) - self.toggleBtn.setObjectName("toggleBtn") - self.verticalLayout.addWidget(self.toggleBtn) + self.readBtn = QtWidgets.QPushButton(parent=self.widget) + self.readBtn.setObjectName("readBtn") + self.verticalLayout.addWidget(self.readBtn) + self.editBtn = QtWidgets.QPushButton(parent=self.widget) + self.editBtn.setObjectName("editBtn") + self.verticalLayout.addWidget(self.editBtn) + self.line = QtWidgets.QFrame(parent=self.widget) + self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.line.setObjectName("line") + self.verticalLayout.addWidget(self.line) 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.addBtn = QtWidgets.QPushButton(parent=self.widget) + self.addBtn.setObjectName("addBtn") + self.verticalLayout.addWidget(self.addBtn) self.horizontalLayout.addWidget(self.widget) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(parent=MainWindow) @@ -45,25 +52,62 @@ class Ui_MainWindow(object): self.menuFile.setObjectName("menuFile") self.menuBooks = QtWidgets.QMenu(parent=self.menubar) self.menuBooks.setObjectName("menuBooks") + self.menuBooks_2 = QtWidgets.QMenu(parent=self.menuBooks) + self.menuBooks_2.setObjectName("menuBooks_2") + self.menuPeople = QtWidgets.QMenu(parent=self.menuBooks) + self.menuPeople.setObjectName("menuPeople") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(parent=MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.actionQuit = QtGui.QAction(parent=MainWindow) self.actionQuit.setObjectName("actionQuit") + self.actionAddBook = QtGui.QAction(parent=MainWindow) + self.actionAddBook.setObjectName("actionAddBook") + self.actionEditBook = QtGui.QAction(parent=MainWindow) + self.actionEditBook.setObjectName("actionEditBook") + self.actionAddPerson = QtGui.QAction(parent=MainWindow) + self.actionAddPerson.setObjectName("actionAddPerson") + self.actionEditPerson = QtGui.QAction(parent=MainWindow) + self.actionEditPerson.setObjectName("actionEditPerson") + self.actionRead = QtGui.QAction(parent=MainWindow) + self.actionRead.setObjectName("actionRead") self.menuFile.addAction(self.actionQuit) + self.menuBooks_2.addAction(self.actionAddBook) + self.menuBooks_2.addAction(self.actionEditBook) + self.menuPeople.addAction(self.actionAddPerson) + self.menuPeople.addAction(self.actionEditPerson) + self.menuBooks.addAction(self.menuBooks_2.menuAction()) + self.menuBooks.addAction(self.menuPeople.menuAction()) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuBooks.menuAction()) self.retranslateUi(MainWindow) + self.editBtn.clicked.connect(self.actionEditPerson.trigger) # type: ignore + self.addBtn.clicked.connect(self.actionAddPerson.trigger) # type: ignore + self.bookBtn.clicked.connect(self.actionAddBook.trigger) # type: ignore + self.readBtn.clicked.connect(self.actionRead.trigger) # type: ignore QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Reading Helper")) - self.WordButton.setText(_translate("MainWindow", "Words")) - self.toggleBtn.setText(_translate("MainWindow", "Enable")) + self.readBtn.setText(_translate("MainWindow", "Read")) + self.editBtn.setText(_translate("MainWindow", "Edit")) self.bookBtn.setText(_translate("MainWindow", "Add Book")) + self.addBtn.setText(_translate("MainWindow", "Add Person")) self.menuFile.setTitle(_translate("MainWindow", "File")) - self.menuBooks.setTitle(_translate("MainWindow", "Books")) + self.menuBooks.setTitle(_translate("MainWindow", "Edit")) + self.menuBooks_2.setTitle(_translate("MainWindow", "Books")) + self.menuPeople.setTitle(_translate("MainWindow", "People")) self.actionQuit.setText(_translate("MainWindow", "Quit")) + self.actionAddBook.setText(_translate("MainWindow", "Add")) + self.actionAddBook.setToolTip(_translate("MainWindow", "Add Book")) + self.actionEditBook.setText(_translate("MainWindow", "Edit")) + self.actionEditBook.setToolTip(_translate("MainWindow", "Edit Book")) + self.actionAddPerson.setText(_translate("MainWindow", "Add")) + self.actionAddPerson.setToolTip(_translate("MainWindow", "Add A Person")) + self.actionEditPerson.setText(_translate("MainWindow", "Edit")) + self.actionEditPerson.setToolTip(_translate("MainWindow", "Edit A Person")) + self.actionRead.setText(_translate("MainWindow", "Read")) + self.actionRead.setToolTip(_translate("MainWindow", "Read Book")) diff --git a/ui/MainWindow.ui b/ui/MainWindow.ui index a099c0d..af4e159 100644 --- a/ui/MainWindow.ui +++ b/ui/MainWindow.ui @@ -22,19 +22,23 @@ - - - false - + - Words + Read - + - Enable + Edit + + + + + + + Qt::Horizontal @@ -58,6 +62,13 @@ + + + + Add Person + + + @@ -80,8 +91,24 @@ - Books + Edit + + + Books + + + + + + + People + + + + + + @@ -92,7 +119,112 @@ Quit + + + Add + + + Add Book + + + + + Edit + + + Edit Book + + + + + Add + + + Add A Person + + + + + Edit + + + Edit A Person + + + + + Read + + + Read Book + + - + + + editBtn + clicked() + actionEditPerson + trigger() + + + 722 + 117 + + + -1 + -1 + + + + + addBtn + clicked() + actionAddPerson + trigger() + + + 722 + 532 + + + -1 + -1 + + + + + bookBtn + clicked() + actionAddBook + trigger() + + + 722 + 491 + + + -1 + -1 + + + + + readBtn + clicked() + actionRead + trigger() + + + 722 + 67 + + + -1 + -1 + + + + diff --git a/ui/display.css b/ui/display.css index 4327686..0227e23 100644 --- a/ui/display.css +++ b/ui/display.css @@ -18,6 +18,6 @@ p, li { font-size: 24px; } p.phonetic { - font-family: "Tex Gyre Heros", sans-serif; - font-size: 32px; + font-family: "Gentium", sans-serif; + font-size: 40px; } diff --git a/ui/resources.rcc b/ui/resources.rcc index 4999042..c72d976 100644 Binary files a/ui/resources.rcc and b/ui/resources.rcc differ