diff --git a/docketModel.py b/docketModel.py
new file mode 100644
index 0000000..184539c
--- /dev/null
+++ b/docketModel.py
@@ -0,0 +1,66 @@
+import datetime
+from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt
+from PySide6.QtGui import QColor, 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__()
+ if case_id == None:
+ return
+ query = QSqlQuery()
+ query.prepare("SELECT * FROM entries WHERE case_id = :cid "
+ "ORDER BY entry_id")
+ q2 = QSqlQuery()
+ q2.prepare("SELECT * FROM documents WHERE entry_id = :eid")
+
+ query.bindValue(":cid", case_id)
+ if not query.exec():
+ query_error(query)
+ while query.next():
+ date = datetime.date.fromtimestamp(query.value(2))
+ assert isinstance(date, datetime.date)
+ 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'))
+ if len(row) > 0:
+ self.entries.append([None, " ".join(row)])
+ return
+
+ def rowCount(self, parent:QModelIndex|None = None) -> int:
+ return len(self.entries)
+
+ def columnCount(self, parent:QModelIndex|None = None) -> int:
+ return 2
+
+ def data(self, index: QModelIndex, role:int):
+ if not index.isValid():
+ 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):
+ if orientation == Qt.Orientation.Vertical:
+ return
+ if role == Qt.ItemDataRole.FontRole:
+ font = QFont()
+ font.setBold(True)
+ return font
+ if role != Qt.ItemDataRole.DisplayRole:
+ return
+ return ['Date', 'Proceedings and Orders'][section]
diff --git a/lib/__init__.py b/lib/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/lib/utils.py b/lib/utils.py
new file mode 100644
index 0000000..3d4514e
--- /dev/null
+++ b/lib/utils.py
@@ -0,0 +1,18 @@
+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(
+ translate("MainWindow", "SQL Error:\n")
+ + "{}\n{}\n{}:{}".format(
+ query.executedQuery(),
+ query.boundValues(),
+ query.lastError().type(),
+ query.lastError().text(),
+ )
+ )
+ raise Exception(translate("MainWindow", "SQL Error"))
diff --git a/scotus-pull.py b/scotus-pull.py
index 0b4f5cd..691b97f 100755
--- a/scotus-pull.py
+++ b/scotus-pull.py
@@ -5,27 +5,16 @@ import sys
import dateparser
import requests
from typing import NoReturn
-from PySide6.QtCore import QCoreApplication, QModelIndex, Signal, Qt
+from PySide6.QtCore import QCoreApplication, QModelIndex, Signal, Qt, Slot
from PySide6.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
from PySide6.QtWidgets import QAbstractItemView, QApplication, QHeaderView, QMainWindow, QStyledItemDelegate, QTableWidgetItem
from bs4 import BeautifulSoup, Tag
+from docketModel import docketModel
from ui.MainWindow import Ui_MainWindow
-
+from lib.utils import query_error
translate = QCoreApplication.translate
-def query_error(query: QSqlQuery) -> NoReturn:
- """Standarized query error reporter."""
- print(
- translate("MainWindow", "SQL Error:\n")
- + "{}\n{}\n{}:{}".format(
- query.executedQuery(),
- query.boundValues(),
- query.lastError().type(),
- query.lastError().text(),
- )
- )
- raise Exception(translate("MainWindow", "SQL Error"))
class dateDelegate(QStyledItemDelegate):
def displayText(self, value, locale) -> str:
@@ -64,40 +53,29 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.casesView.doubleClicked.connect(self.rowClicked)
self.casesView.clicked.connect(self.rowClicked)
- self.docketWidget.setColumnCount(2)
- self.docketWidget.setHorizontalHeaderLabels([
- 'Date','Proceedings and Orders',
- ])
- self.docketWidget.resizeColumnToContents(0)
- self.docketWidget.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
+ self.docketView.setModel(docketModel())
+ self.docketView.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
+ self.docketView.resizeRowsToContents()
return
- def populateDocket(self, case_id:int) -> None:
- query = QSqlQuery()
- query.prepare("SELECT * FROM entries WHERE case_id=:cid ORDER BY entry_id")
- query.bindValue(":cid", case_id)
- if not query.exec():
- query_error(query)
- self.docketWidget.clearContents()
- row = 0
- while query.next():
- print(query.value(0), query.value(1), query.value(2), query.value(3))
- item = QTableWidgetItem()
- item.setData(Qt.ItemDataRole.DisplayRole, query.value(2))
- self.docketWidget.setItem(row,0, item)
- item = QTableWidgetItem()
- item.setData(Qt.ItemDataRole.DisplayRole, query.value(3))
- self.docketWidget.setItem(row, 1, item)
- row += 1
- self.docketWidget.setRowCount(row)
-
- return
-
+ @Slot(QModelIndex)
def rowClicked(self, index:QModelIndex) -> None:
+ if not index.isValid():
+ raise Exception("Bad index")
docket = index.siblingAtColumn(1).data()
- print(docket)
+ self.docketLabel.setText(docket)
self.show_entries.emit(index.siblingAtColumn(0).data())
- self.populateDocket(index.siblingAtColumn(0).data())
+ model = docketModel(index.siblingAtColumn(0).data())
+ self.docketView.setModel(model)
+ self.docketView.resizeColumnToContents(0)
+ self.docketView.resizeRowsToContents()
+ return
+
+ @Slot()
+ def on_updateButton_clicked(self):
+ text = self.docketInput.toPlainText()
+ update_db(text)
+ self.update()
return
SQL_CMDS = [
@@ -107,6 +85,7 @@ SQL_CMDS = [
"docket_id TEXT, "
"linked INTEGER, "
"petitioners TEXT, respondents TEXT, date INTEGER, "
+ "active INTEGER, "
"FOREIGN KEY(linked) REFERENCES cases(case_id))",
#
"CREATE TABLE IF NOT EXISTS entries ("
@@ -141,7 +120,9 @@ def schema_update(db: QSqlDatabase) -> None:
table_name = matches.group(2)
create_cmd = (
matches.group(1)
+ + '"'
+ matches.group(2)
+ + '"'
+ matches.group(3)
)
else:
@@ -173,7 +154,6 @@ def schema_update(db: QSqlDatabase) -> None:
# Step 4 create new table
new_table_name = table_name + "_new"
sql = matches.group(1) + new_table_name + matches.group(3)
- print(sql)
if not query.exec(sql):
query_error(query)
# step 5 transfer content
@@ -228,7 +208,7 @@ def update_proceedings(case_id: int, bs: BeautifulSoup) -> None:
if not query.next():
query.prepare("INSERT INTO entries (case_id, date, text) VALUES (:cid,:date,:text)")
query.bindValue(':cid', case_id)
- query.bindValue(':date', date.timestamp)
+ query.bindValue(':date', date.timestamp())
query.bindValue(':text', text)
if not query.exec():
query_error(query)
@@ -238,7 +218,6 @@ def update_proceedings(case_id: int, bs: BeautifulSoup) -> None:
tr = trs.pop(0)
assert isinstance(tr, Tag)
assert isinstance(tr.contents[1], Tag)
- print(tr.contents[1])
for a in tr.contents[1]:
assert isinstance(a, Tag)
url = a.attrs['href']
@@ -256,7 +235,6 @@ def update_proceedings(case_id: int, bs: BeautifulSoup) -> None:
query.bindValue(":url", url)
if not query.exec():
query_error(query)
- break
return
def update_db(case_id) -> int:
@@ -315,8 +293,6 @@ def update_db(case_id) -> int:
assert isinstance(tr, Tag) and isinstance(tr.contents[0], Tag)
linked = tr.contents[0].string
- print(docket_id, petitioners, respondent, date, linked)
-
#
# See if this case already exists.
#
@@ -376,8 +352,8 @@ def main() -> int:
db.setDatabaseName("scotus.db")
db.open()
schema_update(db)
- #update_db('24-203')
- #update_db('23A1058')
+ update_db('24-203')
+ update_db('23A1058')
window = MainWindow()
return app.exec()
diff --git a/ui/MainWindow.py b/ui/MainWindow.py
index 73c7700..699d258 100644
--- a/ui/MainWindow.py
+++ b/ui/MainWindow.py
@@ -15,15 +15,16 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
-from PySide6.QtWidgets import (QApplication, QHeaderView, QMainWindow, QMenuBar,
- QSizePolicy, QStatusBar, QTableView, QTableWidget,
- QTableWidgetItem, QVBoxLayout, QWidget)
+from PySide6.QtWidgets import (QApplication, QFrame, QHBoxLayout, QHeaderView,
+ QLabel, QMainWindow, QMenuBar, QPlainTextEdit,
+ QPushButton, QSizePolicy, QStatusBar, QTableView,
+ QVBoxLayout, QWidget)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
- MainWindow.resize(800, 600)
+ MainWindow.resize(929, 710)
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.verticalLayout = QVBoxLayout(self.centralwidget)
@@ -33,15 +34,55 @@ class Ui_MainWindow(object):
self.verticalLayout.addWidget(self.casesView)
- self.docketWidget = QTableWidget(self.centralwidget)
- self.docketWidget.setObjectName(u"docketWidget")
+ self.docketLabel = QLabel(self.centralwidget)
+ self.docketLabel.setObjectName(u"docketLabel")
- self.verticalLayout.addWidget(self.docketWidget)
+ self.verticalLayout.addWidget(self.docketLabel)
+
+ self.docketView = QTableView(self.centralwidget)
+ self.docketView.setObjectName(u"docketView")
+
+ self.verticalLayout.addWidget(self.docketView)
+
+ self.frame = QFrame(self.centralwidget)
+ self.frame.setObjectName(u"frame")
+ sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Minimum)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth())
+ self.frame.setSizePolicy(sizePolicy)
+ self.frame.setFrameShape(QFrame.Shape.StyledPanel)
+ self.frame.setFrameShadow(QFrame.Shadow.Raised)
+ self.horizontalLayout = QHBoxLayout(self.frame)
+ self.horizontalLayout.setObjectName(u"horizontalLayout")
+ self.docketInput = QPlainTextEdit(self.frame)
+ self.docketInput.setObjectName(u"docketInput")
+ sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
+ sizePolicy1.setHorizontalStretch(0)
+ sizePolicy1.setVerticalStretch(0)
+ sizePolicy1.setHeightForWidth(self.docketInput.sizePolicy().hasHeightForWidth())
+ self.docketInput.setSizePolicy(sizePolicy1)
+ self.docketInput.setMaximumSize(QSize(16777215, 27))
+
+ self.horizontalLayout.addWidget(self.docketInput)
+
+ self.updateButton = QPushButton(self.frame)
+ self.updateButton.setObjectName(u"updateButton")
+
+ self.horizontalLayout.addWidget(self.updateButton)
+
+ self.searchButton = QPushButton(self.frame)
+ self.searchButton.setObjectName(u"searchButton")
+
+ self.horizontalLayout.addWidget(self.searchButton)
+
+
+ self.verticalLayout.addWidget(self.frame)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar")
- self.menubar.setGeometry(QRect(0, 0, 800, 24))
+ self.menubar.setGeometry(QRect(0, 0, 929, 24))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QStatusBar(MainWindow)
self.statusbar.setObjectName(u"statusbar")
@@ -54,5 +95,8 @@ class Ui_MainWindow(object):
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
+ self.docketLabel.setText(QCoreApplication.translate("MainWindow", u"TextLabel", None))
+ self.updateButton.setText(QCoreApplication.translate("MainWindow", u"Update Docket", None))
+ self.searchButton.setText(QCoreApplication.translate("MainWindow", u"Search", None))
# retranslateUi
diff --git a/ui/MainWindow.ui b/ui/MainWindow.ui
index de469dd..462ad84 100644
--- a/ui/MainWindow.ui
+++ b/ui/MainWindow.ui
@@ -6,8 +6,8 @@
0
0
- 800
- 600
+ 929
+ 710
@@ -19,7 +19,62 @@
-
-
+
+
+ TextLabel
+
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QFrame::Shape::StyledPanel
+
+
+ QFrame::Shadow::Raised
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 27
+
+
+
+
+ -
+
+
+ Update Docket
+
+
+
+ -
+
+
+ Search
+
+
+
+
+
@@ -28,7 +83,7 @@
0
0
- 800
+ 929
24