add statistics widget & code

This commit is contained in:
WorldTeacher
2024-06-12 09:51:56 +02:00
parent 74656535f6
commit f8e8e1fa18
3 changed files with 1254 additions and 0 deletions

View File

@@ -0,0 +1,370 @@
from .widget_sources.Ui_search_statistic_page import Ui_Dialog
from PyQt6 import QtWidgets, QtGui
from PyQt6.QtCore import pyqtSignal
from src.backend import Database, generateSemesterByDate
from src.logic import custom_sort
from src import MyLogger
from src import Icon
from src.ui import DataGraph, Mail_Dialog, StatusWidget
from natsort import natsorted
from icecream import ic
class MyComboBox(QtWidgets.QComboBox):
def __init__(self, parent=None):
super().__init__(parent)
class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
apparat_open = pyqtSignal(str)
reloadSignal = pyqtSignal()
def __init__(self):
self.logger = MyLogger("search_statistic_page")
super().__init__()
self.setupUi(self)
self.book_search_result.horizontalHeader().setSectionResizeMode(
QtWidgets.QHeaderView.ResizeMode.Stretch
)
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.btn_search.clicked.connect(self.statistics)
self.book_search.clicked.connect(self.search_book)
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)
self.tableWidget.resizeColumnsToContents()
self.tableWidget.resizeRowsToContents()
self.db = Database()
self.populate_tab()
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.reloadSignal.emit()
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 tabW2_changed(self):
if self.tabWidget_2.currentIndex() == 0:
self.stackedWidget_4.setCurrentIndex(0)
else:
self.stackedWidget_4.setCurrentIndex(1)
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 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 gridchange(self):
print("gridchange")
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)
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 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, generateSemesterByDate())
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": generateSemesterByDate(),
}
params = {
key: value for key, value in params.items() if value is not None
} # remove empty lines to prevent errors
params = {
key: value for key, value in params.items() if value != "Alle"
} # remove empty lines to prevent errors
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)):
# 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 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
if self.dataLayout.count() > 0:
self.dataLayout.itemAt(0).widget().deleteLater()
self.dataLayout.itemAt(1).widget().deleteLater()
self.dataLayout.addWidget(created_status)
self.dataLayout.addWidget(deleted_status)
# self.setStatisticTableSize()
created_status.person_double_clicked.emit(self.apparat_open)
created_status.setToolTip("Doppelklick um den Semesterapparat zu öffnen")
deleted_status.setToolTip("Nur zur Übersicht")
# set deleted_status background to slightly gray
def show_ui():
app = QtWidgets.QApplication([])
window = SearchStatisticPage()
window.show()
app.exec()