diff --git a/docketModel.py b/docketModel.py index 184539c..dd66f72 100644 --- a/docketModel.py +++ b/docketModel.py @@ -1,19 +1,28 @@ import datetime -from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt -from PySide6.QtGui import QColor, QFont + +from PySide6.QtCore import ( + QAbstractTableModel, + QModelIndex, + QPersistentModelIndex, + Qt, +) +from PySide6.QtGui import QFont from PySide6.QtSql import QSqlQuery from lib.utils import query_error + class docketModel(QAbstractTableModel): - entries = [] - def __init__(self, case_id:int|None = None) -> None: - super(docketModel,self).__init__() + entries: list[list[str | None]] = [] + + def __init__(self, case_id: int | None = None) -> None: + super(docketModel, self).__init__() if case_id == None: return query = QSqlQuery() - query.prepare("SELECT * FROM entries WHERE case_id = :cid " - "ORDER BY entry_id") + query.prepare( + "SELECT * FROM entries WHERE case_id = :cid " "ORDER BY entry_id" + ) q2 = QSqlQuery() q2.prepare("SELECT * FROM documents WHERE entry_id = :eid") @@ -23,38 +32,40 @@ class docketModel(QAbstractTableModel): while query.next(): date = datetime.date.fromtimestamp(query.value(2)) assert isinstance(date, datetime.date) - row = [ - date.strftime("%B %-d, %Y"), - query.value(3) - ] + row = [date.strftime("%B %-d, %Y"), query.value(3)] self.entries.append(row) q2.bindValue(":eid", query.value("entry_id")) if not q2.exec(): query_error(q2) row = [] while q2.next(): - row.append(q2.value('name')) + row.append("" + q2.value("name") + "") if len(row) > 0: self.entries.append([None, " ".join(row)]) return - - def rowCount(self, parent:QModelIndex|None = None) -> int: + + def rowCount( + self, _: QModelIndex | QPersistentModelIndex = QModelIndex() + ) -> int: return len(self.entries) - def columnCount(self, parent:QModelIndex|None = None) -> int: + def columnCount( + self, _: QModelIndex | QPersistentModelIndex = QModelIndex() + ) -> int: return 2 - def data(self, index: QModelIndex, role:int): + def data(self, index: QModelIndex | QPersistentModelIndex, role: int = 0): if not index.isValid(): - return '' + return "" if role == Qt.ItemDataRole.DisplayRole: return self.entries[index.row()][index.column()] if role == Qt.ItemDataRole.TextAlignmentRole and index.column() == 0: return Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop return - - def headerData(self, section:int, orientation:Qt.Orientation, role:int): + def headerData( + self, section: int, orientation: Qt.Orientation, role: int = 0 + ): if orientation == Qt.Orientation.Vertical: return if role == Qt.ItemDataRole.FontRole: @@ -63,4 +74,4 @@ class docketModel(QAbstractTableModel): return font if role != Qt.ItemDataRole.DisplayRole: return - return ['Date', 'Proceedings and Orders'][section] + return ["Date", "Proceedings and Orders"][section] diff --git a/lib/utils.py b/lib/utils.py index 3d4514e..aeb7c33 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -1,9 +1,11 @@ from typing import NoReturn + from PySide6.QtCore import QCoreApplication from PySide6.QtSql import QSqlQuery - translate = QCoreApplication.translate + + def query_error(query: QSqlQuery) -> NoReturn: """Standarized query error reporter.""" print( diff --git a/scotus-pull.py b/scotus-pull.py index 36ecdc5..40e12fc 100755 --- a/scotus-pull.py +++ b/scotus-pull.py @@ -37,25 +37,70 @@ translate = QCoreApplication.translate class dateDelegate(QStyledItemDelegate): - def displayText(self, value, locale) -> str: + def displayText(self, value, locale) -> str: # type: ignore date = datetime.date.fromtimestamp(value) return date.strftime("%B %-d, %Y") - + + +class documentDelegate(QStyledItemDelegate): + def paint( + self, + painter: QPainter, + option: QStyleOptionViewItem, + index: QModelIndex | QPersistentModelIndex, + ): + options = option + self.initStyleOption(options, index) + painter.save() + doc = QTextDocument() + doc.setTextWidth(option.rect.width()) # type: ignore + doc.setHtml(option.text) # type: ignore + option.text = "" # type: ignore + option.widget.style().drawControl( # type: ignore + QStyle.ControlElement.CE_ItemViewItem, + option, + painter, + ) + painter.translate(option.rect.left(), options.rect.top()) # type: ignore + clip = QRect(0, 0, option.rect.width(), option.rect.height()) # type: ignore + doc.drawContents(painter, clip) + painter.restore() + return + + def sizeHint( + self, + option: QStyleOptionViewItem, + index: QModelIndex | QPersistentModelIndex, + ) -> QSize: + self.initStyleOption(option, index) + doc = QTextDocument() + doc.setTextWidth(option.rect.width()) # type: ignore + doc.setHtml(option.text) # type: ignore + doc.setTextWidth(option.rect.width()) # type: ignore + return QSize(int(doc.idealWidth()), int(doc.size().height())) + + class MainWindow(QMainWindow, Ui_MainWindow): show_entries = Signal(int) + def __init__(self) -> None: super(MainWindow, self).__init__() self.setupUi(self) - model = QSqlQueryModel() + # model = QSqlQueryModel() + model = QSqlTableModel() query = QSqlQuery("SELECT * FROM cases ORDER BY docket_id") if not query.exec(): query_error(query) model.setQuery(query) self.casesView.setModel(model) - self.casesView.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) - self.casesView.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) + self.casesView.setSelectionMode( + QAbstractItemView.SelectionMode.SingleSelection + ) + self.casesView.setSelectionBehavior( + QAbstractItemView.SelectionBehavior.SelectRows + ) self.casesView.hideColumn(0) self.casesView.hideColumn(2) self.casesView.setItemDelegateForColumn(5, dateDelegate()) @@ -65,21 +110,29 @@ class MainWindow(QMainWindow, Ui_MainWindow): header.setSectionResizeMode(3, QHeaderView.ResizeMode.Fixed) header.setSectionResizeMode(4, QHeaderView.ResizeMode.Fixed) self.show() - remaining = self.casesView.width() - header.sectionSize(1) - header.sectionSize(5) - 5 - self.casesView.setColumnWidth(3,int(remaining * 0.5)) - self.casesView.setColumnWidth(4,int(remaining * 0.5)) + remaining = ( + self.casesView.width() + - header.sectionSize(1) + - header.sectionSize(5) + - 5 + ) + self.casesView.setColumnWidth(3, int(remaining * 0.5)) + self.casesView.setColumnWidth(4, int(remaining * 0.5)) self.casesView.verticalHeader().hide() self.casesView.resizeRowsToContents() self.casesView.doubleClicked.connect(self.rowClicked) self.casesView.clicked.connect(self.rowClicked) self.docketView.setModel(docketModel()) - self.docketView.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch) + self.docketView.horizontalHeader().setSectionResizeMode( + 1, QHeaderView.ResizeMode.Stretch + ) self.docketView.resizeRowsToContents() + self.docketView.setItemDelegateForColumn(1, documentDelegate()) return - @Slot(QModelIndex) - def rowClicked(self, index:QModelIndex) -> None: + @Slot(QModelIndex) # type: ignore + def rowClicked(self, index: QModelIndex) -> None: if not index.isValid(): raise Exception("Bad index") docket = index.siblingAtColumn(1).data() @@ -91,15 +144,32 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.docketView.resizeRowsToContents() return + updateThread = None + @Slot() def on_updateButton_clicked(self): text = self.docketInput.toPlainText() - update_db(text) - self.update() + print(f"on_updateButton_clicked(): {text}") + if not self.updateThread: + self.updateThread = updateThread() + assert isinstance(self.updateThread, updateThread) + self.updateThread.finished.connect(self.updateDone) + self.updateThread.setDocketId(text) + self.updateThread.start() return - + + @Slot() + def updateDone(self): + self.updateThread = None + print("Done updating") + model: QSqlTableModel = self.casesView.model() # type: ignore + query = model.query() + query.exec() + return + + SQL_CMDS = [ - #"PRAGMA foreign_keys=ON", + # "PRAGMA foreign_keys=ON", "CREATE TABLE IF NOT EXISTS cases " "(case_id INTEGER PRIMARY KEY AUTOINCREMENT, " "docket_id TEXT, " @@ -121,9 +191,15 @@ SQL_CMDS = [ "name TEXT, " "url TEXT, " "FOREIGN KEY(entry_id) REFERENCES entries(entry_id))", - ] + # + "CREATE TABLE IF NOT EXISTS history (" + "history_id INTEGER PRIMARY KEY AUTOINCREMENT, " + "year TEXT, " + "edocket INTEGER, " + "number INTEGER)", +] + - def schema_update(db: QSqlDatabase) -> None: query = QSqlQuery() @@ -148,7 +224,7 @@ def schema_update(db: QSqlDatabase) -> None: else: raise AttributeError(f"No match found: {create_cmd}") - print("Table name = {}".format(table_name)) + print(f"Table name = {table_name}") query.prepare("SELECT sql FROM sqlite_schema WHERE tbl_name = :tbl") query.bindValue(":tbl", table_name) if not query.exec(): @@ -178,7 +254,10 @@ def schema_update(db: QSqlDatabase) -> None: query_error(query) # step 5 transfer content coldefs = re.search(r"\((.+)\)", old).group(1).split(", ") # type: ignore[union-attr] - cols = [x.split(" ")[0] for x in filter(lambda s: not s.startswith('FOREIGN '),coldefs)] + cols = [ + x.split(" ")[0] + for x in filter(lambda s: not s.startswith("FOREIGN "), coldefs) + ] cols_str = ", ".join(cols) sql = f"INSERT INTO {new_table_name} ({cols_str}) SELECT {cols_str} FROM {table_name}" query.prepare(sql) @@ -190,15 +269,17 @@ def schema_update(db: QSqlDatabase) -> None: if not query.exec(): query_error(query) # step 6 rename new table to old table - query.prepare("ALTER TABLE " + new_table_name + " RENAME TO " + table_name) + query.prepare( + "ALTER TABLE " + new_table_name + " RENAME TO " + table_name + ) if not query.exec(): 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) + # if not query.exec("PRAGMA foreign_keys=ON"): + # query_error(query) # step 11 commit the changes db.commit() return @@ -207,12 +288,13 @@ def schema_update(db: QSqlDatabase) -> None: def main() -> int: app = QApplication(sys.argv) db = QSqlDatabase.addDatabase("QSQLITE") - #db.setConnectOptions("PRAGMA foreign_keys = ON") + # db.setConnectOptions("PRAGMA foreign_keys = ON") db.setDatabaseName("scotus.db") db.open() schema_update(db) window = MainWindow() return app.exec() + if __name__ == "__main__": sys.exit(main())