Make the interface better

This commit is contained in:
Christopher T. Johnson
2023-12-08 11:25:06 -05:00
parent 6135c5d278
commit 6752249680
8 changed files with 330 additions and 182 deletions

255
main.py
View File

@@ -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