From fd692b8c99157546459538f5844dd2e6e49248eb Mon Sep 17 00:00:00 2001
From: WorldTeacher <41587052+WorldTeacher@users.noreply.github.com>
Date: Tue, 11 Jun 2024 13:28:23 +0200
Subject: [PATCH] updates
---
icons/dark/notification.svg | 1 +
icons/icons.yaml | 3 +-
icons/light/notification.svg | 1 +
src/backend/database.py | 27 +-
src/ui/Ui_semesterapparat_ui.py | 8 +-
src/ui/dialogs/confirm_extend.py | 14 +
.../dialog_sources/Ui_confirm_extend.py | 9 +-
src/ui/dialogs/reminder.py | 3 +-
src/ui/semesterapparat_ui.ui | 14 +-
src/ui/userInterface.py | 2444 +++++++++++++++++
src/ui/widgets/calendar_entry.py | 23 +-
11 files changed, 2520 insertions(+), 27 deletions(-)
create mode 100644 icons/dark/notification.svg
create mode 100644 icons/light/notification.svg
create mode 100644 src/ui/dialogs/confirm_extend.py
create mode 100644 src/ui/userInterface.py
diff --git a/icons/dark/notification.svg b/icons/dark/notification.svg
new file mode 100644
index 0000000..16527e4
--- /dev/null
+++ b/icons/dark/notification.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/icons.yaml b/icons/icons.yaml
index 9cec28c..cdd2019 100644
--- a/icons/icons.yaml
+++ b/icons/icons.yaml
@@ -16,4 +16,5 @@ template_fail: test_fail.svg
offAction: shutdown.svg
info: info.svg
help: help.svg
-close: close.svg
\ No newline at end of file
+close: close.svg
+notification: notification.svg
\ No newline at end of file
diff --git a/icons/light/notification.svg b/icons/light/notification.svg
new file mode 100644
index 0000000..4a3fcea
--- /dev/null
+++ b/icons/light/notification.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/backend/database.py b/src/backend/database.py
index 512d889..88c69b6 100644
--- a/src/backend/database.py
+++ b/src/backend/database.py
@@ -76,7 +76,6 @@ class Database:
Returns:
sql.Connection: The active connection to the database
"""
- print(self.db_path)
return sql.connect(self.db_path)
def close_connection(self, conn: sql.Connection):
@@ -501,6 +500,31 @@ class Database:
(message["message"], user_id, message["remind_at"], app_id),
)
+ def getAllMessages(self) -> list[dict[str, str, str, str]]:
+ """Get all the messages in the database
+
+ Returns:
+ list[dict[str, str, str, str]]: a list of dictionaries containing the message, the user who added the message, the apparat id and the id of the message
+ """
+
+ def __get_user_name(user_id):
+ return self.query_db(
+ "SELECT username FROM user WHERE id=?", (user_id,), one=True
+ )[0]
+
+ messages = self.query_db("SELECT * FROM messages")
+ ret = [
+ {
+ "message": i[2],
+ "user": __get_user_name(i[4]),
+ "appnr": i[5],
+ "id": i[0],
+ "remind_at": i[3],
+ }
+ for i in messages
+ ]
+ return ret
+
def getMessages(self, date: str) -> list[dict[str, str, str, str]]:
"""Get all the messages for a specific date
@@ -529,6 +553,7 @@ class Database:
Args:
message_id (str): the id of the message
"""
+ logger.log_info(f"Deleting message with id {message_id}")
self.query_db("DELETE FROM messages WHERE id=?", (message_id,))
# Prof data
diff --git a/src/ui/Ui_semesterapparat_ui.py b/src/ui/Ui_semesterapparat_ui.py
index d34a1bf..b989c33 100644
--- a/src/ui/Ui_semesterapparat_ui.py
+++ b/src/ui/Ui_semesterapparat_ui.py
@@ -891,7 +891,7 @@ class Ui_MainWindow(object):
self.elsa_semester.setObjectName("elsa_semester")
self.gridLayout_7.addWidget(self.elsa_semester, 2, 1, 1, 1)
self.table_elsa_list = QtWidgets.QTableWidget(parent=self.tab_8)
- self.table_elsa_list.setGeometry(QtCore.QRect(20, 410, 771, 271))
+ self.table_elsa_list.setGeometry(QtCore.QRect(20, 410, 771, 321))
self.table_elsa_list.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.table_elsa_list.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
self.table_elsa_list.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
@@ -908,15 +908,15 @@ class Ui_MainWindow(object):
self.table_elsa_list.setHorizontalHeaderItem(3, item)
self.table_elsa_list.horizontalHeader().setStretchLastSection(True)
self.elsa_statistic_frame = QtWidgets.QFrame(parent=self.tab_8)
- self.elsa_statistic_frame.setGeometry(QtCore.QRect(810, 410, 431, 271))
+ self.elsa_statistic_frame.setGeometry(QtCore.QRect(800, 410, 451, 321))
self.elsa_statistic_frame.setObjectName("elsa_statistic_frame")
self.elsa_statistics = QtWidgets.QTabWidget(parent=self.elsa_statistic_frame)
- self.elsa_statistics.setGeometry(QtCore.QRect(0, 0, 431, 271))
+ self.elsa_statistics.setGeometry(QtCore.QRect(10, 0, 431, 321))
self.elsa_statistics.setObjectName("elsa_statistics")
self.tab_9 = QtWidgets.QWidget()
self.tab_9.setObjectName("tab_9")
self.elsa_statistics_table = QtWidgets.QTableWidget(parent=self.tab_9)
- self.elsa_statistics_table.setGeometry(QtCore.QRect(0, 0, 421, 241))
+ self.elsa_statistics_table.setGeometry(QtCore.QRect(0, 0, 421, 291))
self.elsa_statistics_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.elsa_statistics_table.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
self.elsa_statistics_table.setTextElideMode(QtCore.Qt.TextElideMode.ElideRight)
diff --git a/src/ui/dialogs/confirm_extend.py b/src/ui/dialogs/confirm_extend.py
new file mode 100644
index 0000000..7fdd74e
--- /dev/null
+++ b/src/ui/dialogs/confirm_extend.py
@@ -0,0 +1,14 @@
+from .dialog_sources.Ui_confirm_extend import Ui_extend_confirm
+from PyQt6 import QtWidgets
+
+class ConfirmExtend(QtWidgets.QDialog, Ui_extend_confirm):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.setupUi(self)
+
+
+def launch():
+ app = QtWidgets.QApplication([])
+ window = ConfirmExtend()
+ window.show()
+ app.exec()
\ No newline at end of file
diff --git a/src/ui/dialogs/dialog_sources/Ui_confirm_extend.py b/src/ui/dialogs/dialog_sources/Ui_confirm_extend.py
index 0d4c620..bcb7531 100644
--- a/src/ui/dialogs/dialog_sources/Ui_confirm_extend.py
+++ b/src/ui/dialogs/dialog_sources/Ui_confirm_extend.py
@@ -16,18 +16,15 @@ class Ui_extend_confirm(object):
self.buttonBox = QtWidgets.QDialogButtonBox(parent=extend_confirm)
self.buttonBox.setGeometry(QtCore.QRect(290, 20, 81, 241))
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Vertical)
- self.buttonBox.setStandardButtons(
- QtWidgets.QDialogButtonBox.StandardButton.Cancel
- | QtWidgets.QDialogButtonBox.StandardButton.Ok
- )
+ self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
self.buttonBox.setObjectName("buttonBox")
self.textEdit = QtWidgets.QTextEdit(parent=extend_confirm)
self.textEdit.setGeometry(QtCore.QRect(10, 10, 271, 81))
self.textEdit.setObjectName("textEdit")
self.retranslateUi(extend_confirm)
- self.buttonBox.accepted.connect(extend_confirm.accept) # type: ignore
- self.buttonBox.rejected.connect(extend_confirm.reject) # type: ignore
+ self.buttonBox.accepted.connect(extend_confirm.accept) # type: ignore
+ self.buttonBox.rejected.connect(extend_confirm.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(extend_confirm)
def retranslateUi(self, extend_confirm):
diff --git a/src/ui/dialogs/reminder.py b/src/ui/dialogs/reminder.py
index e5afe11..26fe9cf 100644
--- a/src/ui/dialogs/reminder.py
+++ b/src/ui/dialogs/reminder.py
@@ -1,12 +1,13 @@
from PyQt6 import QtWidgets
from .dialog_sources.Ui_reminder import Ui_Dialog
-
+from src import Icon
class ReminderDialog(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
+ self.windowIcon(Icon("notification").icon)
def return_message(self) -> dict:
return {
diff --git a/src/ui/semesterapparat_ui.ui b/src/ui/semesterapparat_ui.ui
index 70b3395..906048f 100644
--- a/src/ui/semesterapparat_ui.ui
+++ b/src/ui/semesterapparat_ui.ui
@@ -2169,7 +2169,7 @@
20
410
771
- 271
+ 321
@@ -2208,19 +2208,19 @@
- 810
+ 800
410
- 431
- 271
+ 451
+ 321
- 0
+ 10
0
431
- 271
+ 321
@@ -2233,7 +2233,7 @@
0
0
421
- 241
+ 291
diff --git a/src/ui/userInterface.py b/src/ui/userInterface.py
new file mode 100644
index 0000000..f5965c4
--- /dev/null
+++ b/src/ui/userInterface.py
@@ -0,0 +1,2444 @@
+# encoding: utf-8
+import atexit
+import os
+
+# import re
+import sys
+import tempfile
+import time
+import webbrowser
+from pathlib import Path
+
+from icecream import ic
+from natsort import natsorted
+from omegaconf import OmegaConf
+from PyQt6 import QtCore, QtGui, QtWidgets
+from PyQt6.QtCore import QThread
+from PyQt6.QtGui import QRegularExpressionValidator
+
+from src.backend import (
+ AdminCommands,
+ recreateElsaFile,
+ recreateFile,
+ Database,
+ tempdelete,
+ generateSemesterByDate,
+)
+from src.logic import (
+ AvailChecker,
+ BookGrabber,
+ custom_sort,
+ APP_NRS,
+ PROF_TITLES,
+ ApparatData,
+ BookData,
+ csv_to_list,
+ elsa_word_to_csv,
+ word_docx_to_csv,
+ MyLogger,
+)
+
+from src.ui import (
+ App_Ext_Dialog,
+ DataGraph,
+ FilePicker,
+ Mail_Dialog,
+ StatusWidget,
+ Ui_Semesterapparat,
+ edit_bookdata_ui,
+ login_ui,
+ medienadder_ui,
+ parsed_titles_ui,
+ popus_confirm,
+ reminder_ui,
+ Settings,
+ About,
+ CalendarEntry,
+ MessageCalendar,
+)
+from src.utils import Icon
+
+config = OmegaConf.load("config.yaml")
+
+
+class Medien(medienadder_ui):
+ def __init__(self) -> None:
+ self.logger = MyLogger("Medien")
+ super().__init__()
+ self.mode = ""
+ self.data = []
+
+ def get_list_data(self) -> list:
+ signatures = self.listWidget.findItems("*", QtCore.Qt.MatchFlag.MatchWildcard)
+ return [signature.text() for signature in signatures]
+
+ def get_mode(self) -> str:
+ return self.comboBox.currentText()
+
+
+class MyComboBox(QtWidgets.QComboBox):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+
+valid_input = (0, 0, 0, 0, 0, 0)
+
+
+class Ui(Ui_Semesterapparat):
+ # use the Ui_MainWindow class from mainwindow.py
+ def __init__(self, MainWindow, username: str) -> None:
+ self.logger = MyLogger("Ui")
+ self.logger.log_info("Starting Semesterapparatsmanagement")
+ super().__init__()
+ self.active_user = username
+ self.setupUi(MainWindow)
+ self.MainWindow = MainWindow
+ # set the window title
+ MainWindow.setWindowTitle("Semesterapparatsmanagement")
+ MainWindow.setWindowIcon(Icon("logo").icon)
+
+ self.db = Database()
+ # self.show()
+ # self.setWindowTitle("Semesterapparatsmanagement")
+ # self.setWindowIcon(QIcon("ui\icon.png"))
+ # self.sem_sommer.clicked.connect(self.buttonClicked)
+ self.btn_add_document.clicked.connect(self.add_document)
+ self.check_file.clicked.connect(
+ self.btn_check_file_threaded
+ ) # default: self.add_media_from_file)
+ self.create_new_app.clicked.connect(self.btn_create_new_apparat)
+ # self.load_app.clicked.connect(self.btn_load_apparat)
+ self.btn_apparat_save.clicked.connect(self.btn_save_apparat)
+ self.btn_apparat_apply.clicked.connect(self.update_apparat)
+ self.btn_open_document.clicked.connect(self.open_document)
+ self.add_medium.clicked.connect(self.btn_add_medium)
+ self.btn_copy_adis_command.clicked.connect(self.text_to_clipboard)
+ self.btn_reserve.clicked.connect(self.check_availability)
+ self.calendarWidget = MessageCalendar(self.frame_2)
+ self.calendarWidget.setGridVisible(True)
+ self.calendarWidget.setVerticalHeaderFormat(
+ QtWidgets.QCalendarWidget.VerticalHeaderFormat.NoVerticalHeader
+ )
+ self.calendarWidget.setObjectName("MessageCalendar")
+ self.calendarWidget.clicked.connect(self.open_reminder)
+ # assign a context menu to the calendar
+ self.calendarlayout.addWidget(self.calendarWidget)
+ self.tableWidget_apparat_media.horizontalHeader().setSectionResizeMode(
+ QtWidgets.QHeaderView.ResizeMode.Stretch
+ )
+ self.tableWidget_apparate.horizontalHeader().setSectionResizeMode(
+ QtWidgets.QHeaderView.ResizeMode.Stretch
+ )
+ self.tableWidget_apparate.setSortingEnabled(True)
+
+ # Actions
+ self.actionEinstellungen.triggered.connect(self.open_settings)
+ self.actionDokumentation.triggered.connect(self.open_documentation)
+ Icon("offAction", self.actionBeenden)
+ self.actionBeenden.triggered.connect(self.quit)
+ self.actionAbout.triggered.connect(self.open_about)
+
+ # set validators
+ self.sem_year.setText(str(QtCore.QDate.currentDate().year()))
+ self.prof_mail.setValidator(
+ QRegularExpressionValidator(
+ QtCore.QRegularExpression(
+ r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}"
+ )
+ )
+ )
+ self.prof_tel_nr.setValidator(QtGui.QIntValidator())
+ # set the validator for the app name, allow all letters and umlauts
+ self.app_fach.setValidator(
+ QtGui.QRegularExpressionValidator(
+ QtCore.QRegularExpression(r"[a-zA-Z\s\W]+")
+ )
+ )
+
+ # allow only letters, numbers, whitespaces, symbols for the apparat name
+ self.app_name.setValidator(
+ QtGui.QRegularExpressionValidator(
+ QtCore.QRegularExpression(r"[a-zA-Z0-9\s\W]+")
+ )
+ )
+ self.tableWidget_apparate.addScrollBarWidget(
+ QtWidgets.QScrollBar(), QtCore.Qt.AlignmentFlag.AlignRight
+ )
+ # connect contextmenuevent to tablewidget
+
+ # enable automatic resizing of columns for book_search_result
+ self.book_search_result.horizontalHeader().setSectionResizeMode(
+ QtWidgets.QHeaderView.ResizeMode.Stretch
+ )
+ self.tableWidget_apparate.doubleClicked.connect(self.load_app_data)
+ self.load_app.hide()
+ print(f"user:{self.active_user}")
+ userrole = self.db.getRole(self.active_user)
+ # hide admin interface when non-admin is logged in
+ if userrole == "admin":
+ self.tabWidget.setTabVisible(3, True)
+ else:
+ self.tabWidget.setTabVisible(3, False)
+ # self.update_app_media_list()
+ self.populate_prof_dropdown()
+ self.populate_appfach_dropdown()
+ # if the focus is changed from the prof name dropdown, set the prof data if the prof exists in the database, otherwise show a message
+ self.drpdwn_prof_name.currentIndexChanged.connect(self.set_prof_data)
+ self.cancel_active_selection.clicked.connect(self.btn_cancel_active_selection)
+ self.check_eternal_app.stateChanged.connect(self.set_state)
+ # validate inputs
+ self.prof_mail.textChanged.connect(self.validate_prof_mail)
+ self.drpdwn_prof_name.editTextChanged.connect(self.validate_prof_name)
+ self.prof_tel_nr.textChanged.connect(self.validate_prof_tel)
+ self.app_name.textChanged.connect(self.validate_app_name)
+ self.app_fach.currentTextChanged.connect(self.validate_app_fach)
+ self.sem_year.textChanged.connect(self.validate_semester)
+ self.check_eternal_app.stateChanged.connect(self.validate_semester)
+ self.chkbx_show_del_media.stateChanged.connect(self.update_app_media_list)
+
+ self.progress_label.setText("Bitte warten...")
+
+ # Set visibility/enabled state of certain entries
+ self.chkbx_show_del_media.setEnabled(False)
+ self.label_info.hide()
+ self.app_group_box.setEnabled(False)
+ self.line_2.hide()
+ self.progress_label.hide()
+ # self.message_frame.hide()
+ self.btn_reserve.hide()
+ self.label_20.hide()
+ self.line_3.hide()
+ self.avail_status.hide()
+ self.chkbx_show_del_media.hide()
+ self.groupBox_2.hide()
+ self.groupBox.hide()
+ self.btn_del_select_apparats.setEnabled(False)
+
+ self.check_deletable.stateChanged.connect(self.gridchange)
+ self.tableWidget.horizontalHeader().setSectionResizeMode(
+ QtWidgets.QHeaderView.ResizeMode.Stretch
+ )
+ self.btn_del_select_apparats.clicked.connect(self.delete_selected_apparats)
+ self.statistics_table.doubleClicked.connect(self.display_detailed_data)
+ self.tabWidget_2.currentChanged.connect(self.tabW2_changed)
+ self.tabWidget.currentChanged.connect(self.tabW1_changed)
+ self.tableWidget.resizeColumnsToContents()
+ self.tableWidget.resizeRowsToContents()
+
+ # create a thread, that continually checks the validity of the inputs
+ self.validate_thread = QThread()
+ self.validate_thread.started.connect(self.thread_check)
+ self.validate_thread.start()
+
+ # get all current apparats and cache them in a list
+ self.apparats = self.get_apparats()
+
+ self.old_apparats = self.apparats # create a clone to compare against later
+ # if length of apparats changes, update box_apparats
+ # if tab is changed, gather data needed
+ self.tabWidget.currentChanged.connect(self.tab_changed)
+ self.btn_search.clicked.connect(self.statistics)
+
+ ### Admin interface ###
+ self.select_action_box.addItem("")
+ self.select_action_box.setCurrentText("")
+ self.hide_all()
+ self.select_action_box.currentTextChanged.connect(self.admin_action_changed)
+ self.edit_faculty_member_select_member.currentTextChanged.connect(
+ self.edit_faculty_member_set_data
+ )
+ self.book_search.clicked.connect(self.search_book)
+
+ # Context Menus
+ self.tableWidget_apparate.setContextMenuPolicy(
+ QtCore.Qt.ContextMenuPolicy.CustomContextMenu
+ )
+ self.tableWidget_apparat_media.setContextMenuPolicy(
+ QtCore.Qt.ContextMenuPolicy.CustomContextMenu
+ )
+ self.tableWidget_apparate.customContextMenuRequested.connect(
+ self.open_context_menu
+ )
+ self.tableWidget_apparat_media.customContextMenuRequested.connect(
+ self.media_context_menu
+ )
+ self.tableWidget.customContextMenuRequested.connect(
+ self.statistics_table_context_menu
+ )
+ # statistic side buttons
+ self.btn_notify_for_deletion.clicked.connect(self.notify_for_deletion)
+ self.btn_notify_for_deletion.setEnabled(False)
+ # elsa buttons
+ self.elsa_add_new.clicked.connect(self.add_new_elsa)
+ self.elsa_cancel_create.clicked.connect(self.cancel_elsa_creation)
+ self.elsa_save.clicked.connect(self.save_elsa)
+ self.elsa_date_today.clicked.connect(self.generateTodayDateElsa)
+ self.active_semester.clicked.connect(self.addSemester)
+ Icon("semester", self.active_semester)
+ Icon("today", self.elsa_date_today)
+ self.elsa_table.doubleClicked.connect(self.open_elsa)
+ self.btn_add_document_elsa.clicked.connect(self.addDokumentElsa)
+ self.check_file_elsa.clicked.connect(self.parseDokumentElsa)
+ self.btn_open_document_elsa.clicked.connect(self.openDocumentElsa)
+
+ # admin buttons
+ self.user_frame_addUser.clicked.connect(self.add_user)
+ self.pushButton.clicked.connect(self.delete_user)
+ self.update_user.clicked.connect(self.update_user_data)
+ self.update_faculty_member.clicked.connect(self.edit_faculty_member_action)
+
+ # Create instances to be used by the threads in the application
+ self.bookGrabber = None
+ self.availChecker = None
+ self.mail_thread = None
+ self.autoGrabber = None
+
+ def open_about(self):
+ about = About()
+ about.exec()
+
+ def quit(self):
+ # delete all temporary files
+ delete_temp_contents()
+ sys.exit()
+
+ def add_new_elsa(self):
+ self.create_frame_elsa.setEnabled(True)
+ self.elsa_cancel_create.setEnabled(True)
+ self.active_semester.setEnabled(True)
+ profs = self.db.getProfs()
+ for prof in profs:
+ self.elsa_prof.addItem(f"{prof[3]}, {prof[2]}")
+ self.elsa_prof.setCurrentText("")
+ self.elsa_date.setText("")
+ self.elsa_semester.setText("")
+
+ def cancel_elsa_creation(self):
+ self.create_frame_elsa.setEnabled(False)
+ self.elsa_cancel_create.setEnabled(False)
+ self.elsa_prof.setCurrentText("")
+ self.elsa_date.setText("")
+ self.elsa_semester.setText("")
+ self.dokument_list_elsa.setRowCount(0)
+ self.table_elsa_list.setRowCount(0)
+
+ def generateTodayDateElsa(self):
+ self.elsa_date.setText(QDate.currentDate().toString("dd.MM.yyyy"))
+
+ def addSemester(self):
+ self.elsa_semester.setText(self.generateSemester(today=True))
+
+ def save_elsa(self):
+ if (
+ self.elsa_prof.currentText() == ""
+ or self.elsa_semester.text() == ""
+ or self.elsa_date.text() == ""
+ ):
+ # warning message
+ self.confirm_popup("Bitte füllen Sie alle Felder aus")
+
+ return
+ prof = self.elsa_prof.currentText()
+ semester = self.elsa_semester.text()
+ date = self.elsa_date.text()
+
+ self.db.createElsaApparat(date, prof, semester)
+ self.cancel_elsa_creation()
+
+ def insert_elsa_into_table(self, apparat):
+ self.elsa_table.insertRow(0)
+ date = apparat[1]
+ semester = apparat[2]
+ prof = apparat[3]
+ self.elsa_table.setItem(0, 0, QtWidgets.QTableWidgetItem(prof))
+ self.elsa_table.setItem(0, 1, QtWidgets.QTableWidgetItem(date))
+ self.elsa_table.setItem(0, 2, QtWidgets.QTableWidgetItem(semester))
+ return (semester, 1)
+
+ def open_elsa(self):
+ prof = self.elsa_table.item(self.elsa_table.currentRow(), 0).text()
+ date = self.elsa_table.item(self.elsa_table.currentRow(), 1).text()
+ semester = self.elsa_table.item(self.elsa_table.currentRow(), 2).text()
+ if self.elsa_prof.currentText() == prof:
+ self.logger.log_info("Same prof, stopping")
+ return
+
+ self.dokument_list_elsa.setRowCount(0)
+ self.table_elsa_list.setRowCount(0)
+ self.elsa_cancel_create.setEnabled(True)
+ # get elsa apparats, iterate over them and find the one where all matches
+ elsa_apparats = self.db.getElsaApparats()
+ elsa_id = None
+ for apparat in elsa_apparats:
+ if apparat[1] == date and apparat[2] == semester and apparat[3] == prof:
+ elsa_id = apparat[0]
+ print(elsa_id)
+ break
+ if elsa_id is None:
+ return
+ self.elsa_date.setText(date)
+ self.elsa_semester.setText(semester)
+ self.elsa_prof.setCurrentText(prof)
+ documents = self.db.getElsaFiles(elsa_id)
+ for document in documents:
+ print(document)
+ self.dokument_list_elsa.insertRow(0)
+ self.dokument_list_elsa.setItem(
+ 0, 0, QtWidgets.QTableWidgetItem(document[0])
+ )
+ self.dokument_list_elsa.setItem(
+ 0, 1, QtWidgets.QTableWidgetItem(document[1])
+ )
+ self.dokument_list_elsa.setItem(0, 2, QtWidgets.QTableWidgetItem("❌"))
+ self.dokument_list_elsa.setItem(
+ 0, 3, QtWidgets.QTableWidgetItem("Database")
+ )
+ scans = self.db.getElsaMedia(elsa_id)
+ if scans == []:
+ self.create_frame_elsa.setEnabled(True)
+ else:
+ for scan in scans:
+ self.table_elsa_list.insertRow(0)
+ self.table_elsa_list.setItem(0, 0, QtWidgets.QTableWidgetItem(scan[1]))
+ self.table_elsa_list.setItem(0, 1, QtWidgets.QTableWidgetItem(scan[2]))
+ self.table_elsa_list.setItem(0, 2, QtWidgets.QTableWidgetItem(scan[3]))
+ self.table_elsa_list.setItem(0, 3, QtWidgets.QTableWidgetItem(scan[4]))
+
+ def addDokumentElsa(self):
+ print("Add document")
+ picker = FilePicker()
+ files = picker.pick_files()
+ datalist = []
+ for file in files:
+ data = {}
+ print(file)
+ filename = file.split("/")[-1]
+ filetype = filename.split(".")[-1]
+ self.dokument_list_elsa.insertRow(0)
+ self.dokument_list_elsa.setItem(0, 0, QtWidgets.QTableWidgetItem(filename))
+ self.dokument_list_elsa.setItem(0, 1, QtWidgets.QTableWidgetItem(filetype))
+ self.dokument_list_elsa.setItem(0, 2, QtWidgets.QTableWidgetItem("*"))
+ self.dokument_list_elsa.setItem(0, 3, QtWidgets.QTableWidgetItem(file))
+ # set tooltip of row 3 to the file path for each row
+ self.dokument_list_elsa.item(0, 3).setToolTip(file)
+ data["name"] = filename
+ data["path"] = file
+ data["type"] = filetype
+ datalist.append(data)
+ elsa_id = self.db.getElsaId(
+ self.elsa_prof.currentText(),
+ self.elsa_semester.text(),
+ self.elsa_date.text(),
+ )
+ print(elsa_id)
+ if elsa_id is None:
+ # get length of elsa table
+ rows = self.elsa_table.rowCount()
+ elsa_id = rows + 1
+ self.db.insertElsaFile(datalist, elsa_id)
+ self.elsa_save.click()
+
+ def parseDokumentElsa(self):
+ if self.dokument_list_elsa.rowCount() == 0:
+ return
+ else:
+ # get the file path of the selected file based on it's row
+ row = self.dokument_list_elsa.currentRow()
+ file = self.dokument_list_elsa.item(row, 3).text()
+ print(file)
+ if file == "Database":
+ filename = self.dokument_list_elsa.item(row, 0).text()
+ filetype = self.dokument_list_elsa.item(row, 1).text()
+
+ file = recreateElsaFile(
+ filename=filename, filetype=filetype, open=False
+ )
+ print(file)
+ data = elsa_word_to_csv(file)
+ for row in data:
+ self.table_elsa_list.insertRow(0)
+ ic(row)
+ chapter_title = row[2]
+ book_title = row[4]
+ signature = row[7]
+ pages = row[6]
+ data = {
+ "chapter": chapter_title,
+ "title": book_title,
+ "signature": signature,
+ "pages": pages,
+ }
+ self.table_elsa_list.setItem(
+ 0, 0, QtWidgets.QTableWidgetItem(chapter_title)
+ )
+ self.table_elsa_list.setItem(
+ 0, 1, QtWidgets.QTableWidgetItem(book_title)
+ )
+ self.table_elsa_list.setItem(
+ 0, 2, QtWidgets.QTableWidgetItem(signature)
+ )
+ self.table_elsa_list.setItem(0, 3, QtWidgets.QTableWidgetItem(pages))
+ self.db.addElsaMedia(
+ data,
+ self.db.getElsaId(
+ self.elsa_prof.currentText(),
+ self.elsa_semester.text(),
+ self.elsa_date.text(),
+ ),
+ )
+
+ def openDocumentElsa(self):
+ # open the selected document
+ row = self.dokument_list_elsa.currentRow()
+ location = self.dokument_list_elsa.item(row, 3).text()
+ filetype = self.dokument_list_elsa.item(row, 1).text()
+ filename = self.dokument_list_elsa.item(row, 0).text()
+ if location == "Database":
+ recreateElsaFile(filename, filetype, open=True)
+ else:
+ os.system(f"{filename}")
+
+ def notify_for_deletion(self):
+ # get all selected apparats
+ selected_apparats: list[dict] = []
+ for i in range(self.tableWidget.rowCount()):
+ data = {}
+ if self.tableWidget.cellWidget(i, 0).isChecked():
+ data["app_id"] = self.tableWidget.item(i, 2).text()
+ data["app_name"] = self.tableWidget.item(i, 1).text()
+ data["prof_name"] = self.tableWidget.item(i, 3).text()
+
+ selected_apparats.append(data)
+ # delete all selected apparats
+ ic(selected_apparats)
+ dialogs = []
+ for i in selected_apparats:
+
+ app_id = i["app_id"]
+ app_name = i["app_name"]
+ prof_name = i["prof_name"]
+ prof_mail = self.db.getProfData(prof_name)[0]
+ self.mail_thread = Mail_Dialog(
+ app_id=app_id,
+ app_name=app_name,
+ prof_name=prof_name,
+ prof_mail=prof_mail,
+ app_subject="",
+ default_mail="Information bezüglich der Auflösung des Semesterapparates",
+ )
+ dialogs.append(self.mail_thread)
+ for dialog in dialogs:
+ dialog.exec()
+
+ self.btn_notify_for_deletion.setEnabled(False)
+
+ def setStatisticTableSize(self):
+ print(self.statistics_table.size(), self.statistics_table.rowCount())
+ size = self.statistics_table.size()
+ h = size.height()
+ w = size.width()
+ rows = self.statistics_table.rowCount()
+ rowheight = round(h / rows) - 5
+ header_width = round(w / 3) - 5
+ for i in range(3):
+ self.statistics_table.setColumnWidth(i, header_width)
+ for i in range(rows):
+ self.statistics_table.setRowHeight(i, rowheight)
+
+ def get_apparats(self):
+ alist = self.db.getAllAparats(deleted=0)
+ alist = natsorted(alist, key=lambda x: x[4], reverse=True)
+ for apparat in alist:
+ self.insert_apparat_into_table(apparat)
+ return alist
+
+ def populate_appfach_dropdown(self):
+ self.app_fach.clear()
+ self.app_fach.addItem("")
+ self.app_fach.setCurrentText("")
+ self.app_fach.addItems([subject[1] for subject in self.db.getSubjects()])
+
+ def open_documentation(self):
+ # open the documentation in the default browser
+ webbrowser.open("file:///" + os.path.abspath("docs/index.html"))
+ # documentation = documentationview.DocumentationViewer()
+ # documentation.show()
+
+ def tabW1_changed(self):
+ if self.tabWidget.currentIndex() == 1: # Statistic
+ # self.tabWidget.setCurrentIndex(1)
+ self.tabWidget_2.setCurrentIndex(1)
+ self.tabWidget_2.setCurrentIndex(0)
+ self.populate_tab()
+ if self.tabWidget.currentIndex() == 0: # Apparate
+ # clear all entries from the table
+ self.tableWidget_apparate.setRowCount(0)
+ self.get_apparats()
+ if self.tabWidget.currentIndex() == 2: # Elsa
+ self.elsa_cancel_create.click()
+ try:
+ self.elsa_statistics.removeTab(1)
+ except:
+ pass
+ self.elsa_table.setRowCount(0)
+ elsa_apparats = self.db.getElsaApparats()
+ elsa_apparats = natsorted(elsa_apparats, key=lambda x: x[2], reverse=True)
+ graph_data = {"x": [], "y": []} # x = semester, y = number of apparats
+
+ for apparat in elsa_apparats:
+ print(apparat)
+ data = self.insert_elsa_into_table(apparat)
+ semester = data[0]
+ number = data[1]
+ if semester not in graph_data["x"]:
+ graph_data["x"].append(semester)
+ graph_data["y"].append(number)
+ else:
+ index = graph_data["x"].index(semester)
+ graph_data["y"][index] += number
+
+ generateMissing = True if len(graph_data["x"]) > 1 else False
+ graph = DataGraph(
+ "ELSA Apparate pro Semester",
+ graph_data,
+ generateMissing,
+ "Anzahl der Apparate",
+ )
+ ic(graph_data)
+ self.elsa_statistics_table.setRowCount(0)
+ for i in range(len(graph_data["x"])):
+ self.elsa_statistics_table.insertRow(0)
+ self.elsa_statistics_table.setItem(
+ 0, 0, QtWidgets.QTableWidgetItem(graph_data["x"][i])
+ )
+ self.elsa_statistics_table.setItem(
+ 0, 1, QtWidgets.QTableWidgetItem(str(graph_data["y"][i]))
+ )
+ self.elsa_statistics.addTab(graph, "Graph")
+
+ def search_book(self):
+ self.book_search_result.setRowCount(0)
+ signature = self.seach_by_signature.text()
+ title = self.search_by_title.text()
+ params = {
+ "signature": signature if signature != "" else None,
+ "title": title if title != "" else None,
+ }
+ params = {key: value for key, value in params.items() if value is not None}
+ # ic(params)
+ retdata = self.db.searchBook(params)
+ if retdata is None:
+ return
+ for book in retdata:
+
+ self.book_search_result.insertRow(0)
+ self.book_search_result.setItem(
+ 0, 0, QtWidgets.QTableWidgetItem(book[0].title)
+ )
+ self.book_search_result.setItem(
+ 0, 1, QtWidgets.QTableWidgetItem(book[0].signature)
+ )
+ print(book[1])
+ self.book_search_result.setItem(
+ 0,
+ 2,
+ QtWidgets.QTableWidgetItem(self.db.getApparatName(book[1], book[2])),
+ )
+
+ def edit_faculty_member_set_data(self):
+ # get the selected member
+ name = self.edit_faculty_member_select_member.currentText()
+ fullname = name.replace(",", "")
+ print(fullname, name)
+ # get the data for the selected member
+ data = self.db.getProfByName(fullname)
+ # set the data
+ print(data)
+ if data is None:
+ self.edit_faculty_member_title.setText("")
+ self.faculty_member_old_telnr.setText("")
+ self.faculty_member_oldmail.setText("")
+ self.edit_faculty_member_title.setText("")
+ else:
+ self.edit_faculty_member_title.setText(data[1])
+ self.faculty_member_old_telnr.setText(data[6])
+ self.faculty_member_oldmail.setText(data[5])
+ (
+ self.edit_faculty_member_title.setText(data[1])
+ if data[1] is not None
+ else self.edit_faculty_member_title.setText("")
+ )
+
+ # self.edit_faculty_member_name.setText(f"{data[3]} {data[2]}")
+ # self.edit_faculty_member_title.setCurrentText(data[1])
+ # self.edit_faculty_member_mail.setText(data[4])
+ # self.edit_faculty_member_tel.setText(data[5])
+ # self.edit_faculty_member_adis_id.setText(str(data[0]))
+ # self.edit_faculty_member_id.setText(str(data[6]))
+
+ def add_user(self):
+ username = self.user_create_frame_username.text()
+ password = self.user_create_frame_password.text()
+ role = self.user_frame_userrole.currentText()
+ if self.db.checkUsername(username):
+ # ic("username already exists")
+ # self.user_create_frame_error.setText("Der Nutzername ist bereits vergeben")#TODO: implement error message
+ return
+ userdata = AdminCommands().create_password(password)
+ self.db.createUser(
+ user=username,
+ password=f"{userdata[1]}{userdata[0]}",
+ salt=userdata[1],
+ role=role,
+ )
+ self.user_create_frame_username.clear()
+ self.user_create_frame_password.clear()
+ self.user_frame_userrole.setCurrentText("")
+ self.admin_action_changed()
+
+ def delete_user(self):
+ if self.user_delete_confirm.isChecked():
+ username = self.user_delete_frame_user_select.currentText()
+ self.db.deleteUser(username)
+ self.user_delete_frame_user_select.removeItem(
+ self.user_delete_frame_user_select.currentIndex()
+ )
+ self.user_delete_confirm.setChecked(False)
+ else:
+ self.user_delete_err_message.setText(
+ "Bitte bestätigen Sie die Löschung des Nutzers"
+ ) # TODO: implement error message
+ # ic("please confirm the deletion of the user")
+
+ def update_user_data(self):
+ username = self.user_edit_frame_user_select.currentText()
+ password = (
+ self.user_edit_frame_new_password.text()
+ if self.user_edit_frame_new_password.text() != ""
+ else None
+ )
+ role = (
+ self.user_edit_frame_role_select.currentText()
+ if self.user_edit_frame_role_select.currentText() != ""
+ else None
+ )
+
+ userdata = AdminCommands().create_password(password)
+ data = {
+ "password": f"{userdata[1]}{userdata[0]}",
+ "salt": userdata[1],
+ "role": role,
+ }
+ data = {key: value for key, value in data.items() if value is not None}
+ print(data)
+ self.db.updateUser(username=username, data=data)
+ self.user_edit_frame_user_select.setCurrentText("")
+ self.user_edit_frame_new_password.clear()
+ self.user_edit_frame_role_select.setCurrentText("")
+
+ def edit_faculty_member_action(self):
+ def __gen_fullname(fname, lname, data):
+ if fname == "" and lname == "":
+ return data[3]
+ if fname == "" and lname != "":
+ return f"{lname} {data[1]}"
+ if fname != "" and lname == "":
+ return f"{data[2]} {fname}"
+ if fname != "" and lname != "":
+ return f"{lname} {fname}"
+
+ # get the data and use new value if it is not none and does not mach the old value
+ if self.edit_faculty_member_select_member.currentText() == "":
+ return
+ olddata = self.db.getFacultyMember(
+ self.edit_faculty_member_select_member.currentText()
+ )
+ ic(olddata)
+ data = olddata
+ oldlname = data[2]
+ oldfname = data[1]
+ # take data except first and last entry
+
+ titel = (
+ self.edit_faculty_member_new_title.currentText()
+ if self.edit_faculty_member_new_title.currentText() != "Kein Titel"
+ else None
+ )
+ fname = (
+ self.edit_faculty_member_new_surname.text()
+ if self.edit_faculty_member_new_surname.text() != ""
+ else self.edit_faculty_member_select_member.currentText()
+ .split(" ")[1]
+ .strip()
+ )
+ lname = (
+ self.user_faculty_member_new_name.text()
+ if self.user_faculty_member_new_name.text() != ""
+ else self.edit_faculty_member_select_member.currentText()
+ .split(" ")[0]
+ .strip()
+ )
+ fullname = __gen_fullname(fname, lname, data)
+ telnr = self.user_faculty_member_new_telnr.text()
+ mail = self.user_faculty_member_new_mail.text()
+ new_data = {
+ "titel": titel,
+ "fname": fname,
+ "lname": lname,
+ "fullname": fullname,
+ "mail": mail,
+ "telnr": telnr,
+ }
+ new_data = {key: value for key, value in new_data.items() if value != ""}
+ self.db.updateFacultyMember(data=new_data, oldlname=oldlname, oldfname=oldfname)
+ self.add_faculty_member_data()
+ self.edit_faculty_member_new_title.setCurrentText("")
+ self.edit_faculty_member_new_surname.clear()
+ self.user_faculty_member_new_name.clear()
+ self.user_faculty_member_new_telnr.clear()
+ self.user_faculty_member_new_mail.clear()
+
+ def hide_all(self):
+ self.userCreateBox.hide()
+ self.userChangeDataBox.hide()
+ self.deleteUserBox.hide()
+ self.profChangeDataBox.hide()
+
+ def admin_action_changed(self):
+ action = self.select_action_box.currentText()
+ roles = self.db.getRoles()
+ roles = [role[0] for role in roles]
+ # remove duplicates
+ roles = list(dict.fromkeys(roles))
+ users = self.db.getUsers()
+ users = [user[2] for user in users]
+ users.remove(self.active_user)
+ if "admin" in users:
+ users.remove("admin")
+ if action == "Nutzer anlegen":
+ self.hide_all()
+ self.userCreateBox.show()
+ self.user_frame_userrole.clear()
+ self.user_frame_userrole.addItems(roles)
+ elif action == "Nutzer aktualisieren":
+ self.hide_all()
+ self.userChangeDataBox.show()
+ self.user_edit_frame_role_select.addItems(roles)
+ self.user_edit_frame_user_select.addItems(users)
+ elif action == "Nutzer löschen":
+ self.hide_all()
+ self.deleteUserBox.show()
+ self.user_delete_frame_user_select.addItems(users)
+ self.user_delete_frame_user_select.setCurrentText("")
+ self.user_delete_frame_user_select.addItems(users)
+
+ elif action == "Lehrperson bearbeiten":
+ self.hide_all()
+ self.profChangeDataBox.show()
+ self.add_faculty_member_data()
+ self.edit_faculty_member_new_title.addItems(PROF_TITLES)
+
+ else:
+ self.hide_all()
+ return
+
+ def add_faculty_member_data(self):
+ faculty_members = self.db.getFacultyMembers()
+ names = [f"{member[5]}" for member in faculty_members]
+ self.edit_faculty_member_select_member.clear()
+ self.edit_faculty_member_select_member.addItems(names)
+ self.edit_faculty_member_select_member.addItem("")
+ self.edit_faculty_member_select_member.setCurrentText("")
+
+ def tabW2_changed(self):
+
+ if self.tabWidget_2.currentIndex() == 0:
+ self.stackedWidget_4.setCurrentIndex(0)
+ else:
+ self.stackedWidget_4.setCurrentIndex(1)
+
+ def generateSemester(self, today=False):
+ """Generates the current semester.
+
+ Args:
+ -----
+ today (bool, optional): If True, the current semester is generated. Defaults to False.
+ Returns:
+ --------
+ str: The current semester
+ """
+ if today:
+ return generateSemesterByDate()
+ currentYear = self.sem_year.text()
+ currentYear = int(currentYear[-2:])
+
+ semester = (
+ self.sem_sommer.text()
+ if self.sem_sommer.isChecked()
+ else self.sem_winter.text()
+ )
+ if semester == "Sommer":
+ return "SoSe " + str(currentYear)
+ else:
+ return f"WiSe {currentYear}/{currentYear+1}"
+
+ def display_detailed_data(self):
+ selected_semester = self.statistics_table.item(
+ self.statistics_table.currentRow(), 0
+ ).text()
+ # get all apparats from the selected semester
+ data = self.db.getApparatsBySemester(selected_semester)
+ # replace keys for german names
+ # split to two lists
+ created = {"Erstellt": data["created"]}
+ deleted = {"Gelöscht": data["deleted"]}
+ created_status = StatusWidget(created, selected_semester)
+ deleted_status = StatusWidget(deleted, selected_semester)
+ created_status.setSizePolicy(
+ QtWidgets.QSizePolicy.Policy.Expanding,
+ QtWidgets.QSizePolicy.Policy.Expanding,
+ )
+ deleted_status.setSizePolicy(
+ QtWidgets.QSizePolicy.Policy.Expanding,
+ QtWidgets.QSizePolicy.Policy.Expanding,
+ )
+
+ # add them to the gridLayout_4
+ self.gridLayout_4.addWidget(created_status, 1, 0)
+ self.gridLayout_4.addWidget(deleted_status, 1, 1)
+ # self.setStatisticTableSize()
+ created_status.person_double_clicked.connect(self.open_apparat)
+ created_status.setToolTip("Doppelklick um den Semesterapparat zu öffnen")
+ deleted_status.setToolTip("Nur zur Übersicht")
+ # set deleted_status background to slightly gray
+
+ def open_apparat(self, header: str, apparat: str, parent_depth: int):
+ print(header)
+ if header == "deleted" and parent_depth == 2:
+ # TODO: warn message here
+ print("warning")
+ if parent_depth == 1:
+ print(apparat)
+ # person selected case - open all apparats from this person in the tableWidget
+ self.tableWidget.setRowCount(0)
+ prof_id = self.db.getProfId(apparat.split("(")[0].strip())
+ apparats = self.db.getApparatsByProf(prof_id)
+ for app in apparats:
+ print(app)
+ # set the items 0 = clickable checkbox, 1 = appname, 2 = profname, 3 = fach
+ # insert new row
+ self.tableWidget.insertRow(0)
+ self.tableWidget.setItem(0, 0, QtWidgets.QTableWidgetItem(""))
+ self.tableWidget.setItem(0, 1, QtWidgets.QTableWidgetItem(app[1]))
+ self.tableWidget.setItem(0, 2, QtWidgets.QTableWidgetItem(str(app[4])))
+ self.tableWidget.setItem(0, 3, QtWidgets.QTableWidgetItem(app[2]))
+ self.tableWidget.setItem(0, 4, QtWidgets.QTableWidgetItem(app[3]))
+ # replace the 0 with a checkbox
+ checkbox = QtWidgets.QCheckBox()
+ checkbox.setChecked(False)
+ self.tableWidget.setCellWidget(0, 0, checkbox)
+ # if i[9] is 1, set the background of the row to red
+ if int(app[9]) == 1:
+ for j in range(5):
+ self.tableWidget.item(0, j).setBackground(
+ QtGui.QColor(235, 74, 71)
+ )
+ # disable the checkbox
+ self.tableWidget.cellWidget(0, 0).setEnabled(False)
+ # set the tooltip
+ self.tableWidget.cellWidget(0, 0).setToolTip(
+ "Dieser Semesterapparat kann nicht gelöscht werden, da er bereits gelöscht wurde"
+ )
+ elif parent_depth == 2:
+ # apparat selected case - open the apparat in the frame
+ self.load_app_data(apparat)
+ # change tab focus to tab 0
+ self.tabWidget.setCurrentIndex(0)
+ return
+
+ def gridchange(self):
+ if self.check_deletable.isChecked():
+ self.box_semester.setEnabled(False)
+ self.box_semester.clear()
+ self.box_appnrs.setEnabled(False)
+ self.box_appnrs.clear()
+ self.box_person.setEnabled(False)
+ self.box_person.clear()
+ self.box_fach.setEnabled(False)
+ self.box_fach.clear()
+ self.box_erstellsemester.setEnabled(False)
+ self.box_erstellsemester.clear()
+ self.box_dauerapp.setEnabled(False)
+ self.box_dauerapp.clear()
+ else:
+ self.box_semester.setEnabled(True)
+ self.box_appnrs.setEnabled(True)
+ self.box_person.setEnabled(True)
+ self.box_fach.setEnabled(True)
+ self.box_erstellsemester.setEnabled(True)
+ self.box_dauerapp.setEnabled(True)
+ self.tab_changed()
+
+ def populate_tab(self):
+ # add default values to the dropdowns
+ self.box_appnrs.clear()
+ self.box_appnrs.addItem("")
+ self.box_appnrs.setCurrentText("")
+ self.box_person.clear()
+ self.box_person.addItem("")
+ self.box_person.setCurrentText("")
+ self.box_fach.clear()
+ self.box_fach.addItem("")
+ self.box_fach.setCurrentText("")
+ self.box_erstellsemester.clear()
+ self.box_erstellsemester.addItem("")
+ self.box_erstellsemester.setCurrentText("")
+ self.box_semester.clear()
+ self.box_semester.addItem("")
+ self.box_semester.setCurrentText("")
+ self.box_dauerapp.clear()
+ self.box_dauerapp.addItems(["Ja", "Nein", ""])
+ self.box_dauerapp.setCurrentText("")
+ # add custom vaules
+ appnrs = self.db.getUnavailableApparatNumbers()
+ apparats = natsorted(appnrs)
+ apparats = [str(apparat) for apparat in apparats]
+ self.box_appnrs.addItems(apparats)
+ persons = self.db.getProfs()
+ self.box_person.addItems([f"{person[3]}, {person[2]}" for person in persons])
+ self.box_fach.addItems(subject[1] for subject in self.db.getSubjects())
+ semester = self.db.getSemersters()
+ self.box_erstellsemester.addItems(semester)
+ self.statistics_table.setRowCount(0)
+
+ # set data for table and graph in tab 2 tableWidget_3
+ data = self.db.getApparatCountBySemester()
+ data = custom_sort(data)
+ # self.tabWidget_3.clear()
+ self.tabWidget_3.removeTab(1)
+ self.statistics_table.setRowCount(len(data))
+ for i in range(len(data)):
+ self.statistics_table.setItem(i, 0, QtWidgets.QTableWidgetItem(data[i][0]))
+ self.statistics_table.setItem(
+ i, 1, QtWidgets.QTableWidgetItem(str(data[i][1]))
+ )
+ self.statistics_table.setItem(
+ i, 2, QtWidgets.QTableWidgetItem(str(data[i][2]))
+ )
+ self.statistics_table.resizeColumnsToContents()
+ self.statistics_table.resizeRowsToContents()
+ # self.setStatisticTableSize()
+
+ # get height of the table
+ # create graph
+
+ graph_data = {
+ "x": [i[0] for i in data],
+ "y": {"Erstellt": [i[1] for i in data], "Gelöscht": [i[2] for i in data]},
+ }
+ graph = DataGraph(title="Erstellte und gelöschte Apparate", data=graph_data)
+
+ # place the graph into tabWidget_3
+ self.tabWidget_3.addTab(graph, "Graph")
+ self.tabWidget_3.setCurrentIndex(0)
+
+ def tab_changed(self):
+ curr_tab = self.tabWidget.currentIndex()
+ if curr_tab == 0: # create tab
+ return
+ elif curr_tab == 1: # statistics tab
+ self.populate_tab()
+
+ def populate_dropdown(self, box, data):
+ box.clear()
+ box.addItem("")
+ box.setCurrentText("")
+ box.addItems(data)
+
+ def delete_selected_apparats(self):
+ # get all selected apparats
+ selected_apparats = []
+ selected_apparat_rows = []
+ for i in range(self.tableWidget.rowCount()):
+ if self.tableWidget.cellWidget(i, 0).isChecked():
+ selected_apparats.append(self.tableWidget.item(i, 2).text())
+ selected_apparat_rows.append(i)
+ # delete all selected apparats
+ print(selected_apparats)
+ for apparat in selected_apparats:
+ self.db.deleteApparat(apparat, self.generateSemester(today=True))
+ for row in selected_apparat_rows:
+ # set the background of the row to red
+ for j in range(5):
+ self.tableWidget.item(row, j).setBackground(QtGui.QColor(235, 74, 71))
+ # refresh the table
+ self.populate_tab()
+ self.btn_del_select_apparats.setEnabled(False)
+
+ def statistics(self):
+ """Generate the statistics based on the selected filters."""
+ self.db_err_message.setText("")
+ self.btn_del_select_apparats.setEnabled(True)
+ self.btn_notify_for_deletion.setEnabled(True)
+ params = {
+ "appnr": (
+ self.box_appnrs.currentText()
+ if self.box_appnrs.currentText() != ""
+ else None
+ ),
+ "prof_id": (
+ self.db.getProfId(self.box_person.currentText())
+ if self.box_person.currentText() != ""
+ else None
+ ),
+ "fach": (
+ self.box_fach.currentText()
+ if self.box_fach.currentText() != ""
+ else None
+ ),
+ "erstellsemester": (
+ self.box_erstellsemester.currentText()
+ if self.box_erstellsemester.currentText() != ""
+ else None
+ ),
+ "dauer": (
+ "1"
+ if self.box_dauerapp.currentText() == "Ja"
+ else "0" if self.box_dauerapp.currentText() == "Nein" else None
+ ),
+ "endsemester": (
+ self.box_semester.currentText()
+ if self.box_semester.currentText() != ""
+ else None
+ ),
+ "deletable": "True" if self.check_deletable.isChecked() else None,
+ "deletesemester": self.generateSemester(today=True),
+ }
+ params = {
+ key: value for key, value in params.items() if value is not None
+ } # remove empty lines to prevent errors
+ print(params)
+ params = {
+ key: value for key, value in params.items() if value != "Alle"
+ } # remove empty lines to prevent errors
+ print(params)
+ result = self.db.statistic_request(**params)
+ # add QTableWidgetItems to the table
+ self.tableWidget.setRowCount(len(result))
+ if len(result) == 0:
+ self.db_err_message.setText("Keine Ergebnisse gefunden")
+ return
+ for i in range(len(result)):
+ print(result[i])
+ # set the items 0 = clickable checkbox, 1 = appname, 2 = profname, 3 = fach
+ self.tableWidget.setItem(i, 0, QtWidgets.QTableWidgetItem(""))
+ self.tableWidget.setItem(i, 1, QtWidgets.QTableWidgetItem(result[i][1]))
+ self.tableWidget.setItem(
+ i, 2, QtWidgets.QTableWidgetItem(str(result[i][4]))
+ )
+ self.tableWidget.setItem(i, 3, QtWidgets.QTableWidgetItem(result[i][2]))
+ self.tableWidget.setItem(i, 4, QtWidgets.QTableWidgetItem(result[i][3]))
+ # replace the 0 with a checkbox
+ checkbox = QtWidgets.QCheckBox()
+ checkbox.setChecked(False)
+ self.tableWidget.setCellWidget(i, 0, checkbox)
+ # if i[9] is 1, set the background of the row to red
+ if int(result[i][9]) == 1:
+ for j in range(5):
+ self.tableWidget.item(i, j).setBackground(QtGui.QColor(235, 74, 71))
+ # disable the checkbox
+ self.tableWidget.cellWidget(i, 0).setEnabled(False)
+ # set the tooltip
+ self.tableWidget.cellWidget(i, 0).setToolTip(
+ "Dieser Semesterapparat kann nicht gelöscht werden, da er bereits gelöscht wurde"
+ )
+
+ def populate_frame(self, appdata: ApparatData):
+ # populate the frame with the data from the database
+ # ic(appdata)
+ self.drpdwn_app_nr.setCurrentText(str(appdata.appnr))
+ self.prof_title.setText(appdata.prof_title)
+ prof_name = appdata.profname.split(" ")
+ if len(prof_name) > 2:
+ fname = " ".join(prof_name[1:])
+ lname = prof_name[0]
+ prof_name = f"{lname}, {fname}"
+ else:
+ prof_name = ", ".join(prof_name)
+ self.drpdwn_prof_name.setCurrentText(prof_name)
+ self.prof_mail.setText(appdata.prof_mail)
+ self.prof_tel_nr.setText(appdata.prof_tel)
+ self.app_name.setText(appdata.appname)
+ print("changing dropdown app_fach from '' to ", appdata.app_fach)
+ self.app_fach.setCurrentText(appdata.app_fach)
+ print("changed dropdown app_fach to ", self.app_fach.currentText())
+ if appdata.semester is not None:
+ self.sem_sommer.setChecked(
+ True if appdata.semester.split(" ")[0] == "SoSe" else False
+ )
+ self.sem_winter.setChecked(
+ True if appdata.semester.split(" ")[0] == "WiSe" else False
+ )
+ self.sem_year.setText(appdata.semester.split(" ")[1])
+ else:
+ self.sem_sommer.setChecked(
+ True if appdata.erstellsemester.split(" ")[0] == "SoSe" else False
+ )
+ self.sem_winter.setChecked(
+ True if appdata.erstellsemester.split(" ")[0] == "WiSe" else False
+ )
+ self.sem_year.setText(appdata.erstellsemester.split(" ")[1])
+ self.check_eternal_app.setChecked(appdata.dauerapp)
+ self.prof_id_adis.setText(str(appdata.prof_adis_id))
+ self.apparat_id_adis.setText(str(appdata.apparat_adis_id))
+ self.app_group_box.setEnabled(True)
+ self.groupBox_2.hide()
+ self.groupBox.hide()
+ self.validateLoadedData()
+
+ def validateLoadedData(self):
+ self.validate_prof_mail()
+ self.validate_prof_name()
+ self.validate_prof_tel()
+ self.validate_app_name()
+ self.validate_app_fach()
+ self.validate_semester()
+
+ def update_apparat(self):
+ appdata = ApparatData()
+ appdata.app_fach = self.app_fach.currentText()
+ appdata.appname = self.app_name.text()
+ appdata.appnr = self.active_apparat
+ appdata.dauerapp = self.check_eternal_app.isChecked()
+ appdata.prof_mail = self.prof_mail.text()
+ appdata.prof_tel = self.prof_tel_nr.text()
+ appdata.prof_title = self.prof_title.text()
+ appdata.profname = self.drpdwn_prof_name.currentText()
+ appdata.semester = (
+ self.sem_sommer.text() + " " + self.sem_year.text()
+ if self.sem_sommer.isChecked()
+ else self.sem_winter.text() + " " + self.sem_year.text()
+ )
+ appdata.prof_adis_id = self.prof_id_adis.text()
+ self.add_files()
+ appdata.apparat_adis_id = self.apparat_id_adis.text()
+
+ self.db.updateApparat(appdata)
+
+ self.update_app_media_list()
+ self.cancel_active_selection.click()
+ self.check_send_mail.show()
+ self.chkbx_show_del_media.show()
+ self.cancel_active_selection.setEnabled(False)
+
+ def confirm_popup(self, message: str):
+ popup = popus_confirm()
+ popup.setupUi()
+ popup.textEdit.setReadOnly(True)
+ popup.textEdit.setText(message)
+
+ popup.exec()
+ return popup.result()
+
+ def threads(self):
+ while True:
+ self.validate_prof_mail()
+ self.validate_prof_name()
+ self.validate_prof_tel()
+ self.validate_app_name()
+ self.validate_app_fach()
+ self.validate_semester()
+
+ def thread_check(self):
+ self.prof_mail.textChanged.connect(self.validate_prof_mail)
+ self.drpdwn_prof_name.editTextChanged.connect(self.validate_prof_name)
+ self.prof_tel_nr.textChanged.connect(self.validate_prof_tel)
+ self.app_name.textChanged.connect(self.validate_app_name)
+ self.app_fach.currentTextChanged.connect(self.validate_app_fach)
+ self.sem_year.textChanged.connect(self.validate_semester)
+ self.check_eternal_app.stateChanged.connect(self.validate_semester)
+
+ def validate_prof_name(self):
+ if self.app_group_box.isEnabled():
+ if "," in self.drpdwn_prof_name.currentText():
+ self.drpdwn_prof_name.setStyleSheet("border: 1px solid green;")
+ self.profname_mand.setText("")
+ self.change_state(0, 1)
+ else:
+ self.drpdwn_prof_name.setStyleSheet("border: 1px solid red;")
+ self.profname_mand.setText("*")
+ self.change_state(0, 0)
+ else:
+ pass
+ # self.drpdwn_prof_name.setStyleSheet("border: 1px solid black;")
+
+ def validate_prof_mail(self):
+ if self.app_group_box.isEnabled():
+ if self.prof_mail.hasAcceptableInput():
+ self.prof_mail.setStyleSheet("border: 1px solid green;")
+ self.mail_mand.setText("")
+ self.change_state(1, 1)
+ else:
+ self.prof_mail.setStyleSheet("border: 1px solid red;")
+ self.mail_mand.setText("*")
+ self.change_state(1, 0)
+ else:
+ self.prof_mail.setStyleSheet("border: 1px solid black;")
+
+ def validate_prof_tel(self):
+ if self.app_group_box.isEnabled():
+ if self.prof_tel_nr.text() != "":
+ self.prof_tel_nr.setStyleSheet("border: 1px solid green;")
+ self.telnr_mand.setText("")
+ self.change_state(2, 1)
+ else:
+ self.prof_tel_nr.setStyleSheet("border: 1px solid red;")
+ self.telnr_mand.setText("*")
+ self.change_state(2, 0)
+
+ def validate_app_name(self):
+ if self.app_group_box.isEnabled():
+ if self.app_name.hasAcceptableInput():
+ self.app_name.setStyleSheet("border: 1px solid green;")
+ self.appname_mand.setText("")
+ self.change_state(3, 1)
+ else:
+ self.app_name.setStyleSheet("border: 1px solid red;")
+ self.appname_mand.setText("*")
+ self.change_state(3, 0)
+
+ def validate_app_fach(self):
+ if self.app_group_box.isEnabled():
+ if self.app_fach.currentText() != "":
+ self.app_fach.setStyleSheet("border: 1px solid green;")
+ self.fach_mand.setText("")
+ self.change_state(4, 1)
+ else:
+ self.app_fach.setStyleSheet("border: 1px solid red;")
+ self.fach_mand.setText("*")
+ self.change_state(4, 0)
+
+ def validate_semester(self):
+ if self.app_group_box.isEnabled():
+ if (
+ (self.sem_sommer.isChecked() or self.sem_winter.isChecked())
+ and self.sem_year.hasAcceptableInput()
+ ) or self.check_eternal_app.isChecked():
+ self._mand.setText("")
+ self.change_state(5, 1)
+ self.check_eternal_app.setEnabled(True)
+ else:
+ self._mand.setText("*")
+ self.change_state(5, 0)
+ self.check_eternal_app.setEnabled(False)
+
+ def change_state(self, index, state):
+ global valid_input
+ valid_input = list(valid_input)
+ valid_input[index] = state
+ valid_input = tuple(valid_input)
+
+ def set_state(self):
+ # set state of semester and year
+ if self.check_eternal_app.isChecked():
+ self.sem_winter.setEnabled(False)
+ self.sem_sommer.setEnabled(False)
+ self.sem_year.setEnabled(False)
+ else:
+ self.sem_winter.setEnabled(True)
+ self.sem_sommer.setEnabled(True)
+ self.sem_year.setEnabled(True)
+
+ def validate_fields(self):
+ return all(valid_input)
+
+ # def req_fields_filled(self):
+ # # check if all required fields are filled
+ # values = []
+ # for item in self.app_group_box.findChildren(QtWidgets.QLabel):
+ # # if label name contains "req" and the text is empty, return false
+ # if "mand" in item.objectName() and item.text() == "":
+ # values.append(True)
+ # elif "mand" in item.objectName() and item.text() != "":
+ # values.append(False)
+ # return all(values)
+ #
+ def buttonClicked(self):
+ print("Button clicked")
+
+ def set_prof_data(self):
+ if "," not in self.drpdwn_prof_name.currentText():
+ self.prof_mail.clear()
+ self.prof_tel_nr.clear()
+ return
+ selected_prof = self.drpdwn_prof_name.currentText()
+ data = self.db.getProfData(selected_prof)
+ # ic(data)
+ prof_title = data[2]
+ if prof_title == "None":
+ prof_title = "Kein Titel"
+ self.prof_title.setText(prof_title)
+ self.prof_tel_nr.setText(data[1])
+ self.prof_mail.setText(data[0])
+
+ def get_index_of_value(self, table_widget, value):
+ for i in range(table_widget.rowCount()):
+ for j in range(table_widget.columnCount()):
+ if (
+ table_widget.item(i, j) is not None
+ and table_widget.item(i, j).text() == value
+ ):
+ return i, j
+ return None
+
+ def load_app_data(self, app_id=None):
+ self.cancel_active_selection.setEnabled(True)
+ if isinstance(app_id, str):
+ # double click the tableWidget_apparate row with the given app_id
+ row, column = self.get_index_of_value(self.tableWidget_apparate, app_id)
+ # set the current index to the row
+ self.tableWidget_apparate.setCurrentCell(row, 0)
+ self.check_send_mail.hide()
+ app_pos = self.tableWidget_apparate.currentIndex()
+ appnr = self.tableWidget_apparate.item(app_pos.row(), 0).text()
+ appname = self.tableWidget_apparate.item(app_pos.row(), 1).text()
+ self.sem_sommer.setEnabled(False)
+ self.sem_winter.setEnabled(False)
+ self.sem_year.setEnabled(False)
+ self.dokument_list.setRowCount(0)
+ self.chkbx_show_del_media.setEnabled(True)
+ appdata = self.db.getApparatData(appnr, appname)
+ self.populate_frame(appdata)
+ self.btn_apparat_save.hide()
+ self.btn_reserve.show()
+ self.chkbx_show_del_media.show()
+ self.groupBox_2.show()
+ self.groupBox.show()
+
+ self.drpdwn_app_nr.setDisabled(True)
+ self.update_app_media_list()
+ self.update_documemt_list()
+
+ def update_documemt_list(self):
+ app_id = self.active_apparat
+ prof_id = self.db.getProfId(
+ self.drpdwn_prof_name.currentText().replace(", ", " ")
+ )
+ files = self.db.getFiles(app_id, prof_id)
+ for file in files:
+ self.dokument_list.insertRow(0)
+ self.dokument_list.setItem(0, 0, QtWidgets.QTableWidgetItem(file[0]))
+ self.dokument_list.setItem(0, 1, QtWidgets.QTableWidgetItem(file[1]))
+ self.dokument_list.setItem(0, 2, QtWidgets.QTableWidgetItem(""))
+ self.dokument_list.setItem(0, 3, QtWidgets.QTableWidgetItem("Database"))
+
+ # def btn_load_apparat(self):
+ # # remove all rows from table
+ # #get all
+ # self.tableWidget_apparate.sortItems(0, QtCore.Qt.SortOrder.AscendingOrder)
+ # self.app_group_box.setDisabled(True)
+ # for child in self.app_group_box.findChildren(QtWidgets.QLineEdit):
+ # child.clear()
+
+ def btn_create_new_apparat(self):
+ self.groupBox.show()
+ self.groupBox_2.show()
+ global valid_input
+ # *create a new apparat
+ self.btn_apparat_save.show() if self.btn_apparat_save.isHidden() else None
+ # clear dokumemt_list
+ self.dokument_list.setRowCount(0)
+ self.cancel_active_selection.setEnabled(True)
+ self.app_group_box.setEnabled(True)
+
+ self.sem_year.setEnabled(True)
+ self.sem_sommer.setEnabled(True)
+ self.sem_winter.setEnabled(True)
+ self.chkbx_show_del_media.setEnabled(True)
+ self.drpdwn_app_nr.setEnabled(True)
+ self.app_fach.setEnabled(True)
+
+ if self.tableWidget_apparat_media.rowCount() > 0:
+ self.tableWidget_apparat_media.setRowCount(0)
+ # clear all fields
+ for item in self.app_group_box.findChildren(QtWidgets.QLineEdit):
+ item.clear()
+ self.drpdwn_app_nr.clear()
+ self.prof_title.clear()
+ self.drpdwn_prof_name.clear()
+ # set drop down menu for apparat numbers to only available numbers
+ self.drpdwn_app_nr.addItems(
+ [str(i) for i in APP_NRS if i not in self.db.getUnavailableApparatNumbers()]
+ )
+
+ valid_input = (0, 0, 0, 0, 0, 0)
+ self.populate_prof_dropdown()
+ # self.horizontalLayout_6.show()
+ # increase size by 300px
+
+ def update_progress_label(self, curr, total):
+ text = f"Medium {curr}/{total}"
+ self.logger.log_info(text)
+ self.progress_label.setText(text)
+ # update tableWidget_apparat_media
+ self.update_app_media_list()
+
+ def hide_progress_label(self):
+ self.logger.log_info("Finished adding media, hiding progress label")
+ self.progress_label.hide()
+ self.progress_label.setText("Bitte warten...")
+ self.line_2.hide()
+ self.label_info.hide()
+
+ def btn_add_medium(self):
+ if not self.app_group_box.isEnabled():
+ self.confirm_popup("Bitte erst einen Apparat auswählen!")
+ return
+
+ def __new_ui():
+ dialog = QtWidgets.QDialog()
+ frame = Medien()
+ frame.setupUi(dialog)
+ dialog.exec()
+ mode = frame.get_mode()
+ data = frame.get_list_data()
+ return mode, data, dialog.result()
+
+ self.progress_label.show()
+ self.line_2.show()
+ self.label_info.show()
+ self.progress_label.setText("Bitte warten...")
+ mode, data, result = __new_ui()
+ if result == 1:
+ if data == []:
+ self.confirm_popup("Bitte mindestens ein Medium hinzufügen!")
+
+ app_id = self.active_apparat
+ prof_id = self.db.getProfId(self.drpdwn_prof_name.currentText())
+ # check if app_id is in database
+ if not self.db.checkApparatExists(app_id):
+ # create apparat
+ self.btn_save_apparat()
+ # create a thread that updates the progress label after each medium
+ self.bookGrabber = BookGrabber(
+ mode=mode, app_id=app_id, prof_id=prof_id, data=data
+ )
+ # grabber.mode = mode
+ # grabber.data = data
+ # grabber.app_id = app_id
+ # grabber.prof_id = prof_id
+ self.bookGrabber.finished.connect(self.bookGrabber.deleteLater)
+ self.bookGrabber.finished.connect(self.hide_progress_label)
+ self.bookGrabber.finished.connect(self.update_app_media_list)
+ self.bookGrabber.updateSignal.connect(self.update_progress_label)
+
+ self.bookGrabber.start()
+ # run grabber.deletelater
+
+ # for book in data:
+ # # self.progress_label.setText(f"Medium {ct}/{len(data)}")
+ # # update the progress label
+ # self.logger.log_info(f"trying to add BookData for Signature {book}")
+ # webdata = WebRequest().get_ppn(book).get_data()
+ # bd: BookData = BibTextTransformer(mode).get_data(webdata).return_data()
+ # bd.signature = book
+ # self.db.addBookToDatabase(bookdata=bd, app_id=app_id, prof_id=prof_id)
+
+ # get all media list books
+
+ else:
+ return
+
+ def check_availability(self):
+ # self.threadeds.clear()
+
+ def _update_progress(current, all_titles):
+ self.avail_status.setText("{}/{}".format(current, all_titles))
+
+ def _hide_progress_label():
+ self.label_20.hide()
+ self.avail_status.hide()
+ self.avail_status.setText("0/0")
+
+ # get all links from the table
+ # if no index in tableWidget_apparat_media is selected, check all
+ if self.tableWidget_apparat_media.currentRow() == -1:
+ links = [
+ self.tableWidget_apparat_media.item(i, 1).text()
+ for i in range(self.tableWidget_apparat_media.rowCount())
+ if self.tableWidget_apparat_media.item(i, 4).text() == "❌"
+ or self.tableWidget_apparat_media.item(i, 4).text() == ""
+ ]
+ else:
+ links = [
+ self.tableWidget_apparat_media.item(
+ self.tableWidget_apparat_media.currentRow(), 1
+ ).text()
+ ]
+ items = len(links)
+ self.label_20.setText("Verfügbarkeit wird geprüft, bitte warten...")
+ self.label_20.show()
+ self.avail_status.setText(f"0/{items}")
+ self.avail_status.show()
+ books = self.db.getBooks(
+ self.active_apparat,
+ self.db.getProfId(self.drpdwn_prof_name.currentText()),
+ deleted=0,
+ )
+
+ # thread = QThread()
+ appnumber = self.active_apparat
+ print(links)
+ self.availChecker = AvailChecker(links, appnumber, books=books)
+ # availcheck.moveToThread(thread)
+ # availcheck.finished.connect(thread.quit)
+ self.availChecker.finished.connect(self.availChecker.deleteLater)
+ self.availChecker.finished.connect(self.update_app_media_list)
+ self.availChecker.updateProgress.connect(_update_progress)
+ self.availChecker.finished.connect(_hide_progress_label)
+ self.availChecker.start()
+ # kill availcheck after completion
+
+ # self.threadeds.append(thread)
+ # self.grabbers.append(availcheck)
+
+ def btn_cancel_active_selection(self):
+ # clear the rows of the table
+ self.tableWidget_apparat_media.setRowCount(0)
+ self.dokument_list.setRowCount(0)
+ self.app_group_box.setEnabled(False)
+ self.app_fach.setCurrentText("")
+ self.chkbx_show_del_media.hide()
+ self.check_send_mail.hide()
+ self.btn_reserve.hide()
+ self.groupBox_2.hide()
+ self.groupBox.hide()
+ self.check_eternal_app.setEnabled(False)
+ # set all radio buttons to unchecked
+ self.sem_sommer.setChecked(False)
+ self.sem_winter.setChecked(False)
+
+ for child in self.app_group_box.findChildren(QtWidgets.QLineEdit):
+ child.clear()
+
+ def update_app_media_list(self):
+ deleted = 0 if not self.chkbx_show_del_media.isChecked() else 1
+ app_id = self.active_apparat
+ prof_id = self.db.getProfId(self.drpdwn_prof_name.currentText())
+ books: list[dict[int, BookData, int]] = self.db.getBooks(
+ app_id, prof_id, deleted
+ )
+
+ # print(books)
+ # take the dataclass from the tuple
+ # booklist:list[BookData]=[book[0] for book in books]
+ self.tableWidget_apparat_media.setRowCount(0)
+ for book in books:
+ book["id"]
+ book_data = book["bookdata"]
+ availability = book["available"]
+ # bd = BookData().from_string(book)
+ # print(bd, type(bd))
+ # create a new row below the last one
+ self.tableWidget_apparat_media.insertRow(
+ self.tableWidget_apparat_media.rowCount()
+ )
+ # #set the data
+ self.tableWidget_apparat_media.setItem(
+ self.tableWidget_apparat_media.rowCount() - 1,
+ 0,
+ QtWidgets.QTableWidgetItem(book_data.title),
+ )
+ self.tableWidget_apparat_media.setItem(
+ self.tableWidget_apparat_media.rowCount() - 1,
+ 1,
+ QtWidgets.QTableWidgetItem(book_data.signature),
+ )
+ self.tableWidget_apparat_media.setItem(
+ self.tableWidget_apparat_media.rowCount() - 1,
+ 2,
+ QtWidgets.QTableWidgetItem(book_data.edition),
+ )
+ self.tableWidget_apparat_media.setItem(
+ self.tableWidget_apparat_media.rowCount() - 1,
+ 3,
+ QtWidgets.QTableWidgetItem(book_data.author),
+ )
+ self.tableWidget_apparat_media.setItem(
+ self.tableWidget_apparat_media.rowCount() - 1,
+ 6,
+ QtWidgets.QTableWidgetItem(book_data.link),
+ )
+ if availability == 1:
+ # display green checkmark at column 4 in the row
+ self.tableWidget_apparat_media.setItem(
+ self.tableWidget_apparat_media.rowCount() - 1,
+ 4,
+ QtWidgets.QTableWidgetItem("✅"),
+ )
+ # set tooltip
+ self.tableWidget_apparat_media.item(
+ self.tableWidget_apparat_media.rowCount() - 1, 4
+ ).setToolTip("Das Medium wurde im Apparat gefunden")
+ else:
+ self.tableWidget_apparat_media.setItem(
+ self.tableWidget_apparat_media.rowCount() - 1,
+ 4,
+ QtWidgets.QTableWidgetItem("❌"),
+ )
+ self.tableWidget_apparat_media.item(
+ 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)
+
+ def open_link(self, item):
+ def __openLink(link):
+ if link == "":
+ return
+ if "http" not in link:
+ link = "https://" + link
+
+ webbrowser.open(link)
+
+ # get the name of the column
+ columnname = self.tableWidget_apparat_media.horizontalHeaderItem(
+ item.column()
+ ).text()
+ if columnname == "Link":
+ __openLink(item.text())
+ else:
+ pass
+
+ def text_to_clipboard(self):
+ app_id = self.active_apparat
+ text = f"SQ=select distinct akkey from aupr01 where aufst='{app_id}' union select pr_isn from aks4pd where akruf ='{app_id}'"
+ clipboard = QtWidgets.QApplication.clipboard()
+ clipboard.setText(text)
+
+ def populate_prof_dropdown(self):
+ profs = self.db.getProfs()
+ # add empty entry to dropdown and set it as current
+ self.drpdwn_prof_name.addItem("Kein Name")
+ for prof in profs:
+ self.drpdwn_prof_name.addItem(f"{prof[3]}, {prof[2]}")
+
+ def add_document(self):
+ print("Add document")
+ picker = FilePicker()
+ files = picker.pick_files()
+
+ for file in files:
+ print(file)
+ filename = file.split("/")[-1]
+ filetype = filename.split(".")[-1]
+ self.dokument_list.insertRow(0)
+ self.dokument_list.setItem(0, 0, QtWidgets.QTableWidgetItem(filename))
+ self.dokument_list.setItem(0, 1, QtWidgets.QTableWidgetItem(filetype))
+ self.dokument_list.setItem(0, 2, QtWidgets.QTableWidgetItem("*"))
+ self.dokument_list.setItem(0, 3, QtWidgets.QTableWidgetItem(file))
+ # set tooltip of row 3 to the file path for each row
+ self.dokument_list.item(0, 3).setToolTip(file)
+
+ # self.db.insert_file(files, self.active_apparat, self.db.get_prof_id(self.drpdwn_prof_name.currentText()))
+
+ def open_document(self):
+ _selected_doc_name = ""
+ _selected_doc_filetype = ""
+ try:
+ _selected_doc_name = self.dokument_list.item(
+ self.dokument_list.currentRow(), 0
+ ).text()
+ _selected_doc_location = self.dokument_list.item(
+ self.dokument_list.currentRow(), 3
+ ).text()
+ _selected_doc_filetype = self.dokument_list.item(
+ self.dokument_list.currentRow(), 1
+ ).text()
+ except AttributeError:
+ self.confirm_popup("Bitte erst ein Dokument auswählen!")
+ return
+ if not _selected_doc_location == "Database":
+ path = Path(_selected_doc_location)
+ path: Path = path + "/" + _selected_doc_name
+ if os.getenv("OS") == "Windows_NT":
+ path = path.resolve()
+ os.startfile(path)
+ else:
+ path = path.resolve()
+ os.system(f"open {path}")
+ else:
+ recreateFile(
+ _selected_doc_name, self.active_apparat, filetype=_selected_doc_filetype
+ )
+ # # if ~ in path, replace it with the home directory
+ # if "~" in path:
+ # path = path.replace("~", str(Path.home()))
+ # path = Path(path)
+
+ def add_media_from_file(self):
+ def __open_dialog(signatures):
+ dialog = QtWidgets.QDialog()
+ frame = parsed_titles_ui()
+ frame.setupUi(dialog)
+ dialog.show()
+ frame.signatures = signatures
+ frame.populate_table()
+ frame.progressBar.setMaximum(len(signatures))
+ frame.progressBar.setValue(0)
+ frame.progressBar.show()
+ frame.count.setText(str(len(signatures)))
+ frame.toolButton.click()
+ data = frame.return_data()
+ print(data)
+ # if no data was returned, return
+
+ return data
+ # get
+
+ # if files are in the table, and are selected, check for books in the file
+ if self.dokument_list.rowCount() == 0:
+ return
+ else:
+ # if file is selected, check for books in the file
+ if self.dokument_list.currentRow() != -1:
+ print("File selected")
+ file = self.dokument_list.item(
+ self.dokument_list.currentRow(), 3
+ ).text()
+
+ file_type = self.dokument_list.item(
+ self.dokument_list.currentRow(), 1
+ ).text()
+ file_location = self.dokument_list.item(
+ self.dokument_list.currentRow(), 3
+ ).text()
+ file_name = self.dokument_list.item(
+ self.dokument_list.currentRow(), 0
+ ).text()
+ if file_location == "Database":
+ # create a temporaty file to use, delete it after use
+ temp_file = tempfile.NamedTemporaryFile(
+ delete=False, suffix="." + file_type
+ )
+ temp_file.write(
+ self.db.getBlob(file_name, int(self.active_apparat))
+ )
+ temp_file.close()
+ file = temp_file.name
+ print(file)
+ if file_type == "pdf":
+ # Todo: implement parser here
+ self.confirm_popup("PDF Dateien werden nochnicht unterstützt!")
+ return
+ if file_type == "csv":
+ signatures = csv_to_list(file)
+ data = __open_dialog(signatures)
+ # get the app_id and prof_id
+ app_id = self.active_apparat
+ prof_id = self.db.getProfId(self.drpdwn_prof_name.currentText())
+ # add the data to the database
+ for book in data:
+ if type(book) != BookData:
+ continue
+ self.db.addBookToDatabase(
+ bookdata=book, app_id=app_id, prof_id=prof_id
+ )
+ if file_type == "docx":
+ data = word_docx_to_csv(file)
+ signatures = [
+ i
+ for i in data["Standnummer"].values
+ if i != "\u2002\u2002\u2002\u2002\u2002"
+ ]
+ data = __open_dialog(signatures)
+ # if no data was returned, return
+ if data == []:
+ return
+ # get the app_id and prof_id
+ app_id = self.active_apparat
+ prof_id = self.db.getProfId(self.drpdwn_prof_name.currentText())
+ # add the data to the database
+ for book in data:
+ if type(book) != BookData:
+ continue
+ self.db.addBookToDatabase(
+ bookdata=book, app_id=app_id, prof_id=prof_id
+ )
+ self.update_app_media_list()
+ print(len(signatures))
+
+ def btn_check_file_threaded(self):
+ print("Checking file")
+ # get active app_id and prof_id
+ self.tableWidget_apparate.setEnabled(False)
+ self.tableWidget_apparate.setToolTip(
+ "Bitte warten, bis alle Medien hinzugefügt wurden"
+ )
+ app_id = self.active_apparat
+ prof_id = self.db.getProfId(self.drpdwn_prof_name.currentText())
+ # check if apparat in database
+
+ # if app_id not in database, create apparat
+ if not self.db.checkApparatExistsById(app_id):
+ # create apparat
+ print("Creating apparat")
+ self.btn_save_apparat()
+ if self.dokument_list.rowCount() == 0:
+ print("No file selected")
+ self.tableWidget_apparate.setEnabled(True)
+ self.tableWidget_apparate.setToolTip("")
+ return
+ else:
+ # if file is selected, check for books in the file
+ print("File selected")
+ file = self.dokument_list.item(self.dokument_list.currentRow(), 3).text()
+
+ file_type = self.dokument_list.item(
+ self.dokument_list.currentRow(), 1
+ ).text()
+ file_location = self.dokument_list.item(
+ self.dokument_list.currentRow(), 3
+ ).text()
+ file_name = self.dokument_list.item(
+ self.dokument_list.currentRow(), 0
+ ).text()
+ if file_location == "Database":
+ file = recreateFile(file_name, app_id, file_type, open=False)
+ else:
+ self.add_files()
+ if file_type == "pdf":
+ # Todo: implement parser here
+ self.confirm_popup("PDF Dateien werden noch nicht unterstützt!")
+ return
+ if file_type == "csv":
+ signatures = csv_to_list(file)
+ # add the data to the database
+ if file_type == "docx":
+ data = word_docx_to_csv(file)
+ signatures = [
+ i
+ for i in data["Standnummer"].values
+ if i != "\u2002\u2002\u2002\u2002\u2002"
+ ]
+
+ signatures = [i for i in signatures if i != ""]
+ # ic(signatures)
+ print("starting thread")
+ self.autoGrabber = BookGrabber(
+ mode="ARRAY", app_id=app_id, prof_id=prof_id, data=signatures
+ )
+ # grabber.mode = "ARRAY"
+ # grabber.data = signatures
+ # grabber.app_id = app_id
+ # grabber.prof_id = prof_id
+ # grabber.moveToThread(thread)
+ self.label_info.show()
+ self.progress_label.show()
+ self.line_2.show()
+ # grabber.finished.connect(thread.quit)
+ self.autoGrabber.finished.connect(self.autoGrabber.deleteLater)
+ self.autoGrabber.finished.connect(self.hide_progress_label)
+ self.autoGrabber.finished.connect(self.update_app_media_list)
+ self.autoGrabber.finished.connect(self.unlock_apparate)
+ self.autoGrabber.updateSignal.connect(self.update_progress_label)
+ # worker.finished.connect(worker.deleteLater)
+
+ self.autoGrabber.start()
+ # self.thread = thread
+ # kill grabber after completion
+ # self.grabbers.append(grabber)
+
+ def unlock_apparate(self):
+ self.tableWidget_apparate.setEnabled(True)
+ self.tableWidget_apparate.setToolTip("")
+
+ def btn_save_apparat(self):
+ def __clear_fields():
+ self.drpdwn_app_nr.clear()
+ self.prof_title.clear()
+ self.drpdwn_prof_name.clearMask()
+ self.app_name.clear()
+ self.prof_mail.clear()
+ self.prof_tel_nr.clear()
+ self.app_fach.setCurrentText("")
+ self.app_name.clear()
+ self.sem_year.clear()
+ self.dokument_list.setRowCount(0)
+ self.sem_winter.setChecked(False)
+ self.sem_sommer.setChecked(False)
+ self.check_eternal_app.setChecked(False)
+ self.prof_id_adis.clear()
+ self.prof_id_adis.clear()
+ self.apparat_id_adis.clear()
+ self.drpdwn_prof_name.clear()
+ self.tableWidget_apparat_media.setRowCount(0)
+ self.app_group_box.setEnabled(False)
+ self.groupBox_2.hide()
+ self.groupBox.hide()
+ self.check_send_mail.setChecked(False)
+ self.cancel_active_selection.setEnabled(False)
+
+ if not self.validate_fields():
+ self.confirm_popup("Bitte alle Pflichtfelder ausfüllen!")
+ return
+ appd = ApparatData()
+ appd.appnr = self.active_apparat
+ appd.prof_title = (
+ None if self.prof_title.text() == "" else self.prof_title.text()
+ )
+ appd.profname = self.drpdwn_prof_name.currentText()
+ appd.appname = self.app_name.text()
+ appd.semester = self.generateSemester()
+ appd.dauerapp = 1 if self.check_eternal_app.isChecked() else 0
+ appd.prof_tel = self.prof_tel_nr.text()
+ appd.prof_mail = self.prof_mail.text()
+ appd.app_fach = self.app_fach.currentText()
+ appd.erstellsemester = self.generateSemester()
+ appd.deleted = 0
+ appd.prof_adis_id = self.prof_id_adis.text()
+ appd.apparat_adis_id = self.apparat_id_adis.text()
+ if self.dokument_list.rowCount() > 0:
+ self.add_files()
+ if not self.validate_fields():
+ pass
+ self.db.createApparat(appd)
+ # if self.dokument_list.rowCount() > 0:
+ self.add_files()
+ appdata = self.db.getAllAparats()
+ # merge self.appdata and appdata, remove duplicates
+ self.apparats = list(set(self.apparats + appdata))
+ self.apparats = natsorted(self.apparats, key=lambda x: x[4], reverse=True)
+ self.update_apparat_list()
+
+ # self.btn_load_apparat()
+
+ if self.check_send_mail.isChecked():
+ self.contact_prof(
+ apparat=appd.appnr, mail="Information zum Semesterapparat"
+ )
+ __clear_fields()
+
+ def send_mail_preview(self):
+ pass
+
+ @property
+ def active_apparat(self):
+ return self.drpdwn_app_nr.currentText()
+
+ def add_files(self):
+ files = []
+ for i in range(self.dokument_list.rowCount()):
+ files.append(
+ {
+ "name": self.dokument_list.item(i, 0).text(),
+ "type": self.dokument_list.item(i, 1).text(),
+ "date": self.dokument_list.item(i, 2).text(),
+ "path": self.dokument_list.item(i, 3).text(),
+ }
+ )
+ self.dokument_list.item(i, 2).setText("")
+ self.db.insertFile(
+ files,
+ self.active_apparat,
+ self.db.getProfId(self.drpdwn_prof_name.currentText()),
+ )
+
+ def update_apparat_list(self):
+ # get a list of new apparats based on self.apparats and self.old_apparats
+ new_apparats = [
+ apparat for apparat in self.apparats if apparat not in self.old_apparats
+ ]
+ print(new_apparats)
+ # insert the new apparats into the table
+ for apparat in new_apparats:
+ self.insert_apparat_into_table(apparat)
+ # sort the table by apparat number using natural sorting
+ self.tableWidget_apparate.sortItems(0, QtCore.Qt.SortOrder.AscendingOrder)
+ self.old_apparats = self.apparats
+
+ def insert_apparat_into_table(self, apparat):
+ # ic(apparat)
+ def __dauer_check(apparat):
+ return "Ja" if apparat[7] == 1 else "Nein"
+
+ self.tableWidget_apparate.insertRow(0)
+ self.tableWidget_apparate.setItem(
+ 0, 0, QtWidgets.QTableWidgetItem(str(apparat[4]))
+ )
+ self.tableWidget_apparate.setItem(
+ 0, 1, QtWidgets.QTableWidgetItem(str(apparat[1]))
+ )
+ self.tableWidget_apparate.setItem(
+ 0,
+ 2,
+ QtWidgets.QTableWidgetItem(
+ self.db.getProfNameById(apparat[2], add_title=False)
+ ),
+ )
+ self.tableWidget_apparate.setItem(
+ 0,
+ 3,
+ QtWidgets.QTableWidgetItem(
+ str(apparat[8]) if apparat[8] is not None else apparat[5]
+ ),
+ )
+ self.tableWidget_apparate.setItem(
+ 0, 4, QtWidgets.QTableWidgetItem(__dauer_check(apparat))
+ )
+ self.tableWidget_apparate.setItem(
+ 0, 5, QtWidgets.QTableWidgetItem(str(apparat[13]))
+ )
+ self.logger.log_info(f"Inserted apparat {apparat[4]}")
+
+ def open_context_menu(self, position):
+ menu = QtWidgets.QMenu()
+ extend_action = menu.addAction("Verlängern")
+ contact_action = menu.addAction("Kontaktieren")
+ delete_action = menu.addAction("Löschen")
+ remind_action = menu.addAction("Erinnerung")
+ menu.addAction(extend_action)
+ menu.addActions([contact_action, delete_action, remind_action])
+ extend_action.triggered.connect(self.extend_apparat)
+ delete_action.triggered.connect(self.delete_apparat)
+ contact_action.triggered.connect(self.contact_prof)
+ remind_action.triggered.connect(self.reminder)
+ menu.exec(self.tableWidget_apparate.mapToGlobal(position))
+
+ def statistics_table_context_menu(self, position):
+ menu = QtWidgets.QMenu()
+ restore_action = menu.addAction("Wiederherstellen")
+ menu.addAction(restore_action)
+ restore_action.triggered.connect(self.restore_apparat)
+ menu.exec(self.tableWidget.mapToGlobal(position))
+
+ def restore_apparat(self):
+ row = self.tableWidget.currentRow()
+ apparat = self.tableWidget.item(row, 1).text()
+ ic(apparat)
+ apparat_id = self.db.getApparatId(apparat)
+ # restore the apparat
+ self.db.restoreApparat(apparat_id)
+ # update the table
+ self.reload()
+
+ def reminder(self):
+ self.logger.log_info("Opening reminder dialog")
+ dialog = QtWidgets.QDialog()
+ reminder = reminder_ui()
+ reminder.setupUi(dialog)
+ dialog.exec()
+ if dialog.result() == QtWidgets.QDialog.DialogCode.Accepted:
+ data = reminder.return_message()
+ print(data)
+ self.db.addMessage(
+ data,
+ self.active_user,
+ self.active_apparat if self.active_apparat != "" else None,
+ )
+ self.calendarWidget.setMessages([data])
+ self.calendarWidget.updateCells()
+ # self.db.update_bookdata(data, book_id)
+ # self.db.update_bookdata(data)
+ self.logger.log_info("Commited message to database")
+ # self.update_app_media_list()
+
+ def get_reminders(self):
+ messages = self.db.getMessages()
+ self.logger.log_info(f"Got {len(messages)} messages from database")
+ self.calendarWidget.setMessages(messages)
+ self.calendarWidget.updateCells()
+
+ def open_reminder(self):
+ # def __update_message():
+ # message_select = self.spin_select_message.value()
+ # try:
+ # message = messages[message_select - 1]
+ # except IndexError:
+ # self.message_frame.hide()
+ # return
+ # self.message_box.setText(message["message"])
+ # appnr = message["appnr"]
+ # appnr = "/" if appnr is None else str(appnr)
+ # self.line_app_info.setText(appnr)
+
+ def __delete_message(id):
+ print("trying to delete message", id)
+ self.db.deleteMessage(id)
+ #
+
+ selected_date = self.calendarWidget.selectedDate().toString("yyyy-MM-dd")
+ # print(selected_date)
+ messages = self.db.getMessages(selected_date)
+ if messages == []:
+ # self.message_frame.hide() if self.message_frame.isVisible() else None
+ return
+ # print(messages)
+ # message_count = len(messages)
+ # self.spin_select_message.setMaximum(message_count)
+ # self.message_frame.show()
+ # self.label_total_day_messages.setText("/ " + str(message_count))
+ # # if there is only one message, disable the spinbox
+ # (
+ # self.spin_select_message.setEnabled(False)
+ # if message_count == 1
+ # else self.spin_select_message.setEnabled(True)
+ # )
+ # self.spin_select_message.setValue(1)
+ # # load the first message
+ # __update_message()
+ # # on valuechanged, update the message
+ # self.spin_select_message.valueChanged.connect(__update_message)
+ # self.btn_delete_message.clicked.connect(__delete_message)
+ dialog = CalendarEntry(messages=messages)
+ # append dialog to self.frame_2
+ self.calendarlayout.addWidget(dialog)
+ # dialog.deleteSignal.connect(__delete_message)
+ # if selected_date is not None:
+ # dialog.repaintSignal.connect(
+ # lambda: self.calendarWidget.redraw(selected_date)
+ # )
+
+ def open_settings(self):
+ settings = Settings(self.active_user)
+ settings.exec()
+ if settings.result() == QtWidgets.QDialog.DialogCode.Accepted:
+ data = settings.return_data()
+ print(data)
+ OmegaConf.save(data, "config.yaml")
+ # re-load the config
+ OmegaConf.load("config.yaml")
+ self.logger.log_info("Saved settings to config.yaml")
+ self.reload()
+
+ def reload(self):
+ # create a new connection to the database, refresh table data and replace the old connection
+ self.db = Database()
+ self.apparats = self.db.getAllAparats(deleted=0)
+ self.apparats = natsorted(self.apparats, key=lambda x: x[4], reverse=True)
+ self.tableWidget_apparate.setRowCount(0)
+ for apparat in self.apparats:
+ self.insert_apparat_into_table(apparat)
+
+ def media_context_menu(self, position):
+ menu = QtWidgets.QMenu()
+ delete_action = menu.addAction("Löschen")
+ edit_action = menu.addAction("Bearbeiten")
+ menu.addAction(delete_action)
+ menu.addAction(edit_action)
+ delete_action.triggered.connect(self.delete_medium)
+ edit_action.triggered.connect(self.edit_medium)
+ menu.exec(self.tableWidget_apparat_media.mapToGlobal(position))
+
+ def edit_medium(self):
+ book = self.tableWidget_apparat_media.item(
+ self.tableWidget_apparat_media.currentRow(), 1
+ ).text()
+ data = self.db.getBookBasedOnSignature(
+ app_id=self.active_apparat,
+ signature=book,
+ prof_id=self.db.getProfId(self.drpdwn_prof_name.currentText()),
+ )
+ book_id = self.db.getBookIdBasedOnSignature(
+ self.active_apparat,
+ self.db.getProfId(self.drpdwn_prof_name.currentText()),
+ book,
+ )
+ widget = QtWidgets.QDialog()
+ bookedit = edit_bookdata_ui()
+ bookedit.setupUi(widget)
+ # change title of dialog
+ widget.setWindowTitle("Metadaten")
+ bookedit.populate_fields(data)
+ widget.exec()
+ if widget.result() == QtWidgets.QDialog.DialogCode.Accepted:
+ data = bookedit.get_data()
+ print(data)
+ self.db.updateBookdata(data, book_id)
+ # self.db.update_bookdata(data)
+ print("accepted")
+ self.update_app_media_list()
+ else:
+ return
+ pass
+
+ def delete_medium(self):
+ selected_apparat_id = self.tableWidget_apparate.item(
+ self.tableWidget_apparate.currentRow(), 0
+ ).text()
+ # check how many rows are selected
+ selected_rows = self.tableWidget_apparat_media.selectionModel().selectedRows()
+ if len(selected_rows) == 1:
+ signature = self.tableWidget_apparat_media.item(
+ self.tableWidget_apparat_media.currentRow(), 1
+ ).text()
+ book_id = self.db.getBookIdBasedOnSignature(
+ selected_apparat_id,
+ prof_id=self.db.getProfId(self.drpdwn_prof_name.currentText()),
+ signature=signature,
+ )
+ message = f'Soll das Medium "{self.tableWidget_apparat_media.item(self.tableWidget_apparat_media.currentRow(),0).text()}" wirklich gelöscht werden?'
+ state = self.confirm_popup(message)
+ print(state)
+ if state == 1:
+ self.db.deleteBook(book_id)
+ self.update_app_media_list()
+ self.contact_prof(mail="deleted")
+ pass
+ else:
+ # get all selected rows
+ ranges = self.tableWidget_apparat_media.selectedRanges()
+ rows = []
+ for r in ranges:
+ for row in range(r.topRow(), r.bottomRow() + 1):
+ rows.append(row)
+ print(rows)
+ message = f"Sollen die {len(rows)} Medien wirklich gelöscht werden?"
+ state = self.confirm_popup(message)
+ if state == 1:
+ for _ in rows:
+ signature = self.tableWidget_apparat_media.item(_, 1).text()
+ book_id = self.db.getBookIdBasedOnSignature(
+ selected_apparat_id,
+ prof_id=self.db.getProfId(self.drpdwn_prof_name.currentText()),
+ signature=signature,
+ )
+ self.db.deleteBook(book_id)
+ self.update_app_media_list()
+
+ def extend_apparat(self):
+ framework = QtWidgets.QDialog()
+ frame = App_Ext_Dialog()
+ frame.setupUi(framework)
+ frame.sem_year.setText(str(QtCore.QDate.currentDate().year()))
+ framework.exec()
+ # return data from dialog if ok is pressed
+ if framework.result() == QtWidgets.QDialog.DialogCode.Accepted:
+ data = frame.get_data()
+ print(data)
+ # return data
+ selected_apparat_id = self.tableWidget_apparate.item(
+ self.tableWidget_apparate.currentRow(), 0
+ ).text()
+ print(selected_apparat_id)
+ # update self.apparats with the new data
+ # find matching apparat
+ # for apparat in self.apparats:
+ # if apparat[4] == int(selected_apparat_id):
+ # apparat[5]=data["semester"]
+ # apparat[7]=data["dauerapp"]
+ # break
+ # self.old_apparats = self.apparats
+ self.db.setNewSemesterDate(
+ selected_apparat_id, data["semester"], dauerapp=data["dauerapp"]
+ )
+ else:
+ return
+
+ def contact_prof(self, apparat=None, mail=""):
+ print(apparat)
+ if self.active_apparat == "":
+ if apparat is False:
+ self.confirm_popup("Bitte erst einen Apparat auswählen!")
+ return
+ else:
+ # TODO: stuff
+ pass
+ else:
+ if apparat:
+ active_apparat_id = apparat
+ else:
+ active_apparat_id = self.drpdwn_app_nr.currentText()
+ print(active_apparat_id)
+ profname = self.drpdwn_prof_name.currentText().replace(",", "").split(" ")
+ profname = f"{profname[1]} {profname[0]}"
+ prof_id = self.db.getProfId(self.drpdwn_prof_name.currentText())
+ pmail = self.db.getSpecificProfData(prof_id, ["mail"])
+ # create a new thread to show the mail interface and send the mail
+ self.mail_thread = Mail_Dialog(
+ app_id=active_apparat_id,
+ prof_name=profname,
+ prof_mail=pmail,
+ app_name=self.app_name.text(),
+ app_subject=self.app_fach.currentText(),
+ )
+ self.mail_thread.show()
+
+ def delete_apparat(self):
+ selected_apparat_id = self.tableWidget_apparate.item(
+ self.tableWidget_apparate.currentRow(), 0
+ ).text()
+ message = f"Soll der Apparat {selected_apparat_id} wirklich gelöscht werden?"
+ state = self.confirm_popup(message)
+ print(state)
+ if state == 1:
+ self.db.deleteApparat(selected_apparat_id, generateSemesterByDate())
+ # delete the corresponding entry from self.apparats
+ for apparat in self.apparats:
+ if apparat[4] == int(selected_apparat_id):
+ self.apparats.remove(apparat)
+ break
+ self.old_apparats = self.apparats
+ print(self.apparats)
+ # remove the row from the table
+ self.tableWidget_apparate.removeRow(self.tableWidget_apparate.currentRow())
+ # send mail to prof
+ self.contact_prof(mail="deleted", apparat=selected_apparat_id)
+ # if state==QtWidgets.QDialog.DialogCode.Accepted:
+ # self.db.delete_apparat(selected_apparat_id)
+ # pass
+
+
+def launch_gui():
+ print("trying to login")
+ print("checking if database available")
+ # database = config.database.path + config.database.name
+ # print(database)
+ # if not os.path.exists(database):
+ # print("Database not found, creating new database")
+ # db = Database()
+ # db.create_database()
+ app = QtWidgets.QApplication(sys.argv)
+ login_dialog = QtWidgets.QDialog()
+ ui = login_ui()
+ ui.setupUi(login_dialog)
+ login_dialog.exec() # This will block until the dialog is closed
+
+ if ui.lresult == 1:
+ # if login is successful, open main window
+ # show login dialog
+ print(ui.lusername)
+ MainWindow = QtWidgets.QMainWindow()
+ aui = Ui(MainWindow, username=ui.lusername)
+
+ print(aui.active_user)
+ MainWindow.show()
+ # atexit.register()
+ atexit.register(tempdelete)
+ atexit.register(aui.validate_thread.quit)
+ sys.exit(app.exec())
+
+ elif ui.lresult == 0:
+ warning_dialog = QtWidgets.QMessageBox()
+ warning_dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
+ warning_dialog.setText("Invalid username or password. Please try again.")
+ warning_dialog.setWindowTitle("Login Failed")
+ warning_dialog.exec()
+ elif ui.lresult == 2:
+ # TODO: implement admin functionality here
+ """change passwords for apparats, change passwords for users, list users, create and delete users etc"""
+ # open a console window
+ # console = ""
+ print("admin")
+ atexit.register(tempdelete)
+
+
+if __name__ == "__main__":
+ print("This is the main window")
+ # app = QtWidgets.QApplication(sys.argv)
+ # window = MainWindow()
+ # app.exec()
+ # open login screen
+ launch_gui()
diff --git a/src/ui/widgets/calendar_entry.py b/src/ui/widgets/calendar_entry.py
index fb9bde2..6a3e514 100644
--- a/src/ui/widgets/calendar_entry.py
+++ b/src/ui/widgets/calendar_entry.py
@@ -30,22 +30,31 @@ class CalendarEntry(QtWidgets.QDialog, Ui_Dialog):
if self.messages[i] == message:
return self.messages[i]["id"]
+ def __message_index(self, id):
+ for i in range(len(self.messages)):
+ if self.messages[i]["id"] == id:
+ return i
+
def delete_message(self):
+ print(self.spin_select_message.value())
value = self.spin_select_message.value()
+ print(value)
if value > 0:
value = value - 1
message = self.messages[value]
-
+ print(message)
id = self.__get_id(message)
print("id", id)
- del self.messages[value - 1]
+ # del self.messages[value - 1]
self.spin_select_message.setMaximum(len(self.messages))
self.message_box.clear()
- if value > 0:
- self.set_message()
- self.deleteSignal.emit(id)
- else:
- return
+ self.set_message()
+
+ self.deleteSignal.emit(id)
+ self.messages.pop(self.__message_index(id))
+ if len(self.messages) == 0:
+ self.repaintSignal.emit()
+ self.close()
else:
#
self.repaintSignal.emit()