diff --git a/.gitignore b/.gitignore index c511fc3..04a73a4 100644 --- a/.gitignore +++ b/.gitignore @@ -227,4 +227,4 @@ output config.yaml **/tempCodeRunnerFile.py uv.lock -uv.lock +logs/ \ No newline at end of file diff --git a/icons/print.svg b/icons/print.svg new file mode 100644 index 0000000..fefb7f0 --- /dev/null +++ b/icons/print.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py index b1a49c8..2661405 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,10 +1,11 @@ -import sys +__all__ = ["__version__", "__author__", "Icon", "settings"] from config import Config import os -from loguru import logger as log -from datetime import datetime + settings = Config("config/config.yaml") +if not os.path.exists(settings.database.temp): + os.mkdir(settings.database.temp) from .utils.icon import Icon __version__ = "0.2.1" @@ -14,14 +15,3 @@ __author__ = "Alexander Kirchner" if not os.path.exists("logs"): os.mkdir("logs") # open and close the file to create it -logger = log -logger.remove() -logger.add("logs/application.log", rotation="1 week", enqueue=True) -log.add( - f"logs/{datetime.now().strftime('%Y-%m-%d')}.log", - rotation="1 day", - compression="zip", -) - -# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO") -logger.add(sys.stdout) diff --git a/src/backend/create_file.py b/src/backend/create_file.py index ceeff20..3921624 100644 --- a/src/backend/create_file.py +++ b/src/backend/create_file.py @@ -5,9 +5,18 @@ from pathlib import Path from src.backend.database import Database db = Database() +import loguru +import sys + +log = loguru.logger +log.remove() +log.add("application.log", rotation="1 week", retention="1 month") +log.add( + sys.stdout, +) -def recreateFile(name, app_id, filetype, open=True) -> Path: +def recreateFile(name: str, app_id: int, filetype: str, open: bool = True) -> Path: """ recreateFile creates a file from the database and opens it in the respective program, if the open parameter is set to True. @@ -24,6 +33,7 @@ def recreateFile(name, app_id, filetype, open=True) -> Path: """ path = db.recreateFile(name, app_id, filetype=filetype) path = Path(path) + log.info(f"File created: {path}") if open: if os.getenv("OS") == "Windows_NT": path = path.resolve() diff --git a/src/backend/database.py b/src/backend/database.py index 16c13a9..c2dddf9 100644 --- a/src/backend/database.py +++ b/src/backend/database.py @@ -5,13 +5,12 @@ from pathlib import Path from src import settings from typing import Any, List, Optional, Tuple, Union import datetime -from src import logger + from src.backend.db import ( CREATE_ELSA_FILES_TABLE, CREATE_ELSA_MEDIA_TABLE, CREATE_ELSA_TABLE, CREATE_TABLE_APPARAT, - CREATE_TABLE_APPKONTOS, CREATE_TABLE_FILES, CREATE_TABLE_MEDIA, CREATE_TABLE_MESSAGES, @@ -25,6 +24,18 @@ from src.logic.constants import SEMAP_MEDIA_ACCOUNTS from src.utils import create_blob, dump_pickle, load_pickle from .semester import Semester from string import ascii_lowercase as lower, digits, punctuation +import sys +from loguru import logger as log + +logger = log +logger.remove() +logger.add("logs/application.log", rotation="1 week", enqueue=True) +log.add( + "logs/database.log", +) + +# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO") +logger.add(sys.stdout) ascii_lowercase = lower + digits + punctuation @@ -58,7 +69,7 @@ class Database: path = os.path.abspath(path) if not os.path.exists(path): # create path - # print(path) + # logger.debug(path) os.makedirs(path) if self.get_db_contents() == []: logger.critical("Database does not exist, creating tables") @@ -124,7 +135,6 @@ class Database: cursor.execute(CREATE_TABLE_APPARAT) cursor.execute(CREATE_TABLE_MESSAGES) cursor.execute(CREATE_TABLE_MEDIA) - cursor.execute(CREATE_TABLE_APPKONTOS) cursor.execute(CREATE_TABLE_FILES) cursor.execute(CREATE_TABLE_PROF) cursor.execute(CREATE_TABLE_USER) @@ -152,8 +162,11 @@ class Database: @logger.catch def query_db( - self, query: str, args: Tuple = (), one: bool = False - ) -> Union[Tuple, List[Tuple]]: + self, + query: str, + args: Tuple[Any, Any] = (), # type:ignore + one: bool = False, # type:ignore + ) -> Union[Tuple[Any, Any], List[Tuple[Any, Any]]]: """ Query the Database for the sent query. @@ -168,6 +181,7 @@ class Database: conn = self.connect() cursor = conn.cursor() logs_query = query + logs_args = args if "fileblob" in query: # set fileblob arg in logger to "too long" @@ -181,7 +195,7 @@ class Database: # log_message = f"Querying database with query {query}" if "INTO user" in query: log_message = f"Querying database with query {query}" - logger.debug(f"DB Query: {log_message}") + # logger.debug(f"DB Query: {log_message}") try: cursor.execute(query, args) rv = cursor.fetchall() @@ -204,6 +218,7 @@ class Database: app_id (str): The apparat id where the book should be added to prof_id (str): The id of the professor where the book should be added to. """ + logger.info(f"Adding book {bookdata.signature} to database") if app_id is None or prof_id is None: raise ValueError("Apparate ID or Prof ID is None") conn = self.connect() @@ -212,11 +227,11 @@ class Database: f"SELECT bookdata FROM media WHERE app_id={app_id} AND prof_id={prof_id}" ) logger.debug(t_query) - # # print(t_query) + # # logger.debug(t_query) result = cursor.execute(t_query).fetchall() result = [load_pickle(i[0]) for i in result] if bookdata in result: - # print("Bookdata already in database") + # logger.debug("Bookdata already in database") # check if the book was deleted in the apparat query = ( "SELECT deleted FROM media WHERE app_id=? AND prof_id=? AND bookdata=?" @@ -224,7 +239,7 @@ class Database: params = (app_id, prof_id, dump_pickle(bookdata)) result = cursor.execute(query, params).fetchone() if result[0] == 1: - # print("Book was deleted, updating bookdata") + # logger.debug("Book was deleted, updating bookdata") query = "UPDATE media SET deleted=0 WHERE app_id=? AND prof_id=? AND bookdata=?" params = (app_id, prof_id, dump_pickle(bookdata)) cursor.execute(query, params) @@ -387,7 +402,7 @@ class Database: def getBooks( self, app_id: Union[str, int], prof_id: Union[str, int], deleted=0 - ) -> list[dict[int, BookData, int]]: + ) -> list[dict[str, Union[BookData, int]]]: """ Get the Books based on the apparat id and the professor id @@ -406,14 +421,14 @@ class Database: if qdata is None: return [] for result_a in qdata: - data = {"id": int, "bookdata": BookData, "available": int} + data: dict[str, Any] = {"id": int, "bookdata": BookData, "available": int} data["id"] = result_a[0] data["bookdata"] = load_pickle(result_a[1]) data["available"] = result_a[2] ret_result.append(data) return ret_result - def updateBookdata(self, book_id, bookdata: BookData): + def updateBookdata(self, book_id: int, bookdata: BookData): """ Update the bookdata in the database @@ -435,7 +450,7 @@ class Database: self.query_db("UPDATE media SET deleted=1 WHERE id=?", (book_id,)) # File Interactions - def getBlob(self, filename, app_id: Union[str, int]): + def getBlob(self, filename: str, app_id: Union[str, int]) -> bytes: """ Get a blob from the database @@ -487,7 +502,7 @@ class Database: str: The filename of the recreated file """ blob = self.getBlob(filename, app_id) - tempdir = self.database.tempdir + tempdir = self.database.temp tempdir = tempdir.replace("~", str(Path.home())) tempdir_path = Path(tempdir) if not os.path.exists(tempdir_path): @@ -496,7 +511,7 @@ class Database: delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}" ) file.write(blob) - # print("file created") + # logger.debug("file created") return file.name def getFiles(self, app_id: Union[str, int], prof_id: int) -> list[tuple]: @@ -524,7 +539,7 @@ class Database: return [i[0] for i in data] def insertSubjects(self): - # print("Inserting subjects") + # logger.debug("Inserting subjects") subjects = [ "Biologie", "Chemie", @@ -693,6 +708,18 @@ class Database: query += " FROM prof WHERE id=?" return self.query_db(query, (prof_id,), one=True)[0] + def getProfById(self, prof_id: Union[str, int]) -> Prof: + """Get a professor based on the id + + Args: + prof_id (Union[str,int]): the id of the professor + + Returns: + Prof: a Prof object containing the data of the professor + """ + data = self.query_db("SELECT * FROM prof WHERE id=?", (prof_id,), one=True) + return Prof().from_tuple(data) + def getProfData(self, profname: str): """Get mail, telephone number and title of a professor based on the name @@ -868,7 +895,7 @@ class Database: self.query_db(query) return None - def getApparatsByProf(self, prof_id: Union[str, int]) -> list[tuple]: + def getApparatsByProf(self, prof_id: Union[str, int]) -> list[Apparat]: """Get all apparats based on the professor id Args: @@ -882,7 +909,7 @@ class Database: ) ret = [] for i in data: - print(i) + logger.debug(i) ret.append(Apparat().from_tuple(i)) return ret @@ -1095,9 +1122,9 @@ class Database: kwargs["dauer"] = kwargs["dauer"].replace("Ja", "1").replace("Nein", "0") query = "SELECT * FROM semesterapparat WHERE " for key, value in kwargs.items() if kwargs.items() is not None else {}: - # print(key, value) + # logger.debug(key, value) query += f"{key}='{value}' AND " - # print(query) + # logger.debug(query) # remove deletesemester part from normal query, as this will be added to the database upon deleting the apparat if "deletesemester" in kwargs.keys(): query = query.replace( @@ -1113,7 +1140,7 @@ class Database: query = query.replace( f"endsemester='{kwargs['endsemester']}' AND ", "xyz" ) - # print("replaced") + # logger.debug("replaced") query = query.replace( "xyz", f"(erstellsemester='{kwargs['endsemester']}' OR verlängerung_bis='{kwargs['endsemester']}') AND ", @@ -1128,9 +1155,9 @@ class Database: query = query[:-1] query = query.strip() - # print(query) + # logger.debug(query) res = __query(query) - # print(res) + # logger.debug(res) return res # Admin data @@ -1183,7 +1210,7 @@ class Database: "UPDATE user SET password=? WHERE username=?", (new_password, user) ) - def getRole(self, user): + def getRole(self, user: str) -> str: """get the role of the user Args: @@ -1299,15 +1326,15 @@ class Database: """ return self.query_db("SELECT titel, fname,lname,mail,telnr,fullname FROM prof") - def restoreApparat(self, app_id: Union[str, int]): + def restoreApparat(self, app_id: Union[str, int], app_name: str): """restore an apparat from the database Args: app_id (Union[str, int]): the id of the apparat """ return self.query_db( - "UPDATE semesterapparat SET deletion_status=0, deleted_date=NULL WHERE appnr=?", - (app_id,), + "UPDATE semesterapparat SET deletion_status=0, deleted_date=NULL WHERE appnr=? and name=?", + (app_id, app_name), ) # ELSA @@ -1418,8 +1445,8 @@ class Database: blob = self.query_db( "SELECT fileblob FROM elsa_files WHERE filename=?", (filename,), one=True )[0] - # print(blob) - tempdir = self.database.tempdir + # logger.debug(blob) + tempdir = self.database.temp tempdir = tempdir.replace("~", str(Path.home())) tempdir_path = Path(tempdir) if not os.path.exists(tempdir_path): @@ -1428,7 +1455,7 @@ class Database: delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}" ) file.write(blob) - # print("file created") + # logger.debug("file created") return file.name def getElsaApparats(self) -> ELSA: @@ -1437,9 +1464,11 @@ class Database: Returns: list[tuple]: a list of tuples containing the ELSA apparats """ - return self.query_db("SELECT * FROM elsa") + return self.query_db( + "SELECT * FROM elsa ORDER BY substr(date, 7, 4) || '-' || substr(date, 4, 2) || '-' || substr(date, 1, 2)" + ) - def getElsaId(self, prof_id, semester, date): + def getElsaId(self, prof_id: int, semester: str, date: str) -> int: """get the id of an ELSA apparat based on the professor, semester and date Args: @@ -1510,7 +1539,7 @@ class Database: else: return [] - def getProfId(self, profdata: dict | Prof): + def getProfId(self, profdata: dict[str, Any] | Prof): """Get the prof ID based on the profdata Args: @@ -1521,9 +1550,7 @@ class Database: """ conn = self.connect() cursor = conn.cursor() - if isinstance(profdata, Prof): - fullname = profdata.name() - else: + if isinstance(profdata, dict): name = profdata["profname"] if "," in name: fname = name.split(", ")[1].strip() @@ -1531,6 +1558,8 @@ class Database: fullname = f"{lname} {fname}" else: fullname = profdata["profname"] + else: + fullname = profdata.name() query = f"SELECT id FROM prof WHERE fullname = '{fullname}'" logger.debug(query) diff --git a/src/backend/db.py b/src/backend/db.py index 16cb35c..5416b90 100644 --- a/src/backend/db.py +++ b/src/backend/db.py @@ -12,7 +12,7 @@ CREATE_TABLE_APPARAT = """CREATE TABLE semesterapparat ( deleted_date TEXT, apparat_id_adis INTEGER, prof_id_adis INTEGER, - konto INTEGER REFERENCES app_kontos (id), + konto INTEGER, FOREIGN KEY (prof_id) REFERENCES prof (id) )""" CREATE_TABLE_MEDIA = """CREATE TABLE media ( @@ -26,13 +26,7 @@ CREATE_TABLE_MEDIA = """CREATE TABLE media ( FOREIGN KEY (prof_id) REFERENCES prof (id), FOREIGN KEY (app_id) REFERENCES semesterapparat (id) )""" -CREATE_TABLE_APPKONTOS = """CREATE TABLE app_kontos ( - id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - app_id INTEGER, - konto INTEGER, - passwort TEXT, - FOREIGN KEY (app_id) REFERENCES semesterapparat (id) - )""" + CREATE_TABLE_FILES = """CREATE TABLE files ( id INTEGER PRIMARY KEY, filename TEXT, diff --git a/src/backend/semester.py b/src/backend/semester.py index fadbae6..9185c0a 100644 --- a/src/backend/semester.py +++ b/src/backend/semester.py @@ -1,6 +1,16 @@ import datetime -from src import logger + from dataclasses import dataclass +import sys +from loguru import logger as log + +logger = log +logger.remove() +logger.add("logs/application.log", rotation="1 week", enqueue=True) + + +# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO") +logger.add(sys.stdout) @dataclass @@ -14,6 +24,7 @@ class Semester: logger.debug( f"Initialized Semester class with values: month: {_month}, semester: {_semester}, year {_year}" ) + def __post_init__(self): if isinstance(self._year, str): self._year = int(self._year) @@ -108,10 +119,16 @@ class Semester: return True return False - def from_string(self, val): - self.value = val - self._year = int(val[-2:]) - self._semester = val[:4] + def from_string(self, val: str): + if " " in val: + values = val.split(" ") + if len(values) != 2: + raise ValueError("Invalid semester format") + self._semester = values[0] + if len(values[1]) == 4: + self._year = int(values[1][2:]) + # self._year = int(values[1]) + self.computeValue() return self @property diff --git a/src/backend/thread_bookgrabber.py b/src/backend/thread_bookgrabber.py index 356b305..71752ba 100644 --- a/src/backend/thread_bookgrabber.py +++ b/src/backend/thread_bookgrabber.py @@ -1,55 +1,69 @@ -import sqlite3 - from PyQt6.QtCore import QThread from PyQt6.QtCore import pyqtSignal as Signal from src.backend import Database from src.logic.webrequest import BibTextTransformer, WebRequest +import sys +from loguru import logger as log + +logger = log +logger.remove() +logger.add("logs/bookgrabber_thread.log", rotation="1 week", enqueue=True) +log.add( + "logs/application.log", + rotation="1 day", + compression="zip", +) + +# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO") +logger.add(sys.stdout) class BookGrabber(QThread): updateSignal = Signal(int, int) done = Signal() - def __init__(self, appnr): + def __init__(self): super(BookGrabber, self).__init__(parent=None) self.is_Running = True logger.info("Starting worker thread") - self.data = None + self.data = [] self.app_id = None self.prof_id = None self.mode = None self.book_id = None self.use_any = False self.use_exact = False - self.appnr = appnr + self.app_id = None self.tstate = (self.app_id, self.prof_id, self.mode, self.data) + self.request = WebRequest() - def add_values(self, app_id, prof_id, mode, data, any_book=False, exact=False): + def add_values( + self, app_id: int, prof_id: int, mode: str, data, any_book=False, exact=False + ): self.app_id = app_id self.prof_id = prof_id self.mode = mode - self.data = data + self.data: list[str] = data self.use_any = any_book self.use_exact = exact logger.info(f"Working on {len(self.data)} entries") self.tstate = (self.app_id, self.prof_id, self.mode, self.data) logger.debug("State: " + str(self.tstate)) - # print(self.tstate) + self.request.set_apparat(self.app_id) + # logger.debug(self.tstate) def run(self): self.db = Database() item = 0 iterdata = self.data - # print(iterdata) - if self.prof_id is None: - self.prof_id = self.db.getProfNameByApparat(self.app_id) - for entry in iterdata: - # print(entry) - signature = str(entry) - logger.info("Processing entry: " + signature) + # logger.debug(iterdata) - webdata = WebRequest().set_apparat(self.appnr).get_ppn(entry) + for entry in iterdata: + # logger.debug(entry) + logger.info("Processing entry: {}", entry) + + webdata = self.request.get_ppn(entry) if self.use_any: webdata = webdata.use_any_book webdata = webdata.get_data() @@ -58,12 +72,12 @@ class BookGrabber(QThread): continue bd = BibTextTransformer(self.mode) - print(webdata) + logger.debug(webdata) if self.mode == "ARRAY": if self.use_exact: bd = bd.use_signature(entry) bd = bd.get_data(webdata).return_data() - print(bd) + logger.debug(bd) if bd is None: # bd = BookData continue @@ -79,17 +93,21 @@ class BookGrabber(QThread): logger.info("Added book to database") state = 0 for result in transformer.RDS_DATA: - # print(result.RDS_LOCATION) + # logger.debug(result.RDS_LOCATION) if str(self.app_id) in result.RDS_LOCATION: state = 1 break - logger.info(f"State of {signature}: {state}") - # print("updating availability of " + str(self.book_id) + " to " + str(state)) + logger.info(f"State of {entry}: {state}") + logger.debug( + "updating availability of " + str(self.book_id) + " to " + str(state) + ) try: self.db.setAvailability(self.book_id, state) - except sqlite3.OperationalError as e: + logger.debug("Added book to database") + except Exception as e: logger.error(f"Failed to update availability: {e}") + logger.debug("Failed to update availability: " + str(e)) # time.sleep(5) item += 1 @@ -102,87 +120,89 @@ class BookGrabber(QThread): self.is_Running = False -# class BookGrabber(object): -# updateSignal = Signal(int, int) -# done = Signal() +class BookGrabberTest(QThread): + updateSignal = Signal(int, int) + done = Signal() -# def __init__(self, app_id, prof_id, mode, data, parent=None): -# super(BookGrabber, self).__init__(parent=None) -# self.is_Running = True -# logger = MyLogger("Worker") -# logger.info("Starting worker thread") -# self.data = data -# logger.info(f"Working on {len(self.data)} entries") -# self.app_id = app_id -# self.prof_id = prof_id -# self.mode = mode -# self.book_id = None -# self.state = (self.app_id, self.prof_id, self.mode, self.data) -# # print(self.state) -# logger.info("state: " + str(self.state)) -# # time.sleep(2) + def __init__(self, appnr: int): + super(BookGrabberTest, self).__init__(parent=None) + self.is_Running = True + logger.info("Starting worker thread") + self.data = None + self.app_id = None + self.prof_id = None + self.mode = None + self.book_id = None + self.use_any = False + self.use_exact = False + self.app_id = appnr + self.tstate = (self.app_id, self.prof_id, self.mode, self.data) + self.results = [] -# def resetValues(self): -# self.app_id = None -# self.prof_id = None -# self.mode = None -# self.data = None -# self.book_id = None + def add_values( + self, app_id: int, prof_id: int, mode: str, data, any_book=False, exact=False + ): + self.app_id = app_id + self.prof_id = prof_id + self.mode = mode + self.data = data + self.use_any = any_book + self.use_exact = exact + logger.info(f"Working on {len(self.data)} entries") + self.tstate = (self.app_id, self.prof_id, self.mode, self.data) + logger.debug("State: " + str(self.tstate)) + # logger.debug(self.tstate) -# def run(self): -# while self.is_Running: -# self.db = Database() -# item = 0 -# iterdata = self.data -# # print(iterdata) -# for entry in iterdata: -# # print(entry) -# signature = str(entry) -# logger.info("Processing entry: " + signature) + def run(self): + item = 0 + iterdata = self.data + # logger.debug(iterdata) + for entry in iterdata: + # logger.debug(entry) + signature = str(entry) + logger.info("Processing entry: " + signature) -# webdata = WebRequest().get_ppn(entry).get_data() -# if webdata == "error": -# continue -# bd = BibTextTransformer(self.mode).get_data(webdata).return_data() -# transformer = BibTextTransformer("RDS") -# rds = transformer.get_data(webdata).return_data("rds_availability") -# bd.signature = entry -# # confirm lock is acquired -# self.db.addBookToDatabase(bd, self.app_id, self.prof_id) -# # get latest book id -# self.book_id = self.db.getLastBookId() -# logger.info("Added book to database") -# state = 0 -# # print(len(rds.items)) -# for rds_item in rds.items: -# sign = rds_item.superlocation -# loc = rds_item.location -# # logger.debug(sign, loc) -# # logger.debug(rds_item) -# if self.app_id in sign or self.app_id in loc: -# state = 1 -# break + webdata = WebRequest().set_apparat(self.app_id).get_ppn(entry) + if self.use_any: + webdata = webdata.use_any_book + webdata = webdata.get_data() -# logger.info(f"State of {signature}: {state}") -# # print( -# "updating availability of " -# + str(self.book_id) -# + " to " -# + str(state) -# ) -# try: -# self.db.setAvailability(self.book_id, state) -# except sqlite3.OperationalError as e: -# logger.error(f"Failed to update availability: {e}") + if webdata == "error": + continue -# # time.sleep(5) -# item += 1 -# self.updateSignal.emit(item, len(self.data)) -# logger.info("Worker thread finished") -# # self.done.emit() -# self.stop() -# if not self.is_Running: -# break + bd = BibTextTransformer(self.mode) + if self.mode == "ARRAY": + if self.use_exact: + bd = bd.use_signature(entry) + bd = bd.get_data(webdata).return_data() + if bd is None: + # bd = BookData + continue + bd.signature = entry + transformer = ( + BibTextTransformer("RDS").get_data(webdata).return_data("rds_data") + ) -# def stop(self): -# self.is_Running = False + # confirm lock is acquired + # get latest book id + logger.info("Added book to database") + state = 0 + for result in transformer.RDS_DATA: + # logger.debug(result.RDS_LOCATION) + if str(self.app_id) in result.RDS_LOCATION: + state = 1 + break + + logger.info(f"State of {signature}: {state}") + # logger.debug("updating availability of " + str(self.book_id) + " to " + str(state)) + self.results.append(bd) + + # time.sleep(5) + item += 1 + self.updateSignal.emit(item, len(self.data)) + logger.info("Worker thread finished") + # self.done.emit() + self.quit() + + def stop(self): + self.is_Running = False diff --git a/src/backend/threads_autoadder.py b/src/backend/threads_autoadder.py index ab1f31c..c5cd6b6 100644 --- a/src/backend/threads_autoadder.py +++ b/src/backend/threads_autoadder.py @@ -5,7 +5,19 @@ from PyQt6.QtCore import QThread from PyQt6.QtCore import pyqtSignal as Signal from src.backend import Database +from loguru import logger as log +import sys +logger = log +logger.remove() +logger.add("logs/application.log", rotation="1 week", enqueue=True) +log.add( + "logs/autoadder.log", + compression="zip", +) + +# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO") +logger.add(sys.stdout) # from src.transformers import RDS_AVAIL_DATA diff --git a/src/backend/threads_availchecker.py b/src/backend/threads_availchecker.py index bc981e9..4ae0e4e 100644 --- a/src/backend/threads_availchecker.py +++ b/src/backend/threads_availchecker.py @@ -9,6 +9,18 @@ from src.backend.database import Database from src.logic.webrequest import BibTextTransformer, WebRequest # from src.transformers import RDS_AVAIL_DATA +from loguru import logger as log +import sys + +logger = log +logger.remove() +logger.add("logs/application.log", rotation="1 week", enqueue=True) +log.add( + "logs/availthread.log", +) + +# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO") +logger.add(sys.stdout) class AvailChecker(QThread): diff --git a/src/logic/__init__.py b/src/logic/__init__.py index f139252..dc21d7a 100644 --- a/src/logic/__init__.py +++ b/src/logic/__init__.py @@ -2,5 +2,5 @@ from .dataclass import ApparatData, BookData, Prof, Apparat, ELSA from .c_sort import custom_sort, sort_semesters_list from .constants import APP_NRS, PROF_TITLES, SEMAP_MEDIA_ACCOUNTS from .csvparser import csv_to_list -from .wordparser import elsa_word_to_csv, word_docx_to_csv +from .wordparser import elsa_word_to_csv, word_docx_to_csv, word_to_semap, SemapDocument from .zotero import ZoteroController diff --git a/src/logic/webrequest.py b/src/logic/webrequest.py index 4a90e71..998d660 100644 --- a/src/logic/webrequest.py +++ b/src/logic/webrequest.py @@ -1,13 +1,28 @@ import requests from bs4 import BeautifulSoup -from src import logger + # import sleep_and_retry decorator to retry requests from ratelimit import limits, sleep_and_retry - +from typing import Union, Any, Literal, Optional from src.logic.dataclass import BookData from src.transformers import ARRAYData, BibTeXData, COinSData, RDSData, RISData +from src.transformers.transformers import RDS_AVAIL_DATA, RDS_GENERIC_DATA +import sys +from loguru import logger as log + +logger = log +logger.remove() +logger.add("logs/application.log", rotation="1 week", enqueue=True) +log.add( + f"logs/webrequest.log", + rotation="1 day", + compression="zip", +) + +# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO") +logger.add(sys.stdout) API_URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndexrecord/{}/" @@ -47,14 +62,14 @@ class WebRequest: logger.info("Using any book") return self - def set_apparat(self, apparat): + def set_apparat(self, apparat: int): self.apparat = apparat if int(self.apparat) < 10: self.apparat = f"0{self.apparat}" logger.info(f"Set apparat to {self.apparat}") return self - def get_ppn(self, signature): + def get_ppn(self, signature: str): self.signature = signature if "+" in signature: signature = signature.replace("+", "%2B") @@ -65,15 +80,15 @@ class WebRequest: @sleep_and_retry @limits(calls=RATE_LIMIT, period=RATE_PERIOD) - def search_book(self, searchterm: str): + def search_book(self, searchterm: str) -> str: response = requests.get(PPN_URL.format(searchterm), timeout=self.timeout) return response.text - def get_book_links(self, searchterm: str): - response = self.search_book(searchterm) + def get_book_links(self, searchterm: str) -> list[str]: + response: str = self.search_book(searchterm) # type:ignore soup = BeautifulSoup(response, "html.parser") links = soup.find_all("a", class_="title getFull") - res = [] + res: list[str] = [] for link in links: res.append(BASE + link["href"]) return res @@ -88,10 +103,12 @@ class WebRequest: logger.error(f"Request failed: {e}") return None - def get_data(self): + def get_data(self) -> Union[list[str], None]: links = self.get_book_links(self.ppn) + logger.debug(f"Links: {links}") + return_data: list[str] = [] for link in links: - result = self.search(link) + result: str = self.search(link) # type:ignore # in result search for class col-xs-12 rds-dl RDS_LOCATION # if found, return text of href soup = BeautifulSoup(result, "html.parser") @@ -101,9 +118,9 @@ class WebRequest: item_location = location.find( "div", class_="col-xs-12 col-md-7 col-lg-8 rds-dl-panel" ).text.strip() + logger.debug(f"Item location: {item_location}") if self.use_any: pre_tag = soup.find_all("pre") - return_data = [] if pre_tag: for tag in pre_tag: data = tag.text.strip() @@ -112,7 +129,7 @@ class WebRequest: else: logger.error("No
tag found")
raise ValueError("No tag found")
- if f"Semesterapparat-{self.apparat}" in item_location:
+ elif f"Semesterapparat-{self.apparat}" in item_location:
pre_tag = soup.find_all("pre")
return_data = []
if pre_tag:
@@ -123,6 +140,13 @@ class WebRequest:
else:
logger.error("No tag found")
return return_data
+ else:
+ logger.error(
+ f"Signature {self.signature} not found in {item_location}"
+ )
+ # return_data = []
+
+ return return_data
def get_data_elsa(self):
links = self.get_book_links(self.ppn)
@@ -170,7 +194,7 @@ class BibTextTransformer:
self.signature = signature
return self
- def get_data(self, data: list):
+ def get_data(self, data: Union[list[str]] = None) -> "BibTextTransformer":
RIS_IDENT = "TY -"
ARRAY_IDENT = "[kid]"
COinS_IDENT = "ctx_ver"
@@ -203,7 +227,15 @@ class BibTextTransformer:
self.data = line
return self
- def return_data(self, option=None) -> BookData:
+ def return_data(
+ self, option: Any = None
+ ) -> Union[
+ Optional[BookData],
+ Optional[RDS_GENERIC_DATA],
+ Optional[RDS_AVAIL_DATA],
+ None,
+ dict[str, Union[RDS_AVAIL_DATA, RDS_GENERIC_DATA]],
+ ]:
"""Return Data to caller.
Args:
@@ -225,7 +257,7 @@ class BibTextTransformer:
return RISData().transform(self.data)
case "RDS":
return RDSData().transform(self.data).return_data(option)
- case None:
+ case _:
return None
# if self.mode == "ARRAY":
@@ -242,7 +274,7 @@ class BibTextTransformer:
def cover(isbn):
test_url = f"https://www.buchhandel.de/cover/{isbn}/{isbn}-cover-m.jpg"
- # print(test_url)
+ # logger.debug(test_url)
data = requests.get(test_url, stream=True)
return data.content
@@ -252,8 +284,8 @@ def get_content(soup, css_class):
if __name__ == "__main__":
- # print("main")
+ # logger.debug("main")
link = "CU 8500 K64"
data = WebRequest(71).get_ppn(link).get_data()
bib = BibTextTransformer("ARRAY").get_data().return_data()
- print(bib)
+ logger.debug(bib)
diff --git a/src/logic/wordparser.py b/src/logic/wordparser.py
index d160ccf..69daa46 100644
--- a/src/logic/wordparser.py
+++ b/src/logic/wordparser.py
@@ -1,13 +1,112 @@
import pandas as pd
from docx import Document
+from dataclasses import dataclass
+import sys
+from loguru import logger as log
+from src.backend import Semester
+from typing import Union, Any
+
+logger = log
+logger.remove()
+logger.add("logs/wordparser.log", rotation="1 week", enqueue=True)
+log.add(
+ f"logs/application.log",
+ rotation="1 day",
+ compression="zip",
+ enqueue=True,
+)
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
+
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-def word_docx_to_csv(path) -> pd.DataFrame:
+@dataclass
+class Book:
+ author: str = None
+ year: str = None
+ edition: str = None
+ title: str = None
+ location: str = None
+ publisher: str = None
+ signature: str = None
+ internal_notes: str = None
+
+ @property
+ def has_signature(self) -> bool:
+ return self.signature is not None and self.signature != ""
+
+ @property
+ def is_empty(self) -> bool:
+ return all(
+ [
+ self.author == "",
+ self.year == "",
+ self.edition == "",
+ self.title == "",
+ self.location == "",
+ self.publisher == "",
+ self.signature == "",
+ self.internal_notes == "",
+ ]
+ )
+
+ def from_dict(self, data: dict[str, Any]):
+ for key, value in data.items():
+ value = value.strip()
+ if value == "\u2002\u2002\u2002\u2002\u2002":
+ value = ""
+
+ if key == "Autorenname(n):Nachname, Vorname":
+ self.author = value
+ elif key == "Jahr/Auflage":
+ self.year = value.split("/")[0] if "/" in value else value
+ self.edition = value.split("/")[1] if "/" in value else ""
+ elif key == "Titel":
+ self.title = value
+ elif key == "Ort und Verlag":
+ self.location = value.split(",")[0] if "," in value else value
+ self.publisher = value.split(",")[1] if "," in value else ""
+ elif key == "Standnummer":
+ self.signature = value.strip()
+ elif key == "Interne Vermerke":
+ self.internal_notes = value
+
+
+@dataclass
+class SemapDocument:
+ subject: str = None
+ phoneNumber: int = None
+ mail: str = None
+ title: str = None
+ semester: Union[str, Semester] = None
+ books: list[Book] = None
+ eternal: bool = False
+ personName: str = None
+ personTitle: str = None
+
+ @property
+ def renameSemester(self) -> None:
+ if ", Dauer" in self.semester:
+ self.semester = self.semester.split(",")[0]
+ self.eternal = True
+ self.semester = Semester().from_string(self.semester)
+ else:
+ logger.warning("Semester {} is not valid", self.semester)
+ self.semester = None
+
+ @property
+ def signatures(self) -> list[str]:
+ if self.books is not None:
+ return [book.signature for book in self.books if book.has_signature]
+ return []
+
+
+def word_docx_to_csv(path: str) -> list[pd.DataFrame]:
doc = Document(path)
tables = doc.tables
-
m_data = []
for table in tables:
data = []
@@ -24,8 +123,9 @@ def word_docx_to_csv(path) -> pd.DataFrame:
m_data.append(df)
- df = m_data[2]
- return df
+ # for df[0, 1]: merge i and i+1 as key, value
+
+ return m_data
def makeDict():
@@ -87,7 +187,7 @@ def tuple_to_dict(tlist: tuple, type: str) -> dict:
return ret
-def elsa_word_to_csv(path):
+def elsa_word_to_csv(path: str):
doc = Document(path)
# # print all lines in doc
doctype = [para.text for para in doc.paragraphs if para.text != ""][-1]
@@ -98,18 +198,18 @@ def elsa_word_to_csv(path):
}
tables = doc.tables
- m_data = []
+ m_data: list[pd.DataFrame] = []
for table in tables:
- data = []
+ data: list[list[str]] = []
for row in table.rows:
- row_data = []
+ row_data: list[str] = []
for cell in row.cells:
text = cell.text
text = text.replace("\n", "")
text = text.replace("\u2002", "")
row_data.append(text)
data.append(row_data)
- df = pd.DataFrame(data)
+ df = pd.DataFrame(data)
df.columns = df.iloc[0]
df = df.iloc[1:]
m_data.append(df)
@@ -118,10 +218,54 @@ def elsa_word_to_csv(path):
data = [
row for row in df.itertuples(index=False, name=None) if row != tuples[doctype]
]
- # print(data)
+ # logger.debug(data)
return tuple_to_dict(data, doctype), doctype
+def word_to_semap(word_path: str) -> SemapDocument:
+ logger.info("Parsing Word Document {}", word_path)
+ semap = SemapDocument()
+ df = word_docx_to_csv(word_path)
+ apparatdata = df[0]
+ apparatdata = apparatdata.to_dict()
+
+ keys = list(apparatdata.keys())
+
+ appdata = {keys[i]: keys[i + 1] for i in range(0, len(keys), 2)}
+ semap.phoneNumber = appdata["Telefon:"]
+ semap.subject = appdata["Ihr Fach:"]
+ semap.mail = appdata["Mailadresse:"]
+ semap.personName = ",".join(appdata["Ihr Name und Titel:"].split(",")[:-1])
+ semap.personTitle = ",".join(appdata["Ihr Name und Titel:"].split(",")[-1:]).strip()
+ apparatdata = df[1]
+ apparatdata = apparatdata.to_dict()
+ keys = list(apparatdata.keys())
+ appdata = {keys[i]: keys[i + 1] for i in range(0, len(keys), 2)}
+ semap.title = appdata["Veranstaltung:"]
+ semap.semester = appdata["Semester:"]
+ semap.renameSemester
+ books = df[2]
+ booklist = []
+ for i in range(len(books)):
+ if books.iloc[i].isnull().all():
+ continue
+ data = books.iloc[i].to_dict()
+ book = Book()
+ book.from_dict(data)
+ if book.is_empty:
+ continue
+ elif not book.has_signature:
+ continue
+ else:
+ booklist.append(book)
+ logger.info("Found {} books", len(booklist))
+ semap.books = booklist
+
+ return semap
+
+
if __name__ == "__main__":
- else_df = elsa_word_to_csv("C:/Users/aky547/Desktop/Antrag ELSA Schweitzer.docx")
- # print(else_df)
+ else_df = elsa_word_to_csv(
+ "C:/Users/aky547/Desktop/ELSA_Bestellung Scann Der Westen und der Rest.docx"
+ )
+ print(else_df)
diff --git a/src/transformers/transformers.py b/src/transformers/transformers.py
index 5f8aa48..765a911 100644
--- a/src/transformers/transformers.py
+++ b/src/transformers/transformers.py
@@ -7,8 +7,20 @@ from dataclasses import field as dataclass_field
from typing import Any, List
-
from src.logic.dataclass import BookData
+import sys
+from loguru import logger as log
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+log.add(
+ "logs/transformers.log",
+ enqueue=True,
+)
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
###Pydatnic models
@@ -131,7 +143,7 @@ class ARRAYData:
return data
except Exception:
- # # print(f"ARRAYData.transform failed, {source}, {search}")
+ # # logger.debug(f"ARRAYData.transform failed, {source}, {search}")
logger.exception(f"ARRAYData.transform failed, no string {search}")
return ""
@@ -509,4 +521,4 @@ if __name__ == "__main__":
ret = RDSData().transform(data)
data = ret.return_data("rds_availability")
- # print(data)
+ # logger.debug(data)
diff --git a/src/ui/__init__.py b/src/ui/__init__.py
index 620967d..0867516 100644
--- a/src/ui/__init__.py
+++ b/src/ui/__init__.py
@@ -1,6 +1,6 @@
import pathlib
-from .Ui_semesterapparat_ui import Ui_MainWindow as Ui_Semesterapparat
+from .semesterapparat_ui_ui import Ui_MainWindow as Ui_Semesterapparat
# from .dialogs import (
# ApparatExtendDialog,
diff --git a/src/ui/dialogs/dialog_sources/documentprint.ui b/src/ui/dialogs/dialog_sources/documentprint.ui
new file mode 100644
index 0000000..c4b85aa
--- /dev/null
+++ b/src/ui/dialogs/dialog_sources/documentprint.ui
@@ -0,0 +1,233 @@
+
+
+ Dialog
+
+
+
+ 0
+ 0
+ 725
+ 623
+
+
+
+ Dialog
+
+
+ -
+
+
+
+ true
+
+
+
+ 1
+
+
+
+
+ 0
+ 0
+ 707
+ 545
+
+
+
+ Semesterapparatsübersicht
+
+
+ -
+
+
+
+ false
+
+
+
+ Mit dem Klick auf Okay wird eine Übersicht aller aktiven Semesterapparate erstellt und an den FollowME Drucker gesendet. Es kann bis zu 5 Minuten dauern, bis das Dokument im Drucker angezeigt wird.
+
+
+ true
+
+
+ 5
+
+
+
+ -
+
+
+ Dokument erstellen und drucken
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 707
+ 545
+
+
+
+ Semesterapparatsschilder
+
+
+ -
+
+ -
+
+
+
+ false
+
+
+
+ Hier kann das Dokument für die Semesterapparatsschilder erstellt werden. Hierfür müssen die entsprechenden Apparate ausgewählt werden. Mithilfe dieser wird das Dokument erstellt.
+
+
+ true
+
+
+
+ -
+
+ -
+
+
+ Dokument erstellen und drucken
+
+
+
+ -
+
+
+ Aktuelle Apparate laden
+
+
+
+ -
+
+
+ Expertenmodus
+
+
+
+
+
+
+
+ -
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ false
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+hr { height: 1px; border-width: 0; }
+li.unchecked::marker { content: "\2610"; }
+li.checked::marker { content: "\2612"; }
+</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:700; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">SELECT</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> semesterapparat.name,</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> prof.lname</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">from</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> semesterapparat</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> INNER JOIN prof ON semesterapparat.prof_id = prof.id</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WHERE</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> (erstellsemester = 'SoSe 25'</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> OR erstellsemester = 'WiSe 24/25')</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> and semesterapparat.deletion_status = 0</p></body></html>
+
+
+
+ -
+
+
+ Anfragen und anzeigen
+
+
+
+
+
+
+
+
+ -
+
+
+
+ false
+
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+ AlignLeading|AlignVCenter
+
+
+
+
+ Name
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ui/dialogs/dialog_sources/documentprint_ui.py b/src/ui/dialogs/dialog_sources/documentprint_ui.py
new file mode 100644
index 0000000..2c10119
--- /dev/null
+++ b/src/ui/dialogs/dialog_sources/documentprint_ui.py
@@ -0,0 +1,143 @@
+# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\documentprint.ui'
+#
+# Created by: PyQt6 UI code generator 6.8.0
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic6 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt6 import QtCore, QtGui, QtWidgets
+
+
+class Ui_Dialog(object):
+ def setupUi(self, Dialog):
+ Dialog.setObjectName("Dialog")
+ Dialog.resize(725, 623)
+ self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.toolBox = QtWidgets.QToolBox(parent=Dialog)
+ font = QtGui.QFont()
+ font.setBold(True)
+ self.toolBox.setFont(font)
+ self.toolBox.setObjectName("toolBox")
+ self.page = QtWidgets.QWidget()
+ self.page.setGeometry(QtCore.QRect(0, 0, 707, 545))
+ self.page.setObjectName("page")
+ self.horizontalLayout = QtWidgets.QHBoxLayout(self.page)
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.label = QtWidgets.QLabel(parent=self.page)
+ font = QtGui.QFont()
+ font.setBold(False)
+ self.label.setFont(font)
+ self.label.setWordWrap(True)
+ self.label.setObjectName("label")
+ self.horizontalLayout.addWidget(self.label)
+ self.pushButton = QtWidgets.QPushButton(parent=self.page)
+ self.pushButton.setObjectName("pushButton")
+ self.horizontalLayout.addWidget(self.pushButton)
+ self.toolBox.addItem(self.page, "")
+ self.page_2 = QtWidgets.QWidget()
+ self.page_2.setGeometry(QtCore.QRect(0, 0, 707, 545))
+ self.page_2.setObjectName("page_2")
+ self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.page_2)
+ self.verticalLayout_2.setObjectName("verticalLayout_2")
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ self.label_2 = QtWidgets.QLabel(parent=self.page_2)
+ font = QtGui.QFont()
+ font.setBold(False)
+ self.label_2.setFont(font)
+ self.label_2.setWordWrap(True)
+ self.label_2.setObjectName("label_2")
+ self.horizontalLayout_2.addWidget(self.label_2)
+ self.verticalLayout_3 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_3.setObjectName("verticalLayout_3")
+ self.pushButton_2 = QtWidgets.QPushButton(parent=self.page_2)
+ self.pushButton_2.setObjectName("pushButton_2")
+ self.verticalLayout_3.addWidget(self.pushButton_2)
+ self.btn_load_current_apparats = QtWidgets.QPushButton(parent=self.page_2)
+ self.btn_load_current_apparats.setObjectName("btn_load_current_apparats")
+ self.verticalLayout_3.addWidget(self.btn_load_current_apparats)
+ self.expertMode = QtWidgets.QCheckBox(parent=self.page_2)
+ self.expertMode.setObjectName("expertMode")
+ self.verticalLayout_3.addWidget(self.expertMode)
+ self.horizontalLayout_2.addLayout(self.verticalLayout_3)
+ self.verticalLayout_2.addLayout(self.horizontalLayout_2)
+ self.frame = QtWidgets.QFrame(parent=self.page_2)
+ self.frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
+ self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
+ self.frame.setObjectName("frame")
+ self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.frame)
+ self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
+ self.horizontalLayout_3.setSpacing(0)
+ self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+ self.verticalLayout_4 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_4.setObjectName("verticalLayout_4")
+ self.textBrowser = QtWidgets.QTextBrowser(parent=self.frame)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.textBrowser.sizePolicy().hasHeightForWidth())
+ self.textBrowser.setSizePolicy(sizePolicy)
+ self.textBrowser.setReadOnly(False)
+ self.textBrowser.setObjectName("textBrowser")
+ self.verticalLayout_4.addWidget(self.textBrowser)
+ self.manualCheck = QtWidgets.QPushButton(parent=self.frame)
+ self.manualCheck.setObjectName("manualCheck")
+ self.verticalLayout_4.addWidget(self.manualCheck)
+ self.horizontalLayout_3.addLayout(self.verticalLayout_4)
+ self.verticalLayout_2.addWidget(self.frame)
+ self.tableWidget = QtWidgets.QTableWidget(parent=self.page_2)
+ font = QtGui.QFont()
+ font.setBold(False)
+ self.tableWidget.setFont(font)
+ self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
+ self.tableWidget.setObjectName("tableWidget")
+ self.tableWidget.setColumnCount(2)
+ self.tableWidget.setRowCount(0)
+ item = QtWidgets.QTableWidgetItem()
+ item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignVCenter)
+ self.tableWidget.setHorizontalHeaderItem(0, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(1, item)
+ self.tableWidget.horizontalHeader().setSortIndicatorShown(True)
+ self.tableWidget.horizontalHeader().setStretchLastSection(True)
+ self.verticalLayout_2.addWidget(self.tableWidget)
+ self.toolBox.addItem(self.page_2, "")
+ self.verticalLayout.addWidget(self.toolBox)
+
+ self.retranslateUi(Dialog)
+ self.toolBox.setCurrentIndex(1)
+ QtCore.QMetaObject.connectSlotsByName(Dialog)
+
+ def retranslateUi(self, Dialog):
+ _translate = QtCore.QCoreApplication.translate
+ Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
+ self.label.setText(_translate("Dialog", "Mit dem Klick auf Okay wird eine Übersicht aller aktiven Semesterapparate erstellt und an den FollowME Drucker gesendet. Es kann bis zu 5 Minuten dauern, bis das Dokument im Drucker angezeigt wird."))
+ self.pushButton.setText(_translate("Dialog", "Dokument erstellen und drucken"))
+ self.toolBox.setItemText(self.toolBox.indexOf(self.page), _translate("Dialog", "Semesterapparatsübersicht"))
+ self.label_2.setText(_translate("Dialog", "Hier kann das Dokument für die Semesterapparatsschilder erstellt werden. Hierfür müssen die entsprechenden Apparate ausgewählt werden. Mithilfe dieser wird das Dokument erstellt."))
+ self.pushButton_2.setText(_translate("Dialog", "Dokument erstellen und drucken"))
+ self.btn_load_current_apparats.setText(_translate("Dialog", "Aktuelle Apparate laden"))
+ self.expertMode.setText(_translate("Dialog", "Expertenmodus"))
+ self.textBrowser.setHtml(_translate("Dialog", "\n"
+"\n"
+"SELECT
\n"
+" semesterapparat.name,
\n"
+" prof.lname
\n"
+"from
\n"
+" semesterapparat
\n"
+" INNER JOIN prof ON semesterapparat.prof_id = prof.id
\n"
+"WHERE
\n"
+" (erstellsemester = \'SoSe 25\'
\n"
+" OR erstellsemester = \'WiSe 24/25\')
\n"
+" and semesterapparat.deletion_status = 0
"))
+ self.manualCheck.setText(_translate("Dialog", "Anfragen und anzeigen"))
+ item = self.tableWidget.horizontalHeaderItem(1)
+ item.setText(_translate("Dialog", "Name"))
+ self.toolBox.setItemText(self.toolBox.indexOf(self.page_2), _translate("Dialog", "Semesterapparatsschilder"))
diff --git a/src/ui/dialogs/docuprint.py b/src/ui/dialogs/docuprint.py
new file mode 100644
index 0000000..dea62ef
--- /dev/null
+++ b/src/ui/dialogs/docuprint.py
@@ -0,0 +1,152 @@
+from .dialog_sources.documentprint_ui import Ui_Dialog
+from PyQt6 import QtWidgets, QtCore
+from src import Icon
+
+from src.utils.richtext import SemapSchilder, SemesterDocument
+from src.backend import Semester, Database
+from natsort import natsorted
+
+
+class DocumentPrintDialog(QtWidgets.QDialog, Ui_Dialog):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.setupUi(self)
+ self.setWindowIcon(Icon("print").icon)
+ self.frame.hide()
+
+ self.semester = Semester()
+
+ self.db = Database()
+
+ self.insert_table_data()
+ self.expertMode.clicked.connect(self.enable_expert_mode)
+ # Ensure the signal is connected only once
+ try:
+ self.pushButton_2.clicked.disconnect()
+ except TypeError:
+ pass # Signal was not connected before
+ self.pushButton_2.clicked.connect(self.on_pushButton_2_clicked)
+
+ try:
+ self.pushButton.clicked.disconnect()
+ except TypeError:
+ pass
+ self.pushButton.clicked.connect(self.on_pushButton_clicked)
+
+ try:
+ self.btn_load_current_apparats.clicked.disconnect()
+ except TypeError:
+ pass
+ self.btn_load_current_apparats.clicked.connect(self.load_current_clicked)
+
+ try:
+ self.manualCheck.clicked.disconnect()
+ except TypeError:
+ pass
+ self.manualCheck.clicked.connect(self.manual_request)
+
+ def manual_request(self):
+ self.tableWidget.setRowCount(0)
+ request_text = self.textBrowser.toPlainText()
+ data = self.db.query_db(request_text)
+ apparats: list[str] = []
+ if not data:
+ self.tableWidget.setRowCount(0)
+ return
+ for row in data:
+ apparats.append(f"{row[1]} ({row[0]})")
+
+ self.tableWidget.setHorizontalHeaderLabels(["", "Semesterapparat"])
+ self.tableWidget.setColumnWidth(0, 50)
+ for entry in apparats:
+ # insert the entry, column 1 should be a checkbox, column 2 the data
+ self.tableWidget.insertRow(0)
+ self.tableWidget.setItem(0, 0, QtWidgets.QTableWidgetItem(""))
+ checkbox = QtWidgets.QCheckBox()
+
+ self.tableWidget.setCellWidget(0, 0, checkbox)
+
+ self.tableWidget.setItem(0, 1, QtWidgets.QTableWidgetItem(entry))
+ # align row 0 column 0 to center
+
+ def load_current_clicked(self):
+ entries = self.get_valid_apparats_for_signs()
+ self.tableWidget.setHorizontalHeaderLabels(["", "Semesterapparat"])
+ self.tableWidget.setColumnWidth(0, 50)
+ self.tableWidget.setRowCount(0)
+ for entry in entries:
+ # insert the entry, column 1 should be a checkbox, column 2 the data
+ self.tableWidget.insertRow(0)
+ self.tableWidget.setItem(0, 0, QtWidgets.QTableWidgetItem(""))
+ checkbox = QtWidgets.QCheckBox()
+
+ self.tableWidget.setCellWidget(0, 0, checkbox)
+
+ self.tableWidget.setItem(0, 1, QtWidgets.QTableWidgetItem(entry))
+
+ def enable_expert_mode(self):
+ # if self.exportMode.
+ if self.expertMode.isChecked():
+ self.frame.show()
+ self.expertMode.setText("Expertenmodus deaktivieren")
+ else:
+ self.frame.hide()
+ self.expertMode.setText("Expertenmodus aktivieren")
+
+ def on_pushButton_2_clicked(self):
+ # get the checked items from the table
+ checked_items = []
+ for i in range(self.tableWidget.rowCount()):
+ checkbox = self.tableWidget.cellWidget(i, 0)
+ if isinstance(checkbox, QtWidgets.QCheckBox) and checkbox.isChecked():
+ item = self.tableWidget.item(i, 1)
+ if item is not None:
+ checked_items.append(item.text())
+ document = SemapSchilder(checked_items)
+
+ def on_pushButton_clicked(self):
+ apparats: list[tuple[int, str]] = []
+ apps = self.db.getAllAparats(0)
+ apps = natsorted(apps, key=lambda x: x[4], reverse=True)
+ for app in apps:
+ prof = self.db.getProfById(app[2])
+ data = (app[4], f"{prof.lastname} ({app[1]})")
+ apparats.append(data)
+ semapDocument = SemesterDocument(
+ semester=self.semester.value,
+ filename="Semesterapparat",
+ full=True,
+ apparats=apparats,
+ )
+
+ def insert_table_data(self):
+ entries = self.get_valid_apparats_for_signs()
+ self.tableWidget.setHorizontalHeaderLabels(["", "Semesterapparat"])
+ self.tableWidget.setColumnWidth(0, 50)
+ for entry in entries:
+ # insert the entry, column 1 should be a checkbox, column 2 the data
+ self.tableWidget.insertRow(0)
+ self.tableWidget.setItem(0, 0, QtWidgets.QTableWidgetItem(""))
+ checkbox = QtWidgets.QCheckBox()
+
+ self.tableWidget.setCellWidget(0, 0, checkbox)
+
+ self.tableWidget.setItem(0, 1, QtWidgets.QTableWidgetItem(entry))
+ # align row 0 column 0 to center
+
+ def get_valid_apparats_for_signs(self):
+ this_sem = self.db.query_db(
+ query="SELECT prof.lname, semesterapparat.name from semesterapparat INNER JOIN prof ON semesterapparat.prof_id = prof.id WHERE (erstellsemester = ? OR erstellsemester = ?) AND semesterapparat.deletion_status=0",
+ args=(str(self.semester.value), str(self.semester.previous)),
+ )
+ apparats: list[str] = []
+ for row in this_sem:
+ apparats.append(f"{row[0]} ({row[1]})")
+ return apparats
+
+
+def launch():
+ app = QtWidgets.QApplication([])
+ dialog = DocumentPrintDialog()
+ dialog.show()
+ app.exec()
diff --git a/src/ui/dialogs/login.py b/src/ui/dialogs/login.py
index 74c9708..59a5a61 100644
--- a/src/ui/dialogs/login.py
+++ b/src/ui/dialogs/login.py
@@ -2,11 +2,22 @@ import hashlib
from PyQt6 import QtCore, QtWidgets
-from src import Icon, logger
+
from src.backend.admin_console import AdminCommands
from src.backend.database import Database
from .dialog_sources.Ui_login import Ui_Dialog
+import sys
+from loguru import logger as log
+from src import Icon
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
class LoginDialog(Ui_Dialog):
diff --git a/src/ui/dialogs/mail.py b/src/ui/dialogs/mail.py
index 8e9f3db..1a42836 100644
--- a/src/ui/dialogs/mail.py
+++ b/src/ui/dialogs/mail.py
@@ -3,11 +3,26 @@ import sys
from PyQt6 import QtWidgets
-from src import Icon, settings as config, logger
+from src import Icon, settings as config
from .dialog_sources.Ui_mail_preview import Ui_eMailPreview as MailPreviewDialog
from .mailTemplate import MailTemplateDialog
+import sys
+from loguru import logger as log
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+log.add(
+ "logs/mail.log",
+ rotation="1 day",
+ compression="zip",
+ enqueue=True,
+)
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
empty_signature = """
diff --git a/src/ui/dialogs/mailTemplate.py b/src/ui/dialogs/mailTemplate.py
index 15786b9..b2f0ce1 100644
--- a/src/ui/dialogs/mailTemplate.py
+++ b/src/ui/dialogs/mailTemplate.py
@@ -5,10 +5,25 @@ from PyQt6 import QtGui, QtWidgets, QtCore
from src import Icon
from .dialog_sources import NewMailTemplateDesignerDialog
-from src import logger
+
+import sys
+from loguru import logger as log
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+log.add(
+ f"logs/mail.log",
+ enqueue=True,
+)
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
+
class MailTemplateDialog(QtWidgets.QDialog, NewMailTemplateDesignerDialog):
updateSignal = QtCore.pyqtSignal()
+
def __init__(self, parent=None) -> None:
super().__init__(parent)
self.setupUi(self)
@@ -38,6 +53,7 @@ class MailTemplateDialog(QtWidgets.QDialog, NewMailTemplateDesignerDialog):
QtWidgets.QDialogButtonBox.StandardButton.Cancel
).clicked.connect(self.closeNow)
logger.info("Mail template dialog setup complete")
+
def save_template(self):
# print("save triggered")
# create a dialog to ask for the name of the template
diff --git a/src/ui/dialogs/parsed_titles.py b/src/ui/dialogs/parsed_titles.py
index ece3c57..be4f464 100644
--- a/src/ui/dialogs/parsed_titles.py
+++ b/src/ui/dialogs/parsed_titles.py
@@ -4,6 +4,13 @@ from src.backend import AutoAdder
from .dialog_sources.Ui_parsed_titles import Ui_Form
+import loguru
+import sys
+
+log = loguru.logger
+log.remove()
+log.add("application.log", rotation="1 week", retention="1 month")
+log.add(sys.stdout, level="INFO")
class ParsedTitles(QtWidgets.QWidget, Ui_Form):
@@ -33,7 +40,7 @@ class ParsedTitles(QtWidgets.QWidget, Ui_Form):
self.worker = None
def start(self):
- logger.info("Starting AutoAdder")
+ log.info("Starting AutoAdder")
self.worker = AutoAdder(
data=self.signatures,
@@ -52,8 +59,8 @@ class ParsedTitles(QtWidgets.QWidget, Ui_Form):
self.worker.start()
def on_completion(self):
- logger.info("AutoAdder finished")
- logger.info("Returning data")
+ log.info("AutoAdder finished")
+ log.info("Returning data")
# create a function that closes the dialog
@@ -62,7 +69,7 @@ class ParsedTitles(QtWidgets.QWidget, Ui_Form):
length = self.listWidget.count()
# print(f"Length of listWidget: {length}")
if length == 0:
- logger.info("AutoAdder finished")
+ log.info("AutoAdder finished")
self.buttonBox.accepted.emit()
def update_lists(self, signal):
diff --git a/src/ui/dialogs/settings.py b/src/ui/dialogs/settings.py
index 364f331..f83328e 100644
--- a/src/ui/dialogs/settings.py
+++ b/src/ui/dialogs/settings.py
@@ -1,7 +1,20 @@
from PyQt6 import QtCore, QtGui, QtWidgets
-from src import Icon, settings, logger
+from src import Icon, settings
from .dialog_sources.Ui_settings import Ui_Dialog as _settings
from src.ui.widgets.iconLine import IconWidget
+import sys
+from loguru import logger as log
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+log.add(
+ f"logs/settings.log",
+)
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
+
base = """'
diff --git a/src/ui/semesterapparat_ui.ui b/src/ui/semesterapparat_ui.ui
index 734317d..c458296 100644
--- a/src/ui/semesterapparat_ui.ui
+++ b/src/ui/semesterapparat_ui.ui
@@ -595,67 +595,6 @@
-
-
-
- 1110
- 120
- 131
- 51
-
-
-
-
- 9
- false
-
-
-
- Abhängig von der Anzahl der Medien kann die Suche sehr lange dauern
-
-
- Medien aus Dokument
- hinzufügen
-
-
-
-
-
- 1110
- 80
- 131
- 25
-
-
-
-
- 9
- false
-
-
-
- Dokument öffnen
-
-
-
-
-
- 1110
- 40
- 131
- 25
-
-
-
-
- 9
- false
-
-
-
- Dokument hinzufügen
-
-
@@ -1506,6 +1445,103 @@
Speichern und anlegen
+
+
+
+ 1110
+ 17
+ 131
+ 181
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 9
+ false
+
+
+
+ Dokument hinzufügen
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 9
+ false
+
+
+
+ Dokument öffnen
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 9
+ false
+
+
+
+ Abhängig von der Anzahl der Medien kann die Suche sehr lange dauern
+
+
+ Medien aus Dokument
+ hinzufügen
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 9
+ false
+
+
+
+ Die Apparatsdetails werden aus dem Dokument gelesen und eingetragen
+Einige Angaben müssen ggf angepasst werden
+
+
+ Daten aus Dokument
+übernehmen
+
+
+
+
+
diff --git a/src/ui/semesterapparat_ui_ui.py b/src/ui/semesterapparat_ui_ui.py
new file mode 100644
index 0000000..b4a1be2
--- /dev/null
+++ b/src/ui/semesterapparat_ui_ui.py
@@ -0,0 +1,1002 @@
+# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\semesterapparat_ui.ui'
+#
+# Created by: PyQt6 UI code generator 6.8.0
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic6 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt6 import QtCore, QtGui, QtWidgets
+
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("MainWindow")
+ MainWindow.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
+ MainWindow.setEnabled(True)
+ MainWindow.resize(1590, 800)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
+ MainWindow.setSizePolicy(sizePolicy)
+ MainWindow.setMinimumSize(QtCore.QSize(1278, 800))
+ MainWindow.setMaximumSize(QtCore.QSize(1590, 800))
+ MainWindow.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu)
+ icon = QtGui.QIcon()
+ icon.addPixmap(QtGui.QPixmap("c:\\Users\\aky547\\GitHub\\SemesterapparatsManager\\src\\ui\\../../../../../../icons/logo.ico"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
+ MainWindow.setWindowIcon(icon)
+ MainWindow.setStatusTip("")
+ self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
+ self.centralwidget.setSizePolicy(sizePolicy)
+ self.centralwidget.setObjectName("centralwidget")
+ self.verticalLayoutWidget = QtWidgets.QWidget(parent=self.centralwidget)
+ self.verticalLayoutWidget.setGeometry(QtCore.QRect(0, 0, 1271, 751))
+ self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
+ self.mainLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
+ self.mainLayout.setContentsMargins(0, 0, 0, 0)
+ self.mainLayout.setObjectName("mainLayout")
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.gridLayout = QtWidgets.QGridLayout()
+ self.gridLayout.setObjectName("gridLayout")
+ self.tabWidget = QtWidgets.QTabWidget(parent=self.verticalLayoutWidget)
+ self.tabWidget.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.tabWidget.setObjectName("tabWidget")
+ self.createApparat = QtWidgets.QWidget()
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.createApparat.sizePolicy().hasHeightForWidth())
+ self.createApparat.setSizePolicy(sizePolicy)
+ self.createApparat.setObjectName("createApparat")
+ self.horizontalLayoutWidget_2 = QtWidgets.QWidget(parent=self.createApparat)
+ self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(0, 0, 1261, 163))
+ self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2")
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_2)
+ self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ self.formLayout = QtWidgets.QFormLayout()
+ self.formLayout.setObjectName("formLayout")
+ self.verticalLayout_2 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_2.setObjectName("verticalLayout_2")
+ spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
+ self.verticalLayout_2.addItem(spacerItem)
+ self.create_document = QtWidgets.QPushButton(parent=self.horizontalLayoutWidget_2)
+ self.create_document.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.create_document.setObjectName("create_document")
+ self.verticalLayout_2.addWidget(self.create_document)
+ self.create_new_app = QtWidgets.QPushButton(parent=self.horizontalLayoutWidget_2)
+ self.create_new_app.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.create_new_app.setObjectName("create_new_app")
+ self.verticalLayout_2.addWidget(self.create_new_app)
+ self.cancel_active_selection = QtWidgets.QPushButton(parent=self.horizontalLayoutWidget_2)
+ self.cancel_active_selection.setEnabled(False)
+ self.cancel_active_selection.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.cancel_active_selection.setObjectName("cancel_active_selection")
+ self.verticalLayout_2.addWidget(self.cancel_active_selection)
+ spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
+ self.verticalLayout_2.addItem(spacerItem1)
+ self.formLayout.setLayout(1, QtWidgets.QFormLayout.ItemRole.LabelRole, self.verticalLayout_2)
+ self.tableWidget_apparate = QtWidgets.QTableWidget(parent=self.horizontalLayoutWidget_2)
+ self.tableWidget_apparate.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.tableWidget_apparate.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents)
+ self.tableWidget_apparate.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
+ self.tableWidget_apparate.setAlternatingRowColors(True)
+ self.tableWidget_apparate.setTextElideMode(QtCore.Qt.TextElideMode.ElideMiddle)
+ self.tableWidget_apparate.setObjectName("tableWidget_apparate")
+ self.tableWidget_apparate.setColumnCount(6)
+ self.tableWidget_apparate.setRowCount(0)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparate.setHorizontalHeaderItem(0, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparate.setHorizontalHeaderItem(1, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparate.setHorizontalHeaderItem(2, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparate.setHorizontalHeaderItem(3, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparate.setHorizontalHeaderItem(4, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparate.setHorizontalHeaderItem(5, item)
+ self.tableWidget_apparate.horizontalHeader().setCascadingSectionResizes(True)
+ self.formLayout.setWidget(1, QtWidgets.QFormLayout.ItemRole.FieldRole, self.tableWidget_apparate)
+ self.horizontalLayout_2.addLayout(self.formLayout)
+ self.line = QtWidgets.QFrame(parent=self.createApparat)
+ self.line.setGeometry(QtCore.QRect(0, 160, 1261, 21))
+ self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine)
+ self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
+ self.line.setObjectName("line")
+ self.gridLayoutWidget_2 = QtWidgets.QWidget(parent=self.createApparat)
+ self.gridLayoutWidget_2.setEnabled(True)
+ self.gridLayoutWidget_2.setGeometry(QtCore.QRect(0, 180, 1261, 511))
+ self.gridLayoutWidget_2.setObjectName("gridLayoutWidget_2")
+ self.gridLayout_2 = QtWidgets.QGridLayout(self.gridLayoutWidget_2)
+ self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
+ self.gridLayout_2.setObjectName("gridLayout_2")
+ self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_5.setObjectName("horizontalLayout_5")
+ spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_5.addItem(spacerItem2)
+ self.chkbx_show_del_media = QtWidgets.QCheckBox(parent=self.gridLayoutWidget_2)
+ self.chkbx_show_del_media.setObjectName("chkbx_show_del_media")
+ self.horizontalLayout_5.addWidget(self.chkbx_show_del_media)
+ spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_5.addItem(spacerItem3)
+ self.btn_reserve = QtWidgets.QPushButton(parent=self.gridLayoutWidget_2)
+ self.btn_reserve.setObjectName("btn_reserve")
+ self.horizontalLayout_5.addWidget(self.btn_reserve)
+ self.add_layout = QtWidgets.QHBoxLayout()
+ self.add_layout.setObjectName("add_layout")
+ self.label_info = QtWidgets.QLabel(parent=self.gridLayoutWidget_2)
+ self.label_info.setObjectName("label_info")
+ self.add_layout.addWidget(self.label_info)
+ self.line_2 = QtWidgets.QFrame(parent=self.gridLayoutWidget_2)
+ self.line_2.setFrameShape(QtWidgets.QFrame.Shape.VLine)
+ self.line_2.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
+ self.line_2.setObjectName("line_2")
+ self.add_layout.addWidget(self.line_2)
+ self.progress_label = QtWidgets.QLabel(parent=self.gridLayoutWidget_2)
+ self.progress_label.setObjectName("progress_label")
+ self.add_layout.addWidget(self.progress_label)
+ self.horizontalLayout_5.addLayout(self.add_layout)
+ spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_5.addItem(spacerItem4)
+ self.avail_layout = QtWidgets.QHBoxLayout()
+ self.avail_layout.setObjectName("avail_layout")
+ self.horizontalLayout_5.addLayout(self.avail_layout)
+ self.label_20 = QtWidgets.QLabel(parent=self.gridLayoutWidget_2)
+ self.label_20.setObjectName("label_20")
+ self.horizontalLayout_5.addWidget(self.label_20)
+ self.line_3 = QtWidgets.QFrame(parent=self.gridLayoutWidget_2)
+ self.line_3.setFrameShape(QtWidgets.QFrame.Shape.VLine)
+ self.line_3.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
+ self.line_3.setObjectName("line_3")
+ self.horizontalLayout_5.addWidget(self.line_3)
+ self.avail_status = QtWidgets.QLabel(parent=self.gridLayoutWidget_2)
+ self.avail_status.setObjectName("avail_status")
+ self.horizontalLayout_5.addWidget(self.avail_status)
+ self.automation_add_selected_books = QtWidgets.QPushButton(parent=self.gridLayoutWidget_2)
+ self.automation_add_selected_books.setObjectName("automation_add_selected_books")
+ self.horizontalLayout_5.addWidget(self.automation_add_selected_books)
+ spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_5.addItem(spacerItem5)
+ self.gridLayout_2.addLayout(self.horizontalLayout_5, 4, 0, 1, 1)
+ self.tableWidget_apparat_media = QtWidgets.QTableWidget(parent=self.gridLayoutWidget_2)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Expanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.tableWidget_apparat_media.sizePolicy().hasHeightForWidth())
+ self.tableWidget_apparat_media.setSizePolicy(sizePolicy)
+ self.tableWidget_apparat_media.setMinimumSize(QtCore.QSize(1259, 0))
+ self.tableWidget_apparat_media.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.tableWidget_apparat_media.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
+ self.tableWidget_apparat_media.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents)
+ self.tableWidget_apparat_media.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
+ self.tableWidget_apparat_media.setAlternatingRowColors(True)
+ self.tableWidget_apparat_media.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
+ self.tableWidget_apparat_media.setObjectName("tableWidget_apparat_media")
+ self.tableWidget_apparat_media.setColumnCount(7)
+ self.tableWidget_apparat_media.setRowCount(0)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparat_media.setHorizontalHeaderItem(0, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparat_media.setHorizontalHeaderItem(1, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparat_media.setHorizontalHeaderItem(2, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparat_media.setHorizontalHeaderItem(3, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparat_media.setHorizontalHeaderItem(4, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparat_media.setHorizontalHeaderItem(5, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.tableWidget_apparat_media.setHorizontalHeaderItem(6, item)
+ self.tableWidget_apparat_media.horizontalHeader().setCascadingSectionResizes(True)
+ self.gridLayout_2.addWidget(self.tableWidget_apparat_media, 9, 0, 1, 1)
+ self.label = QtWidgets.QLabel(parent=self.gridLayoutWidget_2)
+ font = QtGui.QFont()
+ font.setPointSize(11)
+ font.setBold(True)
+ self.label.setFont(font)
+ self.label.setObjectName("label")
+ self.gridLayout_2.addWidget(self.label, 2, 0, 1, 1)
+ self.app_group_box = QtWidgets.QGroupBox(parent=self.gridLayoutWidget_2)
+ self.app_group_box.setEnabled(True)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.app_group_box.sizePolicy().hasHeightForWidth())
+ self.app_group_box.setSizePolicy(sizePolicy)
+ self.app_group_box.setMinimumSize(QtCore.QSize(0, 210))
+ font = QtGui.QFont()
+ font.setPointSize(12)
+ font.setBold(True)
+ self.app_group_box.setFont(font)
+ self.app_group_box.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.app_group_box.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignVCenter)
+ self.app_group_box.setCheckable(False)
+ self.app_group_box.setObjectName("app_group_box")
+ self.document_list = QtWidgets.QTableWidget(parent=self.app_group_box)
+ self.document_list.setGeometry(QtCore.QRect(780, 20, 321, 181))
+ font = QtGui.QFont()
+ font.setPointSize(10)
+ font.setBold(False)
+ font.setKerning(False)
+ self.document_list.setFont(font)
+ self.document_list.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.document_list.setAcceptDrops(True)
+ self.document_list.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
+ self.document_list.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents)
+ self.document_list.setDragEnabled(True)
+ self.document_list.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.DragOnly)
+ self.document_list.setDefaultDropAction(QtCore.Qt.DropAction.LinkAction)
+ self.document_list.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection)
+ self.document_list.setObjectName("document_list")
+ self.document_list.setColumnCount(4)
+ self.document_list.setRowCount(0)
+ item = QtWidgets.QTableWidgetItem()
+ font = QtGui.QFont()
+ font.setFamily("Arial")
+ font.setPointSize(8)
+ item.setFont(font)
+ self.document_list.setHorizontalHeaderItem(0, item)
+ item = QtWidgets.QTableWidgetItem()
+ font = QtGui.QFont()
+ font.setFamily("Arial")
+ font.setPointSize(8)
+ item.setFont(font)
+ self.document_list.setHorizontalHeaderItem(1, item)
+ item = QtWidgets.QTableWidgetItem()
+ font = QtGui.QFont()
+ font.setFamily("Arial")
+ font.setPointSize(8)
+ item.setFont(font)
+ self.document_list.setHorizontalHeaderItem(2, item)
+ item = QtWidgets.QTableWidgetItem()
+ self.document_list.setHorizontalHeaderItem(3, item)
+ self.document_list.horizontalHeader().setDefaultSectionSize(107)
+ self.appname_mand = QtWidgets.QLabel(parent=self.app_group_box)
+ self.appname_mand.setGeometry(QtCore.QRect(330, 50, 16, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.appname_mand.setFont(font)
+ self.appname_mand.setObjectName("appname_mand")
+ self.profname_mand = QtWidgets.QLabel(parent=self.app_group_box)
+ self.profname_mand.setGeometry(QtCore.QRect(110, 110, 16, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.profname_mand.setFont(font)
+ self.profname_mand.setObjectName("profname_mand")
+ self.prof_title = QtWidgets.QLineEdit(parent=self.app_group_box)
+ self.prof_title.setGeometry(QtCore.QRect(120, 80, 71, 20))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.prof_title.setFont(font)
+ self.prof_title.setFocusPolicy(QtCore.Qt.FocusPolicy.ClickFocus)
+ self.prof_title.setObjectName("prof_title")
+ self.fach_mand = QtWidgets.QLabel(parent=self.app_group_box)
+ self.fach_mand.setGeometry(QtCore.QRect(510, 50, 47, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.fach_mand.setFont(font)
+ self.fach_mand.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.fach_mand.setObjectName("fach_mand")
+ self.btn_apparat_apply = QtWidgets.QPushButton(parent=self.app_group_box)
+ self.btn_apparat_apply.setGeometry(QtCore.QRect(360, 150, 75, 23))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.btn_apparat_apply.setFont(font)
+ self.btn_apparat_apply.setObjectName("btn_apparat_apply")
+ self.label_9 = QtWidgets.QLabel(parent=self.app_group_box)
+ self.label_9.setGeometry(QtCore.QRect(20, 160, 71, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.label_9.setFont(font)
+ self.label_9.setObjectName("label_9")
+ self.gridLayoutWidget_5 = QtWidgets.QWidget(parent=self.app_group_box)
+ self.gridLayoutWidget_5.setGeometry(QtCore.QRect(520, 30, 241, 61))
+ self.gridLayoutWidget_5.setObjectName("gridLayoutWidget_5")
+ self.gridLayout_6 = QtWidgets.QGridLayout(self.gridLayoutWidget_5)
+ self.gridLayout_6.setContentsMargins(0, 0, 0, 0)
+ self.gridLayout_6.setObjectName("gridLayout_6")
+ self.app_fach = QtWidgets.QComboBox(parent=self.gridLayoutWidget_5)
+ self.app_fach.setMaximumSize(QtCore.QSize(16777215, 25))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.app_fach.setFont(font)
+ self.app_fach.setEditable(True)
+ self.app_fach.setObjectName("app_fach")
+ self.gridLayout_6.addWidget(self.app_fach, 0, 1, 1, 1)
+ spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.gridLayout_6.addItem(spacerItem6, 0, 3, 1, 1)
+ self.valid_check_app_fach = QtWidgets.QToolButton(parent=self.gridLayoutWidget_5)
+ self.valid_check_app_fach.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.valid_check_app_fach.setText("")
+ self.valid_check_app_fach.setAutoRaise(True)
+ self.valid_check_app_fach.setArrowType(QtCore.Qt.ArrowType.NoArrow)
+ self.valid_check_app_fach.setObjectName("valid_check_app_fach")
+ self.gridLayout_6.addWidget(self.valid_check_app_fach, 0, 2, 1, 1)
+ self._mand = QtWidgets.QLabel(parent=self.app_group_box)
+ self._mand.setGeometry(QtCore.QRect(330, 90, 16, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self._mand.setFont(font)
+ self._mand.setObjectName("_mand")
+ self.prof_tel_nr = QtWidgets.QLineEdit(parent=self.app_group_box)
+ self.prof_tel_nr.setGeometry(QtCore.QRect(120, 160, 121, 20))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.prof_tel_nr.setFont(font)
+ self.prof_tel_nr.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhNone)
+ self.prof_tel_nr.setPlaceholderText("")
+ self.prof_tel_nr.setObjectName("prof_tel_nr")
+ self.check_eternal_app = QtWidgets.QCheckBox(parent=self.app_group_box)
+ self.check_eternal_app.setEnabled(False)
+ self.check_eternal_app.setGeometry(QtCore.QRect(340, 120, 101, 17))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.check_eternal_app.setFont(font)
+ self.check_eternal_app.setObjectName("check_eternal_app")
+ self.sem_sommer = QtWidgets.QCheckBox(parent=self.app_group_box)
+ self.sem_sommer.setGeometry(QtCore.QRect(340, 100, 82, 17))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.sem_sommer.setFont(font)
+ self.sem_sommer.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
+ self.sem_sommer.setObjectName("sem_sommer")
+ self.drpdwn_prof_name = QtWidgets.QComboBox(parent=self.app_group_box)
+ self.drpdwn_prof_name.setGeometry(QtCore.QRect(120, 110, 121, 22))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.drpdwn_prof_name.setFont(font)
+ self.drpdwn_prof_name.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
+ self.drpdwn_prof_name.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhNone)
+ self.drpdwn_prof_name.setEditable(True)
+ self.drpdwn_prof_name.setInsertPolicy(QtWidgets.QComboBox.InsertPolicy.InsertAlphabetically)
+ self.drpdwn_prof_name.setPlaceholderText("")
+ self.drpdwn_prof_name.setFrame(True)
+ self.drpdwn_prof_name.setObjectName("drpdwn_prof_name")
+ self.mail_mand = QtWidgets.QLabel(parent=self.app_group_box)
+ self.mail_mand.setGeometry(QtCore.QRect(110, 140, 47, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.mail_mand.setFont(font)
+ self.mail_mand.setObjectName("mail_mand")
+ self.label_3 = QtWidgets.QLabel(parent=self.app_group_box)
+ self.label_3.setGeometry(QtCore.QRect(20, 80, 61, 20))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.label_3.setFont(font)
+ self.label_3.setObjectName("label_3")
+ self.label_2 = QtWidgets.QLabel(parent=self.app_group_box)
+ self.label_2.setGeometry(QtCore.QRect(20, 50, 101, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.label_2.setFont(font)
+ self.label_2.setObjectName("label_2")
+ self.label_8 = QtWidgets.QLabel(parent=self.app_group_box)
+ self.label_8.setGeometry(QtCore.QRect(20, 140, 71, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.label_8.setFont(font)
+ self.label_8.setObjectName("label_8")
+ self.label_10 = QtWidgets.QLabel(parent=self.app_group_box)
+ self.label_10.setGeometry(QtCore.QRect(480, 50, 51, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.label_10.setFont(font)
+ self.label_10.setObjectName("label_10")
+ self.prof_mail = QtWidgets.QLineEdit(parent=self.app_group_box)
+ self.prof_mail.setGeometry(QtCore.QRect(120, 140, 121, 20))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.prof_mail.setFont(font)
+ self.prof_mail.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhEmailCharactersOnly)
+ self.prof_mail.setMaxLength(200)
+ self.prof_mail.setPlaceholderText("")
+ self.prof_mail.setObjectName("prof_mail")
+ self.formLayoutWidget_2 = QtWidgets.QWidget(parent=self.app_group_box)
+ self.formLayoutWidget_2.setGeometry(QtCore.QRect(560, 100, 211, 99))
+ self.formLayoutWidget_2.setObjectName("formLayoutWidget_2")
+ self.formLayout_3 = QtWidgets.QFormLayout(self.formLayoutWidget_2)
+ self.formLayout_3.setContentsMargins(0, 0, 0, 0)
+ self.formLayout_3.setObjectName("formLayout_3")
+ self.label_12 = QtWidgets.QLabel(parent=self.formLayoutWidget_2)
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.label_12.setFont(font)
+ self.label_12.setObjectName("label_12")
+ self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_12)
+ self.prof_id_adis = QtWidgets.QLineEdit(parent=self.formLayoutWidget_2)
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.prof_id_adis.setFont(font)
+ self.prof_id_adis.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhPreferNumbers)
+ self.prof_id_adis.setText("")
+ self.prof_id_adis.setObjectName("prof_id_adis")
+ self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.ItemRole.FieldRole, self.prof_id_adis)
+ self.label_13 = QtWidgets.QLabel(parent=self.formLayoutWidget_2)
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.label_13.setFont(font)
+ self.label_13.setObjectName("label_13")
+ self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_13)
+ self.apparat_id_adis = QtWidgets.QLineEdit(parent=self.formLayoutWidget_2)
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.apparat_id_adis.setFont(font)
+ self.apparat_id_adis.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhPreferNumbers)
+ self.apparat_id_adis.setObjectName("apparat_id_adis")
+ self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.ItemRole.FieldRole, self.apparat_id_adis)
+ self.sem_year = QtWidgets.QLineEdit(parent=self.app_group_box)
+ self.sem_year.setGeometry(QtCore.QRect(410, 90, 113, 20))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.sem_year.setFont(font)
+ self.sem_year.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
+ self.sem_year.setMaxLength(5)
+ self.sem_year.setObjectName("sem_year")
+ self.check_send_mail = QtWidgets.QCheckBox(parent=self.app_group_box)
+ self.check_send_mail.setGeometry(QtCore.QRect(450, 150, 91, 24))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.check_send_mail.setFont(font)
+ self.check_send_mail.setObjectName("check_send_mail")
+ self.sem_winter = QtWidgets.QCheckBox(parent=self.app_group_box)
+ self.sem_winter.setGeometry(QtCore.QRect(340, 80, 82, 17))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.sem_winter.setFont(font)
+ self.sem_winter.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
+ self.sem_winter.setObjectName("sem_winter")
+ self.label_4 = QtWidgets.QLabel(parent=self.app_group_box)
+ self.label_4.setGeometry(QtCore.QRect(20, 110, 71, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.label_4.setFont(font)
+ self.label_4.setObjectName("label_4")
+ self.telnr_mand = QtWidgets.QLabel(parent=self.app_group_box)
+ self.telnr_mand.setGeometry(QtCore.QRect(110, 160, 47, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.telnr_mand.setFont(font)
+ self.telnr_mand.setObjectName("telnr_mand")
+ self.btn_apparat_save = QtWidgets.QPushButton(parent=self.app_group_box)
+ self.btn_apparat_save.setGeometry(QtCore.QRect(270, 150, 75, 23))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.btn_apparat_save.setFont(font)
+ self.btn_apparat_save.setStatusTip("")
+ self.btn_apparat_save.setObjectName("btn_apparat_save")
+ self.label_5 = QtWidgets.QLabel(parent=self.app_group_box)
+ self.label_5.setGeometry(QtCore.QRect(250, 50, 91, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.label_5.setFont(font)
+ self.label_5.setObjectName("label_5")
+ self.app_name = QtWidgets.QLineEdit(parent=self.app_group_box)
+ self.app_name.setGeometry(QtCore.QRect(340, 50, 113, 20))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.app_name.setFont(font)
+ self.app_name.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
+ self.app_name.setObjectName("app_name")
+ self.drpdwn_app_nr = QtWidgets.QComboBox(parent=self.app_group_box)
+ self.drpdwn_app_nr.setGeometry(QtCore.QRect(120, 50, 69, 22))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.drpdwn_app_nr.setFont(font)
+ self.drpdwn_app_nr.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhNone)
+ self.drpdwn_app_nr.setEditable(True)
+ self.drpdwn_app_nr.setObjectName("drpdwn_app_nr")
+ self.label_6 = QtWidgets.QLabel(parent=self.app_group_box)
+ self.label_6.setGeometry(QtCore.QRect(270, 90, 61, 21))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.label_6.setFont(font)
+ self.label_6.setObjectName("label_6")
+ self.valid_check_profname = QtWidgets.QToolButton(parent=self.app_group_box)
+ self.valid_check_profname.setGeometry(QtCore.QRect(240, 110, 23, 22))
+ self.valid_check_profname.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.valid_check_profname.setText("")
+ self.valid_check_profname.setAutoRaise(True)
+ self.valid_check_profname.setArrowType(QtCore.Qt.ArrowType.NoArrow)
+ self.valid_check_profname.setObjectName("valid_check_profname")
+ self.valid_check_appname = QtWidgets.QToolButton(parent=self.app_group_box)
+ self.valid_check_appname.setGeometry(QtCore.QRect(450, 50, 22, 22))
+ self.valid_check_appname.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.valid_check_appname.setText("")
+ self.valid_check_appname.setAutoRaise(True)
+ self.valid_check_appname.setObjectName("valid_check_appname")
+ self.valid_check_semester = QtWidgets.QToolButton(parent=self.app_group_box)
+ self.valid_check_semester.setGeometry(QtCore.QRect(520, 90, 22, 22))
+ self.valid_check_semester.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.valid_check_semester.setText("")
+ self.valid_check_semester.setAutoRaise(True)
+ self.valid_check_semester.setObjectName("valid_check_semester")
+ self.valid_check_mail = QtWidgets.QToolButton(parent=self.app_group_box)
+ self.valid_check_mail.setGeometry(QtCore.QRect(240, 140, 22, 22))
+ self.valid_check_mail.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.valid_check_mail.setText("")
+ self.valid_check_mail.setAutoRaise(True)
+ self.valid_check_mail.setObjectName("valid_check_mail")
+ self.valid_check_telnr = QtWidgets.QToolButton(parent=self.app_group_box)
+ self.valid_check_telnr.setGeometry(QtCore.QRect(240, 160, 22, 22))
+ self.valid_check_telnr.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.valid_check_telnr.setText("")
+ self.valid_check_telnr.setAutoRaise(True)
+ self.valid_check_telnr.setObjectName("valid_check_telnr")
+ self.saveandcreate = QtWidgets.QPushButton(parent=self.app_group_box)
+ self.saveandcreate.setEnabled(False)
+ self.saveandcreate.setGeometry(QtCore.QRect(270, 180, 161, 24))
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.saveandcreate.setFont(font)
+ self.saveandcreate.setObjectName("saveandcreate")
+ self.verticalLayoutWidget_3 = QtWidgets.QWidget(parent=self.app_group_box)
+ self.verticalLayoutWidget_3.setGeometry(QtCore.QRect(1110, 17, 131, 181))
+ self.verticalLayoutWidget_3.setObjectName("verticalLayoutWidget_3")
+ self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_3)
+ self.verticalLayout_8.setContentsMargins(0, 0, 0, 0)
+ self.verticalLayout_8.setObjectName("verticalLayout_8")
+ self.btn_add_document = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_3)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.btn_add_document.sizePolicy().hasHeightForWidth())
+ self.btn_add_document.setSizePolicy(sizePolicy)
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.btn_add_document.setFont(font)
+ self.btn_add_document.setObjectName("btn_add_document")
+ self.verticalLayout_8.addWidget(self.btn_add_document)
+ self.btn_open_document = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_3)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.btn_open_document.sizePolicy().hasHeightForWidth())
+ self.btn_open_document.setSizePolicy(sizePolicy)
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.btn_open_document.setFont(font)
+ self.btn_open_document.setObjectName("btn_open_document")
+ self.verticalLayout_8.addWidget(self.btn_open_document)
+ self.check_file = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_3)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.check_file.sizePolicy().hasHeightForWidth())
+ self.check_file.setSizePolicy(sizePolicy)
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.check_file.setFont(font)
+ self.check_file.setObjectName("check_file")
+ self.verticalLayout_8.addWidget(self.check_file)
+ self.btn_extract_data_from_document = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_3)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.btn_extract_data_from_document.sizePolicy().hasHeightForWidth())
+ self.btn_extract_data_from_document.setSizePolicy(sizePolicy)
+ font = QtGui.QFont()
+ font.setPointSize(9)
+ font.setBold(False)
+ self.btn_extract_data_from_document.setFont(font)
+ self.btn_extract_data_from_document.setObjectName("btn_extract_data_from_document")
+ self.verticalLayout_8.addWidget(self.btn_extract_data_from_document)
+ self.verticalLayout_8.setStretch(0, 1)
+ self.verticalLayout_8.setStretch(1, 1)
+ self.verticalLayout_8.setStretch(2, 2)
+ self.verticalLayout_8.setStretch(3, 2)
+ self.gridLayout_2.addWidget(self.app_group_box, 1, 0, 1, 1)
+ self.add_medium = QtWidgets.QPushButton(parent=self.createApparat)
+ self.add_medium.setGeometry(QtCore.QRect(3, 695, 121, 20))
+ self.add_medium.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.add_medium.setObjectName("add_medium")
+ self.tabWidget.addTab(self.createApparat, "")
+ self.search_statistics = QtWidgets.QWidget()
+ self.search_statistics.setObjectName("search_statistics")
+ self.tabWidget.addTab(self.search_statistics, "")
+ self.elsatab = QtWidgets.QWidget()
+ self.elsatab.setObjectName("elsatab")
+ self.tabWidget.addTab(self.elsatab, "")
+ self.admin = QtWidgets.QWidget()
+ self.admin.setObjectName("admin")
+ self.label_21 = QtWidgets.QLabel(parent=self.admin)
+ self.label_21.setGeometry(QtCore.QRect(10, 30, 47, 22))
+ self.label_21.setObjectName("label_21")
+ self.select_action_box = QtWidgets.QComboBox(parent=self.admin)
+ self.select_action_box.setGeometry(QtCore.QRect(60, 30, 181, 22))
+ self.select_action_box.setObjectName("select_action_box")
+ self.select_action_box.addItem("")
+ self.select_action_box.addItem("")
+ self.select_action_box.addItem("")
+ self.admin_action = QtWidgets.QGroupBox(parent=self.admin)
+ self.admin_action.setGeometry(QtCore.QRect(10, 70, 570, 291))
+ font = QtGui.QFont()
+ font.setBold(False)
+ self.admin_action.setFont(font)
+ self.admin_action.setFlat(True)
+ self.admin_action.setCheckable(False)
+ self.admin_action.setObjectName("admin_action")
+ self.tabWidget.addTab(self.admin, "")
+ self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
+ self.horizontalLayout.addLayout(self.gridLayout)
+ self.mainLayout.addLayout(self.horizontalLayout)
+ self.verticalLayoutWidget_2 = QtWidgets.QWidget(parent=self.centralwidget)
+ self.verticalLayoutWidget_2.setGeometry(QtCore.QRect(1280, 0, 306, 751))
+ self.verticalLayoutWidget_2.setObjectName("verticalLayoutWidget_2")
+ self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_2)
+ self.verticalLayout.setContentsMargins(0, 0, 0, 0)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.calendar_frame = QtWidgets.QFrame(parent=self.verticalLayoutWidget_2)
+ self.calendar_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
+ self.calendar_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
+ self.calendar_frame.setObjectName("calendar_frame")
+ self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.calendar_frame)
+ self.verticalLayout_7.setObjectName("verticalLayout_7")
+ self.calendarlayout = QtWidgets.QVBoxLayout()
+ self.calendarlayout.setObjectName("calendarlayout")
+ self.verticalLayout_7.addLayout(self.calendarlayout)
+ self.verticalLayout.addWidget(self.calendar_frame)
+ self.frame_creation_progress = QtWidgets.QFrame(parent=self.verticalLayoutWidget_2)
+ self.frame_creation_progress.setObjectName("frame_creation_progress")
+ self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_creation_progress)
+ self.verticalLayout_4.setSpacing(6)
+ self.verticalLayout_4.setObjectName("verticalLayout_4")
+ self.steps = QtWidgets.QFrame(parent=self.frame_creation_progress)
+ self.steps.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
+ self.steps.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
+ self.steps.setObjectName("steps")
+ self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.steps)
+ self.verticalLayout_3.setSpacing(0)
+ self.verticalLayout_3.setObjectName("verticalLayout_3")
+ self.groupBox_2 = QtWidgets.QGroupBox(parent=self.steps)
+ self.groupBox_2.setEnabled(True)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.groupBox_2.sizePolicy().hasHeightForWidth())
+ self.groupBox_2.setSizePolicy(sizePolicy)
+ font = QtGui.QFont()
+ font.setPointSize(11)
+ font.setBold(True)
+ self.groupBox_2.setFont(font)
+ self.groupBox_2.setObjectName("groupBox_2")
+ self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.groupBox_2)
+ self.verticalLayout_6.setObjectName("verticalLayout_6")
+ self.appdata_check = QtWidgets.QCheckBox(parent=self.groupBox_2)
+ font = QtGui.QFont()
+ font.setPointSize(8)
+ font.setBold(False)
+ self.appdata_check.setFont(font)
+ self.appdata_check.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.appdata_check.setObjectName("appdata_check")
+ self.verticalLayout_6.addWidget(self.appdata_check)
+ self.media_check = QtWidgets.QCheckBox(parent=self.groupBox_2)
+ font = QtGui.QFont()
+ font.setPointSize(8)
+ font.setBold(False)
+ self.media_check.setFont(font)
+ self.media_check.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.media_check.setObjectName("media_check")
+ self.verticalLayout_6.addWidget(self.media_check)
+ self.ids_check = QtWidgets.QCheckBox(parent=self.groupBox_2)
+ font = QtGui.QFont()
+ font.setPointSize(8)
+ font.setBold(False)
+ self.ids_check.setFont(font)
+ self.ids_check.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.ids_check.setObjectName("ids_check")
+ self.verticalLayout_6.addWidget(self.ids_check)
+ self.verticalLayout_3.addWidget(self.groupBox_2)
+ self.groupBox = QtWidgets.QGroupBox(parent=self.steps)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth())
+ self.groupBox.setSizePolicy(sizePolicy)
+ font = QtGui.QFont()
+ font.setPointSize(11)
+ font.setBold(True)
+ self.groupBox.setFont(font)
+ self.groupBox.setObjectName("groupBox")
+ self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.groupBox)
+ self.verticalLayout_5.setObjectName("verticalLayout_5")
+ self.media_checked = QtWidgets.QCheckBox(parent=self.groupBox)
+ font = QtGui.QFont()
+ font.setPointSize(8)
+ font.setBold(False)
+ font.setItalic(False)
+ font.setUnderline(False)
+ font.setKerning(True)
+ font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferDefault)
+ self.media_checked.setFont(font)
+ self.media_checked.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.media_checked.setObjectName("media_checked")
+ self.verticalLayout_5.addWidget(self.media_checked)
+ self.media_edited_check = QtWidgets.QCheckBox(parent=self.groupBox)
+ font = QtGui.QFont()
+ font.setPointSize(8)
+ font.setBold(False)
+ font.setItalic(False)
+ font.setUnderline(False)
+ font.setKerning(True)
+ font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferDefault)
+ self.media_edited_check.setFont(font)
+ self.media_edited_check.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.media_edited_check.setObjectName("media_edited_check")
+ self.verticalLayout_5.addWidget(self.media_edited_check)
+ self.app_created = QtWidgets.QCheckBox(parent=self.groupBox)
+ font = QtGui.QFont()
+ font.setPointSize(8)
+ font.setBold(False)
+ font.setItalic(False)
+ font.setUnderline(False)
+ font.setKerning(True)
+ font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferDefault)
+ self.app_created.setFont(font)
+ self.app_created.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
+ self.app_created.setObjectName("app_created")
+ self.verticalLayout_5.addWidget(self.app_created)
+ self.btn_copy_adis_command = QtWidgets.QPushButton(parent=self.groupBox)
+ font = QtGui.QFont()
+ font.setPointSize(8)
+ font.setBold(False)
+ font.setItalic(False)
+ font.setUnderline(False)
+ font.setKerning(True)
+ font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferDefault)
+ self.btn_copy_adis_command.setFont(font)
+ self.btn_copy_adis_command.setStatusTip("")
+ self.btn_copy_adis_command.setWhatsThis("")
+ self.btn_copy_adis_command.setAccessibleDescription("")
+ self.btn_copy_adis_command.setAutoFillBackground(False)
+ icon1 = QtGui.QIcon()
+ icon1.addPixmap(QtGui.QPixmap("c:\\Users\\aky547\\GitHub\\SemesterapparatsManager\\src\\ui\\../../../../../../.designer/backup/icons/information.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
+ self.btn_copy_adis_command.setIcon(icon1)
+ self.btn_copy_adis_command.setCheckable(False)
+ self.btn_copy_adis_command.setChecked(False)
+ self.btn_copy_adis_command.setAutoDefault(False)
+ self.btn_copy_adis_command.setObjectName("btn_copy_adis_command")
+ self.verticalLayout_5.addWidget(self.btn_copy_adis_command)
+ self.verticalLayout_3.addWidget(self.groupBox)
+ self.verticalLayout_4.addWidget(self.steps)
+ self.verticalLayout.addWidget(self.frame_creation_progress)
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 1590, 22))
+ self.menubar.setObjectName("menubar")
+ self.menuDatei = QtWidgets.QMenu(parent=self.menubar)
+ self.menuDatei.setObjectName("menuDatei")
+ self.menuEinstellungen = QtWidgets.QMenu(parent=self.menubar)
+ self.menuEinstellungen.setObjectName("menuEinstellungen")
+ self.menuHelp = QtWidgets.QMenu(parent=self.menubar)
+ self.menuHelp.setObjectName("menuHelp")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusBar = QtWidgets.QStatusBar(parent=MainWindow)
+ self.statusBar.setObjectName("statusBar")
+ MainWindow.setStatusBar(self.statusBar)
+ self.actionBeenden = QtGui.QAction(parent=MainWindow)
+ self.actionBeenden.setMenuRole(QtGui.QAction.MenuRole.QuitRole)
+ self.actionBeenden.setShortcutVisibleInContextMenu(True)
+ self.actionBeenden.setObjectName("actionBeenden")
+ self.actionEinstellungen = QtGui.QAction(parent=MainWindow)
+ self.actionEinstellungen.setShortcutVisibleInContextMenu(True)
+ self.actionEinstellungen.setObjectName("actionEinstellungen")
+ self.actionDokumentation = QtGui.QAction(parent=MainWindow)
+ self.actionDokumentation.setShortcutContext(QtCore.Qt.ShortcutContext.ApplicationShortcut)
+ self.actionDokumentation.setObjectName("actionDokumentation")
+ self.actionAbout = QtGui.QAction(parent=MainWindow)
+ self.actionAbout.setMenuRole(QtGui.QAction.MenuRole.AboutRole)
+ self.actionAbout.setObjectName("actionAbout")
+ self.actionDokumentation_lokal = QtGui.QAction(parent=MainWindow)
+ self.actionDokumentation_lokal.setObjectName("actionDokumentation_lokal")
+ self.menuDatei.addAction(self.actionBeenden)
+ self.menuEinstellungen.addAction(self.actionEinstellungen)
+ self.menuHelp.addAction(self.actionDokumentation_lokal)
+ self.menuHelp.addAction(self.actionAbout)
+ self.menubar.addAction(self.menuDatei.menuAction())
+ self.menubar.addAction(self.menuEinstellungen.menuAction())
+ self.menubar.addAction(self.menuHelp.menuAction())
+ self.label_9.setBuddy(self.prof_tel_nr)
+ self.label_3.setBuddy(self.prof_title)
+ self.label_2.setBuddy(self.drpdwn_app_nr)
+ self.label_8.setBuddy(self.prof_mail)
+ self.label_10.setBuddy(self.app_fach)
+ self.label_12.setBuddy(self.prof_id_adis)
+ self.label_13.setBuddy(self.apparat_id_adis)
+ self.label_4.setBuddy(self.drpdwn_prof_name)
+ self.label_5.setBuddy(self.app_name)
+ self.label_6.setBuddy(self.sem_year)
+
+ self.retranslateUi(MainWindow)
+ self.tabWidget.setCurrentIndex(0)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+ MainWindow.setTabOrder(self.drpdwn_app_nr, self.drpdwn_prof_name)
+ MainWindow.setTabOrder(self.drpdwn_prof_name, self.prof_mail)
+ MainWindow.setTabOrder(self.prof_mail, self.prof_tel_nr)
+ MainWindow.setTabOrder(self.prof_tel_nr, self.app_name)
+ MainWindow.setTabOrder(self.app_name, self.app_fach)
+ MainWindow.setTabOrder(self.app_fach, self.sem_sommer)
+ MainWindow.setTabOrder(self.sem_sommer, self.sem_winter)
+ MainWindow.setTabOrder(self.sem_winter, self.sem_year)
+ MainWindow.setTabOrder(self.sem_year, self.check_eternal_app)
+ MainWindow.setTabOrder(self.check_eternal_app, self.btn_add_document)
+ MainWindow.setTabOrder(self.btn_add_document, self.btn_open_document)
+ MainWindow.setTabOrder(self.btn_open_document, self.check_file)
+ MainWindow.setTabOrder(self.check_file, self.check_send_mail)
+ MainWindow.setTabOrder(self.check_send_mail, self.btn_apparat_save)
+ MainWindow.setTabOrder(self.btn_apparat_save, self.btn_apparat_apply)
+ MainWindow.setTabOrder(self.btn_apparat_apply, self.chkbx_show_del_media)
+ MainWindow.setTabOrder(self.chkbx_show_del_media, self.btn_reserve)
+ MainWindow.setTabOrder(self.btn_reserve, self.select_action_box)
+ MainWindow.setTabOrder(self.select_action_box, self.prof_id_adis)
+ MainWindow.setTabOrder(self.prof_id_adis, self.apparat_id_adis)
+ MainWindow.setTabOrder(self.apparat_id_adis, self.automation_add_selected_books)
+ MainWindow.setTabOrder(self.automation_add_selected_books, self.saveandcreate)
+
+ def retranslateUi(self, MainWindow):
+ _translate = QtCore.QCoreApplication.translate
+ MainWindow.setWindowTitle(_translate("MainWindow", "Semesterapparatsmanagement"))
+ self.create_document.setToolTip(_translate("MainWindow", "Erstellt die Übersicht, welche am Regal ausgehängt werden kann"))
+ self.create_document.setText(_translate("MainWindow", "Übersicht erstellen"))
+ self.create_new_app.setText(_translate("MainWindow", "neu. App anlegen"))
+ self.cancel_active_selection.setText(_translate("MainWindow", "Auswahl abbrechen"))
+ self.tableWidget_apparate.setSortingEnabled(False)
+ item = self.tableWidget_apparate.horizontalHeaderItem(0)
+ item.setText(_translate("MainWindow", "AppNr"))
+ item = self.tableWidget_apparate.horizontalHeaderItem(1)
+ item.setText(_translate("MainWindow", "App Name"))
+ item = self.tableWidget_apparate.horizontalHeaderItem(2)
+ item.setText(_translate("MainWindow", "Professor"))
+ item = self.tableWidget_apparate.horizontalHeaderItem(3)
+ item.setText(_translate("MainWindow", "gültig bis"))
+ item = self.tableWidget_apparate.horizontalHeaderItem(4)
+ item.setText(_translate("MainWindow", "Dauerapparat"))
+ item = self.tableWidget_apparate.horizontalHeaderItem(5)
+ item.setText(_translate("MainWindow", "KontoNr"))
+ self.chkbx_show_del_media.setText(_translate("MainWindow", "gel. Medien anzeigen"))
+ self.btn_reserve.setText(_translate("MainWindow", "im Apparat?"))
+ self.label_info.setText(_translate("MainWindow", "Medien werden hinzugefügt"))
+ self.progress_label.setText(_translate("MainWindow", "Medium x/y"))
+ self.label_20.setText(_translate("MainWindow", "Medien werden geprüft"))
+ self.avail_status.setText(_translate("MainWindow", "TextLabel"))
+ self.automation_add_selected_books.setText(_translate("MainWindow", "Ausgewählte als verfügbar markieren"))
+ self.tableWidget_apparat_media.setSortingEnabled(True)
+ item = self.tableWidget_apparat_media.horizontalHeaderItem(0)
+ item.setText(_translate("MainWindow", "Buchtitel"))
+ item.setToolTip(_translate("MainWindow", "Es kann sein, dass der Buchtitel leer ist, dies kommt vor, wenn der Titel nicht passend formatiert ist"))
+ item = self.tableWidget_apparat_media.horizontalHeaderItem(1)
+ item.setText(_translate("MainWindow", "Signatur"))
+ item = self.tableWidget_apparat_media.horizontalHeaderItem(2)
+ item.setText(_translate("MainWindow", "Auflage"))
+ item = self.tableWidget_apparat_media.horizontalHeaderItem(3)
+ item.setText(_translate("MainWindow", "Autor"))
+ item = self.tableWidget_apparat_media.horizontalHeaderItem(4)
+ item.setText(_translate("MainWindow", "im Apparat?"))
+ item.setToolTip(_translate("MainWindow", "Diese Angabe ist nicht zuverlässig. Ist das ❌ vorhanden, kann das Medium im Apparat sein, aber aufgrund eines Bugs nicht gefunden worden"))
+ item = self.tableWidget_apparat_media.horizontalHeaderItem(5)
+ item.setText(_translate("MainWindow", "Vorgemerkt"))
+ item = self.tableWidget_apparat_media.horizontalHeaderItem(6)
+ item.setText(_translate("MainWindow", "Link"))
+ self.label.setText(_translate("MainWindow", " Medienliste"))
+ self.app_group_box.setTitle(_translate("MainWindow", "Apparatsdetails"))
+ item = self.document_list.horizontalHeaderItem(0)
+ item.setText(_translate("MainWindow", "Dokumentname"))
+ item = self.document_list.horizontalHeaderItem(1)
+ item.setText(_translate("MainWindow", "Dateityp"))
+ item = self.document_list.horizontalHeaderItem(2)
+ item.setText(_translate("MainWindow", "Neu?"))
+ item = self.document_list.horizontalHeaderItem(3)
+ item.setText(_translate("MainWindow", "path"))
+ self.appname_mand.setText(_translate("MainWindow", "*"))
+ self.profname_mand.setText(_translate("MainWindow", "*"))
+ self.fach_mand.setText(_translate("MainWindow", "*"))
+ self.btn_apparat_apply.setText(_translate("MainWindow", "Aktualisieren"))
+ self.label_9.setText(_translate("MainWindow", "Tel"))
+ self._mand.setText(_translate("MainWindow", "*"))
+ self.check_eternal_app.setText(_translate("MainWindow", "Dauerapparat"))
+ self.sem_sommer.setText(_translate("MainWindow", "Sommer"))
+ self.drpdwn_prof_name.setToolTip(_translate("MainWindow", "Nachname, Vorname"))
+ self.mail_mand.setText(_translate("MainWindow", "*"))
+ self.label_3.setStatusTip(_translate("MainWindow", "sdvosdvsdv"))
+ self.label_3.setText(_translate("MainWindow", "Prof. Titel"))
+ self.label_2.setText(_translate("MainWindow", "Apparatsnummer"))
+ self.label_8.setText(_translate("MainWindow", "Mail"))
+ self.label_10.setText(_translate("MainWindow", "Fach"))
+ self.label_12.setText(_translate("MainWindow", "Prof-ID-aDIS"))
+ self.label_13.setText(_translate("MainWindow", "Apparat-ID-aDIS"))
+ self.sem_year.setPlaceholderText(_translate("MainWindow", "2023"))
+ self.check_send_mail.setText(_translate("MainWindow", "Mail senden"))
+ self.sem_winter.setText(_translate("MainWindow", "Winter"))
+ self.label_4.setText(_translate("MainWindow", "Prof. Name"))
+ self.telnr_mand.setText(_translate("MainWindow", "*"))
+ self.btn_apparat_save.setText(_translate("MainWindow", "Speichern"))
+ self.label_5.setText(_translate("MainWindow", "Apparatsname"))
+ self.label_6.setText(_translate("MainWindow", "Semester"))
+ self.valid_check_profname.setStatusTip(_translate("MainWindow", "Format: Nachname, Vorname"))
+ self.valid_check_mail.setStatusTip(_translate("MainWindow", "mail@irgendwas.wasanderes"))
+ self.saveandcreate.setText(_translate("MainWindow", "Speichern und anlegen"))
+ self.btn_add_document.setText(_translate("MainWindow", "Dokument hinzufügen"))
+ self.btn_open_document.setText(_translate("MainWindow", "Dokument öffnen"))
+ self.check_file.setToolTip(_translate("MainWindow", "Abhängig von der Anzahl der Medien kann die Suche sehr lange dauern"))
+ self.check_file.setText(_translate("MainWindow", "Medien aus Dokument\n"
+" hinzufügen"))
+ self.btn_extract_data_from_document.setToolTip(_translate("MainWindow", "Die Apparatsdetails werden aus dem Dokument gelesen und eingetragen\n"
+"Einige Angaben müssen ggf angepasst werden"))
+ self.btn_extract_data_from_document.setText(_translate("MainWindow", "Daten aus Dokument\n"
+"übernehmen"))
+ self.add_medium.setText(_translate("MainWindow", "Medien hinzufügen"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.createApparat), _translate("MainWindow", "Anlegen"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.search_statistics), _translate("MainWindow", "Suchen / Statistik"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.elsatab), _translate("MainWindow", "ELSA"))
+ self.label_21.setText(_translate("MainWindow", "Aktion:"))
+ self.select_action_box.setItemText(0, _translate("MainWindow", "Nutzer anlegen"))
+ self.select_action_box.setItemText(1, _translate("MainWindow", "Nutzer bearbeiten"))
+ self.select_action_box.setItemText(2, _translate("MainWindow", "Lehrperson bearbeiten"))
+ self.admin_action.setTitle(_translate("MainWindow", "GroupBox"))
+ self.tabWidget.setTabText(self.tabWidget.indexOf(self.admin), _translate("MainWindow", "Admin"))
+ self.groupBox_2.setTitle(_translate("MainWindow", "Software"))
+ self.appdata_check.setText(_translate("MainWindow", "Apparatsdaten eingegeben"))
+ self.media_check.setText(_translate("MainWindow", "Medien hinzugefügt / importiert"))
+ self.ids_check.setText(_translate("MainWindow", "Prof-ID und Apparat-ID eingetragen"))
+ self.groupBox.setTitle(_translate("MainWindow", "aDIS"))
+ self.media_checked.setText(_translate("MainWindow", "Medien geprüft"))
+ self.media_edited_check.setText(_translate("MainWindow", "Medien bearbeitet"))
+ self.app_created.setText(_translate("MainWindow", "Apparat angelegt"))
+ self.btn_copy_adis_command.setToolTip(_translate("MainWindow", "Hier klicken, um die aDIS Abfrage in die Zwischenablage zu kopieren"))
+ self.btn_copy_adis_command.setText(_translate("MainWindow", " aDIS Abfrage in Zwischenablage kopieren"))
+ self.menuDatei.setTitle(_translate("MainWindow", "Datei"))
+ self.menuEinstellungen.setTitle(_translate("MainWindow", "Bearbeiten"))
+ self.menuHelp.setTitle(_translate("MainWindow", "Help"))
+ self.actionBeenden.setText(_translate("MainWindow", "Beenden"))
+ self.actionBeenden.setShortcut(_translate("MainWindow", "Ctrl+Q"))
+ self.actionEinstellungen.setText(_translate("MainWindow", "Einstellungen"))
+ self.actionEinstellungen.setShortcut(_translate("MainWindow", "Alt+S"))
+ self.actionDokumentation.setText(_translate("MainWindow", "Dokumentation (online)"))
+ self.actionDokumentation.setShortcut(_translate("MainWindow", "F1"))
+ self.actionAbout.setText(_translate("MainWindow", "About"))
+ self.actionDokumentation_lokal.setText(_translate("MainWindow", "Dokumentation (lokal)"))
+ self.actionDokumentation_lokal.setShortcut(_translate("MainWindow", "F1"))
diff --git a/src/ui/userInterface.py b/src/ui/userInterface.py
index 68b61d3..7f8ed91 100644
--- a/src/ui/userInterface.py
+++ b/src/ui/userInterface.py
@@ -6,13 +6,14 @@ import sys
import tempfile
import webbrowser
from pathlib import Path
+from typing import Any, Union
from natsort import natsorted
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtCore import QThread
from PyQt6.QtGui import QRegularExpressionValidator
-from src import Icon, logger, settings
+from src import Icon
from src.backend import Database, BookGrabber, AvailChecker, DocumentationThread
from src.backend.semester import Semester
from src.backend.create_file import recreateFile
@@ -24,7 +25,8 @@ from src.logic import (
ApparatData,
BookData,
csv_to_list,
- word_docx_to_csv,
+ word_to_semap,
+ SemapDocument,
Prof,
Apparat,
)
@@ -39,6 +41,8 @@ from src.ui.dialogs import (
login_ui,
parsed_titles_ui,
reminder_ui,
+ DocumentPrintDialog,
+ launch,
)
from src.ui.widgets import (
ElsaDialog,
@@ -50,65 +54,83 @@ from src.ui.widgets import (
EditUser,
EditProf,
)
-from src.utils import SemesterDocument
+
+from datetime import datetime
+from loguru import logger as log
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+log.add(
+ f"logs/{datetime.now().strftime('%Y-%m-%d')}.log",
+ rotation="1 day",
+ compression="zip",
+)
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
+
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:
+ def __init__(self, MainWindow, username: str) -> None: # type:ignore
logger.info("Starting Semesterapparatsmanagement")
super().__init__()
self.active_user = username
- self.setupUi(MainWindow)
- self.MainWindow = MainWindow
+ self.setupUi(MainWindow) # type:ignore
+ self.MainWindow = MainWindow # type:ignore
# set the window title
- MainWindow.setWindowTitle("Semesterapparatsmanagement")
- MainWindow.setWindowIcon(Icon("logo").icon)
+ MainWindow.setWindowTitle("Semesterapparatsmanagement") # type:ignore
+ MainWindow.setWindowIcon(Icon("logo").icon) # type:ignore
self.db = Database()
- self.btn_add_document.clicked.connect(self.add_document)
- self.check_file.clicked.connect(
+ self.btn_add_document.clicked.connect(self.add_document) # type:ignore
+ self.check_file.clicked.connect( # type:ignore
self.btn_check_file_threaded
) # default: self.add_media_from_file
- self.create_new_app.clicked.connect(self.btn_create_new_apparat)
- self.btn_apparat_save.clicked.connect(lambda: self.btn_save_apparat(True))
- 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.create_document.clicked.connect(self.create_doc)
+ self.btn_extract_data_from_document.clicked.connect( # type:ignore
+ self.import_data_from_document
+ )
+ self.create_new_app.clicked.connect(self.btn_create_new_apparat) # type:ignore
+ self.btn_apparat_save.clicked.connect(lambda: self.btn_save_apparat(True)) # type:ignore
+ self.btn_apparat_apply.clicked.connect(self.update_apparat) # type:ignore
+ self.btn_open_document.clicked.connect(self.open_document) # type:ignore
+ self.add_medium.clicked.connect(self.btn_add_medium) # type:ignore
+ self.btn_copy_adis_command.clicked.connect(self.text_to_clipboard) # type:ignore
+ self.btn_reserve.clicked.connect(self.check_availability) # type:ignore
+ self.create_document.clicked.connect(self.create_doc) # type:ignore
self.calendarWidget = MessageCalendar(self.calendar_frame)
self.calendarWidget.setGridVisible(True)
self.calendarWidget.setVerticalHeaderFormat(
QtWidgets.QCalendarWidget.VerticalHeaderFormat.NoVerticalHeader
)
self.calendarWidget.setObjectName("MessageCalendar")
- self.calendarWidget.clicked.connect(self.open_reminder)
+ self.calendarWidget.clicked.connect(self.open_reminder) # type:ignore
# assign a context menu to the calendar
self.calendarlayout.addWidget(self.calendarWidget)
- self.tableWidget_apparat_media.horizontalHeader().setSectionResizeMode(
+ self.tableWidget_apparat_media.horizontalHeader().setSectionResizeMode( # type:ignore
QtWidgets.QHeaderView.ResizeMode.Stretch
)
- self.tableWidget_apparate.horizontalHeader().setSectionResizeMode(
+ self.tableWidget_apparate.horizontalHeader().setSectionResizeMode( # type:ignore
QtWidgets.QHeaderView.ResizeMode.Stretch
)
self.tableWidget_apparate.setSortingEnabled(True)
self.saveandcreate.hide()
# Actions
- self.actionEinstellungen.triggered.connect(self.open_settings)
+ self.actionEinstellungen.triggered.connect(self.open_settings) # type:ignore
Icon("settings", self.actionEinstellungen)
- self.actionDokumentation_lokal.triggered.connect(self.open_documentation)
+ self.actionDokumentation_lokal.triggered.connect(self.open_documentation) # type:ignore
Icon("offAction", self.actionBeenden)
- self.actionBeenden.triggered.connect(self.quit)
- self.actionAbout.triggered.connect(self.open_about)
+ self.actionBeenden.triggered.connect(self.quit) # type:ignore
+ self.actionAbout.triggered.connect(self.open_about) # type:ignore
# set validators
- self.sem_sommer.clicked.connect(lambda: self.toggleButton(self.sem_winter))
- self.sem_winter.clicked.connect(lambda: self.toggleButton(self.sem_sommer))
+ self.sem_sommer.clicked.connect(lambda: self.toggleButton(self.sem_winter)) # type:ignore
+ self.sem_winter.clicked.connect(lambda: self.toggleButton(self.sem_sommer)) # type:ignore
self.sem_year.setText(str(QtCore.QDate.currentDate().year()))
self.prof_mail.setValidator(
QRegularExpressionValidator(
@@ -121,7 +143,7 @@ class Ui(Ui_Semesterapparat):
self.prof_tel_nr.setValidator(
QtGui.QRegularExpressionValidator(QtCore.QRegularExpression(r"^\d{3,14}"))
)
- # #print(self.prof_tel_nr.maxLength())
+ # #logger.debug(self.prof_tel_nr.maxLength())
self.app_fach.setValidator( # validator to allow typing in the app_fach field
QtGui.QRegularExpressionValidator(
QtCore.QRegularExpression(r"[a-zA-Z0-9\s\W]+")
@@ -137,9 +159,9 @@ class Ui(Ui_Semesterapparat):
self.tableWidget_apparate.addScrollBarWidget(
QtWidgets.QScrollBar(), QtCore.Qt.AlignmentFlag.AlignRight
)
- self.tableWidget_apparate.doubleClicked.connect(self.load_app_data)
+ self.tableWidget_apparate.doubleClicked.connect(self.load_app_data) # type:ignore
- # #print(f"user:{self.active_user}")
+ # #logger.debug(f"user:{self.active_user}")
userrole = self.db.getRole(self.active_user)
# hide admin interface when non-admin is logged in
if userrole == "admin":
@@ -150,18 +172,18 @@ class Ui(Ui_Semesterapparat):
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)
+ self.drpdwn_prof_name.currentIndexChanged.connect(self.set_prof_data) # type:ignore
+ self.cancel_active_selection.clicked.connect(self.btn_cancel_active_selection) # type:ignore
+ self.check_eternal_app.stateChanged.connect(self.set_state) # type:ignore
# 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.prof_mail.textChanged.connect(self.validate_prof_mail) # type:ignore
+ self.drpdwn_prof_name.editTextChanged.connect(self.validate_prof_name) # type:ignore
+ self.prof_tel_nr.textChanged.connect(self.validate_prof_tel) # type:ignore
+ self.app_name.textChanged.connect(self.validate_app_name) # type:ignore
+ self.app_fach.currentTextChanged.connect(self.validate_app_fach) # type:ignore
+ self.sem_year.textChanged.connect(self.validate_semester) # type:ignore
+ self.check_eternal_app.stateChanged.connect(self.validate_semester) # type:ignore
+ self.chkbx_show_del_media.stateChanged.connect(self.update_app_media_list) # type:ignore
self.progress_label.setText("Bitte warten...")
# Set visibility/enabled state of certain entries
@@ -178,16 +200,16 @@ class Ui(Ui_Semesterapparat):
self.automation_add_selected_books.hide()
# self.btn_del_select_apparats.setEnabled(False)
- self.tabWidget.currentChanged.connect(self.tabW1_changed)
+ self.tabWidget.currentChanged.connect(self.tabW1_changed) # type:ignore
# 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.started.connect(self.thread_check) # type:ignore
self.validate_thread.start()
self.add_medium.setEnabled(False)
self.docu = DocumentationThread()
- self.docu.start()
- self.actionDokumentation_lokal.triggered.connect(self.open_documentation)
+
+ self.actionDokumentation_lokal.triggered.connect(self.open_documentation) # type:ignore
# get all current apparats and cache them in a list
self.apparats = self.get_apparats()
@@ -203,15 +225,15 @@ class Ui(Ui_Semesterapparat):
self.tableWidget_apparat_media.setContextMenuPolicy(
QtCore.Qt.ContextMenuPolicy.CustomContextMenu
)
- self.tableWidget_apparate.customContextMenuRequested.connect(
- self.open_context_menu
+ self.tableWidget_apparate.customContextMenuRequested.connect( # type:ignore
+ self.open_context_menu # type:ignore
)
- self.tableWidget_apparat_media.customContextMenuRequested.connect(
- self.media_context_menu
+ self.tableWidget_apparat_media.customContextMenuRequested.connect( # type:ignore
+ self.media_context_menu # type:ignore
)
# admin buttons
- self.select_action_box.currentTextChanged.connect(self.adminActions)
+ self.select_action_box.currentTextChanged.connect(self.adminActions) # type:ignore
self.select_action_box.addItem("")
self.select_action_box.setCurrentText("")
self.admin_action.setLayout(QtWidgets.QVBoxLayout())
@@ -236,36 +258,13 @@ class Ui(Ui_Semesterapparat):
self.steps.hide()
- def create_doc(self):
- result = self.confirm_popup(
- "Mit dem Klick auf Okay wird eine Übersicht aller aktiven Semesterapparate erstellt und an den FollowME Drucker gesendet. Es kann bis zu 10 Minuten dauern, bis das document im Drucker angezeigt wird",
- "document erstellen?",
- )
- logger.debug(f"Result: {result}")
- if result == 1:
- # print("Creating document")
- apparats = self.apparats
- apps = []
- for apparat in apparats:
- prof = self.db.getProf(apparat[2])
- data = (apparat[4], f"{prof.lastname} ({apparat[1]})")
- apps.append(data)
- # print(apps)
- logger.info("Using apparats: {}", apps)
- doc = SemesterDocument(
- semester=Semester().value,
- filename="Semesterapparate",
- apparats=apps,
- full=True,
- config=settings,
- )
- # doc.make_document()
- # doc.create_pdf()
- # doc.print_document()
- # doc.cleanup()
- # logger.info("Document created and sent to printer")
+ self.valid_check_semester.clicked.connect(self.display_valid_semester) # type:ignore
- # kill thread after execution done
+ def create_doc(self):
+ logger.debug("Creating document")
+ # open DocumentPrintDialog
+ dialog = DocumentPrintDialog(self.MainWindow)
+ dialog.show()
def checkValidInput(self):
if valid_input == (1, 1, 1, 1, 1, 1):
@@ -335,6 +334,8 @@ class Ui(Ui_Semesterapparat):
def open_documentation(self):
logger.info("Opening Documentation")
+ if not self.docu.isRunning():
+ self.docu.start()
webbrowser.open("http://localhost:8000")
def update_calendar(self, data):
@@ -357,7 +358,7 @@ class Ui(Ui_Semesterapparat):
statistics.updateCalendar.connect(self.update_calendar)
stats_layout.addWidget(statistics)
- # #print("searchpage")
+ # #logger.debug("searchpage")
if self.tabWidget.currentIndex() == 0: # Apparate
# clear all entries from the table
self.tableWidget_apparate.setRowCount(0)
@@ -375,7 +376,7 @@ class Ui(Ui_Semesterapparat):
widget.deleteLater()
elsa_layout.addWidget(ElsaDialog())
- # print("added")
+ # logger.debug("added")
pass
def generateSemester(self, today=False):
@@ -418,9 +419,9 @@ class Ui(Ui_Semesterapparat):
self.prof_mail.setText(appdata.prof.mail)
self.prof_tel_nr.setText(appdata.prof.telnr)
self.app_name.setText(appdata.apparat.name)
- # #print("changing dropdown app_fach from '' to ", appdata.app_fach)
+ # #logger.debug("changing dropdown app_fach from '' to ", appdata.app_fach)
self.app_fach.setCurrentText(appdata.apparat.subject)
- # #print("changed dropdown app_fach to ", self.app_fach.currentText())
+ # #logger.debug("changed dropdown app_fach to ", self.app_fach.currentText())
self.sem_year.setText(appdata.apparat.get_semester.split(" ")[1])
match appdata.apparat.get_semester.split(" ")[0]:
case "SoSe":
@@ -485,7 +486,7 @@ class Ui(Ui_Semesterapparat):
return popup.result()
def thread_check(self):
- # #print("Thread started")
+ # #logger.debug("Thread started")
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)
@@ -549,22 +550,24 @@ class Ui(Ui_Semesterapparat):
self.__setValidState(self.valid_check_app_fach, 0, self.fach_mand, 4)
def validate_semester(self):
- if (
- self.app_group_box.isEnabled()
- and (
- (self.sem_sommer.isChecked() or self.sem_winter.isChecked())
- and self.sem_year.text() != ""
- and len(self.sem_year.text())
- >= 2 # check if the year is at least 2 digits long
- )
- or self.check_eternal_app.isChecked()
- ):
+ valid = (self.sem_sommer.isChecked() or self.sem_winter.isChecked()) and len(
+ self.sem_year.text()
+ ) >= 2
+ if valid or self.check_eternal_app.isChecked():
self.__setValidState(self.valid_check_semester, 1, self._mand, 5)
self.check_eternal_app.setEnabled(True)
else:
self.__setValidState(self.valid_check_semester, 0, self._mand, 5)
self.check_eternal_app.setEnabled(False)
+ def display_valid_semester(self):
+ print(f"""
+ Semester: {self.sem_year.text()}
+ Sommer: {self.sem_sommer.isChecked()}
+ Winter: {self.sem_winter.isChecked()}
+ Eternal: {self.check_eternal_app.isChecked()}
+ """)
+
def change_state(self, index, state):
global valid_input
valid_input = list(valid_input)
@@ -691,12 +694,12 @@ class Ui(Ui_Semesterapparat):
self.drpdwn_prof_name.clear()
# set drop down menu for apparat numbers to only available numbers
taken_app_nrs = self.db.getUnavailableApparatNumbers()
- self.drpdwn_app_nr.addItems([str(i) for i in APP_NRS if i not in taken_app_nrs])
+ self.drpdwn_app_nr.addItems([str(i) for i in APP_NRS if i not in taken_app_nrs]) # type:ignore
valid_input = (0, 0, 0, 0, 0, 0)
self.populate_prof_dropdown()
- def update_progress_label(self, curr, total):
+ def update_progress_label(self, curr: int, total: int):
text = f"Medium {curr}/{total}"
logger.info(text)
self.progress_label.setText(text)
@@ -739,7 +742,7 @@ class Ui(Ui_Semesterapparat):
# create a thread that updates the progress label after each medium
# self.bookGrabber = None
- bookGrabber = BookGrabber(self.active_apparat)
+ bookGrabber = BookGrabber()
bookGrabber.add_values(
mode=mode,
prof_id=prof_id,
@@ -754,7 +757,7 @@ class Ui(Ui_Semesterapparat):
bookGrabber.start()
while bookGrabber.isRunning():
- # #print("waiting for thread to finish")
+ # #logger.debug("waiting for thread to finish")
QtWidgets.QApplication.processEvents()
# self.__clear_fields()
@@ -763,7 +766,6 @@ class Ui(Ui_Semesterapparat):
return
def check_availability(self):
-
def _update_progress(current, all_titles):
self.avail_status.setText("{}/{}".format(current, all_titles))
@@ -787,7 +789,8 @@ class Ui(Ui_Semesterapparat):
self.tableWidget_apparat_media.currentRow(), 1
).text()
]
- items = len(links)
+ # get the number of selected rows from the table
+ items = self.tableWidget_apparat_media.rowCount()
self.label_20.setText("Verfügbarkeit wird geprüft, bitte warten...")
self.label_20.show()
self.avail_status.setText(f"0/{items}")
@@ -800,7 +803,7 @@ class Ui(Ui_Semesterapparat):
# thread = QThread()
appnumber = self.active_apparat
- # #print(links)
+ # #logger.debug(links)
self.availChecker = AvailChecker(links, appnumber, books=books)
# availcheck.moveToThread(thread)
# availcheck.finished.connect(thread.quit)
@@ -849,7 +852,7 @@ class Ui(Ui_Semesterapparat):
app_id, prof_id, deleted
)
- # # #print(books)
+ # # #logger.debug(books)
# take the dataclass from the tuple
# booklist:list[BookData]=[book[0] for book in books]
self.tableWidget_apparat_media.setRowCount(0)
@@ -858,7 +861,7 @@ class Ui(Ui_Semesterapparat):
book_data = book["bookdata"]
availability = book["available"]
# bd = BookData().from_string(book)
- # # #print(bd, type(bd))
+ # # #logger.debug(bd, type(bd))
# create a new row below the last one
self.tableWidget_apparat_media.insertRow(
self.tableWidget_apparat_media.rowCount()
@@ -911,7 +914,7 @@ class Ui(Ui_Semesterapparat):
).setToolTip("Das Medium wurde nicht im Apparat gefunden")
# make table link clickable
- #self.tableWidget_apparat_media.itemClicked.connect(self.open_link)
+ # self.tableWidget_apparat_media.itemClicked.connect(self.open_link)
# self.tableWidget_apparat_media.
def open_link(self, item):
@@ -931,7 +934,7 @@ class Ui(Ui_Semesterapparat):
link = __openLink(item.text())
if link is not None:
webbrowser.open(link)
- #os.system("start " + link)
+ # os.system("start " + link)
return
else:
pass
@@ -952,11 +955,11 @@ class Ui(Ui_Semesterapparat):
self.drpdwn_prof_name.addItem(prof)
def add_document(self):
- # #print("Add document")
+ # #logger.debug("Add document")
picker = FilePicker()
files = picker.pick_files()
for file in files:
- # #print(file)
+ # #logger.debug(file)
filename = file.split("/")[-1]
filetype = filename.split(".")[-1]
self.document_list.insertRow(0)
@@ -1004,7 +1007,7 @@ class Ui(Ui_Semesterapparat):
app_id = self.active_apparat
prof_id = self.db.getProfId(self.profdata)
- def __open_dialog(signatures):
+ def __open_dialog(signatures: list[str]):
dialog = QtWidgets.QDialog()
frame = parsed_titles_ui()
frame.setupUi(dialog)
@@ -1028,7 +1031,7 @@ class Ui(Ui_Semesterapparat):
else:
# if file is selected, check for books in the file
if self.document_list.currentRow() != -1:
- # #print("File selected")
+ # #logger.debug("File selected")
file = self.document_list.item(
self.document_list.currentRow(), 3
).text()
@@ -1069,12 +1072,8 @@ class Ui(Ui_Semesterapparat):
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 = word_to_semap(file)
+ signatures = data.signatures
data = __open_dialog(signatures)
# if no data was returned, return
if data == []:
@@ -1086,10 +1085,55 @@ class Ui(Ui_Semesterapparat):
bookdata=book, app_id=app_id, prof_id=prof_id
)
self.update_app_media_list()
- # #print(len(signatures))
+ # #logger.debug(len(signatures))
+
+ def extract_document_data(self) -> Union[list[str], SemapDocument]:
+ file_type = self.document_list.item(self.document_list.currentRow(), 1).text()
+ file_location = self.document_list.item(
+ self.document_list.currentRow(), 3
+ ).text()
+ file_name = self.document_list.item(self.document_list.currentRow(), 0).text()
+ file = file_location
+ logger.info("File selected: {}, {}", file_name, file_location)
+ if file_location == "Database":
+ # create warning, then return
+ self.db.recreateFile(file_name, self.active_apparat, filetype=file_type)
+ if file_type == "pdf":
+ # Todo: implement parser here
+ self.confirm_popup("PDF Dateien werden nicht unterstützt!", title="Fehler")
+ return [""]
+ if file_type == "csv":
+ signatures = csv_to_list(file)
+ # add the data to the database
+ return signatures
+ if file_type == "docx":
+ data = word_to_semap(file)
+ logger.info("Converted data from semap file")
+ logger.debug("Got the data: {}", data)
+
+ return data
+
+ def import_data_from_document(self):
+ global valid_input
+ data = self.extract_document_data()
+ if data is None:
+ return
+ if isinstance(data, list):
+ return
+
+ self.prof_mail.setText(data.mail)
+ self.prof_tel_nr.setText(str(data.phoneNumber))
+ self.app_name.setText(data.title)
+ self.app_fach.setCurrentText(data.subject)
+ self.prof_title.setText(data.personTitle)
+ self.drpdwn_prof_name.setCurrentText(data.personName)
+ self.sem_year.setText("20" + data.semester.year)
def btn_check_file_threaded(self):
- # #print("Checking file")
+ for runner in self.bookGrabber:
+ if not runner.isRunning():
+ runner.deleteLater()
+ # #logger.debug("Checking file")
# get active app_id and prof_id
self.tableWidget_apparate.setEnabled(False)
self.tableWidget_apparate.setToolTip(
@@ -1099,68 +1143,53 @@ class Ui(Ui_Semesterapparat):
logger.debug(self.profdata)
prof_id = self.db.getProfId(self.profdata)
- logger.debug(prof_id)
+ logger.debug("Prof id: {}", prof_id)
# check if apparat in database
-
+ if prof_id is None:
+ prof = Prof(
+ fullname=self.drpdwn_prof_name.currentText(),
+ telnr=self.prof_tel_nr.text(),
+ mail=self.prof_mail.text(),
+ firstname=self.drpdwn_prof_name.currentText().split(", ")[1],
+ lastname=self.drpdwn_prof_name.currentText().split(", ")[0],
+ )
+ self.db.createProf(prof)
# if app_id not in database, create apparat
- created = False
if not self.db.checkApparatExistsById(app_id):
+ logger.info("Apparat does not exist, creating new apparat")
# create apparat
- # #print("Creating apparat")
+ # #logger.debug("Creating apparat")
if not self.btn_save_apparat(False):
return
- created = True
+
if self.document_list.rowCount() == 0:
- # #print("No file selected")
+ logger.info("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.document_list.item(self.document_list.currentRow(), 3).text()
+ # #logger.debug("File selected")
- file_type = self.document_list.item(
- self.document_list.currentRow(), 1
- ).text()
- file_location = self.document_list.item(
- self.document_list.currentRow(), 3
- ).text()
- file_name = self.document_list.item(
- self.document_list.currentRow(), 0
- ).text()
- if file_location == "Database":
- file = recreateFile(file_name, app_id, file_type, open=False)
- else:
- if not created:
- self.add_files(prof_id)
- if file_type == "pdf":
- # Todo: implement parser here
- self.confirm_popup(
- "PDF Dateien werden nicht unterstützt!", title="Fehler"
- )
- 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 != ""]
- # logger.debug(signatures)
- # #print("starting thread")
if prof_id is None:
prof_id = self.db.getProfId(self.profdata)
- # print("Prof ID is None", prof_id)
- autoGrabber = BookGrabber(self.active_apparat)
+ # logger.debug("Prof ID is None", prof_id)
+ document = self.extract_document_data()
+ if document is None:
+ logger.error("Document is None")
+ elif isinstance(document, SemapDocument):
+ signatures = document.signatures
+ else:
+ signatures = document
+ autoGrabber = BookGrabber()
autoGrabber.add_values(
- mode="ARRAY", app_id=app_id, prof_id=prof_id, data=signatures
+ mode="ARRAY",
+ app_id=int(app_id),
+ prof_id=int(prof_id),
+ data=signatures,
+ any_book=True,
+ exact=True,
)
self.label_info.show()
self.progress_label.show()
@@ -1169,13 +1198,12 @@ class Ui(Ui_Semesterapparat):
# self.autoGrabber.finished.connect(self.autoGrabber.deleteLater)
autoGrabber.finished.connect(self.hide_progress_label)
autoGrabber.finished.connect(self.unlock_apparate)
-
autoGrabber.updateSignal.connect(self.update_progress_label)
# worker.finished.connect(worker.deleteLater)
autoGrabber.start()
- while autoGrabber.isRunning():
- QtWidgets.QApplication.processEvents()
+ self.bookGrabber.append(autoGrabber)
+ # refresh book table
# end of thread
# self.autoGrabber.exit()
# self.__clear_fields()
@@ -1260,7 +1288,7 @@ class Ui(Ui_Semesterapparat):
pid=appd.prof.fullname,
)
if clear_fields:
- # #print("clearing fields")
+ # #logger.debug("clearing fields")
self.__clear_fields()
return True
@@ -1281,7 +1309,15 @@ class Ui(Ui_Semesterapparat):
}
def add_files(self, prof_id=None):
- files = []
+ """
+ Add Files to the associated prof in the database
+
+ Parameters
+ ----------
+ prof_id : int, optional
+ The ID associated to the prof, by default None
+ """
+ files: list[dict[str, Any]] = []
for i in range(self.document_list.rowCount()):
files.append(
{
@@ -1379,7 +1415,7 @@ class Ui(Ui_Semesterapparat):
appnr = self.tableWidget_apparate.item(tableposition, 0).text()
if reminder.result() == QtWidgets.QDialog.DialogCode.Accepted:
data = reminder.return_message()
- # #print(data)
+ # #logger.debug(data)
self.db.addMessage(
data,
self.active_user,
@@ -1399,7 +1435,7 @@ class Ui(Ui_Semesterapparat):
def open_reminder(self):
selected_date = self.calendarWidget.selectedDate().toString("yyyy-MM-dd")
- # # #print(selected_date)
+ # # #logger.debug(selected_date)
messages = self.db.getMessages(selected_date)
if messages == []:
return
@@ -1407,16 +1443,18 @@ class Ui(Ui_Semesterapparat):
dialog = CalendarEntry(messages=messages, date=selected_date)
# append dialog to self.frame_2
self.calendarlayout.addWidget(dialog)
- dialog.repaintSignal.connect(lambda: self.calendarWidget.reload(selected_date))
+ dialogger.repaintSignal.connect(
+ lambda: self.calendarWidget.reload(selected_date)
+ )
def open_settings(self):
- # print(settings.dict())
+ # logger.debug(settings.dict())
settingsUI = Settings(self.active_user)
settingsUI.exec()
if settingsUI.result() == QtWidgets.QDialog.DialogCode.Accepted:
settingsUI.save()
- # print(settings.dict())
+ # logger.debug(settings.dict())
# self.reload()
@@ -1523,12 +1561,12 @@ class Ui(Ui_Semesterapparat):
cancel_button = QtWidgets.QPushButton("Abbrechen")
layout.addWidget(okay_button)
layout.addWidget(cancel_button)
- okay_button.clicked.connect(dialog.accept)
- cancel_button.clicked.connect(dialog.reject)
+ okay_button.clicked.connect(dialogger.accept)
+ cancel_button.clicked.connect(dialogger.reject)
- dialog.setLayout(layout)
+ dialogger.setLayout(layout)
- return dialog.exec(), self.db.getApparatId(
+ return dialogger.exec(), self.db.getApparatId(
self.db.getApparatNameByAppNr(drpdwn.currentText())
)
@@ -1542,7 +1580,7 @@ class Ui(Ui_Semesterapparat):
signature=signature,
prof_id=self.db.getProfId(self.profdata),
)
- # print(medium.adis_idn, medium.signature)
+ # logger.debug(medium.adis_idn, medium.signature)
def edit_medium(self):
book = self.tableWidget_apparat_media.item(
@@ -1569,10 +1607,10 @@ class Ui(Ui_Semesterapparat):
widget.exec()
if widget.result() == QtWidgets.QDialog.DialogCode.Accepted:
data = bookedit.get_data()
- # #print(data)
+ # #logger.debug(data)
self.db.updateBookdata(bookdata=data, book_id=book_id)
# self.db.update_bookdata(data)
- # #print("accepted")
+ # #logger.debug("accepted")
self.update_app_media_list()
else:
return
@@ -1596,7 +1634,7 @@ class Ui(Ui_Semesterapparat):
)
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, title="Löschen?")
- # #print(state)
+ # #logger.debug(state)
if state == 1:
self.db.deleteBook(book_id)
self.update_app_media_list()
@@ -1608,7 +1646,7 @@ class Ui(Ui_Semesterapparat):
for r in ranges:
for row in range(r.topRow(), r.bottomRow() + 1):
rows.append(row)
- # #print(rows)
+ # #logger.debug(rows)
message = f"Sollen die {len(rows)} Medien wirklich gelöscht werden?"
state = self.confirm_popup(message, title="Löschen?")
if state == 1:
@@ -1628,12 +1666,12 @@ class Ui(Ui_Semesterapparat):
# return data from dialog if ok is pressed
if framework.result() == QtWidgets.QDialog.DialogCode.Accepted:
data = framework.get_data()
- # #print(data)
+ # #logger.debug(data)
# return data
selected_apparat_id = self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 0
).text()
- # #print(selected_apparat_id)
+ # #logger.debug(selected_apparat_id)
self.db.setNewSemesterDate(
selected_apparat_id, data["semester"], dauerapp=data["dauerapp"]
@@ -1704,7 +1742,7 @@ class Ui(Ui_Semesterapparat):
).text()
message = f"Soll der Apparat {selected_apparat_id} wirklich gelöscht werden?"
state = self.confirm_popup(message, title="Löschen?")
- # #print(state)
+ # #logger.debug(state)
logger.info("Result state: {}", state)
if state == 1:
logger.debug("Deleting apparat {}", selected_apparat_id)
@@ -1716,7 +1754,7 @@ class Ui(Ui_Semesterapparat):
self.apparats.remove(apparat)
break
self.old_apparats = self.apparats
- # #print(self.apparats)
+ # #logger.debug(self.apparats)
# remove the row from the table
self.tableWidget_apparate.removeRow(self.tableWidget_apparate.currentRow())
# send mail to prof
@@ -1724,8 +1762,8 @@ class Ui(Ui_Semesterapparat):
def launch_gui():
- # #print("trying to login")
- # #print("checking if database available")
+ # #logger.debug("trying to login")
+ # #logger.debug("checking if database available")
logger.info("Starting login dialog")
app = QtWidgets.QApplication(sys.argv)
@@ -1737,11 +1775,11 @@ def launch_gui():
if ui.lresult == 1:
# if login is successful, open main window
# show login dialog
- # #print(ui.lusername)
+ # #logger.debug(ui.lusername)
MainWindow = QtWidgets.QMainWindow()
aui = Ui(MainWindow, username=ui.lusername)
- # #print(aui.active_user)
+ # #logger.debug(aui.active_user)
MainWindow.show()
# atexit.register()
atexit.register(tempdelete)
@@ -1750,15 +1788,15 @@ def launch_gui():
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()
+ warning_dialogger.setIcon(QtWidgets.QMessageBox.Icon.Warning)
+ warning_dialogger.setText("Invalid username or password. Please try again.")
+ warning_dialogger.setWindowTitle("Login Failed")
+ warning_dialogger.exec()
atexit.register(tempdelete)
if __name__ == "__main__":
- # #print("This is the main window")
+ # #logger.debug("This is the main window")
# app = QtWidgets.QApplication(sys.argv)
# window = MainWindow()
# app.exec()
diff --git a/src/ui/widgets/MessageCalendar.py b/src/ui/widgets/MessageCalendar.py
index 44ec907..bbc6ec8 100644
--- a/src/ui/widgets/MessageCalendar.py
+++ b/src/ui/widgets/MessageCalendar.py
@@ -1,9 +1,18 @@
-from src import logger
from PyQt6 import QtWidgets, QtCore
from PyQt6.QtCore import QDate
from PyQt6.QtGui import QColor, QPen
from src.backend import Database
import darkdetect
+import sys
+from loguru import logger as log
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
color = "#ddfb00" if darkdetect.isDark() else "#2204ff"
pen = QPen(QColor(color))
diff --git a/src/ui/widgets/admin_edit_prof.py b/src/ui/widgets/admin_edit_prof.py
index e3a0870..612c1e3 100644
--- a/src/ui/widgets/admin_edit_prof.py
+++ b/src/ui/widgets/admin_edit_prof.py
@@ -1,8 +1,17 @@
from .widget_sources.Ui_admin_edit_prof import Ui_Dialog #
from PyQt6 import QtWidgets
-from src import logger
+
from src.logic import Prof
from src.backend import Database
+import sys
+from loguru import logger as log
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
class EditProf(QtWidgets.QDialog, Ui_Dialog):
diff --git a/src/ui/widgets/elsa_main.py b/src/ui/widgets/elsa_main.py
index 25fe659..0969e5c 100644
--- a/src/ui/widgets/elsa_main.py
+++ b/src/ui/widgets/elsa_main.py
@@ -1,14 +1,23 @@
import os
-from natsort import natsorted
from .widget_sources.Ui_elsa_maindialog import Ui_Dialog
from PyQt6 import QtCore, QtWidgets, QtGui
from PyQt6.QtGui import QRegularExpressionValidator
from PyQt6.QtCore import QDate
-from src import Icon, logger
+from src import Icon
from src.backend import Semester, Database
from src.logic import elsa_word_to_csv, Prof
from src.ui.dialogs import ElsaAddEntry, popus_confirm
from src.ui.widgets import FilePicker, DataGraph
+from src.backend import recreateElsaFile
+import sys
+from loguru import logger as log
+
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+log.add("logs/elsa_main.log", enqueue=True)
+logger.add(sys.stdout)
class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
@@ -70,7 +79,7 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
##Variables
self.db = Database()
- self.graph_data = {"x": [Semester().value], "y": [0]}
+ self.graph_data = {"x": [""], "y": [0]}
self.createProf = False
self.profs = self.getProfs()
@@ -224,11 +233,11 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
lastname=prof.split(", ")[0],
mail=self.newProf_mail.text(),
telnr=self.newProf_telnr.text(),
- title=self.newProf_title.text(),
+ _title=self.newProf_title.text(),
fullname=f"{prof.split(', ')[0]} {prof.split(', ')[1]}",
)
prof_id = self.db.getProfId(profdata)
- logger.debug(profdata, prof_id)
+ logger.debug(f"ProfData: {profdata}, id:{prof_id}")
if prof_id is None:
self.db.createProf(profdata)
@@ -403,10 +412,7 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
self.elsa_date.text(),
)
logger.debug(
- elsa_id,
- self.elsa_prof.currentText(),
- self.elsa_semester.text(),
- self.elsa_date.text(),
+ f"elsa_id: {elsa_id}, prof: {self.elsa_prof.currentText()}, semester: {self.elsa_semester.text()}, date: {self.elsa_date.text()}"
)
for row in data:
if self.seperateEntries.isChecked():
@@ -442,7 +448,7 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
logger.debug("No tab to remove")
self.elsa_table.setRowCount(0)
elsa_apparats = self.db.getElsaApparats()
- elsa_apparats = natsorted(elsa_apparats, key=lambda x: x[2], reverse=True)
+ # elsa_apparats = natsorted(elsa_apparats, key=lambda x: x[2], reverse=True)
# x = semester, y = number of apparats
for apparat in elsa_apparats:
@@ -455,13 +461,13 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
else:
index = self.graph_data["x"].index(semester)
self.graph_data["y"][index] += number
-
- generateMissing = True if len(self.graph_data["x"]) > 1 else False
+ self.graph_data["x"].pop(0)
+ self.graph_data["y"].pop(0)
+ # generateMissing = True if len(self.graph_data["x"]) > 2 else False
graph = DataGraph(
- "ELSA Apparate pro Semester",
- self.graph_data,
- generateMissing,
- "Anzahl der Apparate",
+ title="ELSA Apparate pro Semester",
+ data=self.graph_data,
+ label="Anzahl der Apparate",
)
logger.debug(self.graph_data)
self.elsa_statistics_table.setRowCount(0)
diff --git a/src/ui/widgets/graph.py b/src/ui/widgets/graph.py
index a4a2ddd..d21f95f 100644
--- a/src/ui/widgets/graph.py
+++ b/src/ui/widgets/graph.py
@@ -3,6 +3,18 @@ from typing import Union
import pyqtgraph as pg
from PyQt6 import QtWidgets
+import sys
+from loguru import logger as log
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+log.add(
+ "logs/graph.log",
+)
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
def mergedicts(d1, d2):
@@ -31,7 +43,11 @@ class DataGraph(QtWidgets.QWidget):
label=None,
):
super().__init__()
-
+ logger.debug(
+ "Initialized with options: {}, {}, {}, {}".format(
+ title, data, generateMissing, label
+ )
+ )
lst = []
if generateMissing:
x_data = data["x"]
@@ -142,20 +158,10 @@ if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
- data_1 = {
- "x": ["SoSe 10", "WiSe 10/11", "SoSe 11", "SoSe 14"],
- "y": {
- "Added": [1, 2, 3, 4],
- "Deleted": [4, 3, 2, 1],
- },
- }
- data_2 = {
- "x": ["SoSe 10"],
- "y": [2],
- }
- graph_data = {"x": ["SoSe 24"], "y": [1]}
+
+ graph_data = {"x": ["WiSe 25/26", "WiSe 24/25", "SoSe 25"], "y": [1, 2, 1]}
widget = DataGraph(
- "ELSA Apparate pro Semester", data_2, True, "Anzahl der Apparate"
+ "ELSA Apparate pro Semester", graph_data, True, "Anzahl der Apparate"
)
widget.show()
sys.exit(app.exec())
diff --git a/src/ui/widgets/iconLine.py b/src/ui/widgets/iconLine.py
index 5beb729..a04c13c 100644
--- a/src/ui/widgets/iconLine.py
+++ b/src/ui/widgets/iconLine.py
@@ -1,6 +1,16 @@
from .widget_sources.Ui_icon_widget import Ui_Dialog
from PyQt6 import QtWidgets
-from src import logger
+
+import sys
+from loguru import logger as log
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
class IconWidget(QtWidgets.QWidget, Ui_Dialog):
diff --git a/src/ui/widgets/searchPage.py b/src/ui/widgets/searchPage.py
index d622154..f70c8eb 100644
--- a/src/ui/widgets/searchPage.py
+++ b/src/ui/widgets/searchPage.py
@@ -2,12 +2,22 @@ from .widget_sources.Ui_search_statistic_page import Ui_Dialog
from PyQt6 import QtWidgets, QtGui, QtCore
from PyQt6.QtCore import pyqtSignal
from src.backend import Database, Semester
-from src import logger
+
from src.logic import custom_sort, Prof, sort_semesters_list
from src.ui.dialogs import Mail_Dialog, ApparatExtendDialog, reminder_ui
from src.ui.widgets import DataGraph, StatusWidget
from natsort import natsorted
+import sys
+from loguru import logger as log
+
+logger = log
+logger.remove()
+logger.add("logs/application.log", rotation="1 week", enqueue=True)
+log.add("logs/searchPage.log", enqueue=True)
+
+# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
+logger.add(sys.stdout)
class MyComboBox(QtWidgets.QComboBox):
@@ -73,7 +83,7 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
apparats.append(self.tableWidget.item(row.row(), 1).text())
for apparat in apparats:
apparat_id = self.db.getApparatId(apparat)
- self.db.restoreApparat(apparat_id)
+ self.db.restoreApparat(apparat_id, apparat)
# remove the red color from the row
# get row where the apparat is
row = self.tableWidget.findItems(apparat, QtCore.Qt.MatchFlag.MatchExactly)[
@@ -483,7 +493,7 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
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:
+ if int(app.deleted) == 1:
for j in range(5):
self.tableWidget.item(0, j).setBackground(
QtGui.QColor(235, 74, 71)
diff --git a/src/utils/blob.py b/src/utils/blob.py
index c28636a..f2c8070 100644
--- a/src/utils/blob.py
+++ b/src/utils/blob.py
@@ -1,4 +1,4 @@
-def create_blob(file):
+def create_blob(file: str):
"""
Creates a blob from a file.
"""
diff --git a/src/utils/pickles.py b/src/utils/pickles.py
index cb5a84f..e943a0d 100644
--- a/src/utils/pickles.py
+++ b/src/utils/pickles.py
@@ -1,9 +1,10 @@
import pickle
+from typing import Any
-def load_pickle(data):
+def load_pickle(data: Any):
return pickle.loads(data)
-def dump_pickle(data):
+def dump_pickle(data: Any):
return pickle.dumps(data)
diff --git a/src/utils/richtext.py b/src/utils/richtext.py
index 8da249d..f1c11e9 100644
--- a/src/utils/richtext.py
+++ b/src/utils/richtext.py
@@ -8,6 +8,7 @@ import os
from os.path import basename
from loguru import logger as log
import sys
+from src import settings
logger = log
@@ -22,11 +23,46 @@ log.add(
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
logger.add(sys.stdout)
+font = "Cascadia Mono"
+
+
+def print_document(file: str):
+ # send document to printer as attachment of email
+ import smtplib
+ from email.mime.multipart import MIMEMultipart
+ from email.mime.application import MIMEApplication
+ from email.mime.text import MIMEText
+
+ smtp = settings.mail.smtp_server
+ port = settings.mail.port
+ sender_email = settings.mail.sender
+ password = settings.mail.password
+ receiver = settings.mail.printer_mail
+ message = MIMEMultipart()
+ message["From"] = sender_email
+ message["To"] = receiver
+ message["cc"] = settings.mail.sender
+ message["Subject"] = "."
+ mail_body = "."
+ message.attach(MIMEText(mail_body, "html"))
+ with open(file, "rb") as fil:
+ part = MIMEApplication(fil.read(), Name=basename(file))
+ # After the file is closed
+ part["Content-Disposition"] = 'attachment; filename="%s"' % basename(file)
+ message.attach(part)
+ mail = message.as_string()
+ with smtplib.SMTP_SSL(smtp, port) as server:
+ server.connect(smtp, port)
+ server.login(settings.mail.user_name, password)
+ server.sendmail(sender_email, receiver, mail)
+ server.quit()
+ logger.success("Mail sent")
+
class SemesterError(Exception):
"""Custom exception for semester-related errors."""
- def __init__(self, message):
+ def __init__(self, message: str):
super().__init__(message)
logger.error(message)
@@ -39,8 +75,7 @@ class SemesterDocument:
self,
apparats: list[tuple[int, str]],
semester: str,
- filename,
- config,
+ filename: str,
full: bool = False,
):
assert isinstance(apparats, list), SemesterError(
@@ -62,25 +97,26 @@ class SemesterDocument:
self.doc = Document()
self.apparats = apparats
self.semester = semester
- self.table_font = "Arial"
- self.header_font = "Times New Roman"
+ self.table_font_normal = font
+ self.table_font_bold = font
+ self.header_font = font
self.header_font_size = Pt(26)
self.sub_header_font_size = Pt(18)
self.table_font_size = Pt(10)
self.color_red = RGBColor(255, 0, 0)
self.color_blue = RGBColor(0, 0, 255)
self.filename = filename
- self.settings = config
if full:
logger.info("Full document generation")
self.make_document()
logger.info("Document created")
self.create_pdf()
logger.info("PDF created")
- self.print_document()
+ print_document(self.filename + ".pdf")
logger.info("Document printed")
- self.cleanup()
+ self.cleanup
logger.info("Cleanup done")
+
def set_table_border(self, table):
"""
Adds a full border to the table.
@@ -110,7 +146,7 @@ class SemesterDocument:
table.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
# Set column widths by directly modifying the cell properties
- widths = [Cm(1.19), Cm(10.39)]
+ widths = [Cm(1.19), Cm(18)]
for col_idx, width in enumerate(widths):
for cell in table.columns[col_idx].cells:
cell_width_element = cell._element.xpath(".//w:tcPr")[0]
@@ -136,7 +172,7 @@ class SemesterDocument:
# Set font for the first column (number)
cell_number_paragraph = row.cells[0].paragraphs[0]
cell_number_run = cell_number_paragraph.add_run(str(number))
- cell_number_run.font.name = self.table_font
+ cell_number_run.font.name = self.table_font_bold
cell_number_run.font.size = self.table_font_size
cell_number_run.font.bold = True
cell_number_run.font.color.rgb = self.color_red
@@ -149,13 +185,13 @@ class SemesterDocument:
# Add the first word in bold
bold_run = cell_name_paragraph.add_run(words[0])
bold_run.font.bold = True
- bold_run.font.name = self.table_font
+ bold_run.font.name = self.table_font_bold
bold_run.font.size = self.table_font_size
# Add the rest of the words normally
if len(words) > 1:
normal_run = cell_name_paragraph.add_run(" " + " ".join(words[1:]))
- normal_run.font.name = self.table_font
+ normal_run.font.name = self.table_font_normal
normal_run.font.size = self.table_font_size
cell_name_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
@@ -198,42 +234,6 @@ class SemesterDocument:
def save_document(self, name):
# Save the document
self.doc.save(name)
- print(f"Document saved as {name}")
-
- def print_document(self):
- # send document to printer as attachment of email
- import smtplib
- from email.mime.multipart import MIMEMultipart
- from email.mime.application import MIMEApplication
- from email.mime.text import MIMEText
-
- config = self.settings
- smtp = config.mail.smtp_server
- port = config.mail.port
- sender_email = config.mail.sender
- password = config.mail.password
- receiver = config.mail.printer_mail
- message = MIMEMultipart()
- message["From"] = sender_email
- message["To"] = receiver
- message["cc"] = config.mail.sender
- message["Subject"] = "."
- mail_body = "."
- message.attach(MIMEText(mail_body, "html"))
- with open(self.filename + ".pdf", "rb") as fil:
- part = MIMEApplication(fil.read(), Name=basename(self.filename + "pdf"))
- # After the file is closed
- part["Content-Disposition"] = 'attachment; filename="%s"' % basename(
- self.filename + ".pdf"
- )
- message.attach(part)
- mail = message.as_string()
- with smtplib.SMTP_SSL(smtp, port) as server:
- server.connect(smtp, port)
- server.login(config.mail.user_name, password)
- server.sendmail(sender_email, receiver, mail)
- server.quit()
- print("Mail sent")
def create_pdf(self):
# Save the document
@@ -249,29 +249,112 @@ class SemesterDocument:
word.Quit()
logger.debug("PDF saved")
+ @property
def cleanup(self):
os.remove(f"{self.filename}.docx")
os.remove(f"{self.filename}.pdf")
+ @property
+ def send(self):
+ print_document(self.filename + ".pdf")
+ logger.debug("Document sent to printer")
+
+
+class SemapSchilder:
+ def __init__(self, entries: list[str]):
+ self.entries = entries
+ self.filename = "Schilder"
+ self.font_size = Pt(23)
+ self.font_name = font
+ self.doc = Document()
+ self.define_doc_properties()
+ self.add_entries()
+ self.cleanup()
+ self.create_pdf()
+
+ def define_doc_properties(self):
+ # set the doc to have a top margin of 1cm, left and right are 0.5cm, bottom is 0cm
+ section = self.doc.sections[0]
+ section.top_margin = Cm(1)
+ section.bottom_margin = Cm(0)
+ section.left_margin = Cm(0.5)
+ section.right_margin = Cm(0.5)
+
+ # set the font to Times New Roman, size 23 bold, color black
+ for paragraph in self.doc.paragraphs:
+ for run in paragraph.runs:
+ run.font.name = self.font_name
+ run.font.size = self.font_size
+ run.font.bold = True
+ run.font.color.rgb = RGBColor(0, 0, 0)
+ paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
+
+ # if the length of the text is
+
+ def add_entries(self):
+ for entry in self.entries:
+ paragraph = self.doc.add_paragraph(entry)
+ paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
+ paragraph.paragraph_format.line_spacing = Pt(20) # Set fixed line spacing
+ paragraph.paragraph_format.space_before = Pt(4) # Remove spacing before
+ paragraph.paragraph_format.space_after = Pt(4) # Remove spacing after
+
+ run = paragraph.runs[0]
+ run.font.name = self.font_name
+ run.font.size = self.font_size
+ run.font.bold = True
+ run.font.color.rgb = RGBColor(0, 0, 0)
+
+ # Add a line to be used as a guideline for cutting
+ line = self.doc.add_paragraph()
+ line.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
+ line.paragraph_format.line_spacing = Pt(20) # Match line spacing
+ line.paragraph_format.space_before = Pt(4) # Remove spacing before
+ line.paragraph_format.space_after = Pt(4) # Remove spacing after
+ line.add_run("--------------------------")
+
+ for paragraph in self.doc.paragraphs:
+ content = paragraph.text.strip()
+ if len(content) > 45:
+ paragraph.runs[0].font.size = Pt(20)
+
+ def save_document(self):
+ # Save the document
+ self.doc.save(f"{self.filename}.docx")
+ logger.debug(f"Document saved as {self.filename}.docx")
+
+ def create_pdf(self):
+ # Save the document
+ import comtypes.client
+
+ word = comtypes.client.CreateObject("Word.Application")
+ self.save_document()
+ docpath = os.path.abspath(f"{self.filename}.docx")
+ doc = word.Documents.Open(docpath)
+ curdir = os.getcwd()
+ doc.SaveAs(f"{curdir}/{self.filename}.pdf", FileFormat=17)
+ doc.Close()
+ word.Quit()
+ logger.debug("PDF saved")
+
+ def cleanup(self):
+ if os.path.exists(f"{self.filename}.docx"):
+ os.remove(f"{self.filename}.docx")
+ if os.path.exists(f"{self.filename}.pdf"):
+ os.remove(f"{self.filename}.pdf")
+
+ @property
+ def send(self):
+ print_document(self.filename + ".pdf")
+ logger.debug("Document sent to printer")
+
if __name__ == "__main__":
- pass
- # apparat = [(i, f"Item {i}") for i in range(405, 438)]
- # doc = SemesterDocument(
- # apparat,
- # "WiSe 24/25",
- # "semap",
- # )
- # doc.make_document()
- # doc.create_pdf()
- # doc.print_document()
-
-
-# def printers():
-# printers = win32print.EnumPrinters(
-# win32print.PRINTER_ENUM_LOCAL | win32print.PRINTER_ENUM_CONNECTIONS
-# )
-# for i, printer in enumerate(printers):
-# print(f"{i}: {printer[2]}")
-
-# list printers
+ entries = [
+ "Schlenke (Glaube und Handels. Luthers Freiheitsschrift)",
+ "Lüsebrink (Theorie und Praxis der Leichtathletik)",
+ "Tester (Apparatstester)",
+ "Entry 4",
+ "Entry 5",
+ ]
+ doc = SemapSchilder(entries).send