UI: update main UI window to allow drops on document list, add support for newedition check & order
This commit is contained in:
@@ -35,6 +35,7 @@ from src.logic import (
|
||||
Prof,
|
||||
SemapDocument,
|
||||
csv_to_list,
|
||||
pdf_to_semap,
|
||||
word_to_semap,
|
||||
)
|
||||
from src.ui import Ui_Semesterapparat
|
||||
@@ -46,6 +47,7 @@ from src.ui.dialogs import (
|
||||
LoginDialog,
|
||||
Mail_Dialog,
|
||||
MedienAdder,
|
||||
NewEditionDialog,
|
||||
ParsedTitles,
|
||||
ReminderDialog,
|
||||
Settings,
|
||||
@@ -69,7 +71,7 @@ from src.ui.widgets import (
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="3 MB", retention="10 days")
|
||||
|
||||
log.add(
|
||||
f"{LOG_DIR}/{datetime.now().strftime('%Y-%m-%d')}.log",
|
||||
@@ -80,7 +82,7 @@ log.success("UI started")
|
||||
valid_input = (0, 0, 0, 0, 0, 0)
|
||||
|
||||
|
||||
class Ui(Ui_Semesterapparat):
|
||||
class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
||||
# use the Ui_MainWindow class from mainwindow.py
|
||||
def __init__(self, MainWindow, username: str) -> None: # type:ignore
|
||||
log.info("Starting Semesterapparatsmanagement")
|
||||
@@ -253,7 +255,6 @@ class Ui(Ui_Semesterapparat):
|
||||
self.mail_thread = None
|
||||
self.autoGrabber = None
|
||||
self.newEditionChecker = NewEditionCheckerThread()
|
||||
|
||||
|
||||
self.elsatab.setLayout(QtWidgets.QVBoxLayout())
|
||||
self.search_statistics.setLayout(QtWidgets.QVBoxLayout())
|
||||
@@ -276,8 +277,54 @@ class Ui(Ui_Semesterapparat):
|
||||
self.status_progress.hide()
|
||||
self.valid_check_semester.clicked.connect(self.display_valid_semester) # type:ignore
|
||||
|
||||
# allow files to be dragged into document_list
|
||||
self.document_list.setDragDropMode(
|
||||
QtWidgets.QAbstractItemView.DragDropMode.DropOnly
|
||||
)
|
||||
self.document_list.setAcceptDrops(True)
|
||||
self.document_list.viewport().setAcceptDrops(True)
|
||||
self.document_list.installEventFilter(self)
|
||||
self.document_list.viewport().installEventFilter(self)
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
# Only handle events for document_list and its viewport
|
||||
if obj in (self.document_list, self.document_list.viewport()):
|
||||
et = event.type()
|
||||
if et == QtCore.QEvent.Type.DragEnter:
|
||||
if event.mimeData().hasUrls():
|
||||
event.setDropAction(QtCore.Qt.CopyAction)
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
event.ignore()
|
||||
return True
|
||||
elif et == QtCore.QEvent.Type.DragMove:
|
||||
if event.mimeData().hasUrls():
|
||||
event.setDropAction(QtCore.Qt.CopyAction)
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
event.ignore()
|
||||
return True
|
||||
elif et == QtCore.QEvent.Type.Drop:
|
||||
if not self.app_group_box.isEnabled():
|
||||
self.confirm_popup(
|
||||
"Bitte öffnen Sie zuerst einen Apparat!", title="Fehler"
|
||||
)
|
||||
return True
|
||||
if event.mimeData().hasUrls():
|
||||
for url in event.mimeData().urls():
|
||||
self.add_document(url.toLocalFile())
|
||||
event.setDropAction(QtCore.Qt.CopyAction)
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
event.ignore()
|
||||
return True
|
||||
return super().eventFilter(obj, event)
|
||||
|
||||
def update_eta(self, eta: str):
|
||||
self.label_eta.setText(f"Bitte warten... (ETA: {eta})")
|
||||
eta = int(eta)
|
||||
# transform seconds eta to HH:MM:SS
|
||||
transformed_eta = f"{eta // 3600}:{(eta % 3600) // 60}:{eta % 60}"
|
||||
self.label_eta.setText(f"Bitte warten... (ETA: {transformed_eta})")
|
||||
|
||||
def create_doc(self):
|
||||
log.debug("Creating document")
|
||||
@@ -320,9 +367,9 @@ class Ui(Ui_Semesterapparat):
|
||||
elif self.select_action_box.currentText() == "Lehrperson bearbeiten":
|
||||
self.setWidget(EditProf())
|
||||
self.admin_action.setTitle("Lehrperson bearbeiten")
|
||||
elif self.select_action_box.currentText() == "Signaturen aktualisieren":
|
||||
elif self.select_action_box.currentText() == "Medien bearbeiten":
|
||||
self.setWidget(UpdateSignatures())
|
||||
self.admin_action.setTitle("Signaturen aktualisieren")
|
||||
self.admin_action.setTitle("Medien bearbeiten")
|
||||
else:
|
||||
self.hideWidget()
|
||||
self.admin_action.setTitle("")
|
||||
@@ -374,7 +421,7 @@ class Ui(Ui_Semesterapparat):
|
||||
self.statusBar.showMessage("")
|
||||
|
||||
def update_calendar(self, data: list[dict[str, Any]]):
|
||||
self.calendarWidget.setMessages([data])
|
||||
self.calendarWidget.setMessages(data)
|
||||
self.calendarWidget.updateCells()
|
||||
|
||||
def status_bar_progress(self, current: int, total: int):
|
||||
@@ -778,13 +825,14 @@ class Ui(Ui_Semesterapparat):
|
||||
"Bitte mindestens ein Medium hinzufügen!", title="Fehler"
|
||||
)
|
||||
|
||||
app_id = self.active_apparat
|
||||
app_nr = self.db.getId(self.app_name.text())
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
log.debug(prof_id)
|
||||
log.debug(f"{prof_id}, {app_nr}")
|
||||
# check if app_id is in database
|
||||
if self.db.checkApparatExistsById(app_id) is False:
|
||||
if app_nr is None:
|
||||
# create apparat
|
||||
self.btn_save_apparat(False)
|
||||
app_nr = self.db.getId(self.app_name.text())
|
||||
# create a thread that updates the progress label after each medium
|
||||
|
||||
# self.bookGrabber = None
|
||||
@@ -792,7 +840,7 @@ class Ui(Ui_Semesterapparat):
|
||||
bookGrabber.add_values(
|
||||
mode=mode,
|
||||
prof_id=prof_id,
|
||||
app_id=app_id,
|
||||
app_id=app_nr,
|
||||
data=data,
|
||||
any_book=use_any,
|
||||
exact=use_exact,
|
||||
@@ -894,7 +942,6 @@ class Ui(Ui_Semesterapparat):
|
||||
deleted = 0 if not self.chkbx_show_del_media.isChecked() else 1
|
||||
app_id = self.db.getId(self.app_name.text())
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
print(app_id, prof_id)
|
||||
books: list[dict[int, BookData, int]] = self.db.getBooks(
|
||||
app_id, prof_id, deleted
|
||||
)
|
||||
@@ -965,10 +1012,6 @@ class Ui(Ui_Semesterapparat):
|
||||
self.tableWidget_apparat_media.rowCount() - 1, 4
|
||||
).setToolTip("Das Medium wurde nicht im Apparat gefunden")
|
||||
|
||||
# make table link clickable
|
||||
# self.tableWidget_apparat_media.itemClicked.connect(self.open_link)
|
||||
# self.tableWidget_apparat_media.
|
||||
|
||||
def open_link(self, item):
|
||||
def __openLink(link):
|
||||
if link == "":
|
||||
@@ -1006,21 +1049,33 @@ class Ui(Ui_Semesterapparat):
|
||||
for prof in profs:
|
||||
self.drpdwn_prof_name.addItem(prof)
|
||||
|
||||
def add_document(self):
|
||||
def add_document(self, url: Optional[str] = None):
|
||||
# #log.debug("Add document")
|
||||
picker = FilePicker()
|
||||
files = picker.pick_files()
|
||||
for file in files:
|
||||
# #log.debug(file)
|
||||
filename = file.split("/")[-1]
|
||||
filetype = filename.split(".")[-1]
|
||||
if not url:
|
||||
picker = FilePicker()
|
||||
files = picker.pick_files()
|
||||
for file in files:
|
||||
# #log.debug(file)
|
||||
filename = file.split("/")[-1]
|
||||
filetype = filename.split(".")[-1]
|
||||
self.document_list.insertRow(0)
|
||||
self.document_list.setItem(0, 0, QtWidgets.QTableWidgetItem(filename))
|
||||
self.document_list.setItem(0, 1, QtWidgets.QTableWidgetItem(filetype))
|
||||
self.document_list.setItem(0, 2, QtWidgets.QTableWidgetItem("*"))
|
||||
self.document_list.setItem(0, 3, QtWidgets.QTableWidgetItem(file))
|
||||
# set tooltip of row 3 to the file path for each row
|
||||
self.document_list.item(0, 3).setToolTip(file)
|
||||
self.document_list.item(0, 0).setToolTip(filename)
|
||||
else:
|
||||
self.document_list.insertRow(0)
|
||||
filename = url.split("/")[-1]
|
||||
filetype = filename.split(".")[-1]
|
||||
self.document_list.setItem(0, 0, QtWidgets.QTableWidgetItem(filename))
|
||||
self.document_list.setItem(0, 1, QtWidgets.QTableWidgetItem(filetype))
|
||||
self.document_list.setItem(0, 2, QtWidgets.QTableWidgetItem("*"))
|
||||
self.document_list.setItem(0, 3, QtWidgets.QTableWidgetItem(file))
|
||||
self.document_list.setItem(0, 3, QtWidgets.QTableWidgetItem(url))
|
||||
# set tooltip of row 3 to the file path for each row
|
||||
self.document_list.item(0, 3).setToolTip(file)
|
||||
self.document_list.item(0, 3).setToolTip(url)
|
||||
self.document_list.item(0, 0).setToolTip(filename)
|
||||
|
||||
def open_document(self):
|
||||
@@ -1037,7 +1092,7 @@ class Ui(Ui_Semesterapparat):
|
||||
self.document_list.currentRow(), 1
|
||||
).text()
|
||||
except AttributeError:
|
||||
self.confirm_popup("Bitte erst ein document auswählen!", title="Fehler")
|
||||
self.confirm_popup("Bitte erst ein Dokument auswählen!", title="Fehler")
|
||||
return
|
||||
if not _selected_doc_location == "Database":
|
||||
path = Path(_selected_doc_location)
|
||||
@@ -1056,7 +1111,7 @@ class Ui(Ui_Semesterapparat):
|
||||
)
|
||||
|
||||
def add_media_from_file(self):
|
||||
app_id = self.active_apparat
|
||||
app_id = self.db.getId(self.app_name.text())
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
|
||||
def __open_dialog(signatures: list[str]):
|
||||
@@ -1102,17 +1157,24 @@ class Ui(Ui_Semesterapparat):
|
||||
temp_file = tempfile.NamedTemporaryFile(
|
||||
delete=False, suffix="." + file_type
|
||||
)
|
||||
temp_file.write(
|
||||
self.db.getBlob(file_name, int(self.active_apparat))
|
||||
)
|
||||
temp_file.write(self.db.getBlob(file_name, int(app_id)))
|
||||
temp_file.close()
|
||||
file = temp_file.name
|
||||
if file_type == "pdf":
|
||||
# Todo: implement parser here
|
||||
self.confirm_popup(
|
||||
"PDF Dateien werden noch nicht unterstützt!", title="Fehler"
|
||||
)
|
||||
return
|
||||
data = pdf_to_semap(file)
|
||||
signatures = data.signatures
|
||||
data = __open_dialog(signatures)
|
||||
# if no data was returned, return
|
||||
if data == []:
|
||||
return
|
||||
for book in data:
|
||||
if not isinstance(book, BookData):
|
||||
continue
|
||||
self.db.addBookToDatabase(
|
||||
bookdata=book,
|
||||
app_id=app_id,
|
||||
prof_id=prof_id,
|
||||
)
|
||||
if file_type == "csv":
|
||||
signatures = csv_to_list(file)
|
||||
data = __open_dialog(signatures)
|
||||
@@ -1203,7 +1265,7 @@ class Ui(Ui_Semesterapparat):
|
||||
dialog.exec()
|
||||
|
||||
if dialog.result() == QtWidgets.QDialog.DialogCode.Accepted:
|
||||
print("Selected title:", dropdown.currentText())
|
||||
# print("Selected title:", dropdown.currentText())
|
||||
self.app_name.setText(dropdown.currentText().split(" [")[0].strip())
|
||||
else:
|
||||
self.app_name.setText("CHANGEME")
|
||||
@@ -1251,7 +1313,7 @@ class Ui(Ui_Semesterapparat):
|
||||
)
|
||||
self.db.createProf(prof)
|
||||
# if app_id not in database, create apparat
|
||||
if not self.db.checkApparatExistsById(app_id):
|
||||
if not app_id:
|
||||
log.info("Apparat does not exist, creating new apparat")
|
||||
# create apparat
|
||||
# #log.debug("Creating apparat")
|
||||
@@ -1281,7 +1343,7 @@ class Ui(Ui_Semesterapparat):
|
||||
autoGrabber = BookGrabber()
|
||||
autoGrabber.add_values(
|
||||
mode="ARRAY",
|
||||
app_id=int(app_id),
|
||||
app_id=app_id,
|
||||
prof_id=int(prof_id),
|
||||
data=signatures,
|
||||
any_book=True,
|
||||
@@ -1393,7 +1455,7 @@ class Ui(Ui_Semesterapparat):
|
||||
|
||||
@property
|
||||
def active_apparat(self):
|
||||
return self.drpdwn_app_nr.currentText()
|
||||
return self.db.getId(self.app_name.text())
|
||||
|
||||
@property
|
||||
def profdata(self):
|
||||
@@ -1488,13 +1550,17 @@ class Ui(Ui_Semesterapparat):
|
||||
delete_action = menu.addAction("Löschen")
|
||||
remind_action = menu.addAction("Erinnerung")
|
||||
new_edition_check = menu.addAction("Auf Neuauflagen prüfen")
|
||||
order_newedition_action = menu.addAction("Neuauflagen bestellen")
|
||||
menu.addAction(extend_action)
|
||||
menu.addActions(
|
||||
[contact_action, delete_action, remind_action, new_edition_check]
|
||||
[
|
||||
contact_action,
|
||||
delete_action,
|
||||
remind_action,
|
||||
new_edition_check,
|
||||
order_newedition_action,
|
||||
]
|
||||
)
|
||||
extend_action.triggered.connect(self.extend_apparat)
|
||||
remind_action.triggered.connect(self.reminder)
|
||||
new_edition_check.triggered.connect(self.check_new_editions)
|
||||
# convert point to row and column
|
||||
row = self.tableWidget_apparate.rowAt(position.y())
|
||||
column = self.tableWidget_apparate.columnAt(position.x())
|
||||
@@ -1504,6 +1570,12 @@ class Ui(Ui_Semesterapparat):
|
||||
app_id = self.tableWidget_apparate.item(row, 0).text()
|
||||
pid = self.db.getProfIDByApparat(app_id)
|
||||
log.debug(app_id, pid)
|
||||
extend_action.triggered.connect(self.extend_apparat)
|
||||
remind_action.triggered.connect(self.reminder)
|
||||
new_edition_check.triggered.connect(lambda: self.check_new_editions())
|
||||
order_newedition_action.triggered.connect(
|
||||
lambda: self.order_new_editions(app_id, pid)
|
||||
)
|
||||
delete_action.triggered.connect(lambda: self.delete_apparat(pos))
|
||||
# pass pos to contact_prof
|
||||
contact_action.triggered.connect(
|
||||
@@ -1511,6 +1583,19 @@ class Ui(Ui_Semesterapparat):
|
||||
)
|
||||
menu.exec(self.tableWidget_apparate.mapToGlobal(position))
|
||||
|
||||
def order_new_editions(self, app_nr, prof_id):
|
||||
log.info("Opening order new editions dialog")
|
||||
app_id = self.db.getId(self.db.getApparatNameByAppNr(app_nr))
|
||||
prof_id = prof_id
|
||||
mail_data = {
|
||||
"prof_name": "Erwerbung",
|
||||
"prof_mail": "erw@ph-freiburg.de",
|
||||
"app_id": app_nr,
|
||||
"app_name": self.db.getApparatName(app_id, prof_id),
|
||||
}
|
||||
orderDialog = NewEditionDialog(app_id, mail_data)
|
||||
orderDialog.exec()
|
||||
|
||||
def update_status(self, curr, total):
|
||||
self.avail_status.show()
|
||||
self.label_20.show()
|
||||
@@ -1547,35 +1632,54 @@ class Ui(Ui_Semesterapparat):
|
||||
[str(app.appnr) for app in self.db.getApparatsByProf(prof_id)]
|
||||
)
|
||||
else:
|
||||
books = self.db.getBooks(app_id, prof_id, deleted=0)
|
||||
books = [book["bookdata"] for book in books]
|
||||
log.info(f"Checking {len(books)} for new editions")
|
||||
apparats_id = self.db.getId(app_name)
|
||||
books = self.db.getBooks(apparats_id, prof_id, deleted=0)
|
||||
searchable_books = []
|
||||
for book in books:
|
||||
b = book["bookdata"]
|
||||
b.in_apparat = True
|
||||
b.library_location = self.db.query_db(
|
||||
"""SELECT s.appnr FROM media AS m
|
||||
JOIN semesterapparat AS s on m.app_id = s.id
|
||||
WHERE m.id = ?""",
|
||||
(book["id"],),
|
||||
one=True,
|
||||
)[0]
|
||||
searchable_books.append(b)
|
||||
|
||||
self.newEditionChecker.entries = books
|
||||
log.info(f"Checking {len(searchable_books)} for new editions")
|
||||
|
||||
self.newEditionChecker.entries = searchable_books
|
||||
self.newEditionChecker.finished.connect(self.newEditionChecker.reset)
|
||||
self.newEditionChecker.finished.connect(self.reset_eta)
|
||||
|
||||
self.newEditionChecker.etaSignal.connect(self.update_eta)
|
||||
|
||||
|
||||
self.progressBar.setMaximum(len(books))
|
||||
self.progressBar.setMaximum(len(searchable_books))
|
||||
self.newEditionChecker.updateSignal.connect(self.update_status)
|
||||
|
||||
self.newEditionChecker.start()
|
||||
while self.newEditionChecker.isRunning():
|
||||
QtWidgets.QApplication.processEvents()
|
||||
self.play_sound("ding.mp3")
|
||||
results = self.newEditionChecker.results
|
||||
log.success("Finished checking for new editions, got {} results", len(results))
|
||||
if results == []:
|
||||
self.play_sound("error.mp3")
|
||||
return
|
||||
self.play_sound("ding.mp3")
|
||||
log.info(f"Found {len(results)} possible new editions - opening dialog")
|
||||
newEditionChecker = NewEditionChecker(results=results)
|
||||
newEditionChecker.exec()
|
||||
|
||||
accepted_books = newEditionChecker.accepted_books
|
||||
# print(accepted_books)
|
||||
print(accepted_books)
|
||||
if accepted_books == []:
|
||||
return
|
||||
for book in accepted_books:
|
||||
oldBookId = self.db.getBookIdByPPN(book.old_book.ppn)
|
||||
|
||||
self.db.insertNewEdition(book, oldBookId, apparats_id)
|
||||
pass
|
||||
|
||||
self.mail_thread = Mail_Dialog(
|
||||
prof_name=self.db.getSpecificProfData(prof_id, ["fullname"]),
|
||||
@@ -1713,7 +1817,7 @@ class Ui(Ui_Semesterapparat):
|
||||
# if result:
|
||||
# book.signature = result.signature
|
||||
# book.in_apparat = True
|
||||
# print(book)
|
||||
# #print(book)
|
||||
# self.db.updateBookdata(book_id, book)
|
||||
# self.update_app_media_list()
|
||||
|
||||
@@ -1761,7 +1865,7 @@ class Ui(Ui_Semesterapparat):
|
||||
def confirm_action_dialog(self, message, title="Bestätigung"):
|
||||
appnrs = self.db.getUnavailableApparatNumbers()
|
||||
appnrs = [str(i) for i in appnrs]
|
||||
appnrs.remove(self.active_apparat)
|
||||
appnrs.remove(self.drpdwn_app_nr.currentText())
|
||||
if len(appnrs) == 0:
|
||||
# create a warning dialog, saying no apparats present
|
||||
self.confirm_popup("Keine weiteren Apparate vorhanden", title="Fehler")
|
||||
@@ -1842,9 +1946,7 @@ class Ui(Ui_Semesterapparat):
|
||||
pass
|
||||
|
||||
def delete_medium(self):
|
||||
selected_apparat_id = self.tableWidget_apparate.item(
|
||||
self.tableWidget_apparate.currentRow(), 0
|
||||
).text()
|
||||
selected_apparat_id = self.active_apparat
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
# check how many rows are selected
|
||||
selected_rows = self.tableWidget_apparat_media.selectionModel().selectedRows()
|
||||
|
||||
Reference in New Issue
Block a user