Compare commits
65 Commits
v1.0.0
...
dev-rebase
| Author | SHA1 | Date | |
|---|---|---|---|
| 0406fe4f6f | |||
| 560d8285b5 | |||
| 3cc6e793d2 | |||
| 7e07bdea0c | |||
| 06965db26a | |||
| 0df7fd9fe6 | |||
| 713dbc1a1d | |||
| e061c1f5a9 | |||
| 8e9eff4f3a | |||
| 6a11b3482e | |||
| d35b2e816e | |||
| 11d5d67538 | |||
| ebf8363b2a | |||
| a2631570ec | |||
| 9831aa3a62 | |||
| c4be1d8bfa | |||
| 7079b4d47f | |||
| 65c86a65cd | |||
| f4e75831d5 | |||
| 4f28cfe55c | |||
| 8b8c1c9393 | |||
| 247db562b1 | |||
| 1263faa23f | |||
| fd6684cc47 | |||
| 1ee7901d49 | |||
| e934a2b3f1 | |||
| 7be9dba9ca | |||
| 6f21c22d22 | |||
| 1f34442397 | |||
| 373257864f | |||
| b577a69dad | |||
| a64fa9770f | |||
| 0061708785 | |||
| a3b68c2b77 | |||
| 0ac5051aef | |||
| bf419ec3bf | |||
| c6f356fda4 | |||
| 087b8753fb | |||
| 09ec304637 | |||
| f6ab64a8ee | |||
| 4254567bfb | |||
| 9ce46abdce | |||
| 8cce13f6e5 | |||
| f22cbcd26a | |||
| 6f22186b67 | |||
| a231213276 | |||
| b344d806e2 | |||
| 0e3199e289 | |||
| c00eb102ff | |||
| 63b2a1b7a3 | |||
| 5a4156ba04 | |||
| af53b0310f | |||
| ce7d22b26b | |||
| 5f15352401 | |||
| 7da2b3f65d | |||
| 5bf5eeae00 | |||
| c6cbb1d825 | |||
| 3bfb788f42 | |||
| 1c5dfc8f3e | |||
| 4c26aa8d21 | |||
| b67a160e7a | |||
| d8fabdbe11 | |||
| ee8ea9dfda | |||
| ec0f72337d | |||
| 6ae52b6626 |
@@ -50,6 +50,7 @@ class Mail:
|
||||
smtp_server: str
|
||||
port: int
|
||||
sender: str
|
||||
sender_name: str
|
||||
password: str
|
||||
use_user_name: bool
|
||||
printer_mail: str
|
||||
|
||||
1
icons/manage_search.svg
Normal file
1
icons/manage_search.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M80-200v-80h400v80H80Zm0-200v-80h200v80H80Zm0-200v-80h200v80H80Zm744 400L670-354q-24 17-52.5 25.5T560-320q-83 0-141.5-58.5T360-520q0-83 58.5-141.5T560-720q83 0 141.5 58.5T760-520q0 29-8.5 57.5T726-410l154 154-56 56ZM560-400q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35Z"/></svg>
|
||||
|
After Width: | Height: | Size: 420 B |
1
icons/search_results.svg
Normal file
1
icons/search_results.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M400-320q100 0 170-70t70-170q0-100-70-170t-170-70q-100 0-170 70t-70 170q0 100 70 170t170 70Zm-40-120v-280h80v280h-80Zm-140 0v-200h80v200h-80Zm280 0v-160h80v160h-80ZM824-80 597-307q-41 32-91 49.5T400-240q-134 0-227-93T80-560q0-134 93-227t227-93q134 0 227 93t93 227q0 56-17.5 106T653-363l227 227-56 56Z"/></svg>
|
||||
|
After Width: | Height: | Size: 425 B |
1
icons/trash.svg
Normal file
1
icons/trash.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"/></svg>
|
||||
|
After Width: | Height: | Size: 319 B |
@@ -0,0 +1,13 @@
|
||||
|
||||
Subject: Bitte um Bestellung von Neuerwerbungen für Semesterapparat {AppNr} - {AppName}
|
||||
|
||||
|
||||
Hallo zusammen,
|
||||
|
||||
für den Semesterapparat {AppNr} - {Appname} wurden folgende Neuauflagen gefunden:
|
||||
|
||||
{newEditionsOrdered}
|
||||
|
||||
Wäre es möglich, diese, oder neuere Auflagen (wenn vorhanden), zu bestellen?
|
||||
|
||||
{signature}
|
||||
@@ -1,54 +0,0 @@
|
||||
Message-ID: <987b46cf-2d8b-4a27-acb3-c50f61d3d85d@ph-freiburg.de>
|
||||
Date: Tue, 31 Oct 2023 11:38:34 +0100
|
||||
MIME-Version: 1.0
|
||||
User-Agent: Mozilla Thunderbird
|
||||
From: Alexander Kirchner <alexander.kirchner@ph-freiburg.de>
|
||||
Subject: =?UTF-8?Q?Information_bez=C3=BCglich_der_Aufl=C3=B6sung_des_Semeste?=
|
||||
=?UTF-8?Q?rapparates_=7BAppNr=7D?=
|
||||
Content-Language: de-DE
|
||||
X-Mozilla-Draft-Info: internal/draft; vcard=0; receipt=0; DSN=0; uuencode=0;
|
||||
attachmentreminder=0; deliveryformat=0
|
||||
X-Identity-Key: id1
|
||||
Fcc: imap://aky547@imap.ph-freiburg.de/INBOX/Sent
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<p>Sehr geehrte/r {Profname}, <br>
|
||||
</p>
|
||||
<p><br>
|
||||
</p>
|
||||
auf die E-Mail bezüglich der Auflösung oder Verlängerung der
|
||||
Semesterapparate haben wir von Ihnen keine Rückmeldung erhalten.
|
||||
Deshalb gehen wir davon aus, dass der Apparat aufgelöst werden kann.
|
||||
Die Medien, die im Apparat aufgestellt waren, werden nun wieder
|
||||
regulär ausleihbar und sind dann an ihren Standorten bei den Fächern
|
||||
zu finden. <br>
|
||||
<br>
|
||||
Falls Sie den Apparat erneut, oder einen neuen Apparat anlegen
|
||||
wollen, können Sie mir das ausgefüllte Formular zur Einrichtung des
|
||||
Apparates (<a class="moz-txt-link-freetext"
|
||||
href="https://www.ph-freiburg.de/bibliothek/lernen/semesterapparate/info-lehrende-sem.html">https://www.ph-freiburg.de/bibliothek/lernen/semesterapparate/info-lehrende-sem.html</a>)
|
||||
zukommen lassen. Im Falle einer Verlängerung des Apparates reicht
|
||||
eine Antwort auf diese Mail.
|
||||
<p><br>
|
||||
</p>
|
||||
<p>Bei Fragen können Sie sich jederzeit an mich wenden.<br>
|
||||
</p>
|
||||
<p><br>
|
||||
</p>
|
||||
<pre class="moz-signature" cols="72">--
|
||||
Freundliche Grüße
|
||||
|
||||
Alexander Kirchner
|
||||
|
||||
|
||||
Bibliothek der Pädagogischen Hochschule Freiburg
|
||||
Tel. 0761/682-778</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,37 +1,17 @@
|
||||
Message-ID: <b44248a9-025e-e86c-85d7-5949534f0ac4@ph-freiburg.de>
|
||||
Date: Mon, 17 Jul 2023 12:59:04 +0200
|
||||
MIME-Version: 1.0
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101
|
||||
Thunderbird/102.13.0
|
||||
Content-Language: de-DE
|
||||
From: {user_name} <{user_mail}>
|
||||
Subject: =?UTF-8?Q?Information_bez=c3=bcglich_der_Aufl=c3=b6sung_des_Semeste?=
|
||||
=?UTF-8?Q?rapparates_=7bAppNr=7d?=
|
||||
X-Mozilla-Draft-Info: internal/draft; vcard=0; receipt=0; DSN=0; uuencode=0;
|
||||
attachmentreminder=0; deliveryformat=0
|
||||
X-Identity-Key: id1
|
||||
Fcc: imap://aky547@imap.ph-freiburg.de/INBOX/Sent
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
<body>{greeting}
|
||||
<br>
|
||||
<p>auf die E-Mail bezüglich der Auflösung oder Verlängerung der Semesterapparate haben wir von Ihnen keine Rückmeldung erhalten. Deshalb gehen wir davon aus, dass der Apparat aufgelöst werden kann.</p>
|
||||
<p> Die Medien, die in den Apparaten aufgestellt waren, werden nun wieder regulär ausleihbar und sind dann an ihren Standorten bei den Fächern zu finden.</p>
|
||||
<p></p>
|
||||
<p>Falls Sie den Apparat erneut, oder einen neuen Apparat anlegen wollen, können Sie mir das ausgefüllte Formular zur Einrichtung des Apparates (<a class="moz-txt-link-freetext" href="https://www.ph-freiburg.de/bibliothek/lernen/semesterapparate/info-lehrende-sem.html">https://www.ph-freiburg.de/bibliothek/lernen/semesterapparate/info-lehrende-sem.html</a>) zukommen lassen.</p>
|
||||
<p>Im Falle einer Verlängerung des Apparates reicht eine Antwort auf diese Mail.<br>
|
||||
</p>
|
||||
<p>Bei Fragen können Sie sich jederzeit an mich wenden.<br>
|
||||
</p>
|
||||
<p><br>
|
||||
</p>
|
||||
<pre class="moz-signature" cols="72">--
|
||||
Subject: Information bezüglich der Auflösung des Semesterapparates {AppNr}
|
||||
|
||||
|
||||
{greeting}
|
||||
|
||||
auf die E-Mail bezüglich der Auflösung oder Verlängerung der Semesterapparate haben wir von Ihnen keine Rückmeldung erhalten. Deshalb gehen wir davon aus, dass der Apparat aufgelöst werden kann.
|
||||
Die Medien, die in den Apparaten aufgestellt waren, werden nun wieder regulär ausleihbar und sind dann an ihren Standorten bei den Fächern zu finden.
|
||||
|
||||
Falls Sie den Apparat erneut, oder einen neuen Apparat anlegen wollen,
|
||||
können Sie mir das ausgefüllte Formular zur Einrichtung des Apparates
|
||||
https://www.ph-freiburg.de/bibliothek/lernen/semesterapparate/info-lehrende-sem.html
|
||||
zukommen lassen. Im Falle einer Verlängerung des Apparates reicht eine Antwort auf diese Mail.
|
||||
|
||||
Bei Fragen können Sie sich jederzeit an mich wenden.
|
||||
|
||||
{signature}
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,36 +1,16 @@
|
||||
Message-ID: <db617c48-29d6-d3d8-a67c-e9a6cf9b5bdb@ph-freiburg.de>
|
||||
Date: Tue, 12 Sep 2023 13:01:35 +0200
|
||||
MIME-Version: 1.0
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101
|
||||
Thunderbird/102.15.0
|
||||
From: Alexander Kirchner <alexander.kirchner@ph-freiburg.de>
|
||||
Subject: Information zum Semesterapparat {AppNr} - {Appname}
|
||||
Content-Language: de-DE
|
||||
X-Mozilla-Draft-Info: internal/draft; vcard=0; receipt=0; DSN=0; uuencode=0;
|
||||
attachmentreminder=0; deliveryformat=0
|
||||
X-Identity-Key: id1
|
||||
Fcc: imap://aky547@imap.ph-freiburg.de/INBOX/Sent
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
<body>{greeting}
|
||||
<br>
|
||||
<p>Ihr Semesterapparat {Appname} wurde angelegt.</p>
|
||||
<p>Unter folgendem Link können Sie die Apparate einsehen:</p>
|
||||
<p><a class="moz-txt-link-freetext" href="https://bsz.ibs-bw.de/aDISWeb/app?service=direct/0/Home/$DirectLink&sp=SOPAC42&sp=SWI00000002&noRedir">https://bsz.ibs-bw.de/aDISWeb/app?service=direct/0/Home/$DirectLink&sp=SOPAC42&sp=SWI00000002&noRedir</a></p>
|
||||
<p>Ihr Apparat ist unter {AppSubject} > {Profname} > {AppNr} {Appname}.<br>
|
||||
</p>
|
||||
<p><br>
|
||||
</p>
|
||||
<p>Noch nicht vorhandene Medien wurden vorgemerkt und werden nach Rückkehr in die Bibliothek eingearbeitet.</p>
|
||||
<p>Bei Fragen können Sie sich per Mail bei mir melden.<br>
|
||||
</p>
|
||||
<pre class="moz-signature" cols="72">--
|
||||
Subject: Information zum Semesterapparat {AppNr} - {AppName}
|
||||
|
||||
|
||||
{greeting}
|
||||
|
||||
Ihr Semesterapparat {Appname} wurde angelegt.
|
||||
Unter folgendem Link können Sie die Apparate einsehen:
|
||||
https://bsz.ibs-bw.de/aDISWeb/app?service=direct/0/Home/$DirectLink&sp=SOPAC42&sp=SWI00000002&noRedir
|
||||
|
||||
Ihr Apparat ist unter {AppSubject} > {Profname} > {AppNr} {Appname}
|
||||
|
||||
Noch nicht vorhandene Medien wurden vorgemerkt und werden nach Rückkehr in die Bibliothek eingearbeitet.
|
||||
Bei Fragen können Sie sich per Mail bei mir melden.
|
||||
|
||||
{signature}
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
Subject: Information zur Auflösung des Semesterapparates {AppNr} - {Appname}
|
||||
|
||||
|
||||
{greeting}
|
||||
|
||||
Ihr Semesterapparat "{Appname} ({AppNr})" wurde wie besprochen aufgelöst.
|
||||
Die Medien sind von nun an wieder in den Regalen zu finden.
|
||||
|
||||
{signature}
|
||||
@@ -1,18 +0,0 @@
|
||||
Subject: Information zur Auflösung des Semesterapparates {AppNr} - {Appname}
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/html; charset="UTF-8"
|
||||
Content-Transfer-Encoding: 8bit
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
<body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">{greeting}</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ihr Semesterapparat "{Appname} ({AppNr})" wurde wie besprochen aufgelöst. </p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Die Medien sind von nun an wieder in den Regalen zu finden.</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><pre class="moz-signature" cols="72">-- </p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">{signature}</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></pre></p></body></html>
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
Subject: Neuauflagen für Semesterapparat {AppNr} - {AppName}
|
||||
|
||||
|
||||
{greeting}
|
||||
|
||||
Für Ihren Semesterapparat {AppNr} - {Appname} wurden folgende Neuauflagen gefunden:
|
||||
|
||||
{newEditions}
|
||||
|
||||
Sollen wir die alte(n) Auflage(n) aus dem Apparat durch diese austauschen?
|
||||
Nicht vorhandene Exemplare werden an die Erwerbungsabteilung weitergegeben
|
||||
und nach Erhalt der Medien in den Apparat eingearbeitet.
|
||||
|
||||
{signature}
|
||||
9
mail_vorlagen/blankomail.eml
Normal file
9
mail_vorlagen/blankomail.eml
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
Subject: CHANGEME
|
||||
|
||||
|
||||
{greeting}
|
||||
|
||||
|
||||
|
||||
{signature}
|
||||
11
main.py
11
main.py
@@ -1,11 +1,14 @@
|
||||
from src import first_launch, settings
|
||||
from src.ui.widgets.welcome_wizard import launch_wizard as startup
|
||||
from PySide6 import QtWidgets
|
||||
import sys
|
||||
from src.ui.userInterface import launch_gui as UI
|
||||
|
||||
from PySide6 import QtWidgets
|
||||
|
||||
from src import first_launch, settings
|
||||
from src.shared.logging import configure
|
||||
from src.ui.userInterface import launch_gui as UI
|
||||
from src.ui.widgets.welcome_wizard import launch_wizard as startup
|
||||
|
||||
if __name__ == "__main__":
|
||||
configure("INFO")
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
if not first_launch:
|
||||
setup = startup()
|
||||
|
||||
@@ -3,15 +3,16 @@ name = "semesterapparatsmanager"
|
||||
version = "1.0.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"appdirs>=1.4.4",
|
||||
"beautifulsoup4>=4.12.3",
|
||||
"beautifulsoup4>=4.13.5",
|
||||
"bump-my-version>=0.29.0",
|
||||
"chardet>=5.2.0",
|
||||
"charset-normalizer>=3.4.3",
|
||||
"comtypes>=1.4.9",
|
||||
"darkdetect>=0.8.0",
|
||||
"docx2pdf>=0.1.8",
|
||||
"httpx>=0.28.1",
|
||||
"loguru>=0.7.3",
|
||||
"mkdocs>=1.6.1",
|
||||
"mkdocs-material>=9.5.49",
|
||||
@@ -35,6 +36,9 @@ dev = [
|
||||
"icecream>=2.1.4",
|
||||
"nuitka>=2.5.9",
|
||||
]
|
||||
swbtest = [
|
||||
"alive-progress>=3.3.0",
|
||||
]
|
||||
|
||||
[tool.bumpversion]
|
||||
current_version = "1.0.0"
|
||||
@@ -61,3 +65,7 @@ post_commit_hooks = []
|
||||
filename = "src/__init__.py"
|
||||
[[tool.bumpversion.files]]
|
||||
filename = ".version"
|
||||
|
||||
[[tool.uv.index]]
|
||||
url = "https://git.theprivateserver.de/api/packages/WorldTeacher/pypi/simple/"
|
||||
default = false
|
||||
|
||||
@@ -3,30 +3,31 @@ __author__ = "Alexander Kirchner"
|
||||
__all__ = ["__version__", "__author__", "Icon", "settings"]
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
from appdirs import AppDirs
|
||||
|
||||
from config import Config
|
||||
|
||||
|
||||
app = AppDirs("SemesterApparatsManager", "SAM")
|
||||
LOG_DIR = app.user_log_dir
|
||||
CONFIG_DIR = app.user_config_dir
|
||||
if not os.path.exists(LOG_DIR):
|
||||
os.makedirs(LOG_DIR)
|
||||
if not os.path.exists(CONFIG_DIR):
|
||||
os.makedirs(CONFIG_DIR)
|
||||
LOG_DIR: str = app.user_log_dir # type: ignore
|
||||
CONFIG_DIR: str = app.user_config_dir # type: ignore
|
||||
if not os.path.exists(LOG_DIR): # type: ignore
|
||||
os.makedirs(LOG_DIR) # type: ignore
|
||||
if not os.path.exists(CONFIG_DIR): # type: ignore
|
||||
os.makedirs(CONFIG_DIR) # type: ignore
|
||||
|
||||
|
||||
settings = Config(f"{CONFIG_DIR}/config.yaml")
|
||||
DATABASE_DIR = (
|
||||
app.user_config_dir if settings.database.path is None else settings.database.path
|
||||
DATABASE_DIR: Union[Path, str] = ( # type: ignore
|
||||
app.user_config_dir if settings.database.path is None else settings.database.path # type: ignore
|
||||
)
|
||||
if not os.path.exists(DATABASE_DIR):
|
||||
os.makedirs(DATABASE_DIR)
|
||||
if not os.path.exists(DATABASE_DIR): # type: ignore
|
||||
os.makedirs(DATABASE_DIR) # type: ignore
|
||||
first_launch = settings.exists
|
||||
if not os.path.exists(settings.database.temp.expanduser()):
|
||||
settings.database.temp.expanduser().mkdir(parents=True, exist_ok=True)
|
||||
if not os.path.exists(settings.database.temp.expanduser()): # type: ignore
|
||||
settings.database.temp.expanduser().mkdir(parents=True, exist_ok=True) # type: ignore
|
||||
from .utils.icon import Icon
|
||||
|
||||
if not os.path.exists("logs"):
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
from .semester import Semester
|
||||
from .database import Database
|
||||
__all__ = [
|
||||
"AdminCommands",
|
||||
"AutoAdder",
|
||||
"AvailChecker",
|
||||
"BookGrabber",
|
||||
"Database",
|
||||
"DocumentationThread",
|
||||
"NewEditionCheckerThread",
|
||||
"recreateElsaFile",
|
||||
"recreateFile",
|
||||
"Catalogue",
|
||||
]
|
||||
|
||||
from .admin_console import AdminCommands
|
||||
from .thread_bookgrabber import BookGrabber
|
||||
from .threads_availchecker import AvailChecker
|
||||
from .threads_autoadder import AutoAdder
|
||||
from .catalogue import Catalogue
|
||||
from .create_file import recreateElsaFile, recreateFile
|
||||
from .database import Database
|
||||
from .documentation_thread import DocumentationThread
|
||||
from .create_file import recreateFile, recreateElsaFile
|
||||
from .thread_bookgrabber import BookGrabber
|
||||
from .thread_neweditions import NewEditionCheckerThread
|
||||
from .threads_autoadder import AutoAdder
|
||||
from .threads_availchecker import AvailChecker
|
||||
|
||||
292
src/backend/catalogue.py
Normal file
292
src/backend/catalogue.py
Normal file
@@ -0,0 +1,292 @@
|
||||
from typing import List
|
||||
|
||||
import regex
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from src.logic import BookData as Book
|
||||
from src.shared.logging import log
|
||||
|
||||
URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndex/Search?type0%5B%5D=allfields&lookfor0%5B%5D={}&join=AND&bool0%5B%5D=AND&type0%5B%5D=au&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ti&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ct&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=isn&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ta&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=co&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=py&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pp&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pu&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=si&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=zr&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=cc&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND"
|
||||
BASE = "https://rds.ibs-bw.de"
|
||||
|
||||
|
||||
class Catalogue:
|
||||
def __init__(self, timeout=15):
|
||||
self.timeout = timeout
|
||||
reachable = self.check_connection()
|
||||
if not reachable:
|
||||
log.error("No internet connection available.")
|
||||
raise ConnectionError("No internet connection available.")
|
||||
|
||||
def check_connection(self):
|
||||
try:
|
||||
response = requests.get("https://www.google.com", timeout=self.timeout)
|
||||
if response.status_code == 200:
|
||||
return True
|
||||
except requests.exceptions.RequestException as e:
|
||||
log.error(f"Could not connect to google.com: {e}")
|
||||
|
||||
def search_book(self, searchterm: str):
|
||||
response = requests.get(URL.format(searchterm), timeout=self.timeout)
|
||||
return response.text
|
||||
|
||||
def search(self, link: str):
|
||||
response = requests.get(link, timeout=self.timeout)
|
||||
return response.text
|
||||
|
||||
def get_book_links(self, searchterm: str) -> List[str]:
|
||||
response = self.search_book(searchterm)
|
||||
soup = BeautifulSoup(response, "html.parser")
|
||||
links = soup.find_all("a", class_="title getFull")
|
||||
res: List[str] = []
|
||||
for link in links:
|
||||
res.append(BASE + link["href"]) # type: ignore
|
||||
return res
|
||||
|
||||
def get_book(self, searchterm: str):
|
||||
log.info(f"Searching for term: {searchterm}")
|
||||
|
||||
links = self.get_book_links(searchterm)
|
||||
print(links)
|
||||
for elink in links:
|
||||
result = self.search(elink)
|
||||
# in result search for class col-xs-12 rds-dl RDS_LOCATION
|
||||
# if found, return text of href
|
||||
soup = BeautifulSoup(result, "html.parser")
|
||||
|
||||
# Optional (unchanged): title and ppn if you need them
|
||||
title_el = soup.find("div", class_="headline text")
|
||||
title = title_el.get_text(strip=True) if title_el else None
|
||||
|
||||
ppn_el = soup.find(
|
||||
"div", class_="col-xs-12 col-md-5 col-lg-4 rds-dl-head RDS_PPN"
|
||||
)
|
||||
# in ppn_el, get text of div col-xs-12 col-md-7 col-lg-8 rds-dl-panel
|
||||
ppn = (
|
||||
ppn_el.find_next_sibling(
|
||||
"div", class_="col-xs-12 col-md-7 col-lg-8 rds-dl-panel"
|
||||
).get_text(strip=True)
|
||||
if ppn_el
|
||||
else None
|
||||
)
|
||||
|
||||
# get edition text at div class col-xs-12 col-md-5 col-lg-4 rds-dl-head RDS_EDITION
|
||||
edition_el = soup.find(
|
||||
"div", class_="col-xs-12 col-md-5 col-lg-4 rds-dl-head RDS_EDITION"
|
||||
)
|
||||
edition = (
|
||||
edition_el.find_next_sibling(
|
||||
"div", class_="col-xs-12 col-md-7 col-lg-8 rds-dl-panel"
|
||||
).get_text(strip=True)
|
||||
if edition_el
|
||||
else None
|
||||
)
|
||||
|
||||
authors = soup.find_all(
|
||||
"div", class_="col-xs-12 col-md-5 col-lg-4 rds-dl-head RDS_PERSON"
|
||||
)
|
||||
author = None
|
||||
if authors:
|
||||
# get the names of the a href links in the div col-xs-12 col-md-7 col-lg-8 rds-dl-panel
|
||||
author_names = []
|
||||
for author in authors:
|
||||
panel = author.find_next_sibling(
|
||||
"div", class_="col-xs-12 col-md-7 col-lg-8 rds-dl-panel"
|
||||
)
|
||||
if panel:
|
||||
links = panel.find_all("a")
|
||||
for link in links:
|
||||
author_names.append(link.text.strip())
|
||||
author = (
|
||||
";".join(author_names) if len(author_names) > 1 else author_names[0]
|
||||
)
|
||||
signature = None
|
||||
|
||||
panel = soup.select_one("div.panel-body")
|
||||
if panel:
|
||||
# Collect the RDS_* blocks in order, using the 'space' divs as separators
|
||||
groups = []
|
||||
cur = {}
|
||||
for node in panel.select(
|
||||
"div.rds-dl.RDS_SIGNATURE, div.rds-dl.RDS_STATUS, div.rds-dl.RDS_LOCATION, div.col-xs-12.space"
|
||||
):
|
||||
classes = node.get("class", [])
|
||||
# Separator between entries
|
||||
if "space" in classes:
|
||||
if cur:
|
||||
groups.append(cur)
|
||||
cur = {}
|
||||
continue
|
||||
|
||||
# Read the value from the corresponding panel cell
|
||||
val_el = node.select_one(".rds-dl-panel")
|
||||
val = (
|
||||
val_el.get_text(" ", strip=True)
|
||||
if val_el
|
||||
else node.get_text(" ", strip=True)
|
||||
)
|
||||
|
||||
if "RDS_SIGNATURE" in classes:
|
||||
cur["signature"] = val
|
||||
elif "RDS_STATUS" in classes:
|
||||
cur["status"] = val
|
||||
elif "RDS_LOCATION" in classes:
|
||||
cur["location"] = val
|
||||
|
||||
if cur: # append the last group if not followed by a space
|
||||
groups.append(cur)
|
||||
|
||||
# Find the signature for the entry whose location mentions "Semesterapparat"
|
||||
for g in groups:
|
||||
loc = g.get("location", "").lower()
|
||||
if "semesterapparat" in loc:
|
||||
signature = g.get("signature")
|
||||
return Book(
|
||||
title=title,
|
||||
ppn=ppn,
|
||||
signature=signature,
|
||||
library_location=loc.split("-")[-1],
|
||||
link=elink,
|
||||
author=author,
|
||||
edition=edition,
|
||||
)
|
||||
else:
|
||||
return Book(
|
||||
title=title,
|
||||
ppn=ppn,
|
||||
signature=signature,
|
||||
library_location=loc.split("\n\n")[-1],
|
||||
link=elink,
|
||||
author=author,
|
||||
edition=edition,
|
||||
)
|
||||
|
||||
def get(self, ppn: str) -> Book | None:
|
||||
# based on PPN, get title, people, edition, year, language, pages, isbn,
|
||||
link = f"https://rds.ibs-bw.de/phfreiburg/opac/RDSIndexrecord/{ppn}"
|
||||
result = self.search(link)
|
||||
soup = BeautifulSoup(result, "html.parser")
|
||||
|
||||
def get_ppn(self, searchterm: str) -> str | None:
|
||||
links = self.get_book_links(searchterm)
|
||||
ppn = None
|
||||
for link in links:
|
||||
result = self.search(link)
|
||||
soup = BeautifulSoup(result, "html.parser")
|
||||
print(link)
|
||||
ppn = link.split("/")[-1]
|
||||
if ppn and regex.match(r"^\d{8,10}[X\d]?$", ppn):
|
||||
return ppn
|
||||
return ppn
|
||||
|
||||
def get_semesterapparat_number(self, searchterm: str) -> int:
|
||||
links = self.get_book_links(searchterm)
|
||||
for link in links:
|
||||
result = self.search(link)
|
||||
# in result search for class col-xs-12 rds-dl RDS_LOCATION
|
||||
# if found, return text of href
|
||||
soup = BeautifulSoup(result, "html.parser")
|
||||
|
||||
locations = soup.find_all("div", class_="col-xs-12 rds-dl RDS_LOCATION")
|
||||
for location_el in locations:
|
||||
if "Semesterapparat-" in location_el.text:
|
||||
match = regex.search(r"Semesterapparat-(\d+)", location_el.text)
|
||||
if match:
|
||||
return int(match.group(1))
|
||||
if "Handbibliothek-" in location_el.text:
|
||||
return location_el.text.strip().split("\n\n")[-1].strip()
|
||||
return location_el.text.strip().split("\n\n")[-1].strip()
|
||||
return 0
|
||||
|
||||
def get_author(self, link: str) -> str:
|
||||
links = self.get_book_links(f"kid:{link}")
|
||||
author = None
|
||||
for link in links:
|
||||
# print(link)
|
||||
result = self.search(link)
|
||||
soup = BeautifulSoup(result, "html.parser")
|
||||
# get all authors, return them as a string seperated by ;
|
||||
authors = soup.find_all(
|
||||
"div", class_="col-xs-12 col-md-5 col-lg-4 rds-dl-head RDS_PERSON"
|
||||
)
|
||||
if authors:
|
||||
# get the names of the a href links in the div col-xs-12 col-md-7 col-lg-8 rds-dl-panel
|
||||
author_names = []
|
||||
for author in authors:
|
||||
panel = author.find_next_sibling(
|
||||
"div", class_="col-xs-12 col-md-7 col-lg-8 rds-dl-panel"
|
||||
)
|
||||
if panel:
|
||||
links = panel.find_all("a")
|
||||
for link in links:
|
||||
author_names.append(link.text.strip())
|
||||
author = "; ".join(author_names)
|
||||
return author
|
||||
|
||||
def get_signature(self, isbn: str):
|
||||
links = self.get_book_links(f"{isbn}")
|
||||
signature = None
|
||||
for link in links:
|
||||
result = self.search(link)
|
||||
soup = BeautifulSoup(result, "html.parser")
|
||||
panel = soup.select_one("div.panel-body")
|
||||
if panel:
|
||||
# Collect the RDS_* blocks in order, using the 'space' divs as separators
|
||||
groups = []
|
||||
cur = {}
|
||||
for node in panel.select(
|
||||
"div.rds-dl.RDS_SIGNATURE, div.rds-dl.RDS_STATUS, div.rds-dl.RDS_LOCATION, div.col-xs-12.space"
|
||||
):
|
||||
classes = node.get("class", [])
|
||||
# Separator between entries
|
||||
if "space" in classes:
|
||||
if cur:
|
||||
groups.append(cur)
|
||||
cur = {}
|
||||
continue
|
||||
|
||||
# Read the value from the corresponding panel cell
|
||||
val_el = node.select_one(".rds-dl-panel")
|
||||
val = (
|
||||
val_el.get_text(" ", strip=True)
|
||||
if val_el
|
||||
else node.get_text(" ", strip=True)
|
||||
)
|
||||
|
||||
if "RDS_SIGNATURE" in classes:
|
||||
cur["signature"] = val
|
||||
elif "RDS_STATUS" in classes:
|
||||
cur["status"] = val
|
||||
elif "RDS_LOCATION" in classes:
|
||||
cur["location"] = val
|
||||
|
||||
if cur: # append the last group if not followed by a space
|
||||
groups.append(cur)
|
||||
|
||||
# Find the signature for the entry whose location mentions "Semesterapparat"
|
||||
for g in groups:
|
||||
print(g)
|
||||
loc = g.get("location", "").lower()
|
||||
if "semesterapparat" in loc:
|
||||
signature = g.get("signature")
|
||||
return signature
|
||||
else:
|
||||
signature = g.get("signature")
|
||||
return signature
|
||||
print("No signature found")
|
||||
return signature
|
||||
|
||||
def in_library(self, ppn: str) -> bool:
|
||||
if ppn is None:
|
||||
return False
|
||||
links = self.get_book_links(f"kid:{ppn}")
|
||||
return len(links) > 0
|
||||
|
||||
def get_location(self, ppn: str) -> str | None:
|
||||
if ppn is None:
|
||||
return None
|
||||
link = self.get_book(f"{ppn}")
|
||||
if link is None:
|
||||
return None
|
||||
return link.library_location
|
||||
@@ -1,8 +1,8 @@
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sqlite3 as sql
|
||||
import sys
|
||||
import tempfile
|
||||
from dataclasses import asdict
|
||||
from pathlib import Path
|
||||
@@ -12,7 +12,7 @@ from typing import Any, List, Optional, Tuple, Union
|
||||
|
||||
import loguru
|
||||
|
||||
from src import LOG_DIR, settings, DATABASE_DIR
|
||||
from src import DATABASE_DIR, settings
|
||||
from src.backend.db import (
|
||||
CREATE_ELSA_FILES_TABLE,
|
||||
CREATE_ELSA_MEDIA_TABLE,
|
||||
@@ -21,6 +21,7 @@ from src.backend.db import (
|
||||
CREATE_TABLE_FILES,
|
||||
CREATE_TABLE_MEDIA,
|
||||
CREATE_TABLE_MESSAGES,
|
||||
CREATE_TABLE_NEWEDITIONS,
|
||||
CREATE_TABLE_PROF,
|
||||
CREATE_TABLE_SUBJECTS,
|
||||
CREATE_TABLE_USER,
|
||||
@@ -28,15 +29,10 @@ from src.backend.db import (
|
||||
from src.errors import AppPresentError, NoResultError
|
||||
from src.logic import ELSA, Apparat, ApparatData, BookData, Prof
|
||||
from src.logic.constants import SEMAP_MEDIA_ACCOUNTS
|
||||
from src.logic.semester import Semester
|
||||
from src.utils.blob import create_blob
|
||||
|
||||
from .semester import Semester
|
||||
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
|
||||
|
||||
ascii_lowercase = lower + digits + punctuation
|
||||
@@ -68,6 +64,60 @@ class Database:
|
||||
self.db_path = db_path
|
||||
log.debug(f"Database path: {self.db_path}")
|
||||
self.db_initialized = False
|
||||
self.startup_check()
|
||||
|
||||
def startup_check(self):
|
||||
# check existence of all tables. if any is missing, recreate the table
|
||||
if not self.db_initialized:
|
||||
self.initializeDatabase()
|
||||
tables = self.get_db_contents()
|
||||
tables = [t[1] for t in tables] if tables is not None else []
|
||||
required_tables = [
|
||||
"semesterapparat",
|
||||
"messages",
|
||||
"media",
|
||||
"files",
|
||||
"prof",
|
||||
"user",
|
||||
"subjects",
|
||||
"elsa",
|
||||
"elsa_files",
|
||||
"elsa_media",
|
||||
"neweditions",
|
||||
]
|
||||
|
||||
for table in required_tables:
|
||||
if table not in tables:
|
||||
log.critical(f"Table {table} is missing, recreating...")
|
||||
self.create_table(table)
|
||||
|
||||
def create_table(self, table_name: str):
|
||||
match table_name:
|
||||
case "semesterapparat":
|
||||
query = CREATE_TABLE_APPARAT
|
||||
case "messages":
|
||||
query = CREATE_TABLE_MESSAGES
|
||||
case "media":
|
||||
query = CREATE_TABLE_MEDIA
|
||||
case "files":
|
||||
query = CREATE_TABLE_FILES
|
||||
case "prof":
|
||||
query = CREATE_TABLE_PROF
|
||||
case "user":
|
||||
query = CREATE_TABLE_USER
|
||||
case "subjects":
|
||||
query = CREATE_TABLE_SUBJECTS
|
||||
case "elsa":
|
||||
query = CREATE_ELSA_TABLE
|
||||
case "elsa_files":
|
||||
query = CREATE_ELSA_FILES_TABLE
|
||||
case "elsa_media":
|
||||
query = CREATE_ELSA_MEDIA_TABLE
|
||||
case "neweditions":
|
||||
query = CREATE_TABLE_NEWEDITIONS
|
||||
case _:
|
||||
log.error(f"Table {table_name} is not a valid table name")
|
||||
self.query_db(query)
|
||||
|
||||
def initializeDatabase(self):
|
||||
if not self.db_initialized:
|
||||
@@ -94,7 +144,7 @@ class Database:
|
||||
self.create_tables()
|
||||
self.insertSubjects()
|
||||
|
||||
def getElsaMediaID(self, work_author, signature, pages):
|
||||
def getElsaMediaID(self, work_author: str, signature: str, pages: str):
|
||||
query = (
|
||||
"SELECT id FROM elsa_media WHERE work_author=? AND signature=? AND pages=?"
|
||||
)
|
||||
@@ -110,7 +160,7 @@ class Database:
|
||||
query = "SELECT type FROM elsa_media WHERE id=?"
|
||||
return self.query_db(query, (id,), one=True)[0]
|
||||
|
||||
def get_db_contents(self) -> Union[List[Tuple], None]:
|
||||
def get_db_contents(self) -> Union[List[Tuple[Any]], None]:
|
||||
"""
|
||||
Get the contents of the
|
||||
|
||||
@@ -132,7 +182,13 @@ class Database:
|
||||
Returns:
|
||||
sql.Connection: The active connection to the database
|
||||
"""
|
||||
return sql.connect(self.db_path)
|
||||
conn = sql.connect(self.db_path)
|
||||
# Fast pragmas suitable for a desktop app DB
|
||||
conn.execute("PRAGMA journal_mode=WAL;")
|
||||
conn.execute("PRAGMA synchronous=NORMAL;")
|
||||
conn.execute("PRAGMA temp_store=MEMORY;")
|
||||
conn.execute("PRAGMA mmap_size=134217728;") # 128MB
|
||||
return conn
|
||||
|
||||
def close_connection(self, conn: sql.Connection):
|
||||
"""
|
||||
@@ -160,6 +216,25 @@ class Database:
|
||||
cursor.execute(CREATE_ELSA_TABLE)
|
||||
cursor.execute(CREATE_ELSA_FILES_TABLE)
|
||||
cursor.execute(CREATE_ELSA_MEDIA_TABLE)
|
||||
# Helpful indices to speed up frequent lookups and joins
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_media_app_prof ON media(app_id, prof_id);"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_media_deleted ON media(deleted);"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_media_available ON media(available);"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_messages_remind_at ON messages(remind_at);"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_semesterapparat_prof ON semesterapparat(prof_id);"
|
||||
)
|
||||
cursor.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_semesterapparat_appnr ON semesterapparat(appnr);"
|
||||
)
|
||||
conn.commit()
|
||||
self.close_connection(conn)
|
||||
|
||||
@@ -173,7 +248,7 @@ class Database:
|
||||
"""
|
||||
conn = self.connect()
|
||||
cursor = conn.cursor()
|
||||
log.debug(f"Inserting {params} into database with query {query}")
|
||||
log.debug(f"Inserting into DB: {query}")
|
||||
cursor.execute(query, params)
|
||||
conn.commit()
|
||||
self.close_connection(conn)
|
||||
@@ -182,7 +257,7 @@ class Database:
|
||||
def query_db(
|
||||
self,
|
||||
query: str,
|
||||
args: Tuple[Any, Any] = (), # type:ignore
|
||||
args: Tuple[Any] = (), # type:ignore
|
||||
one: bool = False, # type:ignore
|
||||
) -> Union[Tuple[Any, Any], List[Tuple[Any, Any]]]:
|
||||
"""
|
||||
@@ -201,12 +276,12 @@ class Database:
|
||||
logs_query = query
|
||||
|
||||
logs_args = args
|
||||
if "fileblob" in query:
|
||||
# set fileblob arg in logger to "too long"
|
||||
logs_query = query
|
||||
fileblob_location = query.find("fileblob")
|
||||
# remove fileblob from query
|
||||
logs_query = query[:fileblob_location] + "fileblob = too long"
|
||||
# if "fileblob" in query:
|
||||
# # set fileblob arg in logger to "too long"
|
||||
# logs_query = query
|
||||
# fileblob_location = query.find("fileblob")
|
||||
# # remove fileblob from query
|
||||
# logs_query = query[:fileblob_location] + "fileblob = too long"
|
||||
|
||||
log_message = f"Querying database with query {logs_query}, args: {logs_args}"
|
||||
# if "INSERT" in query:
|
||||
@@ -332,49 +407,66 @@ class Database:
|
||||
"""
|
||||
return self.query_db("SELECT id FROM media ORDER BY id DESC", one=True)[0]
|
||||
|
||||
def searchBook(self, data: dict[str, str]) -> list[tuple[BookData, int]]:
|
||||
def searchBook(
|
||||
self, data: dict[str, str]
|
||||
) -> Optional[list[tuple["BookData", int, int]]]:
|
||||
"""
|
||||
Search a book in the database based on the sent data.
|
||||
Search a book in the database using regex against signature/title.
|
||||
|
||||
Args:
|
||||
data (dict[str, str]): A dictionary containing the data to be searched for. The dictionary can contain the following:
|
||||
- signature: The signature of the book
|
||||
- title: The title of the book
|
||||
data: may contain:
|
||||
- "signature": regex to match against BookData.signature
|
||||
- "title": regex to match against BookData.title
|
||||
|
||||
Returns:
|
||||
list[tuple[BookData, int]]: A list of tuples containing the wrapped Metadata and the id of the book
|
||||
list of (BookData, app_id, prof_id) tuples, or None if invalid args
|
||||
"""
|
||||
rdata = self.query_db("SELECT * FROM media WHERE deleted=0")
|
||||
# log.debug(rdata, len(rdata))
|
||||
|
||||
# Determine mode (kept compatible with your original logic)
|
||||
mode = 0
|
||||
if len(data) == 1:
|
||||
if "signature" in data.keys():
|
||||
if len(data) == 1 and "signature" in data:
|
||||
mode = 1
|
||||
elif "title" in data.keys():
|
||||
elif len(data) == 1 and "title" in data:
|
||||
mode = 2
|
||||
elif len(data) == 2:
|
||||
elif len(data) == 2 and "signature" in data and "title" in data:
|
||||
mode = 3
|
||||
else:
|
||||
return None
|
||||
ret = []
|
||||
for book in rdata:
|
||||
bookdata = BookData().from_string(book[1])
|
||||
app_id = book[2]
|
||||
prof_id = book[3]
|
||||
|
||||
def _compile(expr: str) -> re.Pattern:
|
||||
try:
|
||||
return re.compile(expr, re.IGNORECASE | re.UNICODE)
|
||||
except re.error:
|
||||
# If user provided a broken regex, treat it as a literal
|
||||
return re.compile(re.escape(expr), re.IGNORECASE | re.UNICODE)
|
||||
|
||||
sig_re = _compile(data["signature"]) if mode in (1, 3) else None
|
||||
title_re = _compile(data["title"]) if mode in (2, 3) else None
|
||||
|
||||
# Fetch candidates once
|
||||
rows = self.query_db("SELECT * FROM media WHERE deleted=0")
|
||||
|
||||
results: list[tuple["BookData", int, int]] = []
|
||||
for row in rows:
|
||||
bookdata = BookData().from_string(
|
||||
row[1]
|
||||
) # assumes row[1] is the serialized bookdata
|
||||
app_id = row[2]
|
||||
prof_id = row[3]
|
||||
|
||||
sig_val = bookdata.signature
|
||||
title_val = bookdata.title
|
||||
if mode == 1:
|
||||
if data["signature"] in bookdata.signature:
|
||||
ret.append((bookdata, app_id, prof_id))
|
||||
if sig_re.search(sig_val):
|
||||
results.append((bookdata, app_id, prof_id))
|
||||
elif mode == 2:
|
||||
if data["title"] in bookdata.title:
|
||||
ret.append((bookdata, app_id, prof_id))
|
||||
elif mode == 3:
|
||||
if (
|
||||
data["signature"] in bookdata.signature
|
||||
and data["title"] in bookdata.title
|
||||
):
|
||||
ret.append((bookdata, app_id, prof_id))
|
||||
# log.debug(ret)
|
||||
return ret
|
||||
if title_re.search(title_val):
|
||||
results.append((bookdata, app_id, prof_id))
|
||||
else: # mode == 3
|
||||
if sig_re.search(sig_val) and title_re.search(title_val):
|
||||
results.append((bookdata, app_id, prof_id))
|
||||
|
||||
return results
|
||||
|
||||
def setAvailability(self, book_id: str, available: str):
|
||||
"""
|
||||
@@ -402,7 +494,7 @@ class Database:
|
||||
"""
|
||||
result = self.query_db(
|
||||
"SELECT id FROM media WHERE bookdata=? AND app_id=? AND prof_id=?",
|
||||
(dump_pickle(bookdata), app_id, prof_id),
|
||||
(bookdata.to_dict, app_id, prof_id),
|
||||
one=True,
|
||||
)
|
||||
return result[0]
|
||||
@@ -435,6 +527,7 @@ class Database:
|
||||
deleted (int, optional): The state of the book. Set to 1 to include deleted ones. Defaults to 0.
|
||||
|
||||
Returns:
|
||||
|
||||
list[dict[int, BookData, int]]: A list of dictionaries containing the id, the metadata of the book and the availability of the book
|
||||
"""
|
||||
qdata = self.query_db(
|
||||
@@ -451,6 +544,68 @@ class Database:
|
||||
ret_result.append(data)
|
||||
return ret_result
|
||||
|
||||
def getAllBooks(self) -> list[dict[str, Union[int, BookData]]]:
|
||||
"""
|
||||
Get all books in the database that are not set as deleted
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[dict[str, Union[int, BookData]]]
|
||||
A list of dictionaries containing the id and the metadata of the book
|
||||
"""
|
||||
# return all books in the database
|
||||
qdata = self.query_db("SELECT id,bookdata FROM media WHERE deleted=0")
|
||||
ret_result: list[dict[str, Any]] = []
|
||||
if qdata is None:
|
||||
return []
|
||||
for result_a in qdata:
|
||||
data: dict[str, Any] = {"id": int, "bookdata": BookData}
|
||||
data["id"] = result_a[0]
|
||||
data["bookdata"] = BookData().from_string(result_a[1])
|
||||
|
||||
ret_result.append(data)
|
||||
return ret_result
|
||||
|
||||
def getApparatNrByBookId(self, book_id):
|
||||
appNr = self.query_db(
|
||||
"SELECT appnr FROM semesterapparat WHERE id IN (SELECT app_id FROM media WHERE id=?)",
|
||||
(book_id,),
|
||||
one=True,
|
||||
)
|
||||
return appNr[0] if appNr else None
|
||||
|
||||
def getBooksByProfId(
|
||||
self, prof_id: int, deleted: int = 0
|
||||
) -> list[dict[str, Union[int, BookData]]]:
|
||||
"""
|
||||
Get the Books based on the professor id
|
||||
|
||||
Parameters
|
||||
----------
|
||||
prof_id : int
|
||||
The ID of the professor
|
||||
deleted : int, optional
|
||||
If set to 1, it will include deleted books, by default 0
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[dict[str, Union[int, BookData]]]
|
||||
A list of dictionaries containing the id, the metadata of the book and the availability of the book
|
||||
"""
|
||||
qdata = self.query_db(
|
||||
f"SELECT id,bookdata,available FROM media WHERE prof_id={prof_id} AND (deleted={deleted if deleted == 0 else '1 OR deleted=0'})"
|
||||
)
|
||||
ret_result = []
|
||||
if qdata is None:
|
||||
return []
|
||||
for result_a in qdata:
|
||||
data: dict[str, Any] = {"id": int, "bookdata": BookData, "available": int}
|
||||
data["id"] = result_a[0]
|
||||
data["bookdata"] = BookData().from_string(result_a[1])
|
||||
data["available"] = result_a[2]
|
||||
ret_result.append(data)
|
||||
return ret_result
|
||||
|
||||
def updateBookdata(self, book_id: int, bookdata: BookData):
|
||||
"""
|
||||
Update the bookdata in the database
|
||||
@@ -472,6 +627,16 @@ class Database:
|
||||
"""
|
||||
self.query_db("UPDATE media SET deleted=1 WHERE id=?", (book_id,))
|
||||
|
||||
def deleteBooks(self, ids: list[int]):
|
||||
"""
|
||||
Delete multiple books from the database
|
||||
|
||||
Args:
|
||||
ids (list[int]): A list of book ids to be deleted
|
||||
"""
|
||||
query = f"UPDATE media SET deleted=1 WHERE id IN ({','.join(['?'] * len(ids))})"
|
||||
self.query_db(query, tuple(ids))
|
||||
|
||||
# File Interactions
|
||||
def getBlob(self, filename: str, app_id: Union[str, int]) -> bytes:
|
||||
"""
|
||||
@@ -525,11 +690,12 @@ class Database:
|
||||
str: The filename of the recreated file
|
||||
"""
|
||||
blob = self.getBlob(filename, app_id)
|
||||
log.debug(blob)
|
||||
tempdir = settings.database.temp.expanduser()
|
||||
if not tempdir.exists():
|
||||
tempdir.mkdir(parents=True, exist_ok=True)
|
||||
file = tempfile.NamedTemporaryFile(
|
||||
delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}"
|
||||
delete=False, dir=tempdir, mode="wb", suffix=f".{filetype}"
|
||||
)
|
||||
file.write(blob)
|
||||
# log.debug("file created")
|
||||
@@ -701,6 +867,20 @@ class Database:
|
||||
else:
|
||||
return prof[0]
|
||||
|
||||
def getProfMailById(self, prof_id: Union[str, int]) -> str:
|
||||
"""get the mail of a professor based on the id
|
||||
|
||||
Args:
|
||||
prof_id (Union[str,int]): the id of the professor
|
||||
|
||||
Returns:
|
||||
str: the mail of the professor
|
||||
"""
|
||||
mail = self.query_db("SELECT mail FROM prof WHERE id=?", (prof_id,), one=True)[
|
||||
0
|
||||
]
|
||||
return mail if mail is not None else ""
|
||||
|
||||
def getTitleById(self, prof_id: Union[str, int]) -> str:
|
||||
"""get the title of a professor based on the id
|
||||
|
||||
@@ -877,6 +1057,23 @@ class Database:
|
||||
(newDate, today, app_id),
|
||||
)
|
||||
|
||||
def getId(self, apparat_name) -> Optional[int]:
|
||||
"""get the id of an apparat based on the name
|
||||
|
||||
Args:
|
||||
apparat_name (str): the name of the apparat e.g. "Semesterapparat 1"
|
||||
|
||||
Returns:
|
||||
Optional[int]: the id of the apparat, if the apparat is not found, None is returned
|
||||
"""
|
||||
data = self.query_db(
|
||||
"SELECT id FROM semesterapparat WHERE name=?", (apparat_name,), one=True
|
||||
)
|
||||
if data is None:
|
||||
return None
|
||||
else:
|
||||
return data[0]
|
||||
|
||||
def getApparatId(self, apparat_name) -> Optional[int]:
|
||||
"""get the id of an apparat based on the name
|
||||
|
||||
@@ -1014,22 +1211,22 @@ class Database:
|
||||
self.close_connection(conn)
|
||||
return ret
|
||||
|
||||
def deleteApparat(self, app_id: Union[str, int], semester):
|
||||
def deleteApparat(self, apparat: Apparat, semester: str):
|
||||
"""Delete an apparat from the database
|
||||
|
||||
Args:
|
||||
app_id (Union[str, int]): the id of the apparat
|
||||
apparat: (Apparat): the apparat to be deleted
|
||||
semester (str): the semester the apparat should be deleted from
|
||||
"""
|
||||
log.info(f"Deleting apparat with id {app_id} in semester {semester}")
|
||||
apparat_nr = apparat.appnr
|
||||
app_id = self.getId(apparat.name)
|
||||
self.query_db(
|
||||
"UPDATE semesterapparat SET deletion_status=1, deleted_date=? WHERE appnr=?",
|
||||
(semester, app_id),
|
||||
)
|
||||
self.query_db(
|
||||
"UPDATE media SET deleted=1 WHERE app_id=?",
|
||||
(app_id,),
|
||||
"UPDATE semesterapparat SET deletion_status=1, deleted_date=? WHERE appnr=? AND name=?",
|
||||
(semester, apparat_nr, apparat.name),
|
||||
)
|
||||
# delete all books associated with the app_id
|
||||
# print(apparat_nr, app_id)
|
||||
self.query_db("UPDATE media SET deleted=1 WHERE app_id=?", (app_id,))
|
||||
|
||||
def isEternal(self, id):
|
||||
"""check if the apparat is eternal (dauerapparat)
|
||||
@@ -1101,11 +1298,11 @@ class Database:
|
||||
else False
|
||||
)
|
||||
|
||||
def checkApparatExistsById(self, app_id: Union[str, int]) -> bool:
|
||||
"""a check to see if the apparat is already present in the database, based on the id
|
||||
def checkApparatExistsByNr(self, app_nr: Union[str, int]) -> bool:
|
||||
"""a check to see if the apparat is already present in the database, based on the nr. This query will exclude deleted apparats
|
||||
|
||||
Args:
|
||||
app_id (Union[str, int]): the id of the apparat
|
||||
app_nr (Union[str, int]): the id of the apparat
|
||||
|
||||
Returns:
|
||||
bool: True if the apparat is present, False if not
|
||||
@@ -1113,7 +1310,9 @@ class Database:
|
||||
return (
|
||||
True
|
||||
if self.query_db(
|
||||
"SELECT appnr FROM semesterapparat WHERE appnr=?", (app_id,), one=True
|
||||
"SELECT id FROM semesterapparat WHERE appnr=? and deletion_status=0",
|
||||
(app_nr,),
|
||||
one=True,
|
||||
)
|
||||
else False
|
||||
)
|
||||
@@ -1498,7 +1697,7 @@ class Database:
|
||||
tempdir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
file = tempfile.NamedTemporaryFile(
|
||||
delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}"
|
||||
delete=False, dir=tempdir, mode="wb", suffix=f".{filetype}"
|
||||
)
|
||||
file.write(blob)
|
||||
# log.debug("file created")
|
||||
@@ -1561,9 +1760,9 @@ class Database:
|
||||
telnr = profdata.telnr
|
||||
title = profdata.title
|
||||
|
||||
query = f"INSERT INTO prof (fname, lname, fullname, mail, telnr,titel) VALUES ('{fname}','{lname}','{fullname}','{mail}','{telnr}','{title}')"
|
||||
query = "INSERT INTO prof (fname, lname, fullname, mail, telnr, titel) VALUES (?,?,?,?,?,?)"
|
||||
log.debug(query)
|
||||
cursor.execute(query)
|
||||
cursor.execute(query, (fname, lname, fullname, mail, telnr, title))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
@@ -1606,10 +1805,10 @@ class Database:
|
||||
fullname = profdata["profname"]
|
||||
else:
|
||||
fullname = profdata.name()
|
||||
query = f"SELECT id FROM prof WHERE fullname = '{fullname}'"
|
||||
query = "SELECT id FROM prof WHERE fullname = ?"
|
||||
log.debug(query)
|
||||
|
||||
cursor.execute(query)
|
||||
cursor.execute(query, (fullname,))
|
||||
result = cursor.fetchone()
|
||||
if result:
|
||||
return result[0]
|
||||
@@ -1624,10 +1823,10 @@ class Database:
|
||||
"""
|
||||
conn = self.connect()
|
||||
cursor = conn.cursor()
|
||||
query = f"SELECT * FROM prof WHERE fullname = '{fullname}'"
|
||||
query = "SELECT * FROM prof WHERE fullname = ?"
|
||||
log.debug(query)
|
||||
|
||||
result = cursor.execute(query).fetchone()
|
||||
result = cursor.execute(query, (fullname,)).fetchone()
|
||||
if result:
|
||||
return Prof().from_tuple(result)
|
||||
else:
|
||||
@@ -1643,8 +1842,8 @@ class Database:
|
||||
|
||||
int | None: The id of the prof or None if not found
|
||||
"""
|
||||
query = f"SELECT prof_id from semesterapparat WHERE appnr = '{apprarat_id}' and deletion_status = 0"
|
||||
data = self.query_db(query)
|
||||
query = "SELECT prof_id from semesterapparat WHERE appnr = ? and deletion_status = 0"
|
||||
data = self.query_db(query, (apprarat_id,))
|
||||
if data:
|
||||
log.info("Prof ID: " + str(data[0][0]))
|
||||
return data[0][0]
|
||||
@@ -1655,20 +1854,13 @@ class Database:
|
||||
# get book data
|
||||
new_apparat_id = apparat
|
||||
new_prof_id = self.getProfIDByApparat(new_apparat_id)
|
||||
query = f"""
|
||||
INSERT INTO media (bookdata, app_id, prof_id, deleted, available, reservation)
|
||||
SELECT
|
||||
bookdata,
|
||||
'{new_apparat_id}',
|
||||
'{new_prof_id}',
|
||||
0,
|
||||
available,
|
||||
reservation
|
||||
FROM media
|
||||
where id = '{book_id}'"""
|
||||
query = (
|
||||
"INSERT INTO media (bookdata, app_id, prof_id, deleted, available, reservation) "
|
||||
"SELECT bookdata, ?, ?, 0, available, reservation FROM media WHERE id = ?"
|
||||
)
|
||||
connection = self.connect()
|
||||
cursor = connection.cursor()
|
||||
cursor.execute(query)
|
||||
cursor.execute(query, (new_apparat_id, new_prof_id, book_id))
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
||||
@@ -1680,16 +1872,18 @@ class Database:
|
||||
appratat (int): the ID of the new apparat
|
||||
"""
|
||||
# get book data
|
||||
query = f"UPDATE media SET app_id = '{appratat}' WHERE id = '{book_id}'"
|
||||
query = "UPDATE media SET app_id = ? WHERE id = ?"
|
||||
connection = self.connect()
|
||||
cursor = connection.cursor()
|
||||
cursor.execute(query)
|
||||
cursor.execute(query, (appratat, book_id))
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
||||
def getApparatNameByAppNr(self, appnr: int):
|
||||
query = f"SELECT name FROM semesterapparat WHERE appnr = '{appnr}' and deletion_status = 0"
|
||||
data = self.query_db(query)
|
||||
query = (
|
||||
"SELECT name FROM semesterapparat WHERE appnr = ? and deletion_status = 0"
|
||||
)
|
||||
data = self.query_db(query, (appnr,))
|
||||
if data:
|
||||
return data[0][0]
|
||||
else:
|
||||
@@ -1702,3 +1896,71 @@ class Database:
|
||||
result = cursor.fetchone()
|
||||
connection.close()
|
||||
return result
|
||||
|
||||
def getBookIdByPPN(self, ppn: str) -> int:
|
||||
query = "SELECT id FROM media WHERE bookdata LIKE ?"
|
||||
data = self.query_db(query, (f"%{ppn}%",))
|
||||
if data:
|
||||
return data[0][0]
|
||||
else:
|
||||
return None
|
||||
|
||||
def getNewEditionsByApparat(self, apparat_id: int) -> list[BookData]:
|
||||
"""Get all new editions for a specific apparat
|
||||
|
||||
Args:
|
||||
apparat_id (int): the id of the apparat
|
||||
|
||||
Returns:
|
||||
list[tuple]: A list of tuples containing the new editions data
|
||||
"""
|
||||
query = "SELECT * FROM neweditions WHERE for_apparat=? AND ordered=0"
|
||||
results = self.query_db(query, (apparat_id,))
|
||||
res = []
|
||||
for result in results:
|
||||
# keep only new edition payload; old edition can be reconstructed if needed
|
||||
res.append(BookData().from_string(result[1]))
|
||||
return res
|
||||
|
||||
def setOrdered(self, newBook_id: int):
|
||||
query = "UPDATE neweditions SET ordered=1 WHERE id=?"
|
||||
self.query_db(query, (newBook_id,))
|
||||
|
||||
def getBooksWithNewEditions(self, app_id) -> List[BookData]:
|
||||
# select all bookdata from media, based on the old_edition_id in neweditions where for_apparat = app_id; also get the new_edition bookdata
|
||||
|
||||
query = "SELECT m.bookdata, new_bookdata FROM media m JOIN neweditions n ON m.id = n.old_edition_id WHERE n.for_apparat = ?"
|
||||
results = self.query_db(query, (app_id,))
|
||||
# store results in tuple old,new
|
||||
res = []
|
||||
for result in results:
|
||||
oldedition = BookData().from_string(result[0])
|
||||
newedition = BookData().from_string(result[1])
|
||||
res.append((oldedition, newedition))
|
||||
return res
|
||||
|
||||
def getNewEditionId(self, newBook: BookData):
|
||||
query = "SELECT id FROM neweditions WHERE new_bookdata LIKE ?"
|
||||
args = (
|
||||
newBook.isbn[0] if newBook.isbn and len(newBook.isbn) > 0 else newBook.ppn
|
||||
)
|
||||
params = (f"%{args}%",)
|
||||
data = self.query_db(query, params, one=True)
|
||||
if data:
|
||||
return data[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
def insertNewEdition(self, newBook: BookData, oldBookId: int, for_apparat: int):
|
||||
# check if new edition already in table, check based on newBook.ppn
|
||||
check_query = "SELECT id FROM neweditions WHERE new_bookdata LIKE ?"
|
||||
check_params = (f"%{newBook.ppn}%",)
|
||||
data = self.query_db(check_query, check_params, one=True)
|
||||
if data:
|
||||
log.info("New edition already in table, skipping insert")
|
||||
return
|
||||
|
||||
query = "INSERT INTO neweditions (new_bookdata, old_edition_id, for_apparat) VALUES (?,?,?)"
|
||||
params = (newBook.to_dict, oldBookId, for_apparat)
|
||||
|
||||
self.query_db(query, params)
|
||||
|
||||
@@ -101,3 +101,12 @@ CREATE_ELSA_MEDIA_TABLE = """CREATE TABLE elsa_media (
|
||||
elsa_id INTEGER NOT NULL,
|
||||
FOREIGN KEY (elsa_id) REFERENCES elsa (id)
|
||||
)"""
|
||||
CREATE_TABLE_NEWEDITIONS = """CREATE TABLE neweditions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
new_bookdata TEXT,
|
||||
old_edition_id INTEGER,
|
||||
for_apparat INTEGER,
|
||||
ordered BOOLEAN DEFAULT (0),
|
||||
FOREIGN KEY (old_edition_id) REFERENCES media (id),
|
||||
FOREIGN KEY (for_apparat) REFERENCES semesterapparat (id)
|
||||
)"""
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
from PySide6.QtCore import QThread
|
||||
from PySide6.QtCore import Signal
|
||||
from PySide6.QtCore import QThread, Signal
|
||||
|
||||
from src.backend import Database
|
||||
|
||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||
import loguru
|
||||
import sys
|
||||
from src import LOG_DIR
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
from src.shared.logging import log
|
||||
|
||||
|
||||
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
||||
log.add(sys.stdout, level="INFO")
|
||||
# Logger configured centrally in main; this module just uses `log`
|
||||
|
||||
|
||||
class BookGrabber(QThread):
|
||||
@@ -31,9 +22,10 @@ class BookGrabber(QThread):
|
||||
self.book_id = None
|
||||
self.use_any = False
|
||||
self.use_exact = False
|
||||
self.app_id = None
|
||||
self.app_nr = None
|
||||
self.tstate = (self.app_id, self.prof_id, self.mode, self.data)
|
||||
self.request = WebRequest()
|
||||
self.db = Database()
|
||||
|
||||
def add_values(
|
||||
self, app_id: int, prof_id: int, mode: str, data, any_book=False, exact=False
|
||||
@@ -45,13 +37,15 @@ class BookGrabber(QThread):
|
||||
self.use_any = any_book
|
||||
self.use_exact = exact
|
||||
log.info(f"Working on {len(self.data)} entries")
|
||||
self.tstate = (self.app_id, self.prof_id, self.mode, self.data)
|
||||
self.tstate = (self.app_nr, self.prof_id, self.mode, self.data)
|
||||
log.debug("State: " + str(self.tstate))
|
||||
self.request.set_apparat(self.app_id)
|
||||
app_nr = self.db.query_db(
|
||||
"SELECT appnr FROM semesterapparat WHERE id = ?", (self.app_id,)
|
||||
)[0][0]
|
||||
self.request.set_apparat(app_nr)
|
||||
# log.debug(self.tstate)
|
||||
|
||||
def run(self):
|
||||
self.db = Database()
|
||||
item = 0
|
||||
iterdata = self.data
|
||||
# log.debug(iterdata)
|
||||
@@ -91,7 +85,7 @@ class BookGrabber(QThread):
|
||||
state = 0
|
||||
for result in transformer.RDS_DATA:
|
||||
# log.debug(result.RDS_LOCATION)
|
||||
if str(self.app_id) in result.RDS_LOCATION:
|
||||
if str(self.app_nr) in result.RDS_LOCATION:
|
||||
state = 1
|
||||
break
|
||||
|
||||
@@ -126,27 +120,27 @@ class BookGrabberTest(QThread):
|
||||
self.is_Running = True
|
||||
log.info("Starting worker thread")
|
||||
self.data = None
|
||||
self.app_id = None
|
||||
self.app_nr = 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.app_nr = appnr
|
||||
self.tstate = (self.app_nr, self.prof_id, self.mode, self.data)
|
||||
self.results = []
|
||||
|
||||
def add_values(
|
||||
self, app_id: int, prof_id: int, mode: str, data, any_book=False, exact=False
|
||||
self, app_nr: int, prof_id: int, mode: str, data, any_book=False, exact=False
|
||||
):
|
||||
self.app_id = app_id
|
||||
self.app_nr = app_nr
|
||||
self.prof_id = prof_id
|
||||
self.mode = mode
|
||||
self.data = data
|
||||
self.use_any = any_book
|
||||
self.use_exact = exact
|
||||
log.info(f"Working on {len(self.data)} entries")
|
||||
self.tstate = (self.app_id, self.prof_id, self.mode, self.data)
|
||||
self.tstate = (self.app_nr, self.prof_id, self.mode, self.data)
|
||||
log.debug("State: " + str(self.tstate))
|
||||
# log.debug(self.tstate)
|
||||
|
||||
@@ -159,7 +153,7 @@ class BookGrabberTest(QThread):
|
||||
signature = str(entry)
|
||||
log.info("Processing entry: " + signature)
|
||||
|
||||
webdata = WebRequest().set_apparat(self.app_id).get_ppn(entry)
|
||||
webdata = WebRequest().set_apparat(self.app_nr).get_ppn(entry)
|
||||
if self.use_any:
|
||||
webdata = webdata.use_any_book
|
||||
webdata = webdata.get_data()
|
||||
@@ -186,7 +180,7 @@ class BookGrabberTest(QThread):
|
||||
state = 0
|
||||
for result in transformer.RDS_DATA:
|
||||
# log.debug(result.RDS_LOCATION)
|
||||
if str(self.app_id) in result.RDS_LOCATION:
|
||||
if str(self.app_nr) in result.RDS_LOCATION:
|
||||
state = 1
|
||||
break
|
||||
|
||||
|
||||
345
src/backend/thread_neweditions.py
Normal file
345
src/backend/thread_neweditions.py
Normal file
@@ -0,0 +1,345 @@
|
||||
import os
|
||||
import re
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from math import ceil
|
||||
from queue import Empty, Queue
|
||||
from time import monotonic # <-- NEW
|
||||
from typing import List, Optional
|
||||
|
||||
from PySide6.QtCore import QThread, Signal
|
||||
|
||||
# from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||
from src.backend.catalogue import Catalogue
|
||||
from src.logic import BookData
|
||||
from src.logic.SRU import SWB
|
||||
from src.shared.logging import log
|
||||
|
||||
# use all available cores - 2, but at least 1
|
||||
THREAD_COUNT = max(os.cpu_count() - 2, 1)
|
||||
THREAD_MIN_ITEMS = 5
|
||||
|
||||
# Logger configured centrally in main; use shared `log`
|
||||
|
||||
swb = SWB()
|
||||
dnb = SWB()
|
||||
cat = Catalogue()
|
||||
|
||||
RVK_ALLOWED = r"[A-Z0-9.\-\/]" # conservative RVK character set
|
||||
|
||||
|
||||
def find_newer_edition(
|
||||
swb_result: BookData, dnb_result: List[BookData]
|
||||
) -> Optional[List[BookData]]:
|
||||
"""
|
||||
New edition if:
|
||||
- year > swb.year OR
|
||||
- edition_number > swb.edition_number
|
||||
BUT: discard any candidate with year < swb.year (if both years are known).
|
||||
|
||||
Same-work check:
|
||||
- Compare RVK roots of signatures (after stripping trailing '+N' and '(N)').
|
||||
- If both have signatures and RVKs differ -> skip.
|
||||
|
||||
Preferences (in order):
|
||||
1) RVK matches SWB
|
||||
2) Print over Online-Ressource
|
||||
3) Has signature
|
||||
4) Newer: (year desc, edition_number desc)
|
||||
"""
|
||||
|
||||
def strip_copy_and_edition(s: str) -> str:
|
||||
s = re.sub(r"\(\s*\d+\s*\)", "", s) # remove '(N)'
|
||||
s = re.sub(r"\s*\+\s*\d+\s*$", "", s) # remove trailing '+N'
|
||||
return s
|
||||
|
||||
def extract_rvk_root(sig: Optional[str]) -> str:
|
||||
if not sig:
|
||||
return ""
|
||||
t = strip_copy_and_edition(sig.upper())
|
||||
t = re.sub(r"\s+", " ", t).strip()
|
||||
m = re.match(rf"^([A-Z]{{1,3}}\s*{RVK_ALLOWED}*)", t)
|
||||
if not m:
|
||||
cleaned = re.sub(rf"[^{RVK_ALLOWED} ]+", "", t).strip()
|
||||
return cleaned.split(" ")[0] if cleaned else ""
|
||||
return re.sub(r"\s+", " ", m.group(1)).strip()
|
||||
|
||||
def has_sig(b: BookData) -> bool:
|
||||
return bool(getattr(b, "signature", None))
|
||||
|
||||
def is_online(b: BookData) -> bool:
|
||||
return (getattr(b, "media_type", None) or "").strip() == "Online-Ressource"
|
||||
|
||||
def is_print(b: BookData) -> bool:
|
||||
return not is_online(b)
|
||||
|
||||
def rvk_matches_swb(b: BookData) -> bool:
|
||||
if not has_sig(b) or not has_sig(swb_result):
|
||||
return False
|
||||
return extract_rvk_root(b.signature) == extract_rvk_root(swb_result.signature)
|
||||
|
||||
def strictly_newer(b: BookData) -> bool:
|
||||
# Hard guard: if both years are known and candidate is older, discard
|
||||
if (
|
||||
b.year is not None
|
||||
and swb_result.year is not None
|
||||
and b.year < swb_result.year
|
||||
):
|
||||
return False
|
||||
|
||||
newer_by_year = (
|
||||
b.year is not None
|
||||
and swb_result.year is not None
|
||||
and b.year > swb_result.year
|
||||
)
|
||||
newer_by_edition = (
|
||||
b.edition_number is not None
|
||||
and swb_result.edition_number is not None
|
||||
and b.edition_number > swb_result.edition_number
|
||||
)
|
||||
# Thanks to the guard above, newer_by_edition can't pick something with a smaller year.
|
||||
return newer_by_year or newer_by_edition
|
||||
|
||||
swb_has_sig = has_sig(swb_result)
|
||||
swb_rvk = extract_rvk_root(getattr(swb_result, "signature", None))
|
||||
|
||||
# 1) Filter: same work (by RVK if both have sigs) AND strictly newer
|
||||
candidates: List[BookData] = []
|
||||
for b in dnb_result:
|
||||
if has_sig(b) and swb_has_sig:
|
||||
if extract_rvk_root(b.signature) != swb_rvk:
|
||||
continue # different work
|
||||
if strictly_newer(b):
|
||||
candidates.append(b)
|
||||
|
||||
if not candidates:
|
||||
return None
|
||||
|
||||
# 2) Dedupe by PPN → prefer (rvk-match, is-print, has-signature)
|
||||
def pref_score(x: BookData) -> tuple[int, int, int]:
|
||||
return (
|
||||
1 if rvk_matches_swb(x) else 0,
|
||||
1 if is_print(x) else 0,
|
||||
1 if has_sig(x) else 0,
|
||||
)
|
||||
|
||||
by_ppn: dict[Optional[str], BookData] = {}
|
||||
for b in candidates:
|
||||
key = getattr(b, "ppn", None)
|
||||
prev = by_ppn.get(key)
|
||||
if prev is None or pref_score(b) > pref_score(prev):
|
||||
by_ppn[key] = b
|
||||
|
||||
deduped = list(by_ppn.values())
|
||||
if not deduped:
|
||||
return None
|
||||
|
||||
# 3) Preserve all qualifying newer editions, but order by preference
|
||||
def sort_key(b: BookData):
|
||||
year = b.year if b.year is not None else -1
|
||||
ed = b.edition_number if b.edition_number is not None else -1
|
||||
return (
|
||||
1 if rvk_matches_swb(b) else 0,
|
||||
1 if is_print(b) else 0,
|
||||
1 if has_sig(b) else 0,
|
||||
year,
|
||||
ed,
|
||||
)
|
||||
|
||||
deduped.sort(key=sort_key, reverse=True)
|
||||
return deduped
|
||||
|
||||
|
||||
class NewEditionCheckerThread(QThread):
|
||||
updateSignal = Signal(int, int) # (processed, total)
|
||||
updateProgress = Signal(int, int) # (processed, total)
|
||||
total_entries_signal = Signal(int)
|
||||
resultsSignal = Signal(list) # list[tuple[BookData, list[BookData]]]
|
||||
|
||||
# NEW: metrics signals
|
||||
rateSignal = Signal(float) # items per second ("it/s")
|
||||
etaSignal = Signal(int) # seconds remaining (-1 when unknown)
|
||||
|
||||
def __init__(self, entries: Optional[list["BookData"]] = None, parent=None):
|
||||
super().__init__(parent)
|
||||
self.entries: list["BookData"] = entries if entries is not None else []
|
||||
self.results: list[tuple["BookData", list["BookData"]]] = []
|
||||
|
||||
def reset(self):
|
||||
self.entries = []
|
||||
self.results = []
|
||||
|
||||
# ---------- internal helpers ----------
|
||||
|
||||
@staticmethod
|
||||
def _split_evenly(items: list, parts: int) -> list[list]:
|
||||
"""Split items as evenly as possible into `parts` chunks (no empty tails)."""
|
||||
if parts <= 1 or len(items) <= 1:
|
||||
return [items]
|
||||
n = len(items)
|
||||
base = n // parts
|
||||
extra = n % parts
|
||||
chunks = []
|
||||
i = 0
|
||||
for k in range(parts):
|
||||
size = base + (1 if k < extra else 0)
|
||||
if size == 0:
|
||||
continue
|
||||
chunks.append(items[i : i + size])
|
||||
i += size
|
||||
return chunks
|
||||
|
||||
@staticmethod
|
||||
def _clean_title(raw: str) -> str:
|
||||
title = raw.rstrip(" .:,;!?")
|
||||
title = re.sub(r"\s*\(.*\)", "", title)
|
||||
return title.strip()
|
||||
|
||||
@classmethod
|
||||
def _process_book(
|
||||
cls, book: "BookData"
|
||||
) -> tuple["BookData", list["BookData"]] | None:
|
||||
"""Process one book; returns (original, [found editions]) or None on failure."""
|
||||
if not book.title:
|
||||
return None
|
||||
response: list["BookData"] = []
|
||||
query = [
|
||||
f"pica.tit={book.title}",
|
||||
f"pica.vlg={book.publisher}",
|
||||
]
|
||||
|
||||
swb_result = swb.getBooks(["pica.bib=20735", f"pica.ppn={book.ppn}"])[0]
|
||||
dnb_results = swb.getBooks(query)
|
||||
new_editions = find_newer_edition(swb_result, dnb_results)
|
||||
|
||||
if new_editions is not None:
|
||||
for new_edition in new_editions:
|
||||
new_edition.library_location = cat.get_location(new_edition.ppn)
|
||||
try:
|
||||
isbn = (
|
||||
str(new_edition.isbn[0])
|
||||
if isinstance(new_edition.isbn, list)
|
||||
else str(new_edition.isbn)
|
||||
)
|
||||
new_edition.link = (
|
||||
f"https://www.lehmanns.de/search/quick?mediatype_id=2&q={isbn}"
|
||||
)
|
||||
except (IndexError, TypeError):
|
||||
isbn = None
|
||||
new_edition.in_library = cat.in_library(new_edition.ppn)
|
||||
response = new_editions
|
||||
|
||||
# client = SWB()
|
||||
# response: list["BookData"] = []
|
||||
# # First, search by title only
|
||||
# results = client.getBooks([f"pica.title={title}", f"pica.vlg={book.publisher}"])
|
||||
|
||||
# lehmanns = LehmannsClient()
|
||||
# results = lehmanns.search_by_title(title)
|
||||
# for result in results:
|
||||
# if "(eBook)" in result.title:
|
||||
# result.title = result.title.replace("(eBook)", "").strip()
|
||||
# swb_results = client.getBooks(
|
||||
# [
|
||||
# f"pica.tit={result.title}",
|
||||
# f"pica.vlg={result.publisher.split(',')[0]}",
|
||||
# ]
|
||||
# )
|
||||
# for swb in swb_results:
|
||||
# if swb.isbn == result.isbn:
|
||||
# result.ppn = swb.ppn
|
||||
# result.signature = swb.signature
|
||||
# response.append(result)
|
||||
# if (result.edition_number < swb.edition_number) and (
|
||||
# swb.year > result.year
|
||||
# ):
|
||||
# response.append(result)
|
||||
if response == []:
|
||||
return None
|
||||
# Remove duplicates based on ppn
|
||||
return (book, response)
|
||||
|
||||
@classmethod
|
||||
def _worker(cls, items: list["BookData"], q: Queue) -> None:
|
||||
"""Worker for one chunk; pushes ('result', ...), ('progress', 1), and ('done', None)."""
|
||||
try:
|
||||
for book in items:
|
||||
try:
|
||||
result = cls._process_book(book)
|
||||
except Exception:
|
||||
result = None
|
||||
if result is not None:
|
||||
q.put(("result", result))
|
||||
q.put(("progress", 1))
|
||||
finally:
|
||||
q.put(("done", None))
|
||||
|
||||
# ---------- thread entry point ----------
|
||||
|
||||
def run(self):
|
||||
total = len(self.entries)
|
||||
self.total_entries_signal.emit(total)
|
||||
|
||||
# start timer for metrics
|
||||
t0 = monotonic()
|
||||
|
||||
if total == 0:
|
||||
log.debug("No entries to process.")
|
||||
# emit metrics (zero work)
|
||||
self.rateSignal.emit(0.0)
|
||||
self.etaSignal.emit(0)
|
||||
self.resultsSignal.emit([])
|
||||
return
|
||||
|
||||
# Up to 4 workers; ~20 items per worker
|
||||
num_workers = min(THREAD_COUNT, max(1, ceil(total / THREAD_MIN_ITEMS)))
|
||||
chunks = self._split_evenly(self.entries, num_workers)
|
||||
sizes = [len(ch) for ch in chunks]
|
||||
|
||||
q: Queue = Queue()
|
||||
processed = 0
|
||||
finished_workers = 0
|
||||
|
||||
with ThreadPoolExecutor(max_workers=len(chunks)) as ex:
|
||||
futures = [ex.submit(self._worker, ch, q) for ch in chunks]
|
||||
|
||||
log.info(
|
||||
f"Launched {len(futures)} worker thread(s) for {total} entries: {sizes} entries per thread."
|
||||
)
|
||||
for idx, sz in enumerate(sizes, 1):
|
||||
log.debug(f"Thread {idx}: {sz} entries")
|
||||
|
||||
# Aggregate progress/results
|
||||
while finished_workers < len(chunks):
|
||||
try:
|
||||
kind, payload = q.get(timeout=0.1)
|
||||
except Empty:
|
||||
continue
|
||||
|
||||
if kind == "progress":
|
||||
processed += int(payload)
|
||||
self.updateSignal.emit(processed, total)
|
||||
self.updateProgress.emit(processed, total)
|
||||
|
||||
# ---- NEW: compute & emit metrics ----
|
||||
elapsed = max(1e-9, monotonic() - t0)
|
||||
rate = processed / elapsed # items per second
|
||||
remaining = max(0, total - processed)
|
||||
eta_sec = int(round(remaining / rate)) if rate > 0 else -1
|
||||
|
||||
self.rateSignal.emit(rate)
|
||||
# clamp negative just in case
|
||||
self.etaSignal.emit(max(0, eta_sec) if eta_sec >= 0 else -1)
|
||||
# -------------------------------------
|
||||
|
||||
elif kind == "result":
|
||||
self.results.append(payload)
|
||||
elif kind == "done":
|
||||
finished_workers += 1
|
||||
|
||||
# Final metrics on completion
|
||||
elapsed_total = max(1e-9, monotonic() - t0)
|
||||
final_rate = total / elapsed_total
|
||||
self.rateSignal.emit(final_rate)
|
||||
self.etaSignal.emit(0)
|
||||
|
||||
self.resultsSignal.emit(self.results)
|
||||
@@ -1,13 +1,15 @@
|
||||
import sys
|
||||
import time
|
||||
|
||||
import loguru
|
||||
|
||||
# from icecream import ic
|
||||
from PySide6.QtCore import QThread
|
||||
from PySide6.QtCore import Signal as Signal
|
||||
|
||||
from src.backend import Database
|
||||
import loguru
|
||||
import sys
|
||||
from src import LOG_DIR
|
||||
from src.backend import Database
|
||||
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
@@ -29,8 +31,8 @@ class AutoAdder(QThread):
|
||||
self.app_id = app_id
|
||||
self.prof_id = prof_id
|
||||
|
||||
# print("Launched AutoAdder")
|
||||
# print(self.data, self.app_id, self.prof_id)
|
||||
# #print("Launched AutoAdder")
|
||||
# #print(self.data, self.app_id, self.prof_id)
|
||||
|
||||
def run(self):
|
||||
self.db = Database()
|
||||
@@ -46,7 +48,7 @@ class AutoAdder(QThread):
|
||||
time.sleep(1)
|
||||
|
||||
except Exception as e:
|
||||
# print(e)
|
||||
# #print(e)
|
||||
log.exception(
|
||||
f"The query failed with message {e} for signature {entry}"
|
||||
)
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
import time
|
||||
|
||||
# from icecream import ic
|
||||
from PySide6.QtCore import QThread
|
||||
from PySide6.QtCore import Signal as Signal
|
||||
|
||||
from src.backend.database import Database
|
||||
from src import LOG_DIR
|
||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||
|
||||
# from src.transformers import RDS_AVAIL_DATA
|
||||
import loguru
|
||||
import sys
|
||||
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
from src.shared.logging import log
|
||||
|
||||
|
||||
class AvailChecker(QThread):
|
||||
@@ -24,7 +12,11 @@ class AvailChecker(QThread):
|
||||
updateProgress = Signal(int, int)
|
||||
|
||||
def __init__(
|
||||
self, links: list = None, appnumber: int = None, parent=None, books=list[dict]
|
||||
self,
|
||||
links: list[str] | None = None,
|
||||
appnumber: int | None = None,
|
||||
parent=None,
|
||||
books: list[dict] | None = None,
|
||||
):
|
||||
if links is None:
|
||||
links = []
|
||||
@@ -39,11 +31,13 @@ class AvailChecker(QThread):
|
||||
)
|
||||
self.links = links
|
||||
self.appnumber = appnumber
|
||||
self.books = books
|
||||
self.books = books or []
|
||||
log.info(
|
||||
f"Started worker with appnumber: {self.appnumber} and links: {self.links} and {len(self.books)} books..."
|
||||
)
|
||||
time.sleep(2)
|
||||
# Pre-create reusable request and transformer to avoid per-item overhead
|
||||
self._request = WebRequest().set_apparat(self.appnumber)
|
||||
self._rds_transformer = BibTextTransformer("RDS")
|
||||
|
||||
def run(self):
|
||||
self.db = Database()
|
||||
@@ -51,16 +45,18 @@ class AvailChecker(QThread):
|
||||
count = 0
|
||||
for link in self.links:
|
||||
log.info("Processing entry: " + str(link))
|
||||
data = WebRequest().set_apparat(self.appnumber).get_ppn(link).get_data()
|
||||
transformer = BibTextTransformer("RDS")
|
||||
rds = transformer.get_data(data).return_data("rds_availability")
|
||||
data = self._request.get_ppn(link).get_data()
|
||||
rds = self._rds_transformer.get_data(data).return_data("rds_availability")
|
||||
|
||||
book_id = None
|
||||
if not rds or not rds.items:
|
||||
log.warning(f"No RDS data found for link {link}")
|
||||
continue
|
||||
for item in rds.items:
|
||||
sign = item.superlocation
|
||||
loc = item.location
|
||||
# # print(item.location)
|
||||
if self.appnumber in sign or self.appnumber in loc:
|
||||
# # #print(item.location)
|
||||
if str(self.appnumber) in sign or str(self.appnumber) in loc:
|
||||
state = 1
|
||||
break
|
||||
for book in self.books:
|
||||
@@ -68,7 +64,7 @@ class AvailChecker(QThread):
|
||||
book_id = book["id"]
|
||||
break
|
||||
log.info(f"State of {link}: " + str(state))
|
||||
# print("Updating availability of " + str(book_id) + " to " + str(state))
|
||||
# #print("Updating availability of " + str(book_id) + " to " + str(state))
|
||||
self.db.setAvailability(book_id, state)
|
||||
count += 1
|
||||
self.updateProgress.emit(count, len(self.links))
|
||||
|
||||
631
src/logic/SRU.py
Normal file
631
src/logic/SRU.py
Normal file
@@ -0,0 +1,631 @@
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Dict, Iterable, List, Optional, Tuple, Union
|
||||
|
||||
import requests
|
||||
from requests.adapters import HTTPAdapter
|
||||
|
||||
# centralized logging used via src.shared.logging
|
||||
from src.logic.dataclass import BookData
|
||||
from src.shared.logging import log
|
||||
|
||||
log # ensure imported logger is referenced
|
||||
|
||||
|
||||
# -----------------------
|
||||
# Dataclasses
|
||||
# -----------------------
|
||||
|
||||
|
||||
# --- MARC XML structures ---
|
||||
@dataclass
|
||||
class ControlField:
|
||||
tag: str
|
||||
value: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class SubField:
|
||||
code: str
|
||||
value: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataField:
|
||||
tag: str
|
||||
ind1: str = " "
|
||||
ind2: str = " "
|
||||
subfields: List[SubField] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class MarcRecord:
|
||||
leader: str
|
||||
controlfields: List[ControlField] = field(default_factory=list)
|
||||
datafields: List[DataField] = field(default_factory=list)
|
||||
|
||||
|
||||
# --- SRU record wrapper ---
|
||||
@dataclass
|
||||
class Record:
|
||||
recordSchema: str
|
||||
recordPacking: str
|
||||
recordData: MarcRecord
|
||||
recordPosition: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class EchoedSearchRequest:
|
||||
version: str
|
||||
query: str
|
||||
maximumRecords: int
|
||||
recordPacking: str
|
||||
recordSchema: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class SearchRetrieveResponse:
|
||||
version: str
|
||||
numberOfRecords: int
|
||||
records: List[Record] = field(default_factory=list)
|
||||
echoedSearchRetrieveRequest: Optional[EchoedSearchRequest] = None
|
||||
|
||||
|
||||
# -----------------------
|
||||
# Parser
|
||||
# -----------------------
|
||||
|
||||
ZS = "http://www.loc.gov/zing/srw/"
|
||||
MARC = "http://www.loc.gov/MARC21/slim"
|
||||
NS = {"zs": ZS, "marc": MARC}
|
||||
|
||||
|
||||
def _text(elem: Optional[ET.Element]) -> str:
|
||||
return (elem.text or "") if elem is not None else ""
|
||||
|
||||
|
||||
def _req_text(parent: ET.Element, path: str) -> Optional[str]:
|
||||
el = parent.find(path, NS)
|
||||
if el is None or el.text is None:
|
||||
return None
|
||||
return el.text
|
||||
|
||||
|
||||
def parse_marc_record(record_el: ET.Element) -> MarcRecord:
|
||||
"""
|
||||
record_el is the <marc:record> element (default ns MARC in your sample)
|
||||
"""
|
||||
# leader
|
||||
leader_text = _req_text(record_el, "marc:leader") or ""
|
||||
|
||||
# controlfields
|
||||
controlfields: List[ControlField] = []
|
||||
for cf in record_el.findall("marc:controlfield", NS):
|
||||
tag = cf.get("tag", "").strip()
|
||||
controlfields.append(ControlField(tag=tag, value=_text(cf)))
|
||||
|
||||
# datafields
|
||||
datafields: List[DataField] = []
|
||||
for df in record_el.findall("marc:datafield", NS):
|
||||
tag = df.get("tag", "").strip()
|
||||
ind1 = df.get("ind1") or " "
|
||||
ind2 = df.get("ind2") or " "
|
||||
subfields: List[SubField] = []
|
||||
for sf in df.findall("marc:subfield", NS):
|
||||
code = sf.get("code", "")
|
||||
subfields.append(SubField(code=code, value=_text(sf)))
|
||||
datafields.append(DataField(tag=tag, ind1=ind1, ind2=ind2, subfields=subfields))
|
||||
|
||||
return MarcRecord(
|
||||
leader=leader_text, controlfields=controlfields, datafields=datafields
|
||||
)
|
||||
|
||||
|
||||
def parse_record(zs_record_el: ET.Element) -> Record:
|
||||
recordSchema = _req_text(zs_record_el, "zs:recordSchema") or ""
|
||||
recordPacking = _req_text(zs_record_el, "zs:recordPacking") or ""
|
||||
|
||||
# recordData contains a MARC <record> with default MARC namespace in your sample
|
||||
recordData_el = zs_record_el.find("zs:recordData", NS)
|
||||
if recordData_el is None:
|
||||
raise ValueError("Missing zs:recordData")
|
||||
|
||||
marc_record_el = recordData_el.find("marc:record", NS)
|
||||
if marc_record_el is None:
|
||||
# If the MARC record uses default ns (xmlns="...") ElementTree still needs the ns-qualified name
|
||||
# We already searched with prefix; this covers both default and prefixed cases.
|
||||
raise ValueError("Missing MARC21 record inside zs:recordData")
|
||||
|
||||
marc_record = parse_marc_record(marc_record_el)
|
||||
|
||||
recordPosition = int(_req_text(zs_record_el, "zs:recordPosition") or "0")
|
||||
return Record(
|
||||
recordSchema=recordSchema,
|
||||
recordPacking=recordPacking,
|
||||
recordData=marc_record,
|
||||
recordPosition=recordPosition,
|
||||
)
|
||||
|
||||
|
||||
def parse_echoed_request(root: ET.Element) -> Optional[EchoedSearchRequest]:
|
||||
el = root.find("zs:echoedSearchRetrieveRequest", NS)
|
||||
if el is None:
|
||||
return None
|
||||
|
||||
# Be permissive with missing fields
|
||||
version = _text(el.find("zs:version", NS))
|
||||
query = _text(el.find("zs:query", NS))
|
||||
maximumRecords_text = _text(el.find("zs:maximumRecords", NS)) or "0"
|
||||
recordPacking = _text(el.find("zs:recordPacking", NS))
|
||||
recordSchema = _text(el.find("zs:recordSchema", NS))
|
||||
|
||||
try:
|
||||
maximumRecords = int(maximumRecords_text)
|
||||
except ValueError:
|
||||
maximumRecords = 0
|
||||
|
||||
return EchoedSearchRequest(
|
||||
version=version,
|
||||
query=query,
|
||||
maximumRecords=maximumRecords,
|
||||
recordPacking=recordPacking,
|
||||
recordSchema=recordSchema,
|
||||
)
|
||||
|
||||
|
||||
def parse_search_retrieve_response(
|
||||
xml_str: Union[str, bytes],
|
||||
) -> SearchRetrieveResponse:
|
||||
root = ET.fromstring(xml_str)
|
||||
|
||||
# Root is zs:searchRetrieveResponse
|
||||
version = _req_text(root, "zs:version")
|
||||
numberOfRecords = int(_req_text(root, "zs:numberOfRecords") or "0")
|
||||
|
||||
records_parent = root.find("zs:records", NS)
|
||||
records: List[Record] = []
|
||||
if records_parent is not None:
|
||||
for r in records_parent.findall("zs:record", NS):
|
||||
records.append(parse_record(r))
|
||||
|
||||
echoed = parse_echoed_request(root)
|
||||
|
||||
return SearchRetrieveResponse(
|
||||
version=version,
|
||||
numberOfRecords=numberOfRecords,
|
||||
records=records,
|
||||
echoedSearchRetrieveRequest=echoed,
|
||||
)
|
||||
|
||||
|
||||
# --- Query helpers over MarcRecord ---
|
||||
|
||||
|
||||
def iter_datafields(
|
||||
rec: MarcRecord,
|
||||
tag: Optional[str] = None,
|
||||
ind1: Optional[str] = None,
|
||||
ind2: Optional[str] = None,
|
||||
) -> Iterable[DataField]:
|
||||
"""Yield datafields, optionally filtered by tag/indicators."""
|
||||
for df in rec.datafields:
|
||||
if tag is not None and df.tag != tag:
|
||||
continue
|
||||
if ind1 is not None and df.ind1 != ind1:
|
||||
continue
|
||||
if ind2 is not None and df.ind2 != ind2:
|
||||
continue
|
||||
yield df
|
||||
|
||||
|
||||
def subfield_values(
|
||||
rec: MarcRecord,
|
||||
tag: str,
|
||||
code: str,
|
||||
*,
|
||||
ind1: Optional[str] = None,
|
||||
ind2: Optional[str] = None,
|
||||
) -> List[str]:
|
||||
"""All values for subfield `code` in every `tag` field (respecting indicators)."""
|
||||
out: List[str] = []
|
||||
for df in iter_datafields(rec, tag, ind1, ind2):
|
||||
out.extend(sf.value for sf in df.subfields if sf.code == code)
|
||||
return out
|
||||
|
||||
|
||||
def first_subfield_value(
|
||||
rec: MarcRecord,
|
||||
tag: str,
|
||||
code: str,
|
||||
*,
|
||||
ind1: Optional[str] = None,
|
||||
ind2: Optional[str] = None,
|
||||
default: Optional[str] = None,
|
||||
) -> Optional[str]:
|
||||
"""First value for subfield `code` in `tag` (respecting indicators)."""
|
||||
for df in iter_datafields(rec, tag, ind1, ind2):
|
||||
for sf in df.subfields:
|
||||
if sf.code == code:
|
||||
return sf.value
|
||||
return default
|
||||
|
||||
|
||||
def find_datafields_with_subfields(
|
||||
rec: MarcRecord,
|
||||
tag: str,
|
||||
*,
|
||||
where_all: Optional[Dict[str, str]] = None,
|
||||
where_any: Optional[Dict[str, str]] = None,
|
||||
casefold: bool = False,
|
||||
ind1: Optional[str] = None,
|
||||
ind2: Optional[str] = None,
|
||||
) -> List[DataField]:
|
||||
"""
|
||||
Return datafields of `tag` whose subfields match constraints:
|
||||
- where_all: every (code -> exact value) must be present
|
||||
- where_any: at least one (code -> exact value) present
|
||||
Set `casefold=True` for case-insensitive comparison.
|
||||
"""
|
||||
where_all = where_all or {}
|
||||
where_any = where_any or {}
|
||||
matched: List[DataField] = []
|
||||
|
||||
for df in iter_datafields(rec, tag, ind1, ind2):
|
||||
# Map code -> list of values (with optional casefold applied)
|
||||
vals: Dict[str, List[str]] = {}
|
||||
for sf in df.subfields:
|
||||
v = sf.value.casefold() if casefold else sf.value
|
||||
vals.setdefault(sf.code, []).append(v)
|
||||
|
||||
ok = True
|
||||
for c, v in where_all.items():
|
||||
vv = v.casefold() if casefold else v
|
||||
if c not in vals or vv not in vals[c]:
|
||||
ok = False
|
||||
break
|
||||
|
||||
if ok and where_any:
|
||||
any_ok = any(
|
||||
(c in vals) and ((v.casefold() if casefold else v) in vals[c])
|
||||
for c, v in where_any.items()
|
||||
)
|
||||
if not any_ok:
|
||||
ok = False
|
||||
|
||||
if ok:
|
||||
matched.append(df)
|
||||
|
||||
return matched
|
||||
|
||||
|
||||
def controlfield_value(
|
||||
rec: MarcRecord, tag: str, default: Optional[str] = None
|
||||
) -> Optional[str]:
|
||||
"""Get the first controlfield value by tag (e.g., '001', '005')."""
|
||||
for cf in rec.controlfields:
|
||||
if cf.tag == tag:
|
||||
return cf.value
|
||||
return default
|
||||
|
||||
|
||||
def datafields_value(
|
||||
data: List[DataField], code: str, default: Optional[str] = None
|
||||
) -> Optional[str]:
|
||||
"""Get the first value for a specific subfield code in a list of datafields."""
|
||||
for df in data:
|
||||
for sf in df.subfields:
|
||||
if sf.code == code:
|
||||
return sf.value
|
||||
return default
|
||||
|
||||
|
||||
def datafield_value(
|
||||
df: DataField, code: str, default: Optional[str] = None
|
||||
) -> Optional[str]:
|
||||
"""Get the first value for a specific subfield code in a datafield."""
|
||||
for sf in df.subfields:
|
||||
if sf.code == code:
|
||||
return sf.value
|
||||
return default
|
||||
|
||||
|
||||
def _smart_join_title(a: str, b: Optional[str]) -> str:
|
||||
"""
|
||||
Join 245 $a and $b with MARC-style punctuation.
|
||||
If $b is present, join with ' : ' unless either side already supplies punctuation.
|
||||
"""
|
||||
a = a.strip()
|
||||
if not b:
|
||||
return a
|
||||
b = b.strip()
|
||||
if a.endswith((":", ";", "/")) or b.startswith((":", ";", "/")):
|
||||
return f"{a} {b}"
|
||||
return f"{a} : {b}"
|
||||
|
||||
|
||||
def subfield_values_from_fields(
|
||||
fields: Iterable[DataField],
|
||||
code: str,
|
||||
) -> List[str]:
|
||||
"""All subfield values with given `code` across a list of DataField."""
|
||||
return [sf.value for df in fields for sf in df.subfields if sf.code == code]
|
||||
|
||||
|
||||
def first_subfield_value_from_fields(
|
||||
fields: Iterable[DataField],
|
||||
code: str,
|
||||
default: Optional[str] = None,
|
||||
) -> Optional[str]:
|
||||
"""First subfield value with given `code` across a list of DataField."""
|
||||
for df in fields:
|
||||
for sf in df.subfields:
|
||||
if sf.code == code:
|
||||
return sf.value
|
||||
return default
|
||||
|
||||
|
||||
def subfield_value_pairs_from_fields(
|
||||
fields: Iterable[DataField],
|
||||
code: str,
|
||||
) -> List[Tuple[DataField, str]]:
|
||||
"""
|
||||
Return (DataField, value) pairs for all subfields with `code`.
|
||||
Useful if you need to know which field a value came from.
|
||||
"""
|
||||
out: List[Tuple[DataField, str]] = []
|
||||
for df in fields:
|
||||
for sf in df.subfields:
|
||||
if sf.code == code:
|
||||
out.append((df, sf.value))
|
||||
return out
|
||||
|
||||
|
||||
def book_from_marc(rec: MarcRecord) -> BookData:
|
||||
# PPN from controlfield 001
|
||||
ppn = controlfield_value(rec, "001")
|
||||
|
||||
# Title = 245 $a + 245 $b (if present)
|
||||
t_a = first_subfield_value(rec, "245", "a")
|
||||
t_b = first_subfield_value(rec, "245", "b")
|
||||
title = _smart_join_title(t_a, t_b) if t_a else None
|
||||
|
||||
# Signature = 924 where $9 == "Frei 129" → take that field's $g
|
||||
frei_fields = find_datafields_with_subfields(
|
||||
rec, "924", where_all={"9": "Frei 129"}
|
||||
)
|
||||
signature = first_subfield_value_from_fields(frei_fields, "g")
|
||||
|
||||
# Year = 264 $c (prefer ind2="1" publication; fallback to any 264)
|
||||
year = first_subfield_value(rec, "264", "c", ind2="1") or first_subfield_value(
|
||||
rec, "264", "c"
|
||||
)
|
||||
isbn = subfield_values(rec, "020", "a")
|
||||
mediatype = first_subfield_value(rec, "338", "a")
|
||||
lang = subfield_values(rec, "041", "a")
|
||||
authors = subfield_values(rec, "700", "a")
|
||||
author = None
|
||||
if authors:
|
||||
author = "; ".join(authors)
|
||||
|
||||
return BookData(
|
||||
ppn=ppn,
|
||||
title=title,
|
||||
signature=signature,
|
||||
edition=first_subfield_value(rec, "250", "a") or "",
|
||||
year=year,
|
||||
pages=first_subfield_value(rec, "300", "a") or "",
|
||||
publisher=first_subfield_value(rec, "264", "b") or "",
|
||||
isbn=isbn,
|
||||
language=lang,
|
||||
link="",
|
||||
author=author,
|
||||
media_type=mediatype,
|
||||
)
|
||||
|
||||
|
||||
class SWBData(Enum):
|
||||
URL = "https://sru.k10plus.de/opac-de-627!rec=1?version=1.1&operation=searchRetrieve&query={}&maximumRecords=100&recordSchema=marcxml"
|
||||
ARGSCHEMA = "pica."
|
||||
NAME = "SWB"
|
||||
|
||||
|
||||
class DNBData(Enum):
|
||||
URL = "https://services.dnb.de/sru/dnb?version=1.1&operation=searchRetrieve&query={}&maximumRecords=100&recordSchema=MARC21-xml"
|
||||
ARGSCHEMA = ""
|
||||
NAME = "DNB"
|
||||
|
||||
|
||||
class SRUSite(Enum):
|
||||
SWB = SWBData
|
||||
DNB = DNBData
|
||||
|
||||
|
||||
RVK_ALLOWED = r"[A-Z0-9.\-\/]" # conservative char set typically seen in RVK notations
|
||||
|
||||
|
||||
def find_newer_edition(
|
||||
swb_result: BookData, dnb_result: List[BookData]
|
||||
) -> Optional[List[BookData]]:
|
||||
"""
|
||||
New edition if:
|
||||
- year > swb.year OR
|
||||
- edition_number > swb.edition_number
|
||||
|
||||
Additional guards & preferences:
|
||||
- If both have signatures and they differ, skip (not the same work).
|
||||
- For duplicates (same ppn): keep the one that has a signature, and
|
||||
prefer a signature that matches swb_result.signature.
|
||||
- If multiple remain: keep the single 'latest' by (year desc,
|
||||
edition_number desc, best-signature-match desc, has-signature desc).
|
||||
"""
|
||||
|
||||
def norm_sig(s: Optional[str]) -> str:
|
||||
if not s:
|
||||
return ""
|
||||
# normalize: lowercase, collapse whitespace, keep alnum + a few separators
|
||||
s = s.lower()
|
||||
s = re.sub(r"\s+", " ", s).strip()
|
||||
# remove obvious noise; adjust if your signature format differs
|
||||
s = re.sub(r"[^a-z0-9\-_/\. ]+", "", s)
|
||||
return s
|
||||
|
||||
def has_sig(b: BookData) -> bool:
|
||||
return bool(getattr(b, "signature", None))
|
||||
|
||||
def sig_matches_swb(b: BookData) -> bool:
|
||||
if not has_sig(b) or not has_sig(swb_result):
|
||||
return False
|
||||
return norm_sig(b.signature) == norm_sig(swb_result.signature)
|
||||
|
||||
def strictly_newer(b: BookData) -> bool:
|
||||
by_year = (
|
||||
b.year is not None
|
||||
and swb_result.year is not None
|
||||
and b.year > swb_result.year
|
||||
)
|
||||
by_edition = (
|
||||
b.edition_number is not None
|
||||
and swb_result.edition_number is not None
|
||||
and b.edition_number > swb_result.edition_number
|
||||
)
|
||||
return by_year or by_edition
|
||||
|
||||
swb_sig_norm = norm_sig(getattr(swb_result, "signature", None))
|
||||
|
||||
# 1) Filter to same-work AND newer
|
||||
candidates: List[BookData] = []
|
||||
for b in dnb_result:
|
||||
# Skip if both signatures exist and don't match (different work)
|
||||
b_sig = getattr(b, "signature", None)
|
||||
if b_sig and swb_result.signature:
|
||||
if norm_sig(b_sig) != swb_sig_norm:
|
||||
continue # not the same work
|
||||
|
||||
# Keep only if newer by rules
|
||||
if strictly_newer(b):
|
||||
candidates.append(b)
|
||||
|
||||
if not candidates:
|
||||
return None
|
||||
|
||||
# 2) Dedupe by PPN, preferring signature (and matching signature if possible)
|
||||
by_ppn: dict[Optional[str], BookData] = {}
|
||||
for b in candidates:
|
||||
key = getattr(b, "ppn", None)
|
||||
prev = by_ppn.get(key)
|
||||
if prev is None:
|
||||
by_ppn[key] = b
|
||||
continue
|
||||
|
||||
# Compute preference score for both
|
||||
def ppn_pref_score(x: BookData) -> tuple[int, int]:
|
||||
# (signature matches swb, has signature)
|
||||
return (1 if sig_matches_swb(x) else 0, 1 if has_sig(x) else 0)
|
||||
|
||||
if ppn_pref_score(b) > ppn_pref_score(prev):
|
||||
by_ppn[key] = b
|
||||
|
||||
deduped = list(by_ppn.values())
|
||||
if not deduped:
|
||||
return None
|
||||
|
||||
# 3) If multiple remain, keep only the latest one.
|
||||
# Order: year desc, edition_number desc, signature-match desc, has-signature desc
|
||||
def sort_key(b: BookData):
|
||||
year = b.year if b.year is not None else -1
|
||||
ed = b.edition_number if b.edition_number is not None else -1
|
||||
sig_match = 1 if sig_matches_swb(b) else 0
|
||||
sig_present = 1 if has_sig(b) else 0
|
||||
return (year, ed, sig_match, sig_present)
|
||||
|
||||
best = max(deduped, key=sort_key)
|
||||
return [best] if best else None
|
||||
|
||||
|
||||
class Api:
|
||||
def __init__(self, site: str, url: str, prefix: str):
|
||||
self.site = site
|
||||
self.url = url
|
||||
self.prefix = prefix
|
||||
# Reuse TCP connections across requests for better performance
|
||||
self._session = requests.Session()
|
||||
# Slightly larger connection pool for concurrent calls
|
||||
adapter = HTTPAdapter(pool_connections=10, pool_maxsize=20)
|
||||
self._session.mount("http://", adapter)
|
||||
self._session.mount("https://", adapter)
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
self._session.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def __del__(self):
|
||||
# Best-effort cleanup
|
||||
self.close()
|
||||
|
||||
def get(self, query_args: Iterable[str]) -> List[Record]:
|
||||
# if any query_arg ends with =, remove it
|
||||
if self.site == "DNB":
|
||||
args = [arg for arg in query_args if not arg.startswith("pica.")]
|
||||
if args == []:
|
||||
raise ValueError("DNB queries must include at least one search term")
|
||||
query_args = args
|
||||
# query_args = [f"{self.prefix}{arg}" for arg in query_args]
|
||||
query = "+and+".join(query_args)
|
||||
query = query.replace(" ", "%20").replace("&", "%26")
|
||||
# query_args = [arg for arg in query_args if not arg.endswith("=")]
|
||||
# query = "+and+".join(query_args)
|
||||
# query = query.replace(" ", "%20").replace("&", "%26")
|
||||
# insert the query into the url url is
|
||||
url = self.url.format(query)
|
||||
|
||||
log.debug(url)
|
||||
headers = {
|
||||
"User-Agent": f"{self.site} SRU Client, <alexander.kirchner@ph-freiburg.de>",
|
||||
"Accept": "application/xml",
|
||||
"Accept-Charset": "latin1,utf-8;q=0.7,*;q=0.3",
|
||||
}
|
||||
# Use persistent session and set timeouts to avoid hanging
|
||||
resp = self._session.get(url, headers=headers, timeout=(3.05, 60))
|
||||
if resp.status_code != 200:
|
||||
raise Exception(f"Error fetching data from SWB: {resp.status_code}")
|
||||
# Parse using raw bytes (original behavior) to preserve encoding edge cases
|
||||
sr = parse_search_retrieve_response(resp.content)
|
||||
return sr.records
|
||||
|
||||
def getBooks(self, query_args: Iterable[str]) -> List[BookData]:
|
||||
records: List[Record] = self.get(query_args)
|
||||
# Avoid printing on hot paths; rely on logger if needed
|
||||
log.debug(f"{self.site} found {len(records)} records for args={query_args}")
|
||||
books: List[BookData] = []
|
||||
# extract title from query_args if present
|
||||
title = None
|
||||
for arg in query_args:
|
||||
if arg.startswith("pica.tit="):
|
||||
title = arg.split("=")[1]
|
||||
break
|
||||
for rec in records:
|
||||
book = book_from_marc(rec.recordData)
|
||||
books.append(book)
|
||||
if title:
|
||||
books = [
|
||||
b
|
||||
for b in books
|
||||
if b.title and b.title.lower().startswith(title.lower())
|
||||
]
|
||||
return books
|
||||
|
||||
def getLinkForBook(self, book: BookData) -> str:
|
||||
# Not implemented: depends on catalog front-end; return empty string for now
|
||||
return ""
|
||||
|
||||
|
||||
class SWB(Api):
|
||||
def __init__(self):
|
||||
self.site = SWBData.NAME.value
|
||||
self.url = SWBData.URL.value
|
||||
self.prefix = SWBData.ARGSCHEMA.value
|
||||
super().__init__(self.site, self.url, self.prefix)
|
||||
@@ -1,6 +1,35 @@
|
||||
from .dataclass import ApparatData, BookData, Prof, Apparat, ELSA
|
||||
__all__ = [
|
||||
"custom_sort",
|
||||
"sort_semesters_list",
|
||||
"APP_NRS",
|
||||
"PROF_TITLES",
|
||||
"SEMAP_MEDIA_ACCOUNTS",
|
||||
"csv_to_list",
|
||||
"ELSA",
|
||||
"Apparat",
|
||||
"ApparatData",
|
||||
"BookData",
|
||||
"Prof",
|
||||
"Semester",
|
||||
"SemapDocument",
|
||||
"elsa_word_to_csv",
|
||||
"pdf_to_semap",
|
||||
"word_docx_to_csv",
|
||||
"word_to_semap",
|
||||
"ZoteroController",
|
||||
"eml_to_semap",
|
||||
]
|
||||
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, word_to_semap, SemapDocument
|
||||
from .dataclass import ELSA, Apparat, ApparatData, BookData, Prof
|
||||
from .semester import Semester
|
||||
from .wordparser import (
|
||||
SemapDocument,
|
||||
elsa_word_to_csv,
|
||||
pdf_to_semap,
|
||||
word_docx_to_csv,
|
||||
word_to_semap,
|
||||
)
|
||||
from .xmlparser import eml_to_semap
|
||||
from .zotero import ZoteroController
|
||||
|
||||
@@ -1,36 +1,4 @@
|
||||
def parse_semester(semester: str):
|
||||
"""
|
||||
Parses the semester string into a sortable format.
|
||||
Returns a tuple of (year, type), where type is 0 for SoSe and 1 for WiSe.
|
||||
"""
|
||||
if semester.startswith("SoSe"):
|
||||
return int(semester.split()[1]), 0
|
||||
elif semester.startswith("WiSe"):
|
||||
year_part = semester.split()[1]
|
||||
start_year, _ = map(int, year_part.split("/"))
|
||||
return start_year, 1
|
||||
else:
|
||||
raise ValueError(f"Invalid semester format: {semester}")
|
||||
|
||||
|
||||
def custom_sort(entries):
|
||||
"""
|
||||
Sorts the list of tuples based on the custom schema.
|
||||
|
||||
:param entries: List of tuples in the format (str, int, int).
|
||||
:return: Sorted list of tuples.
|
||||
"""
|
||||
return sorted(
|
||||
entries,
|
||||
key=lambda entry: (
|
||||
parse_semester(entry[0]), # Sort by semester parsed as (year, type)
|
||||
entry[1], # Then by the second element of the tuple
|
||||
entry[2], # Finally by the third element of the tuple
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def parse_semester(semester: str):
|
||||
def parse_semester(semester: str) -> tuple[int, int]:
|
||||
"""
|
||||
Parses the semester string into a sortable format.
|
||||
Returns a tuple of (year, type), where type is 0 for SoSe and 1 for WiSe.
|
||||
@@ -48,6 +16,23 @@ def parse_semester(semester: str):
|
||||
raise ValueError(f"Invalid semester format: {semester}")
|
||||
|
||||
|
||||
def custom_sort(entries) -> list:
|
||||
"""
|
||||
Sorts the list of tuples based on the custom schema.
|
||||
|
||||
:param entries: List of tuples in the format (str, int, int).
|
||||
:return: Sorted list of tuples.
|
||||
"""
|
||||
return sorted(
|
||||
entries,
|
||||
key=lambda entry: (
|
||||
parse_semester(entry[0]), # Sort by semester parsed as (year, type)
|
||||
entry[1], # Then by the second element of the tuple
|
||||
entry[2], # Finally by the third element of the tuple
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def sort_semesters_list(semesters: list) -> list:
|
||||
"""
|
||||
Sorts a list of semester strings based on year and type.
|
||||
@@ -83,4 +68,4 @@ if __name__ == "__main__":
|
||||
"SoSe 25",
|
||||
]
|
||||
|
||||
print(sort_semesters_list(unsorted))
|
||||
# print(sort_semesters_list(unsorted))
|
||||
|
||||
@@ -30,184 +30,184 @@ PROF_TITLES = [
|
||||
]
|
||||
|
||||
SEMAP_MEDIA_ACCOUNTS = {
|
||||
"1": "1008000055",
|
||||
"2": "1008000188",
|
||||
"3": "1008000211",
|
||||
"4": "1008000344",
|
||||
"5": "1008000477",
|
||||
"6": "1008000500",
|
||||
"7": "1008000633",
|
||||
"8": "1008000766",
|
||||
"9": "1008000899",
|
||||
"10": "1008000922",
|
||||
"11": "1008001044",
|
||||
"12": "1008001177",
|
||||
"13": "1008001200",
|
||||
"14": "1008001333",
|
||||
"15": "1008001466",
|
||||
"16": "1008001599",
|
||||
"17": "1008001622",
|
||||
"18": "1008001755",
|
||||
"19": "1008001888",
|
||||
"20": "1008001911",
|
||||
"21": "1008002033",
|
||||
"22": "1008002166",
|
||||
"23": "1008002299",
|
||||
"24": "1008002322",
|
||||
"25": "1008002455",
|
||||
"26": "1008002588",
|
||||
"27": "1008002611",
|
||||
"28": "1008002744",
|
||||
"29": "1008002877",
|
||||
"30": "1008002900",
|
||||
"31": "1008003022",
|
||||
"32": "1008003155",
|
||||
"33": "1008003288",
|
||||
"34": "1008003311",
|
||||
"35": "1008003444",
|
||||
"36": "1008003577",
|
||||
"37": "1008003600",
|
||||
"38": "1008003733",
|
||||
"39": "1008003866",
|
||||
"40": "1008003999",
|
||||
"41": "1008004011",
|
||||
"42": "1008004144",
|
||||
"43": "1008004277",
|
||||
"44": "1008004300",
|
||||
"45": "1008004433",
|
||||
"46": "1008004566",
|
||||
"47": "1008004699",
|
||||
"48": "1008004722",
|
||||
"49": "1008004855",
|
||||
"50": "1008004988",
|
||||
"51": "1008005000",
|
||||
"52": "1008005133",
|
||||
"53": "1008005266",
|
||||
"54": "1008005399",
|
||||
"55": "1008005422",
|
||||
"56": "1008005555",
|
||||
"57": "1008005688",
|
||||
"58": "1008005711",
|
||||
"59": "1008005844",
|
||||
"60": "1008005977",
|
||||
"61": "1008006099",
|
||||
"62": "1008006122",
|
||||
"63": "1008006255",
|
||||
"64": "1008006388",
|
||||
"65": "1008006411",
|
||||
"66": "1008006544",
|
||||
"67": "1008006677",
|
||||
"68": "1008006700",
|
||||
"69": "1008006833",
|
||||
"70": "1008006966",
|
||||
"71": "1008007088",
|
||||
"72": "1008007111",
|
||||
"73": "1008007244",
|
||||
"74": "1008007377",
|
||||
"75": "1008007400",
|
||||
"76": "1008007533",
|
||||
"77": "1008007666",
|
||||
"78": "1008007799",
|
||||
"79": "1008007822",
|
||||
"80": "1008007955",
|
||||
"81": "1008008077",
|
||||
"82": "1008008100",
|
||||
"83": "1008008233",
|
||||
"84": "1008008366",
|
||||
"85": "1008008499",
|
||||
"86": "1008008522",
|
||||
"87": "1008008655",
|
||||
"88": "1008008788",
|
||||
"89": "1008008811",
|
||||
"90": "1008008944",
|
||||
"91": "1008009066",
|
||||
"92": "1008009199",
|
||||
"93": "1008009222",
|
||||
"94": "1008009355",
|
||||
"95": "1008009488",
|
||||
"96": "1008009511",
|
||||
"97": "1008009644",
|
||||
"98": "1008009777",
|
||||
"99": "1008009800",
|
||||
"100": "1008009933",
|
||||
"101": "1008010022",
|
||||
"102": "1008010155",
|
||||
"103": "1008010288",
|
||||
"104": "1008010311",
|
||||
"105": "1008010444",
|
||||
"106": "1008010577",
|
||||
"107": "1008010600",
|
||||
"108": "1008010733",
|
||||
"109": "1008010866",
|
||||
"110": "1008010999",
|
||||
"111": "1008011011",
|
||||
"112": "1008011144",
|
||||
"113": "1008011277",
|
||||
"114": "1008011300",
|
||||
"115": "1008011433",
|
||||
"116": "1008011566",
|
||||
"117": "1008011699",
|
||||
"118": "1008011722",
|
||||
"119": "1008011855",
|
||||
"120": "1008011988",
|
||||
"121": "1008012000",
|
||||
"122": "1008012133",
|
||||
"123": "1008012266",
|
||||
"124": "1008012399",
|
||||
"125": "1008012422",
|
||||
"126": "1008012555",
|
||||
"127": "1008012688",
|
||||
"128": "1008012711",
|
||||
"129": "1008012844",
|
||||
"130": "1008012977",
|
||||
"131": "1008013099",
|
||||
"132": "1008013122",
|
||||
"133": "1008013255",
|
||||
"134": "1008013388",
|
||||
"135": "1008013411",
|
||||
"136": "1008013544",
|
||||
"137": "1008013677",
|
||||
"138": "1008013700",
|
||||
"139": "1008013833",
|
||||
"140": "1008013966",
|
||||
"141": "1008014088",
|
||||
"142": "1008014111",
|
||||
"143": "1008014244",
|
||||
"144": "1008014377",
|
||||
"145": "1008014400",
|
||||
"146": "1008014533",
|
||||
"147": "1008014666",
|
||||
"148": "1008014799",
|
||||
"149": "1008014822",
|
||||
"150": "1008014955",
|
||||
"151": "1008015077",
|
||||
"152": "1008015100",
|
||||
"153": "1008015233",
|
||||
"154": "1008015366",
|
||||
"155": "1008015499",
|
||||
"156": "1008015522",
|
||||
"157": "1008015655",
|
||||
"158": "1008015788",
|
||||
"159": "1008015811",
|
||||
"160": "1008015944",
|
||||
"161": "1008016066",
|
||||
"162": "1008016199",
|
||||
"163": "1008016222",
|
||||
"164": "1008016355",
|
||||
"165": "1008016488",
|
||||
"166": "1008016511",
|
||||
"167": "1008016644",
|
||||
"168": "1008016777",
|
||||
"169": "1008016800",
|
||||
"170": "1008016933",
|
||||
"171": "1008017055",
|
||||
"172": "1008017188",
|
||||
"173": "1008017211",
|
||||
"174": "1008017344",
|
||||
"175": "1008017477",
|
||||
"176": "1008017500",
|
||||
"177": "1008017633",
|
||||
"178": "1008017766",
|
||||
"179": "1008017899",
|
||||
"180": "1008017922",
|
||||
1: "1008000055",
|
||||
2: "1008000188",
|
||||
3: "1008000211",
|
||||
4: "1008000344",
|
||||
5: "1008000477",
|
||||
6: "1008000500",
|
||||
7: "1008000633",
|
||||
8: "1008000766",
|
||||
9: "1008000899",
|
||||
10: "1008000922",
|
||||
11: "1008001044",
|
||||
12: "1008001177",
|
||||
13: "1008001200",
|
||||
14: "1008001333",
|
||||
15: "1008001466",
|
||||
16: "1008001599",
|
||||
17: "1008001622",
|
||||
18: "1008001755",
|
||||
19: "1008001888",
|
||||
20: "1008001911",
|
||||
21: "1008002033",
|
||||
22: "1008002166",
|
||||
23: "1008002299",
|
||||
24: "1008002322",
|
||||
25: "1008002455",
|
||||
26: "1008002588",
|
||||
27: "1008002611",
|
||||
28: "1008002744",
|
||||
29: "1008002877",
|
||||
30: "1008002900",
|
||||
31: "1008003022",
|
||||
32: "1008003155",
|
||||
33: "1008003288",
|
||||
34: "1008003311",
|
||||
35: "1008003444",
|
||||
36: "1008003577",
|
||||
37: "1008003600",
|
||||
38: "1008003733",
|
||||
39: "1008003866",
|
||||
40: "1008003999",
|
||||
41: "1008004011",
|
||||
42: "1008004144",
|
||||
43: "1008004277",
|
||||
44: "1008004300",
|
||||
45: "1008004433",
|
||||
46: "1008004566",
|
||||
47: "1008004699",
|
||||
48: "1008004722",
|
||||
49: "1008004855",
|
||||
50: "1008004988",
|
||||
51: "1008005000",
|
||||
52: "1008005133",
|
||||
53: "1008005266",
|
||||
54: "1008005399",
|
||||
55: "1008005422",
|
||||
56: "1008005555",
|
||||
57: "1008005688",
|
||||
58: "1008005711",
|
||||
59: "1008005844",
|
||||
60: "1008005977",
|
||||
61: "1008006099",
|
||||
62: "1008006122",
|
||||
63: "1008006255",
|
||||
64: "1008006388",
|
||||
65: "1008006411",
|
||||
66: "1008006544",
|
||||
67: "1008006677",
|
||||
68: "1008006700",
|
||||
69: "1008006833",
|
||||
70: "1008006966",
|
||||
71: "1008007088",
|
||||
72: "1008007111",
|
||||
73: "1008007244",
|
||||
74: "1008007377",
|
||||
75: "1008007400",
|
||||
76: "1008007533",
|
||||
77: "1008007666",
|
||||
78: "1008007799",
|
||||
79: "1008007822",
|
||||
80: "1008007955",
|
||||
81: "1008008077",
|
||||
82: "1008008100",
|
||||
83: "1008008233",
|
||||
84: "1008008366",
|
||||
85: "1008008499",
|
||||
86: "1008008522",
|
||||
87: "1008008655",
|
||||
88: "1008008788",
|
||||
89: "1008008811",
|
||||
90: "1008008944",
|
||||
91: "1008009066",
|
||||
92: "1008009199",
|
||||
93: "1008009222",
|
||||
94: "1008009355",
|
||||
95: "1008009488",
|
||||
96: "1008009511",
|
||||
97: "1008009644",
|
||||
98: "1008009777",
|
||||
99: "1008009800",
|
||||
100: "1008009933",
|
||||
101: "1008010022",
|
||||
102: "1008010155",
|
||||
103: "1008010288",
|
||||
104: "1008010311",
|
||||
105: "1008010444",
|
||||
106: "1008010577",
|
||||
107: "1008010600",
|
||||
108: "1008010733",
|
||||
109: "1008010866",
|
||||
110: "1008010999",
|
||||
111: "1008011011",
|
||||
112: "1008011144",
|
||||
113: "1008011277",
|
||||
114: "1008011300",
|
||||
115: "1008011433",
|
||||
116: "1008011566",
|
||||
117: "1008011699",
|
||||
118: "1008011722",
|
||||
119: "1008011855",
|
||||
120: "1008011988",
|
||||
121: "1008012000",
|
||||
122: "1008012133",
|
||||
123: "1008012266",
|
||||
124: "1008012399",
|
||||
125: "1008012422",
|
||||
126: "1008012555",
|
||||
127: "1008012688",
|
||||
128: "1008012711",
|
||||
129: "1008012844",
|
||||
130: "1008012977",
|
||||
131: "1008013099",
|
||||
132: "1008013122",
|
||||
133: "1008013255",
|
||||
134: "1008013388",
|
||||
135: "1008013411",
|
||||
136: "1008013544",
|
||||
137: "1008013677",
|
||||
138: "1008013700",
|
||||
139: "1008013833",
|
||||
140: "1008013966",
|
||||
141: "1008014088",
|
||||
142: "1008014111",
|
||||
143: "1008014244",
|
||||
144: "1008014377",
|
||||
145: "1008014400",
|
||||
146: "1008014533",
|
||||
147: "1008014666",
|
||||
148: "1008014799",
|
||||
149: "1008014822",
|
||||
150: "1008014955",
|
||||
151: "1008015077",
|
||||
152: "1008015100",
|
||||
153: "1008015233",
|
||||
154: "1008015366",
|
||||
155: "1008015499",
|
||||
156: "1008015522",
|
||||
157: "1008015655",
|
||||
158: "1008015788",
|
||||
159: "1008015811",
|
||||
160: "1008015944",
|
||||
161: "1008016066",
|
||||
162: "1008016199",
|
||||
163: "1008016222",
|
||||
164: "1008016355",
|
||||
165: "1008016488",
|
||||
166: "1008016511",
|
||||
167: "1008016644",
|
||||
168: "1008016777",
|
||||
169: "1008016800",
|
||||
170: "1008016933",
|
||||
171: "1008017055",
|
||||
172: "1008017188",
|
||||
173: "1008017211",
|
||||
174: "1008017344",
|
||||
175: "1008017477",
|
||||
176: "1008017500",
|
||||
177: "1008017633",
|
||||
178: "1008017766",
|
||||
179: "1008017899",
|
||||
180: "1008017922",
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import csv
|
||||
|
||||
import chardet
|
||||
from charset_normalizer import detect
|
||||
|
||||
|
||||
def csv_to_list(path: str) -> list[str]:
|
||||
"""
|
||||
Extracts the data from a csv file and returns it as a pandas dataframe
|
||||
"""
|
||||
encoding = chardet.detect(open(path, "rb").read())["encoding"]
|
||||
encoding = detect(open(path, "rb").read())["encoding"]
|
||||
with open(path, newline="", encoding=encoding) as csvfile:
|
||||
# if decoder fails to map, assign ""
|
||||
reader = csv.reader(csvfile, delimiter=";", quotechar="|")
|
||||
@@ -20,4 +20,4 @@ def csv_to_list(path: str) -> list[str]:
|
||||
if __name__ == "__main__":
|
||||
text = csv_to_list("C:/Users/aky547/Desktop/semap/71.csv")
|
||||
# remove linebreaks
|
||||
# print(text)
|
||||
# #print(text)
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from enum import Enum
|
||||
import json
|
||||
from typing import Union, Any, Optional
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
import regex
|
||||
|
||||
from src.logic.openai import name_tester, run_shortener, semester_converter
|
||||
from src.logic.semester import Semester
|
||||
|
||||
|
||||
@dataclass
|
||||
class Prof:
|
||||
@@ -32,7 +37,7 @@ class Prof:
|
||||
self._title = value
|
||||
|
||||
# add function that sets the data from a tuple
|
||||
def from_tuple(self, data: tuple[Union[str, int], ...]):
|
||||
def from_tuple(self, data: tuple[Union[str, int], ...]) -> "Prof":
|
||||
setattr(self, "id", data[0])
|
||||
setattr(self, "_title", data[1])
|
||||
setattr(self, "firstname", data[2])
|
||||
@@ -67,21 +72,63 @@ class BookData:
|
||||
language: Union[str, list[str], None] = field(default_factory=list)
|
||||
publisher: str | None = None
|
||||
place: str | None = None
|
||||
year: str | None = None
|
||||
year: int | None = None
|
||||
pages: str | None = None
|
||||
library_location: int | None = None
|
||||
library_location: str | None = None
|
||||
in_apparat: bool | None = False
|
||||
adis_idn: str | None = None
|
||||
old_book: Any | None = None
|
||||
media_type: str | None = None #
|
||||
in_library: bool | None = None # whether the book is in the library or not
|
||||
|
||||
def __post_init__(self):
|
||||
self.library_location = (
|
||||
str(self.library_location) if self.library_location else None
|
||||
)
|
||||
if isinstance(self.language, list) and self.language:
|
||||
self.language = [lang.strip() for lang in self.language if lang.strip()]
|
||||
self.language = ",".join(self.language)
|
||||
self.year = regex.sub(r"[^\d]", "", str(self.year)) if self.year else None
|
||||
self.in_library = True if self.signature else False
|
||||
|
||||
def from_dict(self, data: dict) -> "BookData":
|
||||
for key, value in data.items():
|
||||
setattr(self, key, value)
|
||||
return self
|
||||
|
||||
def merge(self, other: "BookData") -> "BookData":
|
||||
for key, value in other.__dict__.items():
|
||||
# merge lists, if the attribute is a list, extend it
|
||||
if isinstance(value, list):
|
||||
current_value = getattr(self, key)
|
||||
if current_value is None:
|
||||
current_value = []
|
||||
elif not isinstance(current_value, list):
|
||||
current_value = [current_value]
|
||||
# extend the list with the new values, but only if they are not already in the list
|
||||
for v in value:
|
||||
if v not in current_value:
|
||||
current_value.append(v)
|
||||
setattr(self, key, current_value)
|
||||
if value is not None and (
|
||||
getattr(self, key) is None or getattr(self, key) == ""
|
||||
):
|
||||
setattr(self, key, value)
|
||||
# in language, drop all entries that are longer than 3 characters
|
||||
if isinstance(self.language, list):
|
||||
self.language = [lang for lang in self.language if len(lang) <= 4]
|
||||
return self
|
||||
|
||||
@property
|
||||
def to_dict(self) -> str:
|
||||
"""Convert the dataclass to a dictionary."""
|
||||
return json.dumps(self.__dict__, ensure_ascii=False)
|
||||
data_dict = {
|
||||
key: value for key, value in self.__dict__.items() if value is not None
|
||||
}
|
||||
# remove old_book from data_dict
|
||||
if "old_book" in data_dict:
|
||||
del data_dict["old_book"]
|
||||
return json.dumps(data_dict, ensure_ascii=False)
|
||||
|
||||
def from_dataclass(self, dataclass: Optional[Any]) -> None:
|
||||
if dataclass is None:
|
||||
@@ -89,10 +136,44 @@ class BookData:
|
||||
for key, value in dataclass.__dict__.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
def get_book_type(self) -> str:
|
||||
if "Online" in self.pages:
|
||||
return "eBook"
|
||||
else:
|
||||
return "Druckausgabe"
|
||||
|
||||
def from_string(self, data: str) -> "BookData":
|
||||
ndata = json.loads(data)
|
||||
|
||||
return BookData(**ndata)
|
||||
|
||||
def from_LehmannsSearchResult(self, result: Any) -> "BookData":
|
||||
self.title = result.title
|
||||
self.author = "; ".join(result.authors) if result.authors else None
|
||||
self.edition = str(result.edition) if result.edition else None
|
||||
self.link = result.url
|
||||
self.isbn = (
|
||||
result.isbn13
|
||||
if isinstance(result.isbn13, list)
|
||||
else [result.isbn13]
|
||||
if result.isbn13
|
||||
else []
|
||||
)
|
||||
self.pages = str(result.pages) if result.pages else None
|
||||
self.publisher = result.publisher
|
||||
self.year = str(result.year) if result.year else None
|
||||
# self.pages = str(result.pages) if result.pages else None
|
||||
return self
|
||||
|
||||
@property
|
||||
def edition_number(self) -> Optional[int]:
|
||||
if self.edition is None:
|
||||
return 0
|
||||
match = regex.search(r"(\d+)", self.edition)
|
||||
if match:
|
||||
return int(match.group(1))
|
||||
return 0
|
||||
|
||||
|
||||
@dataclass
|
||||
class MailData:
|
||||
@@ -141,6 +222,7 @@ class Subjects(Enum):
|
||||
for i in cls:
|
||||
if i.name == name:
|
||||
return i.id - 1
|
||||
return None
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -204,3 +286,124 @@ class ELSA:
|
||||
class ApparatData:
|
||||
prof: Prof = field(default_factory=Prof)
|
||||
apparat: Apparat = field(default_factory=Apparat)
|
||||
|
||||
|
||||
@dataclass
|
||||
class XMLMailSubmission:
|
||||
name: Optional[str] = None
|
||||
lastname: Optional[str] = None
|
||||
title: Optional[str] = None
|
||||
telno: Optional[int] = None
|
||||
email: Optional[str] = None
|
||||
app_name: Optional[str] = None
|
||||
subject: Optional[str] = None
|
||||
semester: Optional[Semester] = None
|
||||
books: Optional[list[BookData]] = None
|
||||
|
||||
|
||||
@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
|
||||
title_suggestions: list[str] = None
|
||||
semester: Union[str, Semester] = None
|
||||
books: list[Book] = None
|
||||
eternal: bool = False
|
||||
personName: str = None
|
||||
personTitle: str = None
|
||||
title_length = 0
|
||||
title_max_length = 0
|
||||
|
||||
def __post_init__(self):
|
||||
self.title_suggestions = []
|
||||
|
||||
@property
|
||||
def nameSetter(self):
|
||||
data = name_tester(self.personTitle)
|
||||
name = f"{data['last_name']}, {data['first_name']}"
|
||||
if data["title"] is not None:
|
||||
title = data["title"]
|
||||
self.personTitle = title
|
||||
self.personName = name
|
||||
self.title_length = len(self.title) + 3 + len(self.personName.split(",")[0])
|
||||
if self.title_length > 40:
|
||||
name_len = len(self.personName.split(",")[0])
|
||||
self.title_max_length = 38 - name_len
|
||||
suggestions = run_shortener(self.title, self.title_max_length)
|
||||
for suggestion in suggestions:
|
||||
self.title_suggestions.append(suggestion["shortened_string"])
|
||||
else:
|
||||
self.title_suggestions = []
|
||||
pass
|
||||
|
||||
@property
|
||||
def renameSemester(self) -> None:
|
||||
if self.semester:
|
||||
if ", Dauer" in self.semester:
|
||||
self.semester = self.semester.split(",")[0]
|
||||
self.eternal = True
|
||||
self.semester = Semester().from_string(self.semester)
|
||||
else:
|
||||
self.semester = Semester().from_string(
|
||||
semester_converter(self.semester)
|
||||
)
|
||||
|
||||
@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 []
|
||||
|
||||
312
src/logic/lehmannsapi.py
Normal file
312
src/logic/lehmannsapi.py
Normal file
@@ -0,0 +1,312 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from typing import Iterable, List, Optional
|
||||
from urllib.parse import quote_plus, urljoin
|
||||
|
||||
import httpx
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from src.logic.dataclass import BookData
|
||||
|
||||
BASE = "https://www.lehmanns.de"
|
||||
SEARCH_URL = "https://www.lehmanns.de/search/quick?mediatype_id=&q="
|
||||
|
||||
|
||||
@dataclass
|
||||
class LehmannsSearchResult:
|
||||
title: str
|
||||
url: str
|
||||
|
||||
# Core fields from the listing card
|
||||
year: Optional[int] = None
|
||||
edition: Optional[int] = None
|
||||
publisher: Optional[str] = None
|
||||
isbn13: Optional[str] = None
|
||||
|
||||
# Extras from the listing card
|
||||
description: Optional[str] = None
|
||||
authors: list[str] = field(default_factory=list)
|
||||
media_type: Optional[str] = None
|
||||
book_format: Optional[str] = None
|
||||
price_eur: Optional[float] = None
|
||||
currency: str = "EUR"
|
||||
image: Optional[str] = None
|
||||
|
||||
# From detail page:
|
||||
pages: Optional[str] = None # "<N> Seiten"
|
||||
buyable: bool = True # set in enrich_pages (detail page)
|
||||
unavailable_hint: Optional[str] = (
|
||||
None # e.g. "Titel ist leider vergriffen; keine Neuauflage"
|
||||
)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return asdict(self)
|
||||
|
||||
|
||||
class LehmannsClient:
|
||||
"""Scrapes quick-search results, then enriches (and filters) via product pages."""
|
||||
|
||||
def __init__(self, timeout: float = 20.0):
|
||||
self.client = httpx.Client(
|
||||
headers={
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
|
||||
"(KHTML, like Gecko) Chrome/124.0 Safari/537.36"
|
||||
),
|
||||
"Accept-Language": "de-DE,de;q=0.9,en;q=0.8",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
},
|
||||
timeout=timeout,
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
def close(self):
|
||||
self.client.close()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc):
|
||||
self.close()
|
||||
|
||||
# ------------------- Search (listing) -------------------
|
||||
|
||||
def build_search_url(self, title: str) -> str:
|
||||
# spaces -> '+'
|
||||
return SEARCH_URL + quote_plus(title)
|
||||
|
||||
def search_by_title(
|
||||
self,
|
||||
title: str,
|
||||
limit: Optional[int] = None,
|
||||
strict: bool = False,
|
||||
only_latest: bool = True,
|
||||
) -> List[BookData]:
|
||||
"""
|
||||
Parse the listing page only (no availability check here).
|
||||
Use enrich_pages(...) afterwards to fetch detail pages, add 'pages',
|
||||
and drop unbuyable items.
|
||||
"""
|
||||
url = self.build_search_url(title=title)
|
||||
html = self._get(url)
|
||||
if not html:
|
||||
return []
|
||||
results = self._parse_results(html)
|
||||
self.enrich_pages(results)
|
||||
|
||||
results = [BookData().from_LehmannsSearchResult(r) for r in results]
|
||||
if strict:
|
||||
# filter results to only those with exact title match (case-insensitive)
|
||||
title_lower = title.lower()
|
||||
results = [r for r in results if r.title and r.title.lower() == title_lower]
|
||||
# results = [r for r in results if r.buyable]
|
||||
return results
|
||||
if limit is not None:
|
||||
results = results[: max(0, limit)]
|
||||
if only_latest and len(results) > 1:
|
||||
# keep only the latest edition (highest edition number)
|
||||
results.sort(key=lambda r: (r.edition_number or 0), reverse=True)
|
||||
results = [results[0]]
|
||||
return results
|
||||
|
||||
# ------------------- Detail enrichment & filtering -------------------
|
||||
|
||||
def enrich_pages(
|
||||
self, results: Iterable[LehmannsSearchResult], drop_unbuyable: bool = True
|
||||
) -> List[LehmannsSearchResult]:
|
||||
"""
|
||||
Fetch each result.url, extract:
|
||||
- pages: from <span class="book-meta meta-seiten" itemprop="numberOfPages">...</span>
|
||||
- availability: from <li class="availability-3">...</li>
|
||||
* if it contains "Titel ist leider vergriffen", mark buyable=False
|
||||
* if it also contains "keine Neuauflage", set unavailable_hint accordingly
|
||||
If drop_unbuyable=True, exclude non-buyable results from the returned list.
|
||||
"""
|
||||
enriched: List[LehmannsSearchResult] = []
|
||||
for r in results:
|
||||
try:
|
||||
html = self._get(r.url)
|
||||
if not html:
|
||||
# Can't verify; keep as-is when not dropping, else skip
|
||||
if not drop_unbuyable:
|
||||
enriched.append(r)
|
||||
continue
|
||||
|
||||
soup = BeautifulSoup(html, "html.parser") # type: ignore
|
||||
|
||||
# Pages
|
||||
pages_node = soup.select_one( # type: ignore
|
||||
"span.book-meta.meta-seiten[itemprop='numberOfPages'], "
|
||||
"span.book-meta.meta-seiten[itemprop='numberofpages'], "
|
||||
".meta-seiten [itemprop='numberOfPages'], "
|
||||
".meta-seiten[itemprop='numberOfPages'], "
|
||||
".book-meta.meta-seiten"
|
||||
)
|
||||
if pages_node:
|
||||
text = pages_node.get_text(" ", strip=True)
|
||||
m = re.search(r"\d+", text)
|
||||
if m:
|
||||
r.pages = f"{m.group(0)} Seiten"
|
||||
|
||||
# Availability via li.availability-3
|
||||
avail_li = soup.select_one("li.availability-3") # type: ignore
|
||||
if avail_li:
|
||||
avail_text = " ".join(
|
||||
avail_li.get_text(" ", strip=True).split()
|
||||
).lower()
|
||||
if "titel ist leider vergriffen" in avail_text:
|
||||
r.buyable = False
|
||||
if "keine neuauflage" in avail_text:
|
||||
r.unavailable_hint = (
|
||||
"Titel ist leider vergriffen; keine Neuauflage"
|
||||
)
|
||||
else:
|
||||
r.unavailable_hint = "Titel ist leider vergriffen"
|
||||
|
||||
# Append or drop
|
||||
if (not drop_unbuyable) or r.buyable:
|
||||
enriched.append(r)
|
||||
|
||||
except Exception:
|
||||
# On any per-item error, keep the record if not dropping; else skip
|
||||
if not drop_unbuyable:
|
||||
enriched.append(r)
|
||||
continue
|
||||
|
||||
return enriched
|
||||
|
||||
# ------------------- Internals -------------------
|
||||
|
||||
def _get(self, url: str) -> Optional[str]:
|
||||
try:
|
||||
r = self.client.get(url)
|
||||
r.encoding = "utf-8"
|
||||
if r.status_code == 200 and "text/html" in (
|
||||
r.headers.get("content-type") or ""
|
||||
):
|
||||
return r.text
|
||||
except httpx.HTTPError:
|
||||
pass
|
||||
return None
|
||||
|
||||
def _parse_results(self, html: str) -> List[LehmannsSearchResult]:
|
||||
soup = BeautifulSoup(html, "html.parser")
|
||||
results: list[LehmannsSearchResult] = []
|
||||
|
||||
for block in soup.select("div.info-block"):
|
||||
a = block.select_one(".title a[href]")
|
||||
if not a:
|
||||
continue
|
||||
url = urljoin(BASE, a["href"].strip())
|
||||
base_title = (block.select_one(".title [itemprop='name']") or a).get_text( # type: ignore
|
||||
strip=True
|
||||
)
|
||||
|
||||
# Alternative headline => extend title
|
||||
alt_tag = block.select_one(".description[itemprop='alternativeHeadline']") # type: ignore
|
||||
alternative_headline = alt_tag.get_text(strip=True) if alt_tag else None
|
||||
title = (
|
||||
f"{base_title} : {alternative_headline}"
|
||||
if alternative_headline
|
||||
else base_title
|
||||
)
|
||||
description = alternative_headline
|
||||
|
||||
# Authors from .author
|
||||
authors: list[str] = []
|
||||
author_div = block.select_one("div.author") # type: ignore
|
||||
if author_div:
|
||||
t = author_div.get_text(" ", strip=True)
|
||||
t = re.sub(r"^\s*von\s+", "", t, flags=re.I)
|
||||
for part in re.split(r"\s*;\s*|\s*&\s*|\s+und\s+", t):
|
||||
name = " ".join(part.split())
|
||||
if name:
|
||||
authors.append(name)
|
||||
|
||||
# Media + format
|
||||
media_type = None
|
||||
book_format = None
|
||||
type_text = block.select_one(".type") # type: ignore
|
||||
if type_text:
|
||||
t = type_text.get_text(" ", strip=True)
|
||||
m = re.search(r"\b(Buch|eBook|Hörbuch)\b", t)
|
||||
if m:
|
||||
media_type = m.group(1)
|
||||
fm = re.search(r"\(([^)]+)\)", t)
|
||||
if fm:
|
||||
book_format = fm.group(1).strip().upper()
|
||||
|
||||
# Year
|
||||
year = None
|
||||
y = block.select_one("[itemprop='copyrightYear']") # type: ignore
|
||||
if y:
|
||||
try:
|
||||
year = int(y.get_text(strip=True))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Edition
|
||||
edition = None
|
||||
ed = block.select_one("[itemprop='bookEdition']") # type: ignore
|
||||
if ed:
|
||||
m = re.search(r"\d+", ed.get_text(strip=True))
|
||||
if m:
|
||||
edition = int(m.group())
|
||||
|
||||
# Publisher
|
||||
publisher = None
|
||||
pub = block.select_one( # type: ignore
|
||||
".publisherprop [itemprop='name']"
|
||||
) or block.select_one(".publisher [itemprop='name']") # type: ignore
|
||||
if pub:
|
||||
publisher = pub.get_text(strip=True)
|
||||
|
||||
# ISBN-13
|
||||
isbn13 = None
|
||||
isbn_tag = block.select_one(".isbn [itemprop='isbn'], [itemprop='isbn']") # type: ignore
|
||||
if isbn_tag:
|
||||
digits = re.sub(r"[^0-9Xx]", "", isbn_tag.get_text(strip=True))
|
||||
m = re.search(r"(97[89]\d{10})", digits)
|
||||
if m:
|
||||
isbn13 = m.group(1)
|
||||
|
||||
# Price (best effort)
|
||||
price_eur = None
|
||||
txt = block.get_text(" ", strip=True)
|
||||
mprice = re.search(r"(\d{1,3}(?:\.\d{3})*,\d{2})\s*€", txt)
|
||||
if not mprice and block.parent:
|
||||
sib = block.parent.get_text(" ", strip=True)
|
||||
mprice = re.search(r"(\d{1,3}(?:\.\d{3})*,\d{2})\s*€", sib)
|
||||
if mprice:
|
||||
num = mprice.group(1).replace(".", "").replace(",", ".")
|
||||
try:
|
||||
price_eur = float(num)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Image (best-effort)
|
||||
image = None
|
||||
left_img = block.find_previous("img") # type: ignore
|
||||
if left_img and left_img.get("src"):
|
||||
image = urljoin(BASE, left_img["src"])
|
||||
|
||||
results.append(
|
||||
LehmannsSearchResult(
|
||||
title=title,
|
||||
url=url,
|
||||
description=description,
|
||||
authors=authors,
|
||||
media_type=media_type,
|
||||
book_format=book_format,
|
||||
year=year,
|
||||
edition=edition,
|
||||
publisher=publisher,
|
||||
isbn13=isbn13,
|
||||
price_eur=price_eur,
|
||||
image=image,
|
||||
)
|
||||
)
|
||||
|
||||
return results
|
||||
@@ -1,10 +1,12 @@
|
||||
from openai import OpenAI
|
||||
from src import settings
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from openai import OpenAI
|
||||
|
||||
from src import settings
|
||||
|
||||
|
||||
|
||||
def init_client():
|
||||
def init_client() -> OpenAI:
|
||||
"""Initialize the OpenAI client with the API key and model from settings."""
|
||||
global client, model, api_key
|
||||
if not settings.openAI.api_key:
|
||||
@@ -16,9 +18,11 @@ def init_client():
|
||||
api_key = settings.openAI.api_key
|
||||
client = OpenAI(api_key=api_key)
|
||||
return client
|
||||
def run_shortener(title:str, length:int):
|
||||
|
||||
|
||||
def run_shortener(title: str, length: int) -> list[dict[str, Any]]:
|
||||
client = init_client()
|
||||
response = client.responses.create(
|
||||
response = client.responses.create( # type: ignore
|
||||
model=model,
|
||||
instructions="""you are a sentence shortener. The next message will contain the string to shorten and the length limit.
|
||||
You need to shorten the string to be under the length limit, while keeping as much detail as possible. The result may NOT be longer than the length limit.
|
||||
@@ -27,26 +31,27 @@ based on that, please reply only the shortened string. Give me 5 choices. if the
|
||||
)
|
||||
answers = response.output_text
|
||||
return eval(answers) # type: ignore
|
||||
#answers are strings in json format, so we need to convert them to a list of dicts
|
||||
# answers are strings in json format, so we need to convert them to a list of dicts
|
||||
|
||||
|
||||
def name_tester(name: str):
|
||||
def name_tester(name: str) -> dict:
|
||||
client = init_client()
|
||||
response = client.responses.create(
|
||||
model = model,
|
||||
response = client.responses.create( # type: ignore
|
||||
model=model,
|
||||
instructions="""you are a name tester, You are given a name and will have to split the name into first name, last name, and if present the title. Return the name in a json format with the keys "title", "first_name", "last_name". If no title is present, set title to none. Do NOt return the answer in a codeblock, use a pure json string. Assume the names are in the usual german naming scheme""",
|
||||
input = f'{{"name":"{name}"}}'
|
||||
input=f'{{"name":"{name}"}}',
|
||||
)
|
||||
answers = response.output_text
|
||||
|
||||
return json.loads(answers)
|
||||
|
||||
def semester_converter(semester:str):
|
||||
|
||||
def semester_converter(semester: str) -> str:
|
||||
client = init_client()
|
||||
response = client.responses.create(
|
||||
model = model,
|
||||
response = client.responses.create( # type: ignore
|
||||
model=model,
|
||||
instructions="""you are a semester converter. You will be given a string. Convert this into a string like this: SoSe YY or WiSe YY/YY+1. Do not return the answer in a codeblock, use a pure string.""",
|
||||
input = semester
|
||||
input=semester,
|
||||
)
|
||||
answers = response.output_text
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
# add depend path to system path
|
||||
|
||||
import pandas as pd
|
||||
from pdfquery import PDFQuery
|
||||
|
||||
|
||||
def pdf_to_csv(path: str) -> pd.DataFrame:
|
||||
def pdf_to_csv(path: str) -> str:
|
||||
"""
|
||||
Extracts the data from a pdf file and returns it as a pandas dataframe
|
||||
"""
|
||||
@@ -21,4 +20,4 @@ if __name__ == "__main__":
|
||||
text = pdf_to_csv("54_pdf.pdf")
|
||||
# remove linebreaks
|
||||
text = text.replace("\n", "")
|
||||
print(text)
|
||||
# print(text)
|
||||
|
||||
@@ -15,20 +15,13 @@ Key points
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
import loguru
|
||||
import sys
|
||||
from src import LOG_DIR
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
from src.shared.logging import log
|
||||
|
||||
|
||||
|
||||
# @dataclass
|
||||
class Semester:
|
||||
"""Represents a German university semester (WiSe or SoSe)."""
|
||||
|
||||
@@ -123,21 +116,22 @@ class Semester:
|
||||
# ------------------------------------------------------------------
|
||||
# Comparison helpers
|
||||
# ------------------------------------------------------------------
|
||||
def isPastSemester(self, other: "Semester") -> bool:
|
||||
if self.year < other.year:
|
||||
def isPastSemester(self, current: "Semester") -> bool:
|
||||
log.debug(f"Comparing {self} < {current}")
|
||||
if self.year < current.year:
|
||||
return True
|
||||
if self.year == other.year:
|
||||
if self.year == current.year:
|
||||
return (
|
||||
self.semester == "WiSe" and other.semester == "SoSe"
|
||||
self.semester == "WiSe" and current.semester == "SoSe"
|
||||
) # WiSe before next SoSe
|
||||
return False
|
||||
|
||||
def isFutureSemester(self, other: "Semester") -> bool:
|
||||
if self.year > other.year:
|
||||
def isFutureSemester(self, current: "Semester") -> bool:
|
||||
if self.year > current.year:
|
||||
return True
|
||||
if self.year == other.year:
|
||||
if self.year == current.year:
|
||||
return (
|
||||
self.semester == "SoSe" and other.semester == "WiSe"
|
||||
self.semester == "SoSe" and current.semester == "WiSe"
|
||||
) # SoSe after WiSe of same year
|
||||
return False
|
||||
|
||||
@@ -235,8 +229,20 @@ if __name__ == "__main__":
|
||||
s_start = Semester(6, "SoSe") # SoSe 6
|
||||
s_end = Semester(25, "WiSe") # WiSe 25/26
|
||||
chain = Semester.generate_missing(s_start, s_end)
|
||||
print("generate_missing:", [str(s) for s in chain])
|
||||
# print("generate_missing:", [str(s) for s in chain])
|
||||
|
||||
# Parsing demo ---------------------------------------------------------
|
||||
for label in ["SoSe 6", "WiSe 6/7", "wise 23/24", "WiSe 9"]:
|
||||
print("from_string:", label, "→", Semester.from_string(label))
|
||||
examples = [
|
||||
"SoSe 6",
|
||||
"WiSe 6/7",
|
||||
"WiSe 6",
|
||||
"SoSe 23",
|
||||
"WiSe 23/24",
|
||||
"WiSe 24",
|
||||
"WiSe 99/00",
|
||||
"SoSe 00",
|
||||
"WiSe 100/101", # test large year
|
||||
]
|
||||
for ex in examples:
|
||||
parsed = Semester.from_string(ex)
|
||||
print(f"'{ex}' → {parsed} ({parsed.year=}, {parsed.semester=})")
|
||||
@@ -13,7 +13,7 @@ class Settings:
|
||||
default_apps: bool = True
|
||||
custom_applications: list[dict] = field(default_factory=list)
|
||||
|
||||
def save_settings(self):
|
||||
def save_settings(self) -> None:
|
||||
"""Save the settings to the config file."""
|
||||
with open("config.yaml", "w") as f:
|
||||
yaml.dump(self.__dict__, f)
|
||||
|
||||
@@ -1,26 +1,19 @@
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
|
||||
# import sleep_and_retry decorator to retry requests
|
||||
from ratelimit import limits, sleep_and_retry
|
||||
from typing import Union, Any, Optional
|
||||
from src.logic.dataclass import BookData
|
||||
|
||||
from src.logic.dataclass import BookData
|
||||
from src.shared.logging import log
|
||||
from src.transformers import ARRAYData, BibTeXData, COinSData, RDSData, RISData
|
||||
from src.transformers.transformers import RDS_AVAIL_DATA, RDS_GENERIC_DATA
|
||||
import loguru
|
||||
import sys
|
||||
from src import LOG_DIR
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
||||
|
||||
|
||||
|
||||
API_URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndexrecord/{}/"
|
||||
PPN_URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndex/Search?type0%5B%5D=allfields&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=au&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ti&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ct&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=isn&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ta&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=co&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=py&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pp&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pu&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=si&lookfor0%5B%5D={}&join=AND&bool0%5B%5D=AND&type0%5B%5D=zr&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=cc&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND"
|
||||
BASE = "https://rds.ibs-bw.de"
|
||||
@@ -58,14 +51,14 @@ class WebRequest:
|
||||
log.info("Using any book")
|
||||
return self
|
||||
|
||||
def set_apparat(self, apparat: int):
|
||||
def set_apparat(self, apparat: int) -> "WebRequest":
|
||||
self.apparat = apparat
|
||||
if int(self.apparat) < 10:
|
||||
self.apparat = f"0{self.apparat}"
|
||||
log.info(f"Set apparat to {self.apparat}")
|
||||
return self
|
||||
|
||||
def get_ppn(self, signature: str):
|
||||
def get_ppn(self, signature: str) -> "WebRequest":
|
||||
self.signature = signature
|
||||
if "+" in signature:
|
||||
signature = signature.replace("+", "%2B")
|
||||
@@ -80,6 +73,12 @@ class WebRequest:
|
||||
response = requests.get(PPN_URL.format(searchterm), timeout=self.timeout)
|
||||
return response.text
|
||||
|
||||
@sleep_and_retry
|
||||
@limits(calls=RATE_LIMIT, period=RATE_PERIOD)
|
||||
def search_ppn(self, ppn: str) -> str:
|
||||
response = requests.get(API_URL.format(ppn), timeout=self.timeout)
|
||||
return response.text
|
||||
|
||||
def get_book_links(self, searchterm: str) -> list[str]:
|
||||
response: str = self.search_book(searchterm) # type:ignore
|
||||
soup = BeautifulSoup(response, "html.parser")
|
||||
@@ -91,7 +90,7 @@ class WebRequest:
|
||||
|
||||
@sleep_and_retry
|
||||
@limits(calls=RATE_LIMIT, period=RATE_PERIOD)
|
||||
def search(self, link: str):
|
||||
def search(self, link: str) -> Optional[str]:
|
||||
try:
|
||||
response = requests.get(link, timeout=self.timeout)
|
||||
return response.text
|
||||
@@ -99,7 +98,7 @@ class WebRequest:
|
||||
log.error(f"Request failed: {e}")
|
||||
return None
|
||||
|
||||
def get_data(self) -> Union[list[str], None]:
|
||||
def get_data(self) -> Optional[list[str]]:
|
||||
links = self.get_book_links(self.ppn)
|
||||
log.debug(f"Links: {links}")
|
||||
return_data: list[str] = []
|
||||
@@ -111,6 +110,19 @@ class WebRequest:
|
||||
locations = soup.find_all("div", class_="col-xs-12 rds-dl RDS_LOCATION")
|
||||
if locations:
|
||||
for location in locations:
|
||||
if "1. OG Semesterapparat" in location.text:
|
||||
log.success("Found Semesterapparat, adding entry")
|
||||
pre_tag = soup.find_all("pre")
|
||||
return_data = []
|
||||
if pre_tag:
|
||||
for tag in pre_tag:
|
||||
data = tag.text.strip()
|
||||
return_data.append(data)
|
||||
return return_data
|
||||
else:
|
||||
log.error("No <pre> tag found")
|
||||
return return_data
|
||||
else:
|
||||
item_location = location.find(
|
||||
"div", class_="col-xs-12 col-md-7 col-lg-8 rds-dl-panel"
|
||||
).text.strip()
|
||||
@@ -144,7 +156,7 @@ class WebRequest:
|
||||
|
||||
return return_data
|
||||
|
||||
def get_data_elsa(self):
|
||||
def get_data_elsa(self) -> Optional[list[str]]:
|
||||
links = self.get_book_links(self.ppn)
|
||||
for link in links:
|
||||
result = self.search(link)
|
||||
@@ -185,12 +197,12 @@ class BibTextTransformer:
|
||||
self.data = None
|
||||
# self.bookdata = BookData(**self.data)
|
||||
|
||||
def use_signature(self, signature: str):
|
||||
def use_signature(self, signature: str) -> "BibTextTransformer":
|
||||
"""use the exact signature to search for the book"""
|
||||
self.signature = signature
|
||||
return self
|
||||
|
||||
def get_data(self, data: Union[list[str]] = None) -> "BibTextTransformer":
|
||||
def get_data(self, data: Optional[list[str]] = None) -> "BibTextTransformer":
|
||||
RIS_IDENT = "TY -"
|
||||
ARRAY_IDENT = "[kid]"
|
||||
COinS_IDENT = "ctx_ver"
|
||||
|
||||
@@ -1,131 +1,13 @@
|
||||
import sys
|
||||
import zipfile
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Union
|
||||
from typing import Any, Optional
|
||||
|
||||
import loguru
|
||||
import fitz # PyMuPDF
|
||||
import pandas as pd
|
||||
from bs4 import BeautifulSoup
|
||||
from docx import Document
|
||||
|
||||
from src import LOG_DIR
|
||||
from src.backend import Semester
|
||||
from src.logic.openai import name_tester, run_shortener, semester_converter
|
||||
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
|
||||
|
||||
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
|
||||
@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
|
||||
title_suggestions: list[str] = None
|
||||
semester: Union[str, Semester] = None
|
||||
books: list[Book] = None
|
||||
eternal: bool = False
|
||||
personName: str = None
|
||||
personTitle: str = None
|
||||
title_length = 0
|
||||
title_max_length = 0
|
||||
|
||||
def __post_init__(self):
|
||||
self.title_suggestions = []
|
||||
|
||||
@property
|
||||
def nameSetter(self):
|
||||
data = name_tester(self.personTitle)
|
||||
name = f"{data['last_name']}, {data['first_name']}"
|
||||
if data["title"] is not None:
|
||||
title = data["title"]
|
||||
self.personTitle = title
|
||||
self.personName = name
|
||||
self.title_length = len(self.title) + 3 + len(self.personName.split(",")[0])
|
||||
if self.title_length > 40:
|
||||
log.warning("Title is too long")
|
||||
name_len = len(self.personName.split(",")[0])
|
||||
self.title_max_length = 38 - name_len
|
||||
suggestions = run_shortener(self.title, self.title_max_length)
|
||||
for suggestion in suggestions:
|
||||
self.title_suggestions.append(suggestion["shortened_string"])
|
||||
else:
|
||||
self.title_suggestions = []
|
||||
pass
|
||||
@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:
|
||||
log.warning("Semester {} is not valid", self.semester)
|
||||
self.semester = Semester().from_string(semester_converter(self.semester))
|
||||
|
||||
@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 []
|
||||
from src.logic.dataclass import Book, SemapDocument
|
||||
from src.shared.logging import log
|
||||
|
||||
|
||||
def word_docx_to_csv(path: str) -> list[pd.DataFrame]:
|
||||
@@ -141,8 +23,8 @@ def word_docx_to_csv(path: str) -> list[pd.DataFrame]:
|
||||
|
||||
text = text.replace("\n", "")
|
||||
row_data.append(text)
|
||||
if text == "Ihr Fach:":
|
||||
row_data.append(get_fach(path))
|
||||
# if text == "Ihr Fach:":
|
||||
# row_data.append(get_fach(path))
|
||||
data.append(row_data)
|
||||
df = pd.DataFrame(data)
|
||||
df.columns = df.iloc[0]
|
||||
@@ -153,7 +35,7 @@ def word_docx_to_csv(path: str) -> list[pd.DataFrame]:
|
||||
return m_data
|
||||
|
||||
|
||||
def get_fach(path: str) -> str:
|
||||
def get_fach(path: str) -> Optional[str]:
|
||||
document = zipfile.ZipFile(path)
|
||||
xml_data = document.read("word/document.xml")
|
||||
document.close()
|
||||
@@ -161,17 +43,18 @@ def get_fach(path: str) -> str:
|
||||
soup = BeautifulSoup(xml_data, "xml")
|
||||
# text we need is in <w:p w14:paraId="12456A32" ... > -> w:r -> w:t
|
||||
paragraphs = soup.find_all("w:p")
|
||||
names = []
|
||||
for para in paragraphs:
|
||||
para_id = para.get("w14:paraId")
|
||||
if para_id == "12456A32":
|
||||
# get the data in the w:t
|
||||
for run in para.find_all("w:r"):
|
||||
data = run.find("w:t")
|
||||
if data and data.contents:
|
||||
return data.contents[0]
|
||||
return None
|
||||
|
||||
|
||||
def makeDict():
|
||||
def makeDict() -> dict[str, Optional[str]]:
|
||||
return {
|
||||
"work_author": None,
|
||||
"section_author": None,
|
||||
@@ -189,8 +72,8 @@ def makeDict():
|
||||
}
|
||||
|
||||
|
||||
def tuple_to_dict(tlist: tuple, type: str) -> dict:
|
||||
ret = []
|
||||
def tuple_to_dict(tlist: tuple, type: str) -> list[dict[str, Optional[str]]]:
|
||||
ret: list[dict[str, Optional[str]]] = []
|
||||
for line in tlist:
|
||||
data = makeDict()
|
||||
if type == "Monografien":
|
||||
@@ -230,7 +113,7 @@ def tuple_to_dict(tlist: tuple, type: str) -> dict:
|
||||
return ret
|
||||
|
||||
|
||||
def elsa_word_to_csv(path: str):
|
||||
def elsa_word_to_csv(path: str) -> tuple[list[dict[str, Optional[str]]], str]:
|
||||
doc = Document(path)
|
||||
# # print all lines in doc
|
||||
doctype = [para.text for para in doc.paragraphs if para.text != ""][-1]
|
||||
@@ -265,14 +148,14 @@ def elsa_word_to_csv(path: str):
|
||||
return tuple_to_dict(data, doctype), doctype
|
||||
|
||||
|
||||
def word_to_semap(word_path: str) -> SemapDocument:
|
||||
def word_to_semap(word_path: str, ai: bool = True) -> SemapDocument:
|
||||
log.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())
|
||||
print(apparatdata, keys)
|
||||
# print(apparatdata, keys)
|
||||
|
||||
appdata = {keys[i]: keys[i + 1] for i in range(0, len(keys) - 1, 2)}
|
||||
semap.phoneNumber = appdata["Telefon:"]
|
||||
@@ -286,6 +169,7 @@ def word_to_semap(word_path: str) -> SemapDocument:
|
||||
appdata = {keys[i]: keys[i + 1] for i in range(0, len(keys), 2)}
|
||||
semap.title = appdata["Veranstaltung:"]
|
||||
semap.semester = appdata["Semester:"]
|
||||
if ai:
|
||||
semap.renameSemester
|
||||
semap.nameSetter
|
||||
|
||||
@@ -308,8 +192,182 @@ def word_to_semap(word_path: str) -> SemapDocument:
|
||||
return semap
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
else_df = elsa_word_to_csv(
|
||||
"C:/Users/aky547/Desktop/ELSA_Bestellung Scann Der Westen und der Rest.docx"
|
||||
def pdf_to_semap(pdf_path: str, ai: bool = True) -> SemapDocument:
|
||||
"""
|
||||
Parse a Semesterapparat PDF like the sample you provided and return a SemapDocument.
|
||||
- No external programs, only PyMuPDF.
|
||||
- Robust to multi-line field values (e.g., hyphenated emails) and multi-line table cells.
|
||||
- Works across multiple pages; headers only need to exist on the first page.
|
||||
"""
|
||||
doc = fitz.open(pdf_path)
|
||||
semap = SemapDocument()
|
||||
|
||||
# ---------- helpers ----------
|
||||
def _join_tokens(tokens: list[str]) -> str:
|
||||
"""Join tokens, preserving hyphen/URL joins across line wraps."""
|
||||
parts = []
|
||||
for tok in tokens:
|
||||
if parts and (
|
||||
parts[-1].endswith("-")
|
||||
or parts[-1].endswith("/")
|
||||
or parts[-1].endswith(":")
|
||||
):
|
||||
parts[-1] = parts[-1] + tok # no space after '-', '/' or ':'
|
||||
else:
|
||||
parts.append(tok)
|
||||
return " ".join(parts).strip()
|
||||
|
||||
def _extract_row_values_multiline(
|
||||
page, labels: list[str], y_window: float = 24
|
||||
) -> dict[str, str]:
|
||||
"""For a row of inline labels (e.g., Name/Fach/Telefon/Mail), grab text to the right of each label."""
|
||||
rects = []
|
||||
for lab in labels:
|
||||
hits = page.search_for(lab)
|
||||
if hits:
|
||||
rects.append((lab, hits[0]))
|
||||
if not rects:
|
||||
return {}
|
||||
|
||||
rects.sort(key=lambda t: t[1].x0)
|
||||
words = page.get_text("words")
|
||||
out = {}
|
||||
for i, (lab, r) in enumerate(rects):
|
||||
x0 = r.x1 + 1
|
||||
x1 = rects[i + 1][1].x0 - 1 if i + 1 < len(rects) else page.rect.width - 5
|
||||
y0 = r.y0 - 3
|
||||
y1 = r.y0 + y_window
|
||||
toks = [w for w in words if x0 <= w[0] <= x1 and y0 <= w[1] <= y1]
|
||||
toks.sort(key=lambda w: (w[1], w[0])) # line, then x
|
||||
out[lab] = _join_tokens([w[4] for w in toks])
|
||||
return out
|
||||
|
||||
def _compute_columns_from_headers(page0):
|
||||
"""Find column headers (once) and derive column centers + header baseline."""
|
||||
headers = [
|
||||
("Autorenname(n):", "Autorenname(n):Nachname, Vorname"),
|
||||
("Jahr/Auflage", "Jahr/Auflage"),
|
||||
("Titel", "Titel"),
|
||||
("Ort und Verlag", "Ort und Verlag"),
|
||||
("Standnummer", "Standnummer"),
|
||||
("Interne Vermerke", "Interne Vermerke"),
|
||||
]
|
||||
found = []
|
||||
for label, canon in headers:
|
||||
rects = [
|
||||
r for r in page0.search_for(label) if r.y0 > 200
|
||||
] # skip top-of-form duplicates
|
||||
if rects:
|
||||
found.append((canon, rects[0]))
|
||||
found.sort(key=lambda t: t[1].x0)
|
||||
cols = [(canon, r.x0, r.x1, (r.x0 + r.x1) / 2.0) for canon, r in found]
|
||||
header_y = min(r.y0 for _, r in found) if found else 0
|
||||
return cols, header_y
|
||||
|
||||
def _extract_table_rows_from_page(
|
||||
page, cols, header_y, y_top_margin=5, y_bottom_margin=40, y_tol=26.0
|
||||
):
|
||||
"""
|
||||
Group words into logical rows (tolerant to wrapped lines), then map each word
|
||||
to the nearest column by x-center and join tokens per column.
|
||||
"""
|
||||
words = [
|
||||
w
|
||||
for w in page.get_text("words")
|
||||
if w[1] > header_y + y_top_margin
|
||||
and w[3] < page.rect.height - y_bottom_margin
|
||||
]
|
||||
|
||||
# group into row bands by y (tolerance big enough to capture wrapped lines, but below next row gap)
|
||||
rows = []
|
||||
for w in sorted(words, key=lambda w: w[1]):
|
||||
y = w[1]
|
||||
for row in rows:
|
||||
if abs(row["y_mean"] - y) <= y_tol:
|
||||
row["ys"].append(y)
|
||||
row["y_mean"] = sum(row["ys"]) / len(row["ys"])
|
||||
row["words"].append(w)
|
||||
break
|
||||
else:
|
||||
rows.append({"y_mean": y, "ys": [y], "words": [w]})
|
||||
|
||||
# map to columns + join
|
||||
joined_rows = []
|
||||
for row in rows:
|
||||
rowdict = {canon: "" for canon, *_ in cols}
|
||||
words_by_col = {canon: [] for canon, *_ in cols}
|
||||
for w in sorted(row["words"], key=lambda w: (w[1], w[0])):
|
||||
xmid = (w[0] + w[2]) / 2.0
|
||||
canon = min(cols, key=lambda c: abs(xmid - c[3]))[0]
|
||||
words_by_col[canon].append(w[4])
|
||||
for canon, toks in words_by_col.items():
|
||||
rowdict[canon] = _join_tokens(toks)
|
||||
if any(v for v in rowdict.values()):
|
||||
joined_rows.append(rowdict)
|
||||
return joined_rows
|
||||
|
||||
# ---------- top-of-form fields ----------
|
||||
p0 = doc[0]
|
||||
row1 = _extract_row_values_multiline(
|
||||
p0,
|
||||
["Ihr Name und Titel:", "Ihr Fach:", "Telefon:", "Mailadresse:"],
|
||||
y_window=22,
|
||||
)
|
||||
print(else_df)
|
||||
row2 = _extract_row_values_multiline(
|
||||
p0, ["Veranstaltung:", "Semester:"], y_window=20
|
||||
)
|
||||
|
||||
name_title = row1.get("Ihr Name und Titel:", "") or ""
|
||||
semap.subject = row1.get("Ihr Fach:", None)
|
||||
semap.phoneNumber = row1.get("Telefon:", None) # keep as-is (string like "682-308")
|
||||
semap.mail = row1.get("Mailadresse:", None)
|
||||
semap.personName = ",".join(name_title.split(",")[:-1]) if name_title else None
|
||||
semap.personTitle = (
|
||||
",".join(name_title.split(",")[-1:]).strip() if name_title else None
|
||||
)
|
||||
|
||||
semap.title = row2.get("Veranstaltung:", None)
|
||||
semap.semester = row2.get("Semester:", None)
|
||||
|
||||
# ---------- table extraction (all pages) ----------
|
||||
cols, header_y = _compute_columns_from_headers(p0)
|
||||
all_rows: list[dict[str, Any]] = []
|
||||
for pn in range(len(doc)):
|
||||
all_rows.extend(_extract_table_rows_from_page(doc[pn], cols, header_y))
|
||||
|
||||
# drop the sub-header line "Nachname, Vorname" etc.
|
||||
filtered = []
|
||||
for r in all_rows:
|
||||
if r.get("Autorenname(n):Nachname, Vorname", "").strip() in (
|
||||
"",
|
||||
"Nachname, Vorname",
|
||||
):
|
||||
# skip if it's just the sub-header line
|
||||
if all(not r[c] for c in r if c != "Autorenname(n):Nachname, Vorname"):
|
||||
continue
|
||||
filtered.append(r)
|
||||
|
||||
# build Book objects (same filters as your word parser)
|
||||
booklist: list[Book] = []
|
||||
for row in filtered:
|
||||
b = Book()
|
||||
b.from_dict(row)
|
||||
if b.is_empty:
|
||||
continue
|
||||
if not b.has_signature:
|
||||
continue
|
||||
booklist.append(b)
|
||||
|
||||
semap.books = booklist
|
||||
|
||||
# keep parity with your post-processing
|
||||
if ai:
|
||||
_ = semap.renameSemester
|
||||
_ = semap.nameSetter
|
||||
|
||||
return semap
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
else_df = pdf_to_semap("C:/Users/aky547/Dokumente/testsemap.pdf")
|
||||
# print(else_df)
|
||||
|
||||
67
src/logic/xmlparser.py
Normal file
67
src/logic/xmlparser.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from src.logic.dataclass import Apparat, BookData, SemapDocument, XMLMailSubmission
|
||||
from src.logic.semester import Semester
|
||||
|
||||
|
||||
def parse_xml_submission(xml_string: str) -> XMLMailSubmission:
|
||||
"""
|
||||
Parse an XML string representing a mail submission and return an XMLMailSubmission object.
|
||||
"""
|
||||
submission = XMLMailSubmission()
|
||||
root = ET.fromstring(xml_string)
|
||||
static_data = root.find("static")
|
||||
static_info = {child.tag: child.text for child in static_data}
|
||||
books = root.find("books")
|
||||
books_info = []
|
||||
for book in books:
|
||||
book_details = {detail.tag: detail.text for detail in book}
|
||||
book = BookData(
|
||||
author=book_details.get("authorname"),
|
||||
year=book_details.get("year").split("/")[0]
|
||||
if "/" in book_details.get("year")
|
||||
else book_details.get("year"),
|
||||
edition=book_details.get("year").split("/")[1]
|
||||
if "/" in book_details.get("year")
|
||||
else None,
|
||||
title=book_details.get("title"),
|
||||
signature=book_details.get("signature"),
|
||||
)
|
||||
books_info.append(book)
|
||||
# Extract static data
|
||||
submission.name = static_info.get("name")
|
||||
submission.lastname = static_info.get("lastname")
|
||||
submission.title = static_info.get("title")
|
||||
submission.telno = int(static_info.get("telno"))
|
||||
submission.email = static_info.get("mail")
|
||||
submission.app_name = static_info.get("apparatsname")
|
||||
submission.subject = static_info.get("subject")
|
||||
sem_year = static_info.get("semester").split()[1]
|
||||
sem_term = static_info.get("semester").split()[0]
|
||||
submission.semester = Semester(semester=sem_term, year=int(sem_year))
|
||||
submission.books = books_info
|
||||
# Extract book information
|
||||
# book_info = []
|
||||
# for book in books:
|
||||
# book_details = {detail.tag: detail.text for detail in book}
|
||||
# book_info.append(book_details)
|
||||
return submission
|
||||
|
||||
|
||||
def eml_parser(path: str) -> XMLMailSubmission:
|
||||
with open(path, "r", encoding="utf-8") as file:
|
||||
xml_content = file.read().split("\n\n", 1)[1] # Skip headers
|
||||
print("EML content loaded, parsing XML...")
|
||||
print(xml_content)
|
||||
return parse_xml_submission(xml_content)
|
||||
|
||||
|
||||
def eml_to_semap(xml_mail: XMLMailSubmission) -> SemapDocument:
|
||||
submission = eml_parser(xml_mail)
|
||||
semap_doc = SemapDocument(
|
||||
# prof=Prof(name=submission.name, lastname=submission.lastname, email=submission.email),
|
||||
apparat=Apparat(name=submission.app_name, subject=submission.subject),
|
||||
semester=submission.semester,
|
||||
books=submission.books,
|
||||
)
|
||||
return semap_doc
|
||||
@@ -1,7 +1,10 @@
|
||||
from pyzotero import zotero
|
||||
from dataclasses import dataclass
|
||||
from src.logic.webrequest import WebRequest, BibTextTransformer
|
||||
from typing import Optional
|
||||
|
||||
from pyzotero import zotero
|
||||
|
||||
from src import settings
|
||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -10,11 +13,11 @@ class Creator:
|
||||
lastName: str = None
|
||||
creatorType: str = "author"
|
||||
|
||||
def from_dict(self, data: dict):
|
||||
def from_dict(self, data: dict) -> None:
|
||||
for key, value in data.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
def from_string(self, data: str):
|
||||
def from_string(self, data: str) -> "Creator":
|
||||
if "," in data:
|
||||
self.firstName = data.split(",")[1]
|
||||
self.lastName = data.split(",")[0]
|
||||
@@ -54,7 +57,7 @@ class Book:
|
||||
rights: str = None
|
||||
extra: str = None
|
||||
|
||||
def to_dict(self):
|
||||
def to_dict(self) -> dict:
|
||||
ret = {}
|
||||
for key, value in self.__dict__.items():
|
||||
if value:
|
||||
@@ -93,14 +96,14 @@ class BookSection:
|
||||
collections = list
|
||||
relations = dict
|
||||
|
||||
def to_dict(self):
|
||||
def to_dict(self) -> dict:
|
||||
ret = {}
|
||||
for key, value in self.__dict__.items():
|
||||
if value:
|
||||
ret[key] = value
|
||||
return ret
|
||||
|
||||
def assign(self, book):
|
||||
def assign(self, book) -> None:
|
||||
for key, value in book.__dict__.items():
|
||||
if key in self.__dict__.keys():
|
||||
try:
|
||||
@@ -140,14 +143,14 @@ class JournalArticle:
|
||||
collections = list
|
||||
relations = dict
|
||||
|
||||
def to_dict(self):
|
||||
def to_dict(self) -> dict:
|
||||
ret = {}
|
||||
for key, value in self.__dict__.items():
|
||||
if value:
|
||||
ret[key] = value
|
||||
return ret
|
||||
|
||||
def assign(self, book: dict):
|
||||
def assign(self, book: dict) -> None:
|
||||
for key, value in book.__dict__.items():
|
||||
if key in self.__dict__.keys():
|
||||
try:
|
||||
@@ -162,15 +165,15 @@ class ZoteroController:
|
||||
def __init__(self):
|
||||
if self.zoterocfg.library_id is None:
|
||||
return
|
||||
self.zot = zotero.Zotero(
|
||||
self.zot = zotero.Zotero( # type: ignore
|
||||
self.zoterocfg.library_id,
|
||||
self.zoterocfg.library_type,
|
||||
self.zoterocfg.api_key,
|
||||
)
|
||||
|
||||
def get_books(self):
|
||||
def get_books(self) -> list:
|
||||
ret = []
|
||||
items = self.zot.top()
|
||||
items = self.zot.top() # type: ignore
|
||||
for item in items:
|
||||
if item["data"]["itemType"] == "book":
|
||||
ret.append(item)
|
||||
@@ -178,7 +181,7 @@ class ZoteroController:
|
||||
|
||||
# create item in zotero
|
||||
# item is a part of a book
|
||||
def __get_data(self, isbn):
|
||||
def __get_data(self, isbn) -> dict:
|
||||
web = WebRequest()
|
||||
web.get_ppn(isbn)
|
||||
data = web.get_data_elsa()
|
||||
@@ -187,8 +190,8 @@ class ZoteroController:
|
||||
book = bib.return_data()
|
||||
return book
|
||||
|
||||
# # print(zot.item_template("bookSection"))
|
||||
def createBook(self, isbn):
|
||||
# # #print(zot.item_template("bookSection"))
|
||||
def createBook(self, isbn) -> Book:
|
||||
book = self.__get_data(isbn)
|
||||
|
||||
bookdata = Book()
|
||||
@@ -207,23 +210,23 @@ class ZoteroController:
|
||||
bookdata.creators = authors
|
||||
return bookdata
|
||||
|
||||
def createItem(self, item):
|
||||
resp = self.zot.create_items([item])
|
||||
def createItem(self, item) -> Optional[str]:
|
||||
resp = self.zot.create_items([item]) # type: ignore
|
||||
if "successful" in resp.keys():
|
||||
# print(resp["successful"]["0"]["key"])
|
||||
# #print(resp["successful"]["0"]["key"])
|
||||
return resp["successful"]["0"]["key"]
|
||||
else:
|
||||
return None
|
||||
|
||||
def deleteItem(self, key):
|
||||
def deleteItem(self, key) -> None:
|
||||
items = self.zot.items()
|
||||
for item in items:
|
||||
if item["key"] == key:
|
||||
self.zot.delete_item(item)
|
||||
# print(item)
|
||||
self.zot.delete_item(item) # type: ignore
|
||||
# #print(item)
|
||||
break
|
||||
|
||||
def createHGSection(self, book: Book, data: dict):
|
||||
def createHGSection(self, book: Book, data: dict) -> Optional[str]:
|
||||
chapter = BookSection()
|
||||
chapter.assign(book)
|
||||
chapter.pages = data["pages"]
|
||||
@@ -241,11 +244,11 @@ class ZoteroController:
|
||||
]
|
||||
chapter.creators += authors
|
||||
|
||||
# print(chapter.to_dict())
|
||||
# #print(chapter.to_dict())
|
||||
return self.createItem(chapter.to_dict())
|
||||
pass
|
||||
|
||||
def createBookSection(self, book: Book, data: dict):
|
||||
def createBookSection(self, book: Book, data: dict) -> Optional[str]:
|
||||
chapter = BookSection()
|
||||
chapter.assign(book)
|
||||
chapter.pages = data["pages"]
|
||||
@@ -256,8 +259,8 @@ class ZoteroController:
|
||||
return self.createItem(chapter.to_dict())
|
||||
# chapter.creators
|
||||
|
||||
def createJournalArticle(self, journal, article):
|
||||
# print(type(article))
|
||||
def createJournalArticle(self, journal, article) -> Optional[str]:
|
||||
# #print(type(article))
|
||||
journalarticle = JournalArticle()
|
||||
journalarticle.assign(journal)
|
||||
journalarticle.itemType = "journalArticle"
|
||||
@@ -273,12 +276,12 @@ class ZoteroController:
|
||||
journalarticle.issue = article["issue"]
|
||||
journalarticle.url = article["isbn"]
|
||||
|
||||
# print(journalarticle.to_dict())
|
||||
# #print(journalarticle.to_dict())
|
||||
|
||||
return self.createItem(journalarticle.to_dict())
|
||||
|
||||
def get_citation(self, item):
|
||||
title = self.zot.item(
|
||||
def get_citation(self, item) -> str:
|
||||
title = self.zot.item( # type: ignore
|
||||
item,
|
||||
content="bib",
|
||||
style="deutsche-gesellschaft-fur-psychologie",
|
||||
@@ -319,16 +322,16 @@ if __name__ == "__main__":
|
||||
# if isinstance(publishers, str):
|
||||
# publishers = [publishers]
|
||||
# for publisher in publishers:
|
||||
# # print(publisher)
|
||||
# # #print(publisher)
|
||||
# creator = Creator().from_string(publisher)
|
||||
# creator.creatorType = "editor"
|
||||
# authors.append(creator.__dict__)
|
||||
|
||||
# chapter.creators = authors
|
||||
# chapter.publisher = book.publisher
|
||||
# # print(chapter.to_dict())
|
||||
# # #print(chapter.to_dict())
|
||||
# createBookSection(chapter.to_dict())
|
||||
# get_citation("9ZXH8DDE")
|
||||
# # # print()
|
||||
# # print(get_books())
|
||||
# # print(zot.item_creator_types("bookSection"))
|
||||
# # # #print()
|
||||
# # #print(get_books())
|
||||
# # #print(zot.item_creator_types("bookSection"))
|
||||
|
||||
25
src/shared/logging.py
Normal file
25
src/shared/logging.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import sys
|
||||
|
||||
import loguru
|
||||
|
||||
from src import LOG_DIR
|
||||
|
||||
log = loguru.logger
|
||||
_configured = False
|
||||
|
||||
|
||||
def configure(level: str = "INFO", to_stdout: bool = True, rotate_bytes: str = "1 MB"):
|
||||
global _configured
|
||||
if _configured:
|
||||
return log
|
||||
log.remove()
|
||||
if to_stdout:
|
||||
log.add(sys.stdout, level=level)
|
||||
# application rolling log
|
||||
log.add(
|
||||
f"{LOG_DIR}/application.log",
|
||||
rotation=rotate_bytes,
|
||||
retention="10 days",
|
||||
)
|
||||
_configured = True
|
||||
return log
|
||||
BIN
src/sounds/ding.mp3
Normal file
BIN
src/sounds/ding.mp3
Normal file
Binary file not shown.
BIN
src/sounds/error.mp3
Normal file
BIN
src/sounds/error.mp3
Normal file
Binary file not shown.
@@ -10,8 +10,9 @@ import hashlib
|
||||
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
|
||||
from src.backend.database import Database
|
||||
from src.backend.admin_console import AdminCommands
|
||||
from src.backend.database import Database
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
@@ -64,13 +65,11 @@ class Ui_Dialog(object):
|
||||
def login(self):
|
||||
username = self.lineEdit.text()
|
||||
password = self.lineEdit_2.text()
|
||||
print(type(username), password)
|
||||
# print(type(username), password)
|
||||
# Assuming 'Database' is a class to interact with your database
|
||||
db = Database()
|
||||
|
||||
hashed_password = hashlib.sha256(
|
||||
password.encode()
|
||||
).hexdigest()
|
||||
hashed_password = hashlib.sha256(password.encode()).hexdigest()
|
||||
if len(db.getUsers()) == 0:
|
||||
AdminCommands().create_admin()
|
||||
self.lresult = 1 # Indicate successful login
|
||||
|
||||
@@ -6,17 +6,18 @@
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
import subprocess
|
||||
import tempfile
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from omegaconf import OmegaConf
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
|
||||
config = OmegaConf.load("config.yaml")
|
||||
|
||||
class Ui_eMailPreview(object):
|
||||
|
||||
class Ui_eMailPreview(object):
|
||||
def setupUi(
|
||||
self,
|
||||
eMailPreview,
|
||||
@@ -31,7 +32,10 @@ class Ui_eMailPreview(object):
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(eMailPreview)
|
||||
self.buttonBox.setGeometry(QtCore.QRect(310, 630, 341, 32))
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
|
||||
self.buttonBox.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Ok
|
||||
)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.gridLayoutWidget = QtWidgets.QWidget(eMailPreview)
|
||||
self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 10, 661, 621))
|
||||
@@ -46,7 +50,11 @@ class Ui_eMailPreview(object):
|
||||
self.prof_name.setObjectName("prof_name")
|
||||
self.gridLayout.addWidget(self.prof_name, 2, 2, 1, 1)
|
||||
self.label_3 = QtWidgets.QLabel(self.gridLayoutWidget)
|
||||
self.label_3.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
|
||||
self.label_3.setAlignment(
|
||||
QtCore.Qt.AlignmentFlag.AlignLeading
|
||||
| QtCore.Qt.AlignmentFlag.AlignLeft
|
||||
| QtCore.Qt.AlignmentFlag.AlignTop
|
||||
)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout.addWidget(self.label_3, 5, 0, 1, 1)
|
||||
self.mail_name = QtWidgets.QLineEdit(self.gridLayoutWidget)
|
||||
@@ -81,7 +89,12 @@ class Ui_eMailPreview(object):
|
||||
self.gender_non = QtWidgets.QRadioButton(self.gridLayoutWidget)
|
||||
self.gender_non.setObjectName("gender_non")
|
||||
self.horizontalLayout_3.addWidget(self.gender_non)
|
||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||
spacerItem = QtWidgets.QSpacerItem(
|
||||
40,
|
||||
20,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
)
|
||||
self.horizontalLayout_3.addItem(spacerItem)
|
||||
self.gridLayout.addLayout(self.horizontalLayout_3, 4, 2, 1, 1)
|
||||
self.label_6 = QtWidgets.QLabel(self.gridLayoutWidget)
|
||||
@@ -128,7 +141,6 @@ class Ui_eMailPreview(object):
|
||||
elif self.gender_non.isChecked():
|
||||
return "Guten Tag"
|
||||
|
||||
|
||||
def set_mail(self):
|
||||
email_template = self.comboBox.currentText()
|
||||
if email_template == "":
|
||||
@@ -145,14 +157,19 @@ class Ui_eMailPreview(object):
|
||||
mail_html = mail_template.split("<html>")[1]
|
||||
mail_html = "<html>" + mail_html
|
||||
mail_html = mail_html.format(
|
||||
Profname=self.prof_name.text().split(" ")[1], Appname=self._appname, AppNr=self._appid, AppSubject = self._subject,greeting = self.get_greeting()
|
||||
Profname=self.prof_name.text().split(" ")[1],
|
||||
Appname=self._appname,
|
||||
AppNr=self._appid,
|
||||
AppSubject=self._subject,
|
||||
greeting=self.get_greeting(),
|
||||
)
|
||||
|
||||
self.mail_body.setHtml(mail_html)
|
||||
|
||||
def load_mail_templates(self):
|
||||
mail_templates = os.listdir("mail_vorlagen")
|
||||
mail_templates = [f for f in mail_templates if f.endswith(".eml")]
|
||||
print(mail_templates)
|
||||
# print(mail_templates)
|
||||
self.comboBox.addItems(mail_templates)
|
||||
|
||||
def save_mail(self):
|
||||
@@ -168,16 +185,17 @@ class Ui_eMailPreview(object):
|
||||
) as f:
|
||||
f.write(mail)
|
||||
self.mail_path = f.name
|
||||
print(self.mail_path)
|
||||
# print(self.mail_path)
|
||||
# open the file using thunderbird
|
||||
subprocess.Popen([f"{self.mail_path}"])
|
||||
# delete the file
|
||||
# os.remove(self.mail_path)
|
||||
|
||||
|
||||
def launch():
|
||||
app = QtWidgets.QApplication([])
|
||||
eMailPreview = QtWidgets.QDialog()
|
||||
ui = Ui_eMailPreview()
|
||||
ui.setupUi(eMailPreview, "1","Test","Biologie","Kirchner, Alexander")
|
||||
ui.setupUi(eMailPreview, "1", "Test", "Biologie", "Kirchner, Alexander")
|
||||
eMailPreview.show()
|
||||
app.exec()
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1">
|
||||
</TS>
|
||||
@@ -110,7 +110,7 @@ class Ui_Form(object):
|
||||
self.progressBar.setValue(value)
|
||||
|
||||
def thread_quit(self):
|
||||
print("Terminating thread")
|
||||
# print("Terminating thread")
|
||||
self.thread.terminate()
|
||||
self.thread.quit()
|
||||
self.thread.deleteLater()
|
||||
@@ -144,7 +144,7 @@ class Ui_Form(object):
|
||||
def determine_progress(self, signal):
|
||||
# check length of listWidget
|
||||
length = self.listWidget.count()
|
||||
print(f"Length of listWidget: {length}")
|
||||
# print(f"Length of listWidget: {length}")
|
||||
if length == 0:
|
||||
logger.log_info("AutoAdder finished")
|
||||
self.buttonBox.accepted.emit()
|
||||
|
||||
@@ -169,7 +169,7 @@ class Ui_Dialog(object):
|
||||
name = application.application
|
||||
file_type = application.extensions
|
||||
display_name = application.name
|
||||
print(name, file_type, display_name) #
|
||||
# print(name, file_type, display_name) #
|
||||
# create new item
|
||||
item = QtWidgets.QTreeWidgetItem(self.treeWidget)
|
||||
item.setText(0, display_name)
|
||||
|
||||
@@ -12,20 +12,23 @@ __all__ = [
|
||||
"ElsaAddEntry",
|
||||
"ApparatExtendDialog",
|
||||
"DocumentPrintDialog",
|
||||
"NewEditionDialog",
|
||||
"Settings",
|
||||
"DeleteDialog",
|
||||
]
|
||||
from .about import About
|
||||
from .app_ext import ApparatExtendDialog
|
||||
from .bookdata import BookDataUI
|
||||
from .deletedialog import DeleteDialog
|
||||
from .docuprint import DocumentPrintDialog
|
||||
from .elsa_add_entry import ElsaAddEntry
|
||||
from .elsa_gen_confirm import ElsaGenConfirm
|
||||
from .login import LoginDialog
|
||||
from .mail import Mail_Dialog
|
||||
from .mailTemplate import MailTemplateDialog
|
||||
from .medienadder import MedienAdder
|
||||
from .newEdition import NewEditionDialog
|
||||
from .parsed_titles import ParsedTitles
|
||||
from .popup_confirm import ConfirmDialog as popus_confirm
|
||||
from .reminder import ReminderDialog
|
||||
from .about import About
|
||||
from .elsa_gen_confirm import ElsaGenConfirm
|
||||
from .elsa_add_entry import ElsaAddEntry
|
||||
from .app_ext import ApparatExtendDialog
|
||||
from .docuprint import DocumentPrintDialog
|
||||
|
||||
from .settings import Settings
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
from .dialog_sources.Ui_about import Ui_about
|
||||
from PySide6 import QtWidgets
|
||||
import PySide6
|
||||
from src import Icon, __version__, __author__
|
||||
from PySide6 import QtWidgets
|
||||
|
||||
from src import Icon, __author__, __version__
|
||||
|
||||
from .dialog_sources.about_ui import Ui_about
|
||||
|
||||
|
||||
class About(QtWidgets.QDialog, Ui_about):
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
from PySide6 import QtWidgets
|
||||
from .dialog_sources.Ui_apparat_extend import Ui_Dialog
|
||||
|
||||
from src import Icon
|
||||
|
||||
from .dialog_sources.apparat_extend_ui import Ui_Dialog
|
||||
|
||||
|
||||
class ApparatExtendDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
def __init__(
|
||||
|
||||
@@ -2,7 +2,7 @@ from PySide6 import QtWidgets
|
||||
|
||||
from src.logic.dataclass import BookData
|
||||
|
||||
from .dialog_sources.Ui_edit_bookdata import Ui_Dialog
|
||||
from .dialog_sources.edit_bookdata_ui import Ui_Dialog
|
||||
|
||||
|
||||
class BookDataUI(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
129
src/ui/dialogs/deletedialog.py
Normal file
129
src/ui/dialogs/deletedialog.py
Normal file
@@ -0,0 +1,129 @@
|
||||
from typing import Any
|
||||
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
|
||||
from src import Icon
|
||||
from src.backend.database import Database
|
||||
|
||||
from .dialog_sources.deletedialog_ui import Ui_Dialog
|
||||
|
||||
|
||||
class DeleteDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setupUi(self)
|
||||
self.setWindowTitle("Medien löschen")
|
||||
self.setWindowIcon(Icon("trash").icon)
|
||||
self.reset_btn.clicked.connect(self.reset_selection)
|
||||
self.cancel_btn.clicked.connect(self.close)
|
||||
self.delete_btn.clicked.connect(self.delete_selected)
|
||||
|
||||
self.db = Database()
|
||||
self.books = self.setBooks()
|
||||
self.lineEdit.textChanged.connect(self.populate_books)
|
||||
self.populate_books()
|
||||
|
||||
def delete_selected(self):
|
||||
to_delete = []
|
||||
for row in range(self.tableWidget.rowCount()):
|
||||
checkbox = self.tableWidget.cellWidget(row, 0)
|
||||
if checkbox is not None and checkbox.isChecked():
|
||||
book_id_item = self.tableWidget.item(row, 6)
|
||||
if book_id_item is not None:
|
||||
book_id = int(book_id_item.text())
|
||||
to_delete.append(book_id)
|
||||
if to_delete:
|
||||
self.db.deleteBooks(to_delete)
|
||||
self.accept()
|
||||
|
||||
def reset_selection(self):
|
||||
for row in range(self.tableWidget.rowCount()):
|
||||
checkbox = self.tableWidget.cellWidget(row, 0)
|
||||
if checkbox is not None:
|
||||
checkbox.setChecked(False)
|
||||
|
||||
def setBooks(self) -> list[dict[str, Any]]:
|
||||
result: list[dict[str, Any]] = []
|
||||
books = self.db.getAllBooks()
|
||||
for book in books:
|
||||
title = book["bookdata"].title
|
||||
signature = book["bookdata"].signature
|
||||
edition = book["bookdata"].edition
|
||||
appnr = self.db.getApparatNrByBookId(book["id"])
|
||||
result.append(
|
||||
{
|
||||
"id": book["id"],
|
||||
"appnr": appnr,
|
||||
"title": title,
|
||||
"signature": signature,
|
||||
"edition": edition,
|
||||
}
|
||||
)
|
||||
return result
|
||||
|
||||
def populate_books(self):
|
||||
searchterm = self.lineEdit.text().lower()
|
||||
self.tableWidget.setRowCount(0)
|
||||
for book in self.books:
|
||||
checkbox = QtWidgets.QCheckBox()
|
||||
app_nr = book["appnr"]
|
||||
title = book["title"]
|
||||
signature = book["signature"]
|
||||
edition = book["edition"] if book["edition"] else ""
|
||||
|
||||
if searchterm in title.lower() or searchterm in signature.lower():
|
||||
self.tableWidget.insertRow(self.tableWidget.rowCount())
|
||||
self.tableWidget.setCellWidget(
|
||||
self.tableWidget.rowCount() - 1, 0, checkbox
|
||||
)
|
||||
self.tableWidget.setItem(
|
||||
self.tableWidget.rowCount() - 1,
|
||||
1,
|
||||
QtWidgets.QTableWidgetItem(str(app_nr)),
|
||||
)
|
||||
self.tableWidget.setItem(
|
||||
self.tableWidget.rowCount() - 1,
|
||||
2,
|
||||
QtWidgets.QTableWidgetItem(signature),
|
||||
)
|
||||
self.tableWidget.setItem(
|
||||
self.tableWidget.rowCount() - 1,
|
||||
3,
|
||||
QtWidgets.QTableWidgetItem(title),
|
||||
)
|
||||
self.tableWidget.setItem(
|
||||
self.tableWidget.rowCount() - 1,
|
||||
4,
|
||||
QtWidgets.QTableWidgetItem(edition),
|
||||
)
|
||||
self.tableWidget.setItem(
|
||||
self.tableWidget.rowCount() - 1,
|
||||
5,
|
||||
QtWidgets.QTableWidgetItem(""),
|
||||
)
|
||||
self.tableWidget.setItem(
|
||||
self.tableWidget.rowCount() - 1,
|
||||
6,
|
||||
QtWidgets.QTableWidgetItem(str(book["id"])),
|
||||
)
|
||||
else:
|
||||
continue
|
||||
# set column signature to be 10px wider than the longest entry
|
||||
self.tableWidget.setColumnWidth(1, 100)
|
||||
self.tableWidget.setColumnWidth(2, 150)
|
||||
self.tableWidget.setColumnWidth(3, 150)
|
||||
self.tableWidget.setColumnWidth(4, 100)
|
||||
|
||||
self.tableWidget.setColumnWidth(0, 50)
|
||||
# horizontal header 0 should be centered
|
||||
self.tableWidget.horizontalHeader().setDefaultAlignment(
|
||||
QtCore.Qt.AlignmentFlag.AlignCenter
|
||||
)
|
||||
|
||||
|
||||
def launch():
|
||||
app = QtWidgets.QApplication.instance()
|
||||
if app is None:
|
||||
app = QtWidgets.QApplication([])
|
||||
dialog = DeleteDialog()
|
||||
dialog.exec()
|
||||
@@ -1,38 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\about.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.6.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_about(object):
|
||||
def setupUi(self, about):
|
||||
about.setObjectName("about")
|
||||
about.resize(301, 313)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(about)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.version = QtWidgets.QLabel(parent=about)
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(12)
|
||||
font.setBold(True)
|
||||
self.version.setFont(font)
|
||||
self.version.setScaledContents(False)
|
||||
self.version.setObjectName("version")
|
||||
self.verticalLayout.addWidget(self.version)
|
||||
self.description = QtWidgets.QTextEdit(parent=about)
|
||||
self.description.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.description.setReadOnly(True)
|
||||
self.description.setObjectName("description")
|
||||
self.verticalLayout.addWidget(self.description)
|
||||
|
||||
self.retranslateUi(about)
|
||||
QtCore.QMetaObject.connectSlotsByName(about)
|
||||
|
||||
def retranslateUi(self, about):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
about.setWindowTitle(_translate("about", "Dialog"))
|
||||
self.version.setText(_translate("about", "SemesterapparatsManagement"))
|
||||
@@ -1,22 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\app_status.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.6.1
|
||||
#
|
||||
# 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 PySide6 import QtCore
|
||||
|
||||
|
||||
class Ui_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName("Form")
|
||||
Form.resize(300, 500)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Form.setWindowTitle(_translate("Form", "Form"))
|
||||
@@ -1,83 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\apparat_extend.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.7.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(388, 103)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth())
|
||||
Dialog.setSizePolicy(sizePolicy)
|
||||
Dialog.setMinimumSize(QtCore.QSize(388, 103))
|
||||
Dialog.setMaximumSize(QtCore.QSize(388, 103))
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
|
||||
self.buttonBox.setGeometry(QtCore.QRect(290, 30, 81, 241))
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Vertical)
|
||||
self.buttonBox.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Abort
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Save
|
||||
)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.label = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label.setGeometry(QtCore.QRect(10, 0, 281, 31))
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
|
||||
self.label.setSizePolicy(sizePolicy)
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(10)
|
||||
self.label.setFont(font)
|
||||
self.label.setObjectName("label")
|
||||
self.frame = QtWidgets.QFrame(parent=Dialog)
|
||||
self.frame.setGeometry(QtCore.QRect(10, 30, 241, 41))
|
||||
self.frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||
self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||
self.frame.setObjectName("frame")
|
||||
self.line = QtWidgets.QFrame(parent=self.frame)
|
||||
self.line.setGeometry(QtCore.QRect(120, 0, 3, 61))
|
||||
self.line.setFrameShape(QtWidgets.QFrame.Shape.VLine)
|
||||
self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
|
||||
self.line.setObjectName("line")
|
||||
self.rad_sommer = QtWidgets.QRadioButton(parent=self.frame)
|
||||
self.rad_sommer.setGeometry(QtCore.QRect(10, 10, 82, 21))
|
||||
self.rad_sommer.setObjectName("rad_sommer")
|
||||
self.rad_winter = QtWidgets.QRadioButton(parent=self.frame)
|
||||
self.rad_winter.setGeometry(QtCore.QRect(140, 10, 82, 21))
|
||||
self.rad_winter.setObjectName("rad_winter")
|
||||
self.sem_year = QtWidgets.QLineEdit(parent=Dialog)
|
||||
self.sem_year.setGeometry(QtCore.QRect(10, 70, 121, 20))
|
||||
self.sem_year.setObjectName("sem_year")
|
||||
self.dauerapp = QtWidgets.QCheckBox(parent=Dialog)
|
||||
self.dauerapp.setGeometry(QtCore.QRect(150, 70, 111, 21))
|
||||
self.dauerapp.setObjectName("dauerapp")
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.label.setText(
|
||||
_translate("Dialog", "Bis wann soll der Apparat verlängert werden?")
|
||||
)
|
||||
self.rad_sommer.setText(_translate("Dialog", "Sommer"))
|
||||
self.rad_winter.setText(_translate("Dialog", "Winter"))
|
||||
self.sem_year.setPlaceholderText(_translate("Dialog", "2023"))
|
||||
self.dauerapp.setText(_translate("Dialog", "Dauerapparat"))
|
||||
@@ -1,37 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\confirm_extend.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.7.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtWidgets
|
||||
|
||||
|
||||
class Ui_extend_confirm(object):
|
||||
def setupUi(self, extend_confirm):
|
||||
extend_confirm.setObjectName("extend_confirm")
|
||||
extend_confirm.resize(380, 97)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout(extend_confirm)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.textEdit = QtWidgets.QTextEdit(parent=extend_confirm)
|
||||
self.textEdit.setObjectName("textEdit")
|
||||
self.horizontalLayout.addWidget(self.textEdit)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=extend_confirm)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Vertical)
|
||||
self.buttonBox.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Ok
|
||||
)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.horizontalLayout.addWidget(self.buttonBox)
|
||||
|
||||
self.retranslateUi(extend_confirm)
|
||||
self.buttonBox.accepted.connect(extend_confirm.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(extend_confirm.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(extend_confirm)
|
||||
|
||||
def retranslateUi(self, extend_confirm):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
extend_confirm.setWindowTitle(_translate("extend_confirm", "Dialog"))
|
||||
@@ -1,127 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\edit_bookdata.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.6.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(448, 572)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
|
||||
self.buttonBox.setGeometry(QtCore.QRect(260, 530, 161, 32))
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
self.buttonBox.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Ok
|
||||
)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.gridLayoutWidget = QtWidgets.QWidget(parent=Dialog)
|
||||
self.gridLayoutWidget.setGeometry(QtCore.QRect(0, 0, 441, 531))
|
||||
self.gridLayoutWidget.setObjectName("gridLayoutWidget")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
|
||||
self.gridLayout.setSizeConstraint(
|
||||
QtWidgets.QLayout.SizeConstraint.SetDefaultConstraint
|
||||
)
|
||||
self.gridLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label_10 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label_10.setObjectName("label_10")
|
||||
self.gridLayout.addWidget(self.label_10, 10, 1, 1, 1)
|
||||
self.label = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout.addWidget(self.label, 0, 1, 1, 1)
|
||||
self.label_9 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label_9.setObjectName("label_9")
|
||||
self.gridLayout.addWidget(self.label_9, 9, 1, 1, 1)
|
||||
self.label_8 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label_8.setObjectName("label_8")
|
||||
self.gridLayout.addWidget(self.label_8, 8, 1, 1, 1)
|
||||
self.label_12 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label_12.setObjectName("label_12")
|
||||
self.gridLayout.addWidget(self.label_12, 6, 1, 1, 1)
|
||||
self.line_edition = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_edition.setObjectName("line_edition")
|
||||
self.gridLayout.addWidget(self.line_edition, 2, 2, 1, 1)
|
||||
self.label_3 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout.addWidget(self.label_3, 2, 1, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout.addWidget(self.label_4, 3, 1, 1, 1)
|
||||
self.line_link = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_link.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor))
|
||||
self.line_link.setReadOnly(True)
|
||||
self.line_link.setObjectName("line_link")
|
||||
self.gridLayout.addWidget(self.line_link, 6, 2, 1, 1)
|
||||
self.label_5 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.gridLayout.addWidget(self.label_5, 4, 1, 1, 1)
|
||||
self.label_7 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label_7.setObjectName("label_7")
|
||||
self.gridLayout.addWidget(self.label_7, 7, 1, 1, 1)
|
||||
self.label_6 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label_6.setObjectName("label_6")
|
||||
self.gridLayout.addWidget(self.label_6, 5, 1, 1, 1)
|
||||
self.label_2 = QtWidgets.QLabel(parent=self.gridLayoutWidget)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout.addWidget(self.label_2, 1, 1, 1, 1)
|
||||
spacerItem = QtWidgets.QSpacerItem(
|
||||
5,
|
||||
20,
|
||||
QtWidgets.QSizePolicy.Policy.Fixed,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
)
|
||||
self.gridLayout.addItem(spacerItem, 8, 0, 1, 1)
|
||||
self.line_title = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_title.setObjectName("line_title")
|
||||
self.gridLayout.addWidget(self.line_title, 0, 2, 1, 1)
|
||||
self.line_signature = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_signature.setObjectName("line_signature")
|
||||
self.gridLayout.addWidget(self.line_signature, 1, 2, 1, 1)
|
||||
self.line_author = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_author.setObjectName("line_author")
|
||||
self.gridLayout.addWidget(self.line_author, 3, 2, 1, 1)
|
||||
self.line_lang = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_lang.setObjectName("line_lang")
|
||||
self.gridLayout.addWidget(self.line_lang, 8, 2, 1, 1)
|
||||
self.line_ppn = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_ppn.setObjectName("line_ppn")
|
||||
self.gridLayout.addWidget(self.line_ppn, 5, 2, 1, 1)
|
||||
self.line_isbn = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_isbn.setObjectName("line_isbn")
|
||||
self.gridLayout.addWidget(self.line_isbn, 7, 2, 1, 1)
|
||||
self.line_year = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_year.setObjectName("line_year")
|
||||
self.gridLayout.addWidget(self.line_year, 9, 2, 1, 1)
|
||||
self.line_pages = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_pages.setObjectName("line_pages")
|
||||
self.gridLayout.addWidget(self.line_pages, 10, 2, 1, 1)
|
||||
self.line_publisher = QtWidgets.QLineEdit(parent=self.gridLayoutWidget)
|
||||
self.line_publisher.setObjectName("line_publisher")
|
||||
self.gridLayout.addWidget(self.line_publisher, 4, 2, 1, 1)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.label_10.setText(_translate("Dialog", "Seiten"))
|
||||
self.label.setText(_translate("Dialog", "Titel"))
|
||||
self.label_9.setText(_translate("Dialog", "Jahr"))
|
||||
self.label_8.setText(_translate("Dialog", "Sprache"))
|
||||
self.label_12.setText(_translate("Dialog", "Link"))
|
||||
self.label_3.setText(_translate("Dialog", "Auflage"))
|
||||
self.label_4.setText(_translate("Dialog", "Autor"))
|
||||
self.label_5.setText(_translate("Dialog", "Herausgeber"))
|
||||
self.label_7.setText(_translate("Dialog", "ISBN(s)"))
|
||||
self.label_6.setText(_translate("Dialog", "PPN"))
|
||||
self.label_2.setText(_translate("Dialog", "Signatur"))
|
||||
@@ -1,470 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_add_table_entry.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.7.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtWidgets
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(529, 482)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.groupBox = QtWidgets.QGroupBox(parent=Dialog)
|
||||
self.groupBox.setFlat(True)
|
||||
self.groupBox.setCheckable(False)
|
||||
self.groupBox.setObjectName("groupBox")
|
||||
self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox)
|
||||
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||
spacerItem = QtWidgets.QSpacerItem(
|
||||
40,
|
||||
20,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
)
|
||||
self.gridLayout_4.addItem(spacerItem, 0, 3, 1, 1)
|
||||
self.btn_mono = QtWidgets.QRadioButton(parent=self.groupBox)
|
||||
self.btn_mono.setChecked(False)
|
||||
self.btn_mono.setObjectName("btn_mono")
|
||||
self.gridLayout_4.addWidget(self.btn_mono, 0, 0, 1, 1)
|
||||
self.btn_zs = QtWidgets.QRadioButton(parent=self.groupBox)
|
||||
self.btn_zs.setObjectName("btn_zs")
|
||||
self.gridLayout_4.addWidget(self.btn_zs, 0, 2, 1, 1)
|
||||
self.btn_hg = QtWidgets.QRadioButton(parent=self.groupBox)
|
||||
self.btn_hg.setObjectName("btn_hg")
|
||||
self.gridLayout_4.addWidget(self.btn_hg, 0, 1, 1, 1)
|
||||
self.verticalLayout.addWidget(self.groupBox)
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.label_2 = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.horizontalLayout_2.addWidget(self.label_2)
|
||||
self.searchIdent = QtWidgets.QLineEdit(parent=Dialog)
|
||||
self.searchIdent.setObjectName("searchIdent")
|
||||
self.horizontalLayout_2.addWidget(self.searchIdent)
|
||||
self.btn_search = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.btn_search.setObjectName("btn_search")
|
||||
self.horizontalLayout_2.addWidget(self.btn_search)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(
|
||||
40,
|
||||
20,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
)
|
||||
self.horizontalLayout_2.addItem(spacerItem1)
|
||||
self.make_quote = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.make_quote.setObjectName("make_quote")
|
||||
self.horizontalLayout_2.addWidget(self.make_quote)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
self.stackedWidget = QtWidgets.QStackedWidget(parent=Dialog)
|
||||
self.stackedWidget.setObjectName("stackedWidget")
|
||||
self.mono = QtWidgets.QWidget()
|
||||
self.mono.setObjectName("mono")
|
||||
self.gridLayout_2 = QtWidgets.QGridLayout(self.mono)
|
||||
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||
self.label = QtWidgets.QLabel(parent=self.mono)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
|
||||
self.book_author = QtWidgets.QLineEdit(parent=self.mono)
|
||||
self.book_author.setObjectName("book_author")
|
||||
self.gridLayout_2.addWidget(self.book_author, 0, 1, 1, 1)
|
||||
self.label_3 = QtWidgets.QLabel(parent=self.mono)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout_2.addWidget(self.label_3, 1, 0, 1, 1)
|
||||
self.book_year = QtWidgets.QLineEdit(parent=self.mono)
|
||||
self.book_year.setObjectName("book_year")
|
||||
self.gridLayout_2.addWidget(self.book_year, 1, 1, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(parent=self.mono)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout_2.addWidget(self.label_4, 2, 0, 1, 1)
|
||||
self.book_edition = QtWidgets.QLineEdit(parent=self.mono)
|
||||
self.book_edition.setObjectName("book_edition")
|
||||
self.gridLayout_2.addWidget(self.book_edition, 2, 1, 1, 1)
|
||||
self.label_5 = QtWidgets.QLabel(parent=self.mono)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.gridLayout_2.addWidget(self.label_5, 3, 0, 1, 1)
|
||||
self.book_title = QtWidgets.QLineEdit(parent=self.mono)
|
||||
self.book_title.setObjectName("book_title")
|
||||
self.gridLayout_2.addWidget(self.book_title, 3, 1, 1, 1)
|
||||
self.label_6 = QtWidgets.QLabel(parent=self.mono)
|
||||
self.label_6.setObjectName("label_6")
|
||||
self.gridLayout_2.addWidget(self.label_6, 4, 0, 1, 1)
|
||||
self.book_place = QtWidgets.QLineEdit(parent=self.mono)
|
||||
self.book_place.setObjectName("book_place")
|
||||
self.gridLayout_2.addWidget(self.book_place, 4, 1, 1, 1)
|
||||
self.label_7 = QtWidgets.QLabel(parent=self.mono)
|
||||
self.label_7.setObjectName("label_7")
|
||||
self.gridLayout_2.addWidget(self.label_7, 5, 0, 1, 1)
|
||||
self.book_publisher = QtWidgets.QLineEdit(parent=self.mono)
|
||||
self.book_publisher.setObjectName("book_publisher")
|
||||
self.gridLayout_2.addWidget(self.book_publisher, 5, 1, 1, 1)
|
||||
self.label_8 = QtWidgets.QLabel(parent=self.mono)
|
||||
self.label_8.setObjectName("label_8")
|
||||
self.gridLayout_2.addWidget(self.label_8, 6, 0, 1, 1)
|
||||
self.book_signature = QtWidgets.QLineEdit(parent=self.mono)
|
||||
self.book_signature.setObjectName("book_signature")
|
||||
self.gridLayout_2.addWidget(self.book_signature, 6, 1, 1, 1)
|
||||
self.label_9 = QtWidgets.QLabel(parent=self.mono)
|
||||
self.label_9.setObjectName("label_9")
|
||||
self.gridLayout_2.addWidget(self.label_9, 7, 0, 1, 1)
|
||||
self.book_pages = QtWidgets.QLineEdit(parent=self.mono)
|
||||
self.book_pages.setObjectName("book_pages")
|
||||
self.gridLayout_2.addWidget(self.book_pages, 7, 1, 1, 1)
|
||||
self.page_warn_2 = QtWidgets.QToolButton(parent=self.mono)
|
||||
self.page_warn_2.setText("")
|
||||
self.page_warn_2.setAutoRaise(True)
|
||||
self.page_warn_2.setObjectName("page_warn_2")
|
||||
self.gridLayout_2.addWidget(self.page_warn_2, 7, 2, 1, 1)
|
||||
self.label_29 = QtWidgets.QLabel(parent=self.mono)
|
||||
self.label_29.setObjectName("label_29")
|
||||
self.gridLayout_2.addWidget(self.label_29, 8, 0, 1, 1)
|
||||
self.book_isbn = QtWidgets.QLineEdit(parent=self.mono)
|
||||
self.book_isbn.setObjectName("book_isbn")
|
||||
self.gridLayout_2.addWidget(self.book_isbn, 8, 1, 1, 1)
|
||||
self.stackedWidget.addWidget(self.mono)
|
||||
self.hg = QtWidgets.QWidget()
|
||||
self.hg.setObjectName("hg")
|
||||
self.gridLayout_3 = QtWidgets.QGridLayout(self.hg)
|
||||
self.gridLayout_3.setObjectName("gridLayout_3")
|
||||
self.hg_editor = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_editor.setObjectName("hg_editor")
|
||||
self.gridLayout_3.addWidget(self.hg_editor, 4, 1, 1, 1)
|
||||
self.label_26 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_26.setObjectName("label_26")
|
||||
self.gridLayout_3.addWidget(self.label_26, 7, 0, 1, 1)
|
||||
self.hg_edition = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_edition.setObjectName("hg_edition")
|
||||
self.gridLayout_3.addWidget(self.hg_edition, 2, 1, 1, 1)
|
||||
self.label_20 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_20.setObjectName("label_20")
|
||||
self.gridLayout_3.addWidget(self.label_20, 1, 0, 1, 1)
|
||||
self.label_24 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_24.setObjectName("label_24")
|
||||
self.gridLayout_3.addWidget(self.label_24, 3, 0, 1, 1)
|
||||
self.label_27 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_27.setObjectName("label_27")
|
||||
self.gridLayout_3.addWidget(self.label_27, 8, 0, 1, 1)
|
||||
self.label_28 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_28.setObjectName("label_28")
|
||||
self.gridLayout_3.addWidget(self.label_28, 9, 0, 1, 1)
|
||||
self.label_23 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_23.setObjectName("label_23")
|
||||
self.gridLayout_3.addWidget(self.label_23, 5, 0, 1, 1)
|
||||
self.label_21 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_21.setObjectName("label_21")
|
||||
self.gridLayout_3.addWidget(self.label_21, 2, 0, 1, 1)
|
||||
self.hg_pages = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_pages.setObjectName("hg_pages")
|
||||
self.gridLayout_3.addWidget(self.hg_pages, 8, 1, 1, 1)
|
||||
self.label_19 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_19.setObjectName("label_19")
|
||||
self.gridLayout_3.addWidget(self.label_19, 0, 0, 1, 1)
|
||||
self.hg_signature = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_signature.setObjectName("hg_signature")
|
||||
self.gridLayout_3.addWidget(self.hg_signature, 9, 1, 1, 1)
|
||||
self.label_30 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_30.setObjectName("label_30")
|
||||
self.gridLayout_3.addWidget(self.label_30, 10, 0, 1, 1)
|
||||
self.label_25 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_25.setObjectName("label_25")
|
||||
self.gridLayout_3.addWidget(self.label_25, 6, 0, 1, 1)
|
||||
self.hg_year = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_year.setObjectName("hg_year")
|
||||
self.gridLayout_3.addWidget(self.hg_year, 1, 1, 1, 1)
|
||||
self.label_22 = QtWidgets.QLabel(parent=self.hg)
|
||||
self.label_22.setObjectName("label_22")
|
||||
self.gridLayout_3.addWidget(self.label_22, 4, 0, 1, 1)
|
||||
self.hg_title = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_title.setObjectName("hg_title")
|
||||
self.gridLayout_3.addWidget(self.hg_title, 5, 1, 1, 1)
|
||||
self.hg_chaptertitle = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_chaptertitle.setObjectName("hg_chaptertitle")
|
||||
self.gridLayout_3.addWidget(self.hg_chaptertitle, 3, 1, 1, 1)
|
||||
self.hg_author = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_author.setObjectName("hg_author")
|
||||
self.gridLayout_3.addWidget(self.hg_author, 0, 1, 1, 1)
|
||||
self.hg_isbn = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_isbn.setObjectName("hg_isbn")
|
||||
self.gridLayout_3.addWidget(self.hg_isbn, 10, 1, 1, 1)
|
||||
self.hg_publisher = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_publisher.setObjectName("hg_publisher")
|
||||
self.gridLayout_3.addWidget(self.hg_publisher, 7, 1, 1, 1)
|
||||
self.hg_place = QtWidgets.QLineEdit(parent=self.hg)
|
||||
self.hg_place.setObjectName("hg_place")
|
||||
self.gridLayout_3.addWidget(self.hg_place, 6, 1, 1, 1)
|
||||
self.page_warn_3 = QtWidgets.QToolButton(parent=self.hg)
|
||||
self.page_warn_3.setText("")
|
||||
self.page_warn_3.setAutoRaise(True)
|
||||
self.page_warn_3.setObjectName("page_warn_3")
|
||||
self.gridLayout_3.addWidget(self.page_warn_3, 8, 2, 1, 1)
|
||||
self.stackedWidget.addWidget(self.hg)
|
||||
self.zs = QtWidgets.QWidget()
|
||||
self.zs.setObjectName("zs")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.zs)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label_10 = QtWidgets.QLabel(parent=self.zs)
|
||||
self.label_10.setObjectName("label_10")
|
||||
self.gridLayout.addWidget(self.label_10, 0, 0, 1, 1)
|
||||
self.zs_publisher = QtWidgets.QLineEdit(parent=self.zs)
|
||||
self.zs_publisher.setObjectName("zs_publisher")
|
||||
self.gridLayout.addWidget(self.zs_publisher, 6, 1, 1, 1)
|
||||
self.zs_place = QtWidgets.QLineEdit(parent=self.zs)
|
||||
self.zs_place.setObjectName("zs_place")
|
||||
self.gridLayout.addWidget(self.zs_place, 5, 1, 1, 1)
|
||||
self.label_14 = QtWidgets.QLabel(parent=self.zs)
|
||||
self.label_14.setObjectName("label_14")
|
||||
self.gridLayout.addWidget(self.label_14, 4, 0, 1, 1)
|
||||
self.label_11 = QtWidgets.QLabel(parent=self.zs)
|
||||
self.label_11.setObjectName("label_11")
|
||||
self.gridLayout.addWidget(self.label_11, 1, 0, 1, 1)
|
||||
self.zs_year = QtWidgets.QLineEdit(parent=self.zs)
|
||||
self.zs_year.setObjectName("zs_year")
|
||||
self.gridLayout.addWidget(self.zs_year, 1, 1, 1, 1)
|
||||
self.label_17 = QtWidgets.QLabel(parent=self.zs)
|
||||
self.label_17.setObjectName("label_17")
|
||||
self.gridLayout.addWidget(self.label_17, 7, 0, 1, 1)
|
||||
self.label_16 = QtWidgets.QLabel(parent=self.zs)
|
||||
self.label_16.setObjectName("label_16")
|
||||
self.gridLayout.addWidget(self.label_16, 6, 0, 1, 1)
|
||||
self.zs_issue = QtWidgets.QLineEdit(parent=self.zs)
|
||||
self.zs_issue.setObjectName("zs_issue")
|
||||
self.gridLayout.addWidget(self.zs_issue, 2, 1, 1, 1)
|
||||
self.zs_chapter_title = QtWidgets.QLineEdit(parent=self.zs)
|
||||
self.zs_chapter_title.setObjectName("zs_chapter_title")
|
||||
self.gridLayout.addWidget(self.zs_chapter_title, 3, 1, 1, 1)
|
||||
self.zs_isbn = QtWidgets.QLineEdit(parent=self.zs)
|
||||
self.zs_isbn.setObjectName("zs_isbn")
|
||||
self.gridLayout.addWidget(self.zs_isbn, 9, 1, 1, 1)
|
||||
self.label_12 = QtWidgets.QLabel(parent=self.zs)
|
||||
self.label_12.setObjectName("label_12")
|
||||
self.gridLayout.addWidget(self.label_12, 2, 0, 1, 1)
|
||||
self.label_31 = QtWidgets.QLabel(parent=self.zs)
|
||||
self.label_31.setObjectName("label_31")
|
||||
self.gridLayout.addWidget(self.label_31, 9, 0, 1, 1)
|
||||
self.label_15 = QtWidgets.QLabel(parent=self.zs)
|
||||
self.label_15.setObjectName("label_15")
|
||||
self.gridLayout.addWidget(self.label_15, 5, 0, 1, 1)
|
||||
self.zs_signature = QtWidgets.QLineEdit(parent=self.zs)
|
||||
self.zs_signature.setObjectName("zs_signature")
|
||||
self.gridLayout.addWidget(self.zs_signature, 8, 1, 1, 1)
|
||||
self.zs_pages = QtWidgets.QLineEdit(parent=self.zs)
|
||||
self.zs_pages.setObjectName("zs_pages")
|
||||
self.gridLayout.addWidget(self.zs_pages, 7, 1, 1, 1)
|
||||
self.label_13 = QtWidgets.QLabel(parent=self.zs)
|
||||
self.label_13.setObjectName("label_13")
|
||||
self.gridLayout.addWidget(self.label_13, 3, 0, 1, 1)
|
||||
self.label_18 = QtWidgets.QLabel(parent=self.zs)
|
||||
self.label_18.setObjectName("label_18")
|
||||
self.gridLayout.addWidget(self.label_18, 8, 0, 1, 1)
|
||||
self.zs_author = QtWidgets.QLineEdit(parent=self.zs)
|
||||
self.zs_author.setObjectName("zs_author")
|
||||
self.gridLayout.addWidget(self.zs_author, 0, 1, 1, 1)
|
||||
self.zs_title = QtWidgets.QLineEdit(parent=self.zs)
|
||||
self.zs_title.setObjectName("zs_title")
|
||||
self.gridLayout.addWidget(self.zs_title, 4, 1, 1, 1)
|
||||
self.page_warn = QtWidgets.QToolButton(parent=self.zs)
|
||||
self.page_warn.setText("")
|
||||
self.page_warn.setAutoRaise(True)
|
||||
self.page_warn.setObjectName("page_warn")
|
||||
self.gridLayout.addWidget(self.page_warn, 7, 2, 1, 1)
|
||||
self.stackedWidget.addWidget(self.zs)
|
||||
self.page = QtWidgets.QWidget()
|
||||
self.page.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight)
|
||||
self.page.setObjectName("page")
|
||||
self.gridLayout_5 = QtWidgets.QGridLayout(self.page)
|
||||
self.gridLayout_5.setObjectName("gridLayout_5")
|
||||
self.label_32 = QtWidgets.QLabel(parent=self.page)
|
||||
self.label_32.setObjectName("label_32")
|
||||
self.gridLayout_5.addWidget(self.label_32, 0, 0, 1, 1)
|
||||
spacerItem2 = QtWidgets.QSpacerItem(
|
||||
20,
|
||||
40,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
)
|
||||
self.gridLayout_5.addItem(spacerItem2, 7, 0, 1, 1)
|
||||
self.file_desc_edit = QtWidgets.QTextEdit(parent=self.page)
|
||||
self.file_desc_edit.setReadOnly(True)
|
||||
self.file_desc_edit.setObjectName("file_desc_edit")
|
||||
self.gridLayout_5.addWidget(self.file_desc_edit, 6, 0, 1, 1)
|
||||
self.label_34 = QtWidgets.QLabel(parent=self.page)
|
||||
self.label_34.setObjectName("label_34")
|
||||
self.gridLayout_5.addWidget(self.label_34, 3, 0, 1, 1)
|
||||
self.filename_edit = QtWidgets.QTextEdit(parent=self.page)
|
||||
self.filename_edit.setReadOnly(True)
|
||||
self.filename_edit.setObjectName("filename_edit")
|
||||
self.gridLayout_5.addWidget(self.filename_edit, 1, 0, 1, 1)
|
||||
self.label_33 = QtWidgets.QLabel(parent=self.page)
|
||||
self.label_33.setObjectName("label_33")
|
||||
self.gridLayout_5.addWidget(self.label_33, 5, 0, 1, 1)
|
||||
self.ilias_filename = QtWidgets.QTextEdit(parent=self.page)
|
||||
self.ilias_filename.setReadOnly(True)
|
||||
self.ilias_filename.setObjectName("ilias_filename")
|
||||
self.gridLayout_5.addWidget(self.ilias_filename, 4, 0, 1, 1)
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
spacerItem3 = QtWidgets.QSpacerItem(
|
||||
20,
|
||||
40,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
)
|
||||
self.verticalLayout_2.addItem(spacerItem3)
|
||||
self.copy_filename = QtWidgets.QToolButton(parent=self.page)
|
||||
self.copy_filename.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight)
|
||||
self.copy_filename.setAutoFillBackground(False)
|
||||
self.copy_filename.setObjectName("copy_filename")
|
||||
self.verticalLayout_2.addWidget(self.copy_filename)
|
||||
self.filename_edit_label = QtWidgets.QLabel(parent=self.page)
|
||||
self.filename_edit_label.setText("")
|
||||
self.filename_edit_label.setObjectName("filename_edit_label")
|
||||
self.verticalLayout_2.addWidget(self.filename_edit_label)
|
||||
spacerItem4 = QtWidgets.QSpacerItem(
|
||||
20,
|
||||
40,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
)
|
||||
self.verticalLayout_2.addItem(spacerItem4)
|
||||
self.gridLayout_5.addLayout(self.verticalLayout_2, 1, 1, 1, 1)
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
spacerItem5 = QtWidgets.QSpacerItem(
|
||||
20,
|
||||
40,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
)
|
||||
self.verticalLayout_3.addItem(spacerItem5)
|
||||
self.copy_ilias_filename = QtWidgets.QToolButton(parent=self.page)
|
||||
self.copy_ilias_filename.setObjectName("copy_ilias_filename")
|
||||
self.verticalLayout_3.addWidget(self.copy_ilias_filename)
|
||||
self.ilias_filename_label = QtWidgets.QLabel(parent=self.page)
|
||||
self.ilias_filename_label.setText("")
|
||||
self.ilias_filename_label.setObjectName("ilias_filename_label")
|
||||
self.verticalLayout_3.addWidget(self.ilias_filename_label)
|
||||
spacerItem6 = QtWidgets.QSpacerItem(
|
||||
20,
|
||||
40,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
)
|
||||
self.verticalLayout_3.addItem(spacerItem6)
|
||||
self.gridLayout_5.addLayout(self.verticalLayout_3, 4, 1, 1, 1)
|
||||
self.verticalLayout_4 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_4.setObjectName("verticalLayout_4")
|
||||
spacerItem7 = QtWidgets.QSpacerItem(
|
||||
20,
|
||||
40,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
)
|
||||
self.verticalLayout_4.addItem(spacerItem7)
|
||||
self.copy_qoute = QtWidgets.QToolButton(parent=self.page)
|
||||
self.copy_qoute.setObjectName("copy_qoute")
|
||||
self.verticalLayout_4.addWidget(self.copy_qoute)
|
||||
self.file_desc_edit_label = QtWidgets.QLabel(parent=self.page)
|
||||
self.file_desc_edit_label.setText("")
|
||||
self.file_desc_edit_label.setObjectName("file_desc_edit_label")
|
||||
self.verticalLayout_4.addWidget(self.file_desc_edit_label)
|
||||
spacerItem8 = QtWidgets.QSpacerItem(
|
||||
20,
|
||||
40,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
)
|
||||
self.verticalLayout_4.addItem(spacerItem8)
|
||||
self.gridLayout_5.addLayout(self.verticalLayout_4, 6, 1, 1, 1)
|
||||
self.stackedWidget.addWidget(self.page)
|
||||
self.verticalLayout.addWidget(self.stackedWidget)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
|
||||
self.buttonBox.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Discard
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Ok
|
||||
)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.horizontalLayout.addWidget(self.buttonBox)
|
||||
self.retryButton = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.retryButton.setObjectName("retryButton")
|
||||
self.horizontalLayout.addWidget(self.retryButton)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.stackedWidget.setCurrentIndex(3)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.groupBox.setTitle(_translate("Dialog", "Medientyp?"))
|
||||
self.btn_mono.setText(_translate("Dialog", "Monografie"))
|
||||
self.btn_zs.setText(_translate("Dialog", "Zeitschrift"))
|
||||
self.btn_hg.setText(_translate("Dialog", "Herausgeberwerk"))
|
||||
self.label_2.setText(_translate("Dialog", "Identifikator"))
|
||||
self.btn_search.setText(_translate("Dialog", "Suchen"))
|
||||
self.make_quote.setToolTip(
|
||||
_translate("Dialog", "Zuerst die Seitenzahl anpassen")
|
||||
)
|
||||
self.make_quote.setText(_translate("Dialog", "Zitat erstellen"))
|
||||
self.label.setText(_translate("Dialog", "Autor(en)\n Nachname, Vorname"))
|
||||
self.book_author.setToolTip(
|
||||
_translate("Dialog", "Bei mehreren Autoren mit ; trennen")
|
||||
)
|
||||
self.label_3.setText(_translate("Dialog", "Jahr"))
|
||||
self.label_4.setText(_translate("Dialog", "Auflage"))
|
||||
self.label_5.setText(_translate("Dialog", "Titel"))
|
||||
self.label_6.setText(_translate("Dialog", "Ort"))
|
||||
self.label_7.setText(_translate("Dialog", "Verlag"))
|
||||
self.label_8.setText(_translate("Dialog", "Signatur"))
|
||||
self.label_9.setText(_translate("Dialog", "Seiten"))
|
||||
self.book_pages.setPlaceholderText(
|
||||
_translate("Dialog", "Seitenanzahl des Mediums, zum zitieren ändern!")
|
||||
)
|
||||
self.label_29.setText(_translate("Dialog", "ISBN"))
|
||||
self.hg_editor.setToolTip(
|
||||
_translate("Dialog", "Bei mehreren Autoren mit ; trennen")
|
||||
)
|
||||
self.label_26.setText(_translate("Dialog", "Verlag"))
|
||||
self.label_20.setText(_translate("Dialog", "Jahr"))
|
||||
self.label_24.setText(_translate("Dialog", "Beitragstitel"))
|
||||
self.label_27.setText(_translate("Dialog", "Seiten"))
|
||||
self.label_28.setText(_translate("Dialog", "Signatur"))
|
||||
self.label_23.setText(_translate("Dialog", "Titel des Werkes"))
|
||||
self.label_21.setText(_translate("Dialog", "Auflage"))
|
||||
self.label_19.setText(_translate("Dialog", "Autor(en)\nNachname, Vorname"))
|
||||
self.label_30.setText(_translate("Dialog", "ISBN"))
|
||||
self.label_25.setText(_translate("Dialog", "Ort"))
|
||||
self.label_22.setText(
|
||||
_translate("Dialog", "Herausgebername(n)\nNachname, Vorname")
|
||||
)
|
||||
self.hg_author.setToolTip(
|
||||
_translate("Dialog", "Bei mehreren Autoren mit ; trennen")
|
||||
)
|
||||
self.label_10.setText(_translate("Dialog", "Autor(en)\nNachname, Vorname"))
|
||||
self.label_14.setText(_translate("Dialog", "Name der Zeitschrift"))
|
||||
self.label_11.setText(_translate("Dialog", "Jahr"))
|
||||
self.label_17.setText(_translate("Dialog", "Seiten"))
|
||||
self.label_16.setText(_translate("Dialog", "Verlag"))
|
||||
self.label_12.setText(_translate("Dialog", "Heft"))
|
||||
self.label_31.setText(_translate("Dialog", "ISSN"))
|
||||
self.label_15.setText(_translate("Dialog", "Ort"))
|
||||
self.label_13.setText(_translate("Dialog", "Artikeltitel"))
|
||||
self.label_18.setText(_translate("Dialog", "Signatur"))
|
||||
self.zs_author.setToolTip(
|
||||
_translate("Dialog", "Bei mehreren Autoren mit ; trennen")
|
||||
)
|
||||
self.label_32.setText(_translate("Dialog", "Dateiname"))
|
||||
self.label_34.setText(_translate("Dialog", "ILIAS Name"))
|
||||
self.label_33.setText(_translate("Dialog", "ILIAS Dateibeschreibung"))
|
||||
self.copy_filename.setText(_translate("Dialog", "Kopieren"))
|
||||
self.copy_ilias_filename.setText(_translate("Dialog", "Kopieren"))
|
||||
self.copy_qoute.setText(_translate("Dialog", "Kopieren"))
|
||||
self.retryButton.setText(_translate("Dialog", "Wiederholen"))
|
||||
@@ -1,83 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generate_citation.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.6.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(564, 517)
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.select_type = QtWidgets.QFrame(parent=Dialog)
|
||||
self.select_type.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||
self.select_type.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||
self.select_type.setObjectName("select_type")
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(self.select_type)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.radio_mono = QtWidgets.QRadioButton(parent=self.select_type)
|
||||
self.radio_mono.setObjectName("radio_mono")
|
||||
self.verticalLayout.addWidget(self.radio_mono)
|
||||
self.radio_zs = QtWidgets.QRadioButton(parent=self.select_type)
|
||||
self.radio_zs.setObjectName("radio_zs")
|
||||
self.verticalLayout.addWidget(self.radio_zs)
|
||||
self.radio_hg = QtWidgets.QRadioButton(parent=self.select_type)
|
||||
self.radio_hg.setObjectName("radio_hg")
|
||||
self.verticalLayout.addWidget(self.radio_hg)
|
||||
spacerItem = QtWidgets.QSpacerItem(
|
||||
20,
|
||||
40,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
)
|
||||
self.verticalLayout.addItem(spacerItem)
|
||||
self.verticalLayout_2.addWidget(self.select_type)
|
||||
self.check = QtWidgets.QGroupBox(parent=Dialog)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
self.check.setFont(font)
|
||||
self.check.setObjectName("check")
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.check)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.citation_style_result = QtWidgets.QStackedWidget(parent=self.check)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.citation_style_result.setFont(font)
|
||||
self.citation_style_result.setObjectName("citation_style_result")
|
||||
self.monografie = QtWidgets.QWidget()
|
||||
self.monografie.setObjectName("monografie")
|
||||
self.citation_style_result.addWidget(self.monografie)
|
||||
self.zsaufsatz = QtWidgets.QWidget()
|
||||
self.zsaufsatz.setObjectName("zsaufsatz")
|
||||
self.citation_style_result.addWidget(self.zsaufsatz)
|
||||
self.herausgeberwerk = QtWidgets.QWidget()
|
||||
self.herausgeberwerk.setObjectName("herausgeberwerk")
|
||||
self.citation_style_result.addWidget(self.herausgeberwerk)
|
||||
self.verticalLayout_3.addWidget(self.citation_style_result)
|
||||
self.pushButton = QtWidgets.QPushButton(parent=self.check)
|
||||
self.pushButton.setObjectName("pushButton")
|
||||
self.verticalLayout_3.addWidget(
|
||||
self.pushButton, 0, QtCore.Qt.AlignmentFlag.AlignRight
|
||||
)
|
||||
self.verticalLayout_2.addWidget(self.check)
|
||||
self.verticalLayout_2.setStretch(0, 20)
|
||||
self.verticalLayout_2.setStretch(1, 80)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.citation_style_result.setCurrentIndex(2)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.radio_mono.setText(_translate("Dialog", "Monografie"))
|
||||
self.radio_zs.setText(_translate("Dialog", "Zeitschriftenaufsatz"))
|
||||
self.radio_hg.setText(_translate("Dialog", "Herausgeberwerk"))
|
||||
self.check.setTitle(_translate("Dialog", "Daten"))
|
||||
self.pushButton.setText(_translate("Dialog", "Bestätigen"))
|
||||
@@ -1,129 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generator_confirm.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.6.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(530, 210)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth())
|
||||
Dialog.setSizePolicy(sizePolicy)
|
||||
Dialog.setMaximumSize(QtCore.QSize(530, 210))
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout(Dialog)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.groupBox = QtWidgets.QGroupBox(parent=Dialog)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
self.groupBox.setFont(font)
|
||||
self.groupBox.setObjectName("groupBox")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.groupBox)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label = QtWidgets.QLabel(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.label.setFont(font)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
|
||||
self.bookauthor = QtWidgets.QLineEdit(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.bookauthor.setFont(font)
|
||||
self.bookauthor.setObjectName("bookauthor")
|
||||
self.gridLayout.addWidget(self.bookauthor, 5, 1, 1, 1)
|
||||
self.book_title = QtWidgets.QLineEdit(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.book_title.setFont(font)
|
||||
self.book_title.setObjectName("book_title")
|
||||
self.gridLayout.addWidget(self.book_title, 3, 1, 1, 1)
|
||||
self.label_5 = QtWidgets.QLabel(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.label_5.setFont(font)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.gridLayout.addWidget(self.label_5, 5, 0, 1, 1)
|
||||
self.pages = QtWidgets.QLineEdit(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.pages.setFont(font)
|
||||
self.pages.setObjectName("pages")
|
||||
self.gridLayout.addWidget(self.pages, 4, 1, 1, 1)
|
||||
self.label_2 = QtWidgets.QLabel(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.label_2.setFont(font)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
|
||||
self.label_3 = QtWidgets.QLabel(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.label_3.setFont(font)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout.addWidget(self.label_3, 3, 0, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.label_4.setFont(font)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout.addWidget(self.label_4, 4, 0, 1, 1)
|
||||
self.chapter_title = QtWidgets.QLineEdit(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.chapter_title.setFont(font)
|
||||
self.chapter_title.setObjectName("chapter_title")
|
||||
self.gridLayout.addWidget(self.chapter_title, 1, 1, 1, 1)
|
||||
self.chapter_authors = QtWidgets.QLineEdit(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.chapter_authors.setFont(font)
|
||||
self.chapter_authors.setObjectName("chapter_authors")
|
||||
self.gridLayout.addWidget(self.chapter_authors, 2, 1, 1, 1)
|
||||
self.label_6 = QtWidgets.QLabel(parent=self.groupBox)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
self.label_6.setFont(font)
|
||||
self.label_6.setObjectName("label_6")
|
||||
self.gridLayout.addWidget(self.label_6, 0, 1, 1, 1)
|
||||
self.horizontalLayout.addWidget(self.groupBox)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
|
||||
self.buttonBox.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Vertical)
|
||||
self.buttonBox.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Ok
|
||||
)
|
||||
self.buttonBox.setCenterButtons(False)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.horizontalLayout.addWidget(self.buttonBox)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.groupBox.setTitle(_translate("Dialog", "Angaben korrekt?"))
|
||||
self.label.setText(_translate("Dialog", "Kapiteltitel"))
|
||||
self.label_5.setText(_translate("Dialog", "Herausgebername"))
|
||||
self.label_2.setText(_translate("Dialog", "Autor(en)"))
|
||||
self.label_3.setText(_translate("Dialog", "Buchtitel"))
|
||||
self.label_4.setText(_translate("Dialog", "Seite(n)"))
|
||||
self.label_6.setText(
|
||||
_translate(
|
||||
"Dialog", "Hier können fehlerhafte / fehlende Daten geändert werden"
|
||||
)
|
||||
)
|
||||
@@ -1,53 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\login.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.6.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(218, 190)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(
|
||||
QtGui.QPixmap(":/icons/resources/1f510.svg"),
|
||||
QtGui.QIcon.Mode.Normal,
|
||||
QtGui.QIcon.State.Off,
|
||||
)
|
||||
Dialog.setWindowIcon(icon)
|
||||
self.label = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label.setGeometry(QtCore.QRect(20, 40, 71, 21))
|
||||
self.label.setObjectName("label")
|
||||
self.lineEdit = QtWidgets.QLineEdit(parent=Dialog)
|
||||
self.lineEdit.setGeometry(QtCore.QRect(80, 40, 113, 21))
|
||||
self.lineEdit.setObjectName("lineEdit")
|
||||
self.label_2 = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label_2.setGeometry(QtCore.QRect(20, 80, 71, 21))
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.lineEdit_2 = QtWidgets.QLineEdit(parent=Dialog)
|
||||
self.lineEdit_2.setGeometry(QtCore.QRect(80, 80, 113, 21))
|
||||
self.lineEdit_2.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhSensitiveData)
|
||||
self.lineEdit_2.setClearButtonEnabled(True)
|
||||
self.lineEdit_2.setObjectName("lineEdit_2")
|
||||
self.login_button = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.login_button.setGeometry(QtCore.QRect(30, 140, 76, 32))
|
||||
self.login_button.setObjectName("login_button")
|
||||
self.cancel_button = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.cancel_button.setGeometry(QtCore.QRect(120, 140, 76, 32))
|
||||
self.cancel_button.setObjectName("cancel_button")
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Login"))
|
||||
self.label.setText(_translate("Dialog", "Username"))
|
||||
self.label_2.setText(_translate("Dialog", "Password"))
|
||||
self.login_button.setText(_translate("Dialog", "Login"))
|
||||
self.cancel_button.setText(_translate("Dialog", "Cancel"))
|
||||
@@ -1,137 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\mail_preview.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.7.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_eMailPreview(object):
|
||||
def setupUi(self, eMailPreview):
|
||||
eMailPreview.setObjectName("eMailPreview")
|
||||
eMailPreview.resize(700, 668)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(
|
||||
QtGui.QPixmap(
|
||||
"c:\\Users\\aky547\\GitHub\\SemesterapparatsManager\\src\\ui\\dialogs\\dialog_sources\\../../../../../../icons/email.svg"
|
||||
),
|
||||
QtGui.QIcon.Mode.Normal,
|
||||
QtGui.QIcon.State.Off,
|
||||
)
|
||||
eMailPreview.setWindowIcon(icon)
|
||||
self.gridLayout_2 = QtWidgets.QGridLayout(eMailPreview)
|
||||
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||
self.gridLayout = QtWidgets.QGridLayout()
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.prof_name = QtWidgets.QLineEdit(parent=eMailPreview)
|
||||
self.prof_name.setObjectName("prof_name")
|
||||
self.gridLayout.addWidget(self.prof_name, 2, 2, 1, 1)
|
||||
self.newTemplate = QtWidgets.QPushButton(parent=eMailPreview)
|
||||
self.newTemplate.setAutoFillBackground(False)
|
||||
self.newTemplate.setText("")
|
||||
self.newTemplate.setIconSize(QtCore.QSize(24, 24))
|
||||
self.newTemplate.setAutoDefault(True)
|
||||
self.newTemplate.setDefault(False)
|
||||
self.newTemplate.setFlat(False)
|
||||
self.newTemplate.setObjectName("newTemplate")
|
||||
self.gridLayout.addWidget(self.newTemplate, 0, 3, 1, 1)
|
||||
self.comboBox = QtWidgets.QComboBox(parent=eMailPreview)
|
||||
self.comboBox.setObjectName("comboBox")
|
||||
self.gridLayout.addWidget(self.comboBox, 0, 2, 1, 1)
|
||||
self.mail_header = QtWidgets.QLineEdit(parent=eMailPreview)
|
||||
self.mail_header.setObjectName("mail_header")
|
||||
self.gridLayout.addWidget(self.mail_header, 3, 2, 1, 1)
|
||||
self.label_6 = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label_6.setObjectName("label_6")
|
||||
self.gridLayout.addWidget(self.label_6, 4, 0, 1, 1)
|
||||
self.mail_body = QtWidgets.QTextEdit(parent=eMailPreview)
|
||||
self.mail_body.setObjectName("mail_body")
|
||||
self.gridLayout.addWidget(self.mail_body, 5, 2, 1, 1)
|
||||
self.label_2 = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
|
||||
self.mail_name = QtWidgets.QLineEdit(parent=eMailPreview)
|
||||
self.mail_name.setObjectName("mail_name")
|
||||
self.gridLayout.addWidget(self.mail_name, 1, 2, 1, 1)
|
||||
self.label_5 = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.gridLayout.addWidget(self.label_5, 0, 0, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout.addWidget(self.label_4, 3, 0, 1, 1)
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.gender_male = QtWidgets.QRadioButton(parent=eMailPreview)
|
||||
self.gender_male.setObjectName("gender_male")
|
||||
self.horizontalLayout_3.addWidget(self.gender_male)
|
||||
self.gender_female = QtWidgets.QRadioButton(parent=eMailPreview)
|
||||
self.gender_female.setObjectName("gender_female")
|
||||
self.horizontalLayout_3.addWidget(self.gender_female)
|
||||
self.gender_non = QtWidgets.QRadioButton(parent=eMailPreview)
|
||||
self.gender_non.setObjectName("gender_non")
|
||||
self.horizontalLayout_3.addWidget(self.gender_non)
|
||||
spacerItem = QtWidgets.QSpacerItem(
|
||||
40,
|
||||
20,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
)
|
||||
self.horizontalLayout_3.addItem(spacerItem)
|
||||
self.gridLayout.addLayout(self.horizontalLayout_3, 4, 2, 1, 1)
|
||||
self.label_3 = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label_3.setAlignment(
|
||||
QtCore.Qt.AlignmentFlag.AlignLeading
|
||||
| QtCore.Qt.AlignmentFlag.AlignLeft
|
||||
| QtCore.Qt.AlignmentFlag.AlignTop
|
||||
)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout.addWidget(self.label_3, 5, 0, 1, 1)
|
||||
self.label = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
spacerItem1 = QtWidgets.QSpacerItem(
|
||||
40,
|
||||
20,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
)
|
||||
self.horizontalLayout_2.addItem(spacerItem1)
|
||||
self.btn_okay = QtWidgets.QPushButton(parent=eMailPreview)
|
||||
self.btn_okay.setStatusTip("")
|
||||
self.btn_okay.setObjectName("btn_okay")
|
||||
self.horizontalLayout_2.addWidget(self.btn_okay)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=eMailPreview)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
self.buttonBox.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
)
|
||||
self.buttonBox.setCenterButtons(True)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.horizontalLayout_2.addWidget(self.buttonBox)
|
||||
self.gridLayout.addLayout(self.horizontalLayout_2, 6, 2, 1, 1)
|
||||
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
|
||||
|
||||
self.retranslateUi(eMailPreview)
|
||||
self.buttonBox.accepted.connect(eMailPreview.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(eMailPreview.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(eMailPreview)
|
||||
|
||||
def retranslateUi(self, eMailPreview):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
eMailPreview.setWindowTitle(_translate("eMailPreview", "eMail Voransicht"))
|
||||
self.label_6.setText(_translate("eMailPreview", "Anrede"))
|
||||
self.label_2.setText(_translate("eMailPreview", "Prof"))
|
||||
self.label_5.setText(_translate("eMailPreview", "Art"))
|
||||
self.label_4.setText(_translate("eMailPreview", "Betreff"))
|
||||
self.gender_male.setText(_translate("eMailPreview", "M"))
|
||||
self.gender_female.setText(_translate("eMailPreview", "W"))
|
||||
self.gender_non.setText(_translate("eMailPreview", "Divers"))
|
||||
self.label_3.setText(_translate("eMailPreview", "Mail"))
|
||||
self.label.setText(_translate("eMailPreview", "eMail"))
|
||||
self.btn_okay.setWhatsThis(_translate("eMailPreview", "test"))
|
||||
self.btn_okay.setText(_translate("eMailPreview", "Senden"))
|
||||
@@ -1,385 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\medianadder.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.7.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(620, 481)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(
|
||||
QtGui.QPixmap(":/icons/resources/2795.svg"),
|
||||
QtGui.QIcon.Mode.Normal,
|
||||
QtGui.QIcon.State.Off,
|
||||
)
|
||||
Dialog.setWindowIcon(icon)
|
||||
self.label = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label.setGeometry(QtCore.QRect(20, 10, 47, 21))
|
||||
self.label.setObjectName("label")
|
||||
self.label_2 = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label_2.setGeometry(QtCore.QRect(20, 40, 47, 21))
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.comboBox = QtWidgets.QComboBox(parent=Dialog)
|
||||
self.comboBox.setGeometry(QtCore.QRect(70, 40, 69, 22))
|
||||
self.comboBox.setObjectName("comboBox")
|
||||
self.comboBox.addItem("")
|
||||
self.comboBox.addItem("")
|
||||
self.comboBox.addItem("")
|
||||
self.comboBox.addItem("")
|
||||
self.lineEdit = QtWidgets.QLineEdit(parent=Dialog)
|
||||
self.lineEdit.setGeometry(QtCore.QRect(70, 10, 113, 20))
|
||||
self.lineEdit.setObjectName("lineEdit")
|
||||
self.label_3 = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label_3.setGeometry(QtCore.QRect(20, 90, 47, 21))
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.widget = QtWidgets.QWidget(parent=Dialog)
|
||||
self.widget.setGeometry(QtCore.QRect(330, 90, 281, 381))
|
||||
self.widget.setObjectName("widget")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)
|
||||
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.tableWidget = QtWidgets.QTableWidget(parent=self.widget)
|
||||
self.tableWidget.setEnabled(True)
|
||||
self.tableWidget.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.tableWidget.setAutoFillBackground(False)
|
||||
self.tableWidget.setLineWidth(0)
|
||||
self.tableWidget.setMidLineWidth(0)
|
||||
self.tableWidget.setVerticalScrollBarPolicy(
|
||||
QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff
|
||||
)
|
||||
self.tableWidget.setHorizontalScrollBarPolicy(
|
||||
QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff
|
||||
)
|
||||
self.tableWidget.setSizeAdjustPolicy(
|
||||
QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents
|
||||
)
|
||||
self.tableWidget.setEditTriggers(
|
||||
QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers
|
||||
)
|
||||
self.tableWidget.setAlternatingRowColors(True)
|
||||
self.tableWidget.setSelectionMode(
|
||||
QtWidgets.QAbstractItemView.SelectionMode.NoSelection
|
||||
)
|
||||
self.tableWidget.setTextElideMode(QtCore.Qt.TextElideMode.ElideMiddle)
|
||||
self.tableWidget.setObjectName("tableWidget")
|
||||
self.tableWidget.setColumnCount(4)
|
||||
self.tableWidget.setRowCount(11)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(4, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(5, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(6, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(7, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(8, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(9, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setVerticalHeaderItem(10, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(0, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(0, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(0, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(0, 3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(1, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(1, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(1, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(1, 3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(2, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(2, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(2, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(2, 3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(3, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(3, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(3, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(3, 3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(4, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(4, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(4, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(4, 3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(5, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(5, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(5, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(5, 3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(6, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(6, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(6, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(6, 3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(7, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(7, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(7, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(7, 3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(8, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(8, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(8, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(8, 3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(9, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(9, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(9, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(9, 3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(10, 0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(10, 1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(10, 2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setItem(10, 3, item)
|
||||
self.tableWidget.horizontalHeader().setDefaultSectionSize(45)
|
||||
self.horizontalLayout.addWidget(self.tableWidget)
|
||||
self.listWidget = QtWidgets.QListWidget(parent=Dialog)
|
||||
self.listWidget.setGeometry(QtCore.QRect(10, 110, 281, 321))
|
||||
self.listWidget.setContextMenuPolicy(
|
||||
QtCore.Qt.ContextMenuPolicy.CustomContextMenu
|
||||
)
|
||||
self.listWidget.setObjectName("listWidget")
|
||||
self.label_4 = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label_4.setGeometry(QtCore.QRect(330, 50, 181, 21))
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.label_5 = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label_5.setGeometry(QtCore.QRect(200, 90, 41, 21))
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.list_amount = QtWidgets.QLabel(parent=Dialog)
|
||||
self.list_amount.setGeometry(QtCore.QRect(240, 90, 47, 21))
|
||||
self.list_amount.setObjectName("list_amount")
|
||||
self.horizontalLayoutWidget = QtWidgets.QWidget(parent=Dialog)
|
||||
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 440, 160, 31))
|
||||
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
|
||||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.btn_save = QtWidgets.QPushButton(parent=self.horizontalLayoutWidget)
|
||||
self.btn_save.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.btn_save.setObjectName("btn_save")
|
||||
self.horizontalLayout_2.addWidget(self.btn_save)
|
||||
self.btn_cancel = QtWidgets.QPushButton(parent=self.horizontalLayoutWidget)
|
||||
self.btn_cancel.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.btn_cancel.setObjectName("btn_cancel")
|
||||
self.horizontalLayout_2.addWidget(self.btn_cancel)
|
||||
self.check_use_any_book = QtWidgets.QCheckBox(parent=Dialog)
|
||||
self.check_use_any_book.setGeometry(QtCore.QRect(20, 70, 141, 20))
|
||||
self.check_use_any_book.setObjectName("check_use_any_book")
|
||||
self.check_use_exact_signature = QtWidgets.QCheckBox(parent=Dialog)
|
||||
self.check_use_exact_signature.setGeometry(QtCore.QRect(165, 70, 121, 20))
|
||||
self.check_use_exact_signature.setObjectName("check_use_exact_signature")
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
Dialog.setTabOrder(self.lineEdit, self.comboBox)
|
||||
Dialog.setTabOrder(self.comboBox, self.listWidget)
|
||||
Dialog.setTabOrder(self.listWidget, self.tableWidget)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Medien"))
|
||||
self.label.setText(_translate("Dialog", "Signatur"))
|
||||
self.label_2.setText(_translate("Dialog", "Modus"))
|
||||
self.comboBox.setItemText(0, _translate("Dialog", "ARRAY"))
|
||||
self.comboBox.setItemText(1, _translate("Dialog", "BibTeX"))
|
||||
self.comboBox.setItemText(2, _translate("Dialog", "COinS"))
|
||||
self.comboBox.setItemText(3, _translate("Dialog", "RIS"))
|
||||
self.lineEdit.setPlaceholderText(_translate("Dialog", "Signatur / ISBN"))
|
||||
self.label_3.setText(_translate("Dialog", "Queue"))
|
||||
item = self.tableWidget.verticalHeaderItem(0)
|
||||
item.setText(_translate("Dialog", "PPN"))
|
||||
item = self.tableWidget.verticalHeaderItem(1)
|
||||
item.setText(_translate("Dialog", "Signatur"))
|
||||
item = self.tableWidget.verticalHeaderItem(2)
|
||||
item.setText(_translate("Dialog", "Autor"))
|
||||
item = self.tableWidget.verticalHeaderItem(3)
|
||||
item.setText(_translate("Dialog", "ISBN"))
|
||||
item = self.tableWidget.verticalHeaderItem(4)
|
||||
item.setText(_translate("Dialog", "Jahr"))
|
||||
item = self.tableWidget.verticalHeaderItem(5)
|
||||
item.setText(_translate("Dialog", "Auflage"))
|
||||
item = self.tableWidget.verticalHeaderItem(6)
|
||||
item.setText(_translate("Dialog", "Sprache"))
|
||||
item = self.tableWidget.verticalHeaderItem(7)
|
||||
item.setText(_translate("Dialog", "Herausgeber"))
|
||||
item = self.tableWidget.verticalHeaderItem(8)
|
||||
item.setText(_translate("Dialog", "Seiten"))
|
||||
item = self.tableWidget.verticalHeaderItem(9)
|
||||
item.setText(_translate("Dialog", "Titel"))
|
||||
item = self.tableWidget.verticalHeaderItem(10)
|
||||
item.setText(_translate("Dialog", "Link"))
|
||||
item = self.tableWidget.horizontalHeaderItem(0)
|
||||
item.setText(_translate("Dialog", "Array"))
|
||||
item = self.tableWidget.horizontalHeaderItem(1)
|
||||
item.setText(_translate("Dialog", "BibTeX"))
|
||||
item = self.tableWidget.horizontalHeaderItem(2)
|
||||
item.setText(_translate("Dialog", "COinS"))
|
||||
item = self.tableWidget.horizontalHeaderItem(3)
|
||||
item.setText(_translate("Dialog", "RIS"))
|
||||
__sortingEnabled = self.tableWidget.isSortingEnabled()
|
||||
self.tableWidget.setSortingEnabled(False)
|
||||
item = self.tableWidget.item(0, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(0, 1)
|
||||
item.setText(_translate("Dialog", "0"))
|
||||
item = self.tableWidget.item(0, 2)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(0, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(1, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(1, 1)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(1, 2)
|
||||
item.setText(_translate("Dialog", "0"))
|
||||
item = self.tableWidget.item(1, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(2, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(2, 1)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(2, 2)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(2, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(3, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(3, 1)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(3, 2)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(3, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(4, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(4, 1)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(4, 2)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(4, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(5, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(5, 1)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(5, 2)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(5, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(6, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(6, 1)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(6, 2)
|
||||
item.setText(_translate("Dialog", "0"))
|
||||
item = self.tableWidget.item(6, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(7, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(7, 1)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(7, 2)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(7, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(8, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(8, 1)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(8, 2)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(8, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(9, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(9, 1)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(9, 2)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(9, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(10, 0)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(10, 1)
|
||||
item.setText(_translate("Dialog", "0"))
|
||||
item = self.tableWidget.item(10, 2)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
item = self.tableWidget.item(10, 3)
|
||||
item.setText(_translate("Dialog", "1"))
|
||||
self.tableWidget.setSortingEnabled(__sortingEnabled)
|
||||
self.label_4.setText(_translate("Dialog", "Belegbare Felder per Anbieter"))
|
||||
self.label_5.setText(_translate("Dialog", "Anzahl:"))
|
||||
self.list_amount.setText(_translate("Dialog", "0"))
|
||||
self.btn_save.setText(_translate("Dialog", "Ok"))
|
||||
self.btn_cancel.setText(_translate("Dialog", "Abbrechen"))
|
||||
self.check_use_any_book.setToolTip(
|
||||
_translate(
|
||||
"Dialog",
|
||||
"Verwendet ein zufälliges Buch des Datensatzes, nützlich wenn das Buch noch nicht im Apparat ist",
|
||||
)
|
||||
)
|
||||
self.check_use_any_book.setText(_translate("Dialog", "Jedes Buch verwenden"))
|
||||
self.check_use_exact_signature.setToolTip(
|
||||
_translate(
|
||||
"Dialog", "Verwendet die eingegebene Signatur für die Suche von Daten"
|
||||
)
|
||||
)
|
||||
self.check_use_exact_signature.setText(_translate("Dialog", "Exakte Signatur"))
|
||||
@@ -1,181 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\newMailTemplateDesigner.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.6.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtWidgets
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(689, 572)
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.bold = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.bold.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.bold.setCheckable(True)
|
||||
self.bold.setObjectName("bold")
|
||||
self.horizontalLayout_2.addWidget(self.bold)
|
||||
self.italic = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.italic.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.italic.setCheckable(True)
|
||||
self.italic.setObjectName("italic")
|
||||
self.horizontalLayout_2.addWidget(self.italic)
|
||||
self.underlined = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.underlined.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.underlined.setCheckable(True)
|
||||
self.underlined.setObjectName("underlined")
|
||||
self.horizontalLayout_2.addWidget(self.underlined)
|
||||
self.fontBox = QtWidgets.QFontComboBox(parent=Dialog)
|
||||
self.fontBox.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.fontBox.setObjectName("fontBox")
|
||||
self.horizontalLayout_2.addWidget(self.fontBox)
|
||||
self.fontSize = QtWidgets.QComboBox(parent=Dialog)
|
||||
self.fontSize.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.fontSize.setObjectName("fontSize")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.horizontalLayout_2.addWidget(self.fontSize)
|
||||
spacerItem = QtWidgets.QSpacerItem(
|
||||
40,
|
||||
20,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
)
|
||||
self.horizontalLayout_2.addItem(spacerItem)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_4)
|
||||
self.gridLayout = QtWidgets.QGridLayout()
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
|
||||
self.placeholder_list = QtWidgets.QComboBox(parent=Dialog)
|
||||
self.placeholder_list.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.placeholder_list.setSizeAdjustPolicy(
|
||||
QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents
|
||||
)
|
||||
self.placeholder_list.setObjectName("placeholder_list")
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.addItem("")
|
||||
self.gridLayout.addWidget(self.placeholder_list, 1, 0, 1, 1)
|
||||
self.label_2 = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1)
|
||||
self.lineEdit = QtWidgets.QLineEdit(parent=Dialog)
|
||||
self.lineEdit.setEnabled(True)
|
||||
self.lineEdit.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.lineEdit.setFrame(False)
|
||||
self.lineEdit.setReadOnly(True)
|
||||
self.lineEdit.setObjectName("lineEdit")
|
||||
self.gridLayout.addWidget(self.lineEdit, 1, 1, 1, 1)
|
||||
self.insertPlaceholder = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.insertPlaceholder.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.insertPlaceholder.setObjectName("insertPlaceholder")
|
||||
self.gridLayout.addWidget(self.insertPlaceholder, 1, 2, 1, 1)
|
||||
self.verticalLayout.addLayout(self.gridLayout)
|
||||
self.label_3 = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.verticalLayout.addWidget(self.label_3)
|
||||
self.subject = QtWidgets.QLineEdit(parent=Dialog)
|
||||
self.subject.setObjectName("subject")
|
||||
self.verticalLayout.addWidget(self.subject)
|
||||
self.templateEdit = QtWidgets.QTextEdit(parent=Dialog)
|
||||
self.templateEdit.setObjectName("templateEdit")
|
||||
self.verticalLayout.addWidget(self.templateEdit)
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.testTemplate = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.testTemplate.setObjectName("testTemplate")
|
||||
self.horizontalLayout_3.addWidget(self.testTemplate)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(
|
||||
40,
|
||||
20,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
)
|
||||
self.horizontalLayout_3.addItem(spacerItem1)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_3)
|
||||
self.verticalLayout_2.addLayout(self.verticalLayout)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
self.buttonBox.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Discard
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Save
|
||||
)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.verticalLayout_2.addWidget(self.buttonBox)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.fontSize.setCurrentIndex(1)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
Dialog.setTabOrder(self.subject, self.templateEdit)
|
||||
Dialog.setTabOrder(self.templateEdit, self.testTemplate)
|
||||
Dialog.setTabOrder(self.testTemplate, self.insertPlaceholder)
|
||||
Dialog.setTabOrder(self.insertPlaceholder, self.lineEdit)
|
||||
Dialog.setTabOrder(self.lineEdit, self.fontSize)
|
||||
Dialog.setTabOrder(self.fontSize, self.placeholder_list)
|
||||
Dialog.setTabOrder(self.placeholder_list, self.fontBox)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.bold.setText(_translate("Dialog", "Fett"))
|
||||
self.italic.setText(_translate("Dialog", "Kursiv"))
|
||||
self.underlined.setText(_translate("Dialog", "Unterstrichen"))
|
||||
self.fontSize.setItemText(0, _translate("Dialog", "8"))
|
||||
self.fontSize.setItemText(1, _translate("Dialog", "9"))
|
||||
self.fontSize.setItemText(2, _translate("Dialog", "11"))
|
||||
self.fontSize.setItemText(3, _translate("Dialog", "12"))
|
||||
self.fontSize.setItemText(4, _translate("Dialog", "14"))
|
||||
self.fontSize.setItemText(5, _translate("Dialog", "16"))
|
||||
self.fontSize.setItemText(6, _translate("Dialog", "18"))
|
||||
self.fontSize.setItemText(7, _translate("Dialog", "20"))
|
||||
self.fontSize.setItemText(8, _translate("Dialog", "22"))
|
||||
self.fontSize.setItemText(9, _translate("Dialog", "24"))
|
||||
self.fontSize.setItemText(10, _translate("Dialog", "26"))
|
||||
self.fontSize.setItemText(11, _translate("Dialog", "28"))
|
||||
self.fontSize.setItemText(12, _translate("Dialog", "36"))
|
||||
self.fontSize.setItemText(13, _translate("Dialog", "48"))
|
||||
self.fontSize.setItemText(14, _translate("Dialog", "76"))
|
||||
self.label.setText(_translate("Dialog", "Platzhalter"))
|
||||
self.placeholder_list.setItemText(0, _translate("Dialog", "«Anrede»"))
|
||||
self.placeholder_list.setItemText(1, _translate("Dialog", "«ApparatsName»"))
|
||||
self.placeholder_list.setItemText(2, _translate("Dialog", "«ApparatsFach»"))
|
||||
self.placeholder_list.setItemText(3, _translate("Dialog", "«ApparatsNummer»"))
|
||||
self.placeholder_list.setItemText(4, _translate("Dialog", "«DozentName»"))
|
||||
self.placeholder_list.setItemText(5, _translate("Dialog", "«Signatur»"))
|
||||
self.label_2.setText(_translate("Dialog", "Beschreibung"))
|
||||
self.insertPlaceholder.setText(
|
||||
_translate("Dialog", "An aktiver Position einfügen")
|
||||
)
|
||||
self.label_3.setText(_translate("Dialog", "Betreff"))
|
||||
self.testTemplate.setText(_translate("Dialog", "Template testen"))
|
||||
@@ -1,91 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\parsed_titles.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.6.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName("Form")
|
||||
Form.resize(402, 316)
|
||||
self.frame = QtWidgets.QFrame(parent=Form)
|
||||
self.frame.setGeometry(QtCore.QRect(10, 10, 381, 41))
|
||||
self.frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||
self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||
self.frame.setObjectName("frame")
|
||||
self.horizontalLayoutWidget = QtWidgets.QWidget(parent=self.frame)
|
||||
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(0, 0, 381, 41))
|
||||
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
|
||||
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.label = QtWidgets.QLabel(parent=self.horizontalLayoutWidget)
|
||||
self.label.setObjectName("label")
|
||||
self.horizontalLayout.addWidget(self.label)
|
||||
self.count = QtWidgets.QLabel(parent=self.horizontalLayoutWidget)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.count.setFont(font)
|
||||
self.count.setTextFormat(QtCore.Qt.TextFormat.PlainText)
|
||||
self.count.setObjectName("count")
|
||||
self.horizontalLayout.addWidget(self.count)
|
||||
self.label_2 = QtWidgets.QLabel(parent=self.horizontalLayoutWidget)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.horizontalLayout.addWidget(self.label_2)
|
||||
spacerItem = QtWidgets.QSpacerItem(
|
||||
40,
|
||||
20,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
)
|
||||
self.horizontalLayout.addItem(spacerItem)
|
||||
self.frame_2 = QtWidgets.QFrame(parent=Form)
|
||||
self.frame_2.setGeometry(QtCore.QRect(10, 80, 381, 201))
|
||||
self.frame_2.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||
self.frame_2.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||
self.frame_2.setObjectName("frame_2")
|
||||
self.horizontalLayoutWidget_2 = QtWidgets.QWidget(parent=self.frame_2)
|
||||
self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(0, 10, 381, 191))
|
||||
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.listWidget = QtWidgets.QListWidget(parent=self.horizontalLayoutWidget_2)
|
||||
self.listWidget.setObjectName("listWidget")
|
||||
self.horizontalLayout_2.addWidget(self.listWidget)
|
||||
self.listWidget_done = QtWidgets.QListWidget(
|
||||
parent=self.horizontalLayoutWidget_2
|
||||
)
|
||||
self.listWidget_done.setObjectName("listWidget_done")
|
||||
self.horizontalLayout_2.addWidget(self.listWidget_done)
|
||||
self.progressBar = QtWidgets.QProgressBar(parent=Form)
|
||||
self.progressBar.setGeometry(QtCore.QRect(10, 60, 381, 23))
|
||||
self.progressBar.setProperty("value", 24)
|
||||
self.progressBar.setObjectName("progressBar")
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Form)
|
||||
self.buttonBox.setGeometry(QtCore.QRect(230, 290, 156, 23))
|
||||
self.buttonBox.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Ok
|
||||
)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.toolButton = QtWidgets.QToolButton(parent=Form)
|
||||
self.toolButton.setGeometry(QtCore.QRect(20, 290, 25, 19))
|
||||
self.toolButton.setObjectName("toolButton")
|
||||
|
||||
self.retranslateUi(Form)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Form.setWindowTitle(_translate("Form", "Form"))
|
||||
self.label.setText(_translate("Form", "Es wurden"))
|
||||
self.count.setText(_translate("Form", "0"))
|
||||
self.label_2.setText(_translate("Form", "Signaturen gefunden."))
|
||||
self.toolButton.setText(_translate("Form", "..."))
|
||||
@@ -1,46 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\reminder.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.6.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtWidgets
|
||||
|
||||
|
||||
class Ui_Erinnerung(object):
|
||||
def setupUi(self, Erinnerung):
|
||||
Erinnerung.setObjectName("Erinnerung")
|
||||
Erinnerung.resize(358, 308)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Erinnerung)
|
||||
self.buttonBox.setGeometry(QtCore.QRect(190, 270, 161, 32))
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
self.buttonBox.setStandardButtons(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
| QtWidgets.QDialogButtonBox.StandardButton.Ok
|
||||
)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.message_box = QtWidgets.QTextEdit(parent=Erinnerung)
|
||||
self.message_box.setGeometry(QtCore.QRect(10, 60, 341, 201))
|
||||
self.message_box.setObjectName("message_box")
|
||||
self.label = QtWidgets.QLabel(parent=Erinnerung)
|
||||
self.label.setGeometry(QtCore.QRect(10, 30, 61, 21))
|
||||
self.label.setObjectName("label")
|
||||
self.label_2 = QtWidgets.QLabel(parent=Erinnerung)
|
||||
self.label_2.setGeometry(QtCore.QRect(120, 30, 81, 21))
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.dateEdit = QtWidgets.QDateEdit(parent=Erinnerung)
|
||||
self.dateEdit.setGeometry(QtCore.QRect(210, 30, 141, 22))
|
||||
self.dateEdit.setObjectName("dateEdit")
|
||||
|
||||
self.retranslateUi(Erinnerung)
|
||||
self.buttonBox.accepted.connect(Erinnerung.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(Erinnerung.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(Erinnerung)
|
||||
|
||||
def retranslateUi(self, Erinnerung):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Erinnerung.setWindowTitle(_translate("Erinnerung", "Dialog"))
|
||||
self.label.setText(_translate("Erinnerung", "Nachricht:"))
|
||||
self.label_2.setText(_translate("Erinnerung", "Erinnerung am:"))
|
||||
@@ -1,341 +0,0 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\settings.ui'
|
||||
#
|
||||
# Created by: PySide6 UI code generator 6.7.1
|
||||
#
|
||||
# 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 PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.setWindowModality(QtCore.Qt.WindowModality.NonModal)
|
||||
Dialog.resize(651, 679)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth())
|
||||
Dialog.setSizePolicy(sizePolicy)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.toolBox = QtWidgets.QToolBox(parent=Dialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.toolBox.sizePolicy().hasHeightForWidth())
|
||||
self.toolBox.setSizePolicy(sizePolicy)
|
||||
self.toolBox.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhNone)
|
||||
self.toolBox.setObjectName("toolBox")
|
||||
self.page_1 = QtWidgets.QWidget()
|
||||
self.page_1.setGeometry(QtCore.QRect(0, 0, 633, 511))
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.page_1.sizePolicy().hasHeightForWidth())
|
||||
self.page_1.setSizePolicy(sizePolicy)
|
||||
self.page_1.setObjectName("page_1")
|
||||
self.gridLayout_3 = QtWidgets.QGridLayout(self.page_1)
|
||||
self.gridLayout_3.setObjectName("gridLayout_3")
|
||||
self.db_name = QtWidgets.QLineEdit(parent=self.page_1)
|
||||
self.db_name.setObjectName("db_name")
|
||||
self.gridLayout_3.addWidget(self.db_name, 0, 1, 1, 1)
|
||||
self.label_5 = QtWidgets.QLabel(parent=self.page_1)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.gridLayout_3.addWidget(self.label_5, 0, 0, 1, 1)
|
||||
self.db_path = QtWidgets.QLineEdit(parent=self.page_1)
|
||||
self.db_path.setEnabled(False)
|
||||
self.db_path.setObjectName("db_path")
|
||||
self.gridLayout_3.addWidget(self.db_path, 1, 1, 1, 1)
|
||||
self.label_12 = QtWidgets.QLabel(parent=self.page_1)
|
||||
self.label_12.setObjectName("label_12")
|
||||
self.gridLayout_3.addWidget(self.label_12, 2, 0, 1, 1)
|
||||
self.label_11 = QtWidgets.QLabel(parent=self.page_1)
|
||||
self.label_11.setObjectName("label_11")
|
||||
self.gridLayout_3.addWidget(self.label_11, 1, 0, 1, 1)
|
||||
self.tb_set_save_path = QtWidgets.QToolButton(parent=self.page_1)
|
||||
self.tb_set_save_path.setObjectName("tb_set_save_path")
|
||||
self.gridLayout_3.addWidget(self.tb_set_save_path, 2, 2, 1, 1)
|
||||
self.tb_select_db = QtWidgets.QToolButton(parent=self.page_1)
|
||||
self.tb_select_db.setObjectName("tb_select_db")
|
||||
self.gridLayout_3.addWidget(self.tb_select_db, 0, 2, 1, 1)
|
||||
self.save_path = QtWidgets.QLineEdit(parent=self.page_1)
|
||||
self.save_path.setObjectName("save_path")
|
||||
self.gridLayout_3.addWidget(self.save_path, 2, 1, 1, 1)
|
||||
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
|
||||
self.gridLayout_3.addItem(spacerItem, 3, 1, 1, 1)
|
||||
self.toolBox.addItem(self.page_1, "")
|
||||
self.page_2 = QtWidgets.QWidget()
|
||||
self.page_2.setGeometry(QtCore.QRect(0, 0, 633, 511))
|
||||
self.page_2.setObjectName("page_2")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.page_2)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.zotero_library_type = QtWidgets.QLineEdit(parent=self.page_2)
|
||||
self.zotero_library_type.setObjectName("zotero_library_type")
|
||||
self.gridLayout.addWidget(self.zotero_library_type, 2, 2, 1, 1)
|
||||
self.zotero_library_id = QtWidgets.QLineEdit(parent=self.page_2)
|
||||
self.zotero_library_id.setObjectName("zotero_library_id")
|
||||
self.gridLayout.addWidget(self.zotero_library_id, 1, 2, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(parent=self.page_2)
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.gridLayout.addWidget(self.label_4, 2, 0, 1, 1)
|
||||
self.label_3 = QtWidgets.QLabel(parent=self.page_2)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1)
|
||||
self.zotero_api_key = QtWidgets.QLineEdit(parent=self.page_2)
|
||||
self.zotero_api_key.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhHiddenText|QtCore.Qt.InputMethodHint.ImhSensitiveData)
|
||||
self.zotero_api_key.setObjectName("zotero_api_key")
|
||||
self.gridLayout.addWidget(self.zotero_api_key, 0, 2, 1, 1)
|
||||
self.label_2 = QtWidgets.QLabel(parent=self.page_2)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1)
|
||||
self.toggle_api_visibility = QtWidgets.QToolButton(parent=self.page_2)
|
||||
self.toggle_api_visibility.setText("")
|
||||
self.toggle_api_visibility.setObjectName("toggle_api_visibility")
|
||||
self.gridLayout.addWidget(self.toggle_api_visibility, 0, 3, 1, 1)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
|
||||
self.gridLayout.addItem(spacerItem1, 3, 2, 1, 1)
|
||||
self.toolBox.addItem(self.page_2, "")
|
||||
self.page_3 = QtWidgets.QWidget()
|
||||
self.page_3.setGeometry(QtCore.QRect(0, 0, 633, 511))
|
||||
self.page_3.setObjectName("page_3")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.page_3)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.email_settings = QtWidgets.QTabWidget(parent=self.page_3)
|
||||
self.email_settings.setObjectName("email_settings")
|
||||
self.email_settingsPage1_2 = QtWidgets.QWidget()
|
||||
self.email_settingsPage1_2.setObjectName("email_settingsPage1_2")
|
||||
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.email_settingsPage1_2)
|
||||
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
|
||||
self.gridLayout_2 = QtWidgets.QGridLayout()
|
||||
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||
self.use_username_smtp_login = QtWidgets.QCheckBox(parent=self.email_settingsPage1_2)
|
||||
self.use_username_smtp_login.setTristate(False)
|
||||
self.use_username_smtp_login.setObjectName("use_username_smtp_login")
|
||||
self.gridLayout_2.addWidget(self.use_username_smtp_login, 4, 1, 1, 1)
|
||||
self.label_6 = QtWidgets.QLabel(parent=self.email_settingsPage1_2)
|
||||
self.label_6.setObjectName("label_6")
|
||||
self.gridLayout_2.addWidget(self.label_6, 1, 0, 1, 1)
|
||||
self.smtp_port = QtWidgets.QLineEdit(parent=self.email_settingsPage1_2)
|
||||
self.smtp_port.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhDigitsOnly|QtCore.Qt.InputMethodHint.ImhPreferNumbers)
|
||||
self.smtp_port.setClearButtonEnabled(True)
|
||||
self.smtp_port.setObjectName("smtp_port")
|
||||
self.gridLayout_2.addWidget(self.smtp_port, 1, 1, 1, 1)
|
||||
self.label_7 = QtWidgets.QLabel(parent=self.email_settingsPage1_2)
|
||||
self.label_7.setObjectName("label_7")
|
||||
self.gridLayout_2.addWidget(self.label_7, 2, 0, 1, 1)
|
||||
self.sender_email = QtWidgets.QLineEdit(parent=self.email_settingsPage1_2)
|
||||
self.sender_email.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhEmailCharactersOnly)
|
||||
self.sender_email.setClearButtonEnabled(True)
|
||||
self.sender_email.setObjectName("sender_email")
|
||||
self.gridLayout_2.addWidget(self.sender_email, 2, 1, 1, 1)
|
||||
self.mail_username = QtWidgets.QLineEdit(parent=self.email_settingsPage1_2)
|
||||
self.mail_username.setClearButtonEnabled(True)
|
||||
self.mail_username.setObjectName("mail_username")
|
||||
self.gridLayout_2.addWidget(self.mail_username, 3, 1, 1, 1)
|
||||
self.label_9 = QtWidgets.QLabel(parent=self.email_settingsPage1_2)
|
||||
self.label_9.setText("")
|
||||
self.label_9.setObjectName("label_9")
|
||||
self.gridLayout_2.addWidget(self.label_9, 7, 0, 1, 1)
|
||||
self.password = QtWidgets.QLineEdit(parent=self.email_settingsPage1_2)
|
||||
self.password.setInputMethodHints(QtCore.Qt.InputMethodHint.ImhHiddenText|QtCore.Qt.InputMethodHint.ImhSensitiveData)
|
||||
self.password.setClearButtonEnabled(True)
|
||||
self.password.setObjectName("password")
|
||||
self.gridLayout_2.addWidget(self.password, 5, 1, 1, 1)
|
||||
self.smtp_address = QtWidgets.QLineEdit(parent=self.email_settingsPage1_2)
|
||||
self.smtp_address.setClearButtonEnabled(True)
|
||||
self.smtp_address.setObjectName("smtp_address")
|
||||
self.gridLayout_2.addWidget(self.smtp_address, 0, 1, 1, 1)
|
||||
self.label = QtWidgets.QLabel(parent=self.email_settingsPage1_2)
|
||||
self.label.setObjectName("label")
|
||||
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
|
||||
self.label_10 = QtWidgets.QLabel(parent=self.email_settingsPage1_2)
|
||||
self.label_10.setObjectName("label_10")
|
||||
self.gridLayout_2.addWidget(self.label_10, 5, 0, 1, 1)
|
||||
self.togglePassword = QtWidgets.QPushButton(parent=self.email_settingsPage1_2)
|
||||
self.togglePassword.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.togglePassword.setText("")
|
||||
self.togglePassword.setObjectName("togglePassword")
|
||||
self.gridLayout_2.addWidget(self.togglePassword, 5, 2, 1, 1)
|
||||
self.label_8 = QtWidgets.QLabel(parent=self.email_settingsPage1_2)
|
||||
self.label_8.setObjectName("label_8")
|
||||
self.gridLayout_2.addWidget(self.label_8, 3, 0, 1, 1)
|
||||
self.label_13 = QtWidgets.QLabel(parent=self.email_settingsPage1_2)
|
||||
self.label_13.setObjectName("label_13")
|
||||
self.gridLayout_2.addWidget(self.label_13, 6, 0, 1, 1)
|
||||
self.printermail = QtWidgets.QLineEdit(parent=self.email_settingsPage1_2)
|
||||
self.printermail.setObjectName("printermail")
|
||||
self.gridLayout_2.addWidget(self.printermail, 6, 1, 1, 1)
|
||||
self.horizontalLayout_4.addLayout(self.gridLayout_2)
|
||||
self.email_settings.addTab(self.email_settingsPage1_2, "")
|
||||
self.email_settingsPage2_2 = QtWidgets.QWidget()
|
||||
self.email_settingsPage2_2.setObjectName("email_settingsPage2_2")
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.email_settingsPage2_2)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout_3.addItem(spacerItem2)
|
||||
self.bold = QtWidgets.QPushButton(parent=self.email_settingsPage2_2)
|
||||
self.bold.setCheckable(True)
|
||||
self.bold.setObjectName("bold")
|
||||
self.horizontalLayout_3.addWidget(self.bold)
|
||||
self.italic = QtWidgets.QPushButton(parent=self.email_settingsPage2_2)
|
||||
self.italic.setCheckable(True)
|
||||
self.italic.setObjectName("italic")
|
||||
self.horizontalLayout_3.addWidget(self.italic)
|
||||
self.underscore = QtWidgets.QPushButton(parent=self.email_settingsPage2_2)
|
||||
self.underscore.setCheckable(True)
|
||||
self.underscore.setObjectName("underscore")
|
||||
self.horizontalLayout_3.addWidget(self.underscore)
|
||||
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout_3.addItem(spacerItem3)
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout_3)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.fontComboBox = QtWidgets.QFontComboBox(parent=self.email_settingsPage2_2)
|
||||
self.fontComboBox.setObjectName("fontComboBox")
|
||||
self.horizontalLayout.addWidget(self.fontComboBox)
|
||||
self.font_size = QtWidgets.QComboBox(parent=self.email_settingsPage2_2)
|
||||
self.font_size.setObjectName("font_size")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.font_size.addItem("")
|
||||
self.horizontalLayout.addWidget(self.font_size)
|
||||
spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout.addItem(spacerItem4)
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout)
|
||||
self.verticalLayout_3.addLayout(self.verticalLayout_2)
|
||||
self.editSignature = QtWidgets.QTextEdit(parent=self.email_settingsPage2_2)
|
||||
self.editSignature.setObjectName("editSignature")
|
||||
self.verticalLayout_3.addWidget(self.editSignature)
|
||||
self.debug = QtWidgets.QPushButton(parent=self.email_settingsPage2_2)
|
||||
self.debug.setObjectName("debug")
|
||||
self.verticalLayout_3.addWidget(self.debug)
|
||||
self.email_settings.addTab(self.email_settingsPage2_2, "")
|
||||
self.horizontalLayout_2.addWidget(self.email_settings)
|
||||
self.toolBox.addItem(self.page_3, "")
|
||||
self.page_4 = QtWidgets.QWidget()
|
||||
self.page_4.setGeometry(QtCore.QRect(0, 0, 633, 511))
|
||||
self.page_4.setObjectName("page_4")
|
||||
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.page_4)
|
||||
self.verticalLayout_4.setObjectName("verticalLayout_4")
|
||||
self.groupBox = QtWidgets.QGroupBox(parent=self.page_4)
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(12)
|
||||
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.scrollArea_3 = QtWidgets.QScrollArea(parent=self.groupBox)
|
||||
self.scrollArea_3.setWidgetResizable(True)
|
||||
self.scrollArea_3.setObjectName("scrollArea_3")
|
||||
self.scrollAreaWidgetContents_3 = QtWidgets.QWidget()
|
||||
self.scrollAreaWidgetContents_3.setGeometry(QtCore.QRect(0, 0, 593, 201))
|
||||
self.scrollAreaWidgetContents_3.setObjectName("scrollAreaWidgetContents_3")
|
||||
self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents_3)
|
||||
self.verticalLayout_7.setObjectName("verticalLayout_7")
|
||||
self.gridLayout_4 = QtWidgets.QGridLayout()
|
||||
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||
self.verticalLayout_7.addLayout(self.gridLayout_4)
|
||||
self.scrollArea_3.setWidget(self.scrollAreaWidgetContents_3)
|
||||
self.verticalLayout_5.addWidget(self.scrollArea_3)
|
||||
self.verticalLayout_4.addWidget(self.groupBox)
|
||||
self.scrollArea_2 = QtWidgets.QScrollArea(parent=self.page_4)
|
||||
self.scrollArea_2.setWidgetResizable(True)
|
||||
self.scrollArea_2.setObjectName("scrollArea_2")
|
||||
self.scrollAreaWidgetContents_2 = QtWidgets.QWidget()
|
||||
self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 613, 241))
|
||||
self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2")
|
||||
self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents_2)
|
||||
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
||||
self.vertical_icons = QtWidgets.QVBoxLayout()
|
||||
self.vertical_icons.setObjectName("vertical_icons")
|
||||
self.verticalLayout_6.addLayout(self.vertical_icons)
|
||||
self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2)
|
||||
self.verticalLayout_4.addWidget(self.scrollArea_2)
|
||||
self.toolBox.addItem(self.page_4, "")
|
||||
self.verticalLayout.addWidget(self.toolBox)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
self.verticalLayout.addWidget(self.buttonBox)
|
||||
self.label_5.setBuddy(self.db_name)
|
||||
self.label_12.setBuddy(self.save_path)
|
||||
self.label_11.setBuddy(self.db_path)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.toolBox.setCurrentIndex(2)
|
||||
self.email_settings.setCurrentIndex(0)
|
||||
self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.db_name.setText(_translate("Dialog", "sap.db"))
|
||||
self.label_5.setToolTip(_translate("Dialog", "<html><head/><body><p>Name der Datenbank, welche verwendet werden soll. <span style=\" font-weight:600;\">Muss</span> auf .db enden</p></body></html>"))
|
||||
self.label_5.setText(_translate("Dialog", "Datenbankname"))
|
||||
self.label_12.setToolTip(_translate("Dialog", "Pfad, an dem heruntergeladene Dateien gespeichert werden sollen"))
|
||||
self.label_12.setText(_translate("Dialog", "Temporäre Dateien"))
|
||||
self.label_11.setText(_translate("Dialog", "Datenbankpfad"))
|
||||
self.tb_set_save_path.setText(_translate("Dialog", "..."))
|
||||
self.tb_select_db.setText(_translate("Dialog", "..."))
|
||||
self.toolBox.setItemText(self.toolBox.indexOf(self.page_1), _translate("Dialog", "Datenbank"))
|
||||
self.label_4.setText(_translate("Dialog", "Bibliothekstyp"))
|
||||
self.label_3.setText(_translate("Dialog", "Bibliotheks-ID"))
|
||||
self.label_2.setText(_translate("Dialog", "API Key"))
|
||||
self.toolBox.setItemText(self.toolBox.indexOf(self.page_2), _translate("Dialog", "Zotero"))
|
||||
self.use_username_smtp_login.setStatusTip(_translate("Dialog", "Anklicken, wenn Nutzername benötigt wird, um sich beim Server anzumelden"))
|
||||
self.use_username_smtp_login.setText(_translate("Dialog", "Nutzername zum\n"
|
||||
" Anmelden verwenden"))
|
||||
self.label_6.setText(_translate("Dialog", "Port"))
|
||||
self.label_7.setText(_translate("Dialog", "Sender-eMail"))
|
||||
self.mail_username.setStatusTip(_translate("Dialog", "Kürzel, von der Hochschule vergeben, bsp: Aky547"))
|
||||
self.label.setText(_translate("Dialog", "SMTP-Server"))
|
||||
self.label_10.setText(_translate("Dialog", "Passwort"))
|
||||
self.label_8.setText(_translate("Dialog", "Nutzername"))
|
||||
self.label_13.setText(_translate("Dialog", "Printmail"))
|
||||
self.email_settings.setTabText(self.email_settings.indexOf(self.email_settingsPage1_2), _translate("Dialog", "Allgemeines"))
|
||||
self.bold.setText(_translate("Dialog", "Fett"))
|
||||
self.italic.setText(_translate("Dialog", "Kursiv"))
|
||||
self.underscore.setText(_translate("Dialog", "Unterstrichen"))
|
||||
self.font_size.setItemText(0, _translate("Dialog", "8"))
|
||||
self.font_size.setItemText(1, _translate("Dialog", "9"))
|
||||
self.font_size.setItemText(2, _translate("Dialog", "11"))
|
||||
self.font_size.setItemText(3, _translate("Dialog", "12"))
|
||||
self.font_size.setItemText(4, _translate("Dialog", "14"))
|
||||
self.font_size.setItemText(5, _translate("Dialog", "16"))
|
||||
self.font_size.setItemText(6, _translate("Dialog", "18"))
|
||||
self.font_size.setItemText(7, _translate("Dialog", "20"))
|
||||
self.font_size.setItemText(8, _translate("Dialog", "22"))
|
||||
self.font_size.setItemText(9, _translate("Dialog", "24"))
|
||||
self.font_size.setItemText(10, _translate("Dialog", "26"))
|
||||
self.font_size.setItemText(11, _translate("Dialog", "28"))
|
||||
self.font_size.setItemText(12, _translate("Dialog", "36"))
|
||||
self.font_size.setItemText(13, _translate("Dialog", "48"))
|
||||
self.font_size.setItemText(14, _translate("Dialog", "72"))
|
||||
self.debug.setText(_translate("Dialog", "Debug"))
|
||||
self.email_settings.setTabText(self.email_settings.indexOf(self.email_settingsPage2_2), _translate("Dialog", "Signatur"))
|
||||
self.toolBox.setItemText(self.toolBox.indexOf(self.page_3), _translate("Dialog", "e-Mail"))
|
||||
self.groupBox.setTitle(_translate("Dialog", "Farben"))
|
||||
self.toolBox.setItemText(self.toolBox.indexOf(self.page_4), _translate("Dialog", "Icons"))
|
||||
@@ -1,2 +1 @@
|
||||
from .Ui_mail_preview import Ui_eMailPreview as MailPreviewDialog
|
||||
from .Ui_newMailTemplateDesigner import Ui_Dialog as NewMailTemplateDesignerDialog
|
||||
from .newMailTemplateDesigner_ui import Ui_Dialog as NewMailTemplateDesignerDialog
|
||||
|
||||
138
src/ui/dialogs/dialog_sources/deletedialog.ui
Normal file
138
src/ui/dialogs/dialog_sources/deletedialog.ui
Normal file
@@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1001</width>
|
||||
<height>649</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Medium suchen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Titel/Signatursuche</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableWidget">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Apparat</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Signatur</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Titel</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Auflage</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>ISBN</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>ID</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="reset_btn">
|
||||
<property name="text">
|
||||
<string>Zurücksetzen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="delete_btn">
|
||||
<property name="text">
|
||||
<string>Löschen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancel_btn">
|
||||
<property name="text">
|
||||
<string>Abbrechen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
122
src/ui/dialogs/dialog_sources/deletedialog_ui.py
Normal file
122
src/ui/dialogs/dialog_sources/deletedialog_ui.py
Normal file
@@ -0,0 +1,122 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'deletedialog.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.9.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||
QMetaObject, QObject, QPoint, QRect,
|
||||
QSize, QTime, QUrl, Qt)
|
||||
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QApplication, QDialog, QHBoxLayout, QHeaderView,
|
||||
QLabel, QLineEdit, QPushButton, QSizePolicy,
|
||||
QSpacerItem, QTableWidget, QTableWidgetItem, QVBoxLayout,
|
||||
QWidget)
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
if not Dialog.objectName():
|
||||
Dialog.setObjectName(u"Dialog")
|
||||
Dialog.resize(1001, 649)
|
||||
self.verticalLayout = QVBoxLayout(Dialog)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.label = QLabel(Dialog)
|
||||
self.label.setObjectName(u"label")
|
||||
|
||||
self.horizontalLayout.addWidget(self.label)
|
||||
|
||||
self.lineEdit = QLineEdit(Dialog)
|
||||
self.lineEdit.setObjectName(u"lineEdit")
|
||||
|
||||
self.horizontalLayout.addWidget(self.lineEdit)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
|
||||
self.tableWidget = QTableWidget(Dialog)
|
||||
if (self.tableWidget.columnCount() < 7):
|
||||
self.tableWidget.setColumnCount(7)
|
||||
__qtablewidgetitem = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem)
|
||||
__qtablewidgetitem1 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1)
|
||||
__qtablewidgetitem2 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(2, __qtablewidgetitem2)
|
||||
__qtablewidgetitem3 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(3, __qtablewidgetitem3)
|
||||
__qtablewidgetitem4 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(4, __qtablewidgetitem4)
|
||||
__qtablewidgetitem5 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(5, __qtablewidgetitem5)
|
||||
__qtablewidgetitem6 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(6, __qtablewidgetitem6)
|
||||
self.tableWidget.setObjectName(u"tableWidget")
|
||||
self.tableWidget.setAlternatingRowColors(True)
|
||||
self.tableWidget.horizontalHeader().setStretchLastSection(True)
|
||||
|
||||
self.verticalLayout.addWidget(self.tableWidget)
|
||||
|
||||
self.horizontalLayout_2 = QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.horizontalSpacer_2 = QSpacerItem(20, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_2.addItem(self.horizontalSpacer_2)
|
||||
|
||||
self.reset_btn = QPushButton(Dialog)
|
||||
self.reset_btn.setObjectName(u"reset_btn")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.reset_btn)
|
||||
|
||||
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_2.addItem(self.horizontalSpacer)
|
||||
|
||||
self.delete_btn = QPushButton(Dialog)
|
||||
self.delete_btn.setObjectName(u"delete_btn")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.delete_btn)
|
||||
|
||||
self.cancel_btn = QPushButton(Dialog)
|
||||
self.cancel_btn.setObjectName(u"cancel_btn")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.cancel_btn)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
|
||||
QMetaObject.connectSlotsByName(Dialog)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Dialog", None))
|
||||
self.label.setText(QCoreApplication.translate("Dialog", u"Medium suchen", None))
|
||||
self.lineEdit.setPlaceholderText(QCoreApplication.translate("Dialog", u"Titel/Signatursuche", None))
|
||||
___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(1)
|
||||
___qtablewidgetitem.setText(QCoreApplication.translate("Dialog", u"Apparat", None));
|
||||
___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(2)
|
||||
___qtablewidgetitem1.setText(QCoreApplication.translate("Dialog", u"Signatur", None));
|
||||
___qtablewidgetitem2 = self.tableWidget.horizontalHeaderItem(3)
|
||||
___qtablewidgetitem2.setText(QCoreApplication.translate("Dialog", u"Titel", None));
|
||||
___qtablewidgetitem3 = self.tableWidget.horizontalHeaderItem(4)
|
||||
___qtablewidgetitem3.setText(QCoreApplication.translate("Dialog", u"Auflage", None));
|
||||
___qtablewidgetitem4 = self.tableWidget.horizontalHeaderItem(5)
|
||||
___qtablewidgetitem4.setText(QCoreApplication.translate("Dialog", u"ISBN", None));
|
||||
___qtablewidgetitem5 = self.tableWidget.horizontalHeaderItem(6)
|
||||
___qtablewidgetitem5.setText(QCoreApplication.translate("Dialog", u"ID", None));
|
||||
self.reset_btn.setText(QCoreApplication.translate("Dialog", u"Zur\u00fccksetzen", None))
|
||||
self.delete_btn.setText(QCoreApplication.translate("Dialog", u"L\u00f6schen", None))
|
||||
self.cancel_btn.setText(QCoreApplication.translate("Dialog", u"Abbrechen", None))
|
||||
# retranslateUi
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
<property name="windowTitle">
|
||||
<string>eMail Voransicht</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
<normaloff>../../../../../../icons/email.svg</normaloff>../../../../../../icons/email.svg</iconset>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
@@ -190,9 +186,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../../../resources.qrc"/>
|
||||
</resources>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
|
||||
@@ -1,115 +1,177 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\mail_preview.ui'
|
||||
#
|
||||
# Created by: PySide6 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.
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'mail_preview.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.9.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||
QMetaObject, QObject, QPoint, QRect,
|
||||
QSize, QTime, QUrl, Qt)
|
||||
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QAbstractButton, QApplication, QComboBox, QDialog,
|
||||
QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel,
|
||||
QLineEdit, QPushButton, QRadioButton, QSizePolicy,
|
||||
QSpacerItem, QTextEdit, QWidget)
|
||||
|
||||
class Ui_eMailPreview(object):
|
||||
def setupUi(self, eMailPreview):
|
||||
eMailPreview.setObjectName("eMailPreview")
|
||||
if not eMailPreview.objectName():
|
||||
eMailPreview.setObjectName(u"eMailPreview")
|
||||
eMailPreview.resize(700, 668)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap("c:\\Users\\aky547\\GitHub\\SemesterapparatsManager\\src\\ui\\dialogs\\dialog_sources\\../../../../../../icons/email.svg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
eMailPreview.setWindowIcon(icon)
|
||||
self.gridLayout_2 = QtWidgets.QGridLayout(eMailPreview)
|
||||
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||
self.gridLayout = QtWidgets.QGridLayout()
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.prof_name = QtWidgets.QLineEdit(parent=eMailPreview)
|
||||
self.prof_name.setObjectName("prof_name")
|
||||
self.gridLayout_2 = QGridLayout(eMailPreview)
|
||||
self.gridLayout_2.setObjectName(u"gridLayout_2")
|
||||
self.gridLayout = QGridLayout()
|
||||
self.gridLayout.setObjectName(u"gridLayout")
|
||||
self.prof_name = QLineEdit(eMailPreview)
|
||||
self.prof_name.setObjectName(u"prof_name")
|
||||
|
||||
self.gridLayout.addWidget(self.prof_name, 2, 2, 1, 1)
|
||||
self.newTemplate = QtWidgets.QPushButton(parent=eMailPreview)
|
||||
|
||||
self.newTemplate = QPushButton(eMailPreview)
|
||||
self.newTemplate.setObjectName(u"newTemplate")
|
||||
self.newTemplate.setAutoFillBackground(False)
|
||||
self.newTemplate.setText("")
|
||||
self.newTemplate.setIconSize(QtCore.QSize(24, 24))
|
||||
self.newTemplate.setIconSize(QSize(24, 24))
|
||||
self.newTemplate.setAutoDefault(True)
|
||||
self.newTemplate.setDefault(False)
|
||||
self.newTemplate.setFlat(False)
|
||||
self.newTemplate.setObjectName("newTemplate")
|
||||
|
||||
self.gridLayout.addWidget(self.newTemplate, 0, 3, 1, 1)
|
||||
self.comboBox = QtWidgets.QComboBox(parent=eMailPreview)
|
||||
self.comboBox.setObjectName("comboBox")
|
||||
|
||||
self.comboBox = QComboBox(eMailPreview)
|
||||
self.comboBox.setObjectName(u"comboBox")
|
||||
|
||||
self.gridLayout.addWidget(self.comboBox, 0, 2, 1, 1)
|
||||
self.mail_header = QtWidgets.QLineEdit(parent=eMailPreview)
|
||||
self.mail_header.setObjectName("mail_header")
|
||||
|
||||
self.mail_header = QLineEdit(eMailPreview)
|
||||
self.mail_header.setObjectName(u"mail_header")
|
||||
|
||||
self.gridLayout.addWidget(self.mail_header, 3, 2, 1, 1)
|
||||
self.label_6 = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label_6.setObjectName("label_6")
|
||||
|
||||
self.label_6 = QLabel(eMailPreview)
|
||||
self.label_6.setObjectName(u"label_6")
|
||||
|
||||
self.gridLayout.addWidget(self.label_6, 4, 0, 1, 1)
|
||||
self.mail_body = QtWidgets.QTextEdit(parent=eMailPreview)
|
||||
self.mail_body.setObjectName("mail_body")
|
||||
|
||||
self.mail_body = QTextEdit(eMailPreview)
|
||||
self.mail_body.setObjectName(u"mail_body")
|
||||
|
||||
self.gridLayout.addWidget(self.mail_body, 5, 2, 1, 1)
|
||||
self.label_2 = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label_2.setObjectName("label_2")
|
||||
|
||||
self.label_2 = QLabel(eMailPreview)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
|
||||
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
|
||||
self.mail_name = QtWidgets.QLineEdit(parent=eMailPreview)
|
||||
self.mail_name.setObjectName("mail_name")
|
||||
|
||||
self.mail_name = QLineEdit(eMailPreview)
|
||||
self.mail_name.setObjectName(u"mail_name")
|
||||
|
||||
self.gridLayout.addWidget(self.mail_name, 1, 2, 1, 1)
|
||||
self.label_5 = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label_5.setObjectName("label_5")
|
||||
|
||||
self.label_5 = QLabel(eMailPreview)
|
||||
self.label_5.setObjectName(u"label_5")
|
||||
|
||||
self.gridLayout.addWidget(self.label_5, 0, 0, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label_4.setObjectName("label_4")
|
||||
|
||||
self.label_4 = QLabel(eMailPreview)
|
||||
self.label_4.setObjectName(u"label_4")
|
||||
|
||||
self.gridLayout.addWidget(self.label_4, 3, 0, 1, 1)
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.gender_male = QtWidgets.QRadioButton(parent=eMailPreview)
|
||||
self.gender_male.setObjectName("gender_male")
|
||||
|
||||
self.horizontalLayout_3 = QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||
self.gender_male = QRadioButton(eMailPreview)
|
||||
self.gender_male.setObjectName(u"gender_male")
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.gender_male)
|
||||
self.gender_female = QtWidgets.QRadioButton(parent=eMailPreview)
|
||||
self.gender_female.setObjectName("gender_female")
|
||||
|
||||
self.gender_female = QRadioButton(eMailPreview)
|
||||
self.gender_female.setObjectName(u"gender_female")
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.gender_female)
|
||||
self.gender_non = QtWidgets.QRadioButton(parent=eMailPreview)
|
||||
self.gender_non.setObjectName("gender_non")
|
||||
|
||||
self.gender_non = QRadioButton(eMailPreview)
|
||||
self.gender_non.setObjectName(u"gender_non")
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.gender_non)
|
||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout_3.addItem(spacerItem)
|
||||
|
||||
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_3.addItem(self.horizontalSpacer)
|
||||
|
||||
|
||||
self.gridLayout.addLayout(self.horizontalLayout_3, 4, 2, 1, 1)
|
||||
self.label_3 = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label_3.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
|
||||
self.label_3.setObjectName("label_3")
|
||||
|
||||
self.label_3 = QLabel(eMailPreview)
|
||||
self.label_3.setObjectName(u"label_3")
|
||||
self.label_3.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
|
||||
|
||||
self.gridLayout.addWidget(self.label_3, 5, 0, 1, 1)
|
||||
self.label = QtWidgets.QLabel(parent=eMailPreview)
|
||||
self.label.setObjectName("label")
|
||||
|
||||
self.label = QLabel(eMailPreview)
|
||||
self.label.setObjectName(u"label")
|
||||
|
||||
self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem1)
|
||||
self.btn_okay = QtWidgets.QPushButton(parent=eMailPreview)
|
||||
self.btn_okay.setStatusTip("")
|
||||
self.btn_okay.setObjectName("btn_okay")
|
||||
|
||||
self.horizontalLayout_2 = QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_2.addItem(self.horizontalSpacer_2)
|
||||
|
||||
self.btn_okay = QPushButton(eMailPreview)
|
||||
self.btn_okay.setObjectName(u"btn_okay")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.btn_okay)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=eMailPreview)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel)
|
||||
|
||||
self.buttonBox = QDialogButtonBox(eMailPreview)
|
||||
self.buttonBox.setObjectName(u"buttonBox")
|
||||
self.buttonBox.setOrientation(Qt.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel)
|
||||
self.buttonBox.setCenterButtons(True)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.buttonBox)
|
||||
|
||||
|
||||
self.gridLayout.addLayout(self.horizontalLayout_2, 6, 2, 1, 1)
|
||||
|
||||
|
||||
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
|
||||
|
||||
|
||||
self.retranslateUi(eMailPreview)
|
||||
self.buttonBox.accepted.connect(eMailPreview.accept) # type: ignore
|
||||
self.buttonBox.rejected.connect(eMailPreview.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(eMailPreview)
|
||||
self.buttonBox.accepted.connect(eMailPreview.accept)
|
||||
self.buttonBox.rejected.connect(eMailPreview.reject)
|
||||
|
||||
self.newTemplate.setDefault(False)
|
||||
|
||||
|
||||
QMetaObject.connectSlotsByName(eMailPreview)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, eMailPreview):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
eMailPreview.setWindowTitle(_translate("eMailPreview", "eMail Voransicht"))
|
||||
self.label_6.setText(_translate("eMailPreview", "Anrede"))
|
||||
self.label_2.setText(_translate("eMailPreview", "Prof"))
|
||||
self.label_5.setText(_translate("eMailPreview", "Art"))
|
||||
self.label_4.setText(_translate("eMailPreview", "Betreff"))
|
||||
self.gender_male.setText(_translate("eMailPreview", "M"))
|
||||
self.gender_female.setText(_translate("eMailPreview", "W"))
|
||||
self.gender_non.setText(_translate("eMailPreview", "Divers"))
|
||||
self.label_3.setText(_translate("eMailPreview", "Mail"))
|
||||
self.label.setText(_translate("eMailPreview", "eMail"))
|
||||
self.btn_okay.setWhatsThis(_translate("eMailPreview", "test"))
|
||||
self.btn_okay.setText(_translate("eMailPreview", "Senden"))
|
||||
eMailPreview.setWindowTitle(QCoreApplication.translate("eMailPreview", u"eMail Voransicht", None))
|
||||
self.newTemplate.setText("")
|
||||
self.label_6.setText(QCoreApplication.translate("eMailPreview", u"Anrede", None))
|
||||
self.label_2.setText(QCoreApplication.translate("eMailPreview", u"Prof", None))
|
||||
self.label_5.setText(QCoreApplication.translate("eMailPreview", u"Art", None))
|
||||
self.label_4.setText(QCoreApplication.translate("eMailPreview", u"Betreff", None))
|
||||
self.gender_male.setText(QCoreApplication.translate("eMailPreview", u"M", None))
|
||||
self.gender_female.setText(QCoreApplication.translate("eMailPreview", u"W", None))
|
||||
self.gender_non.setText(QCoreApplication.translate("eMailPreview", u"Divers", None))
|
||||
self.label_3.setText(QCoreApplication.translate("eMailPreview", u"Mail", None))
|
||||
self.label.setText(QCoreApplication.translate("eMailPreview", u"eMail", None))
|
||||
#if QT_CONFIG(statustip)
|
||||
self.btn_okay.setStatusTip("")
|
||||
#endif // QT_CONFIG(statustip)
|
||||
#if QT_CONFIG(whatsthis)
|
||||
self.btn_okay.setWhatsThis(QCoreApplication.translate("eMailPreview", u"test", None))
|
||||
#endif // QT_CONFIG(whatsthis)
|
||||
self.btn_okay.setText(QCoreApplication.translate("eMailPreview", u"Senden", None))
|
||||
# retranslateUi
|
||||
|
||||
|
||||
@@ -16,157 +16,6 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="bold">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fett</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="italic">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Kursiv</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="underlined">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Unterstrichen</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFontComboBox" name="fontBox">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="fontSize">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>8</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>9</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>11</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>12</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>14</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>16</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>18</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>20</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>22</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>24</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>26</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>28</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>36</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>48</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>76</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
@@ -308,9 +157,7 @@
|
||||
<tabstop>testTemplate</tabstop>
|
||||
<tabstop>insertPlaceholder</tabstop>
|
||||
<tabstop>lineEdit</tabstop>
|
||||
<tabstop>fontSize</tabstop>
|
||||
<tabstop>placeholder_list</tabstop>
|
||||
<tabstop>fontBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -1,163 +1,140 @@
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\newMailTemplateDesigner.ui'
|
||||
#
|
||||
# Created by: PySide6 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.
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'newMailTemplateDesigner.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.9.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||
QMetaObject, QObject, QPoint, QRect,
|
||||
QSize, QTime, QUrl, Qt)
|
||||
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QAbstractButton, QApplication, QComboBox, QDialog,
|
||||
QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel,
|
||||
QLineEdit, QPushButton, QSizePolicy, QSpacerItem,
|
||||
QTextEdit, QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
if not Dialog.objectName():
|
||||
Dialog.setObjectName(u"Dialog")
|
||||
Dialog.resize(689, 572)
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.bold = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.bold.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.bold.setCheckable(True)
|
||||
self.bold.setObjectName("bold")
|
||||
self.horizontalLayout_2.addWidget(self.bold)
|
||||
self.italic = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.italic.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.italic.setCheckable(True)
|
||||
self.italic.setObjectName("italic")
|
||||
self.horizontalLayout_2.addWidget(self.italic)
|
||||
self.underlined = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.underlined.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.underlined.setCheckable(True)
|
||||
self.underlined.setObjectName("underlined")
|
||||
self.horizontalLayout_2.addWidget(self.underlined)
|
||||
self.fontBox = QtWidgets.QFontComboBox(parent=Dialog)
|
||||
self.fontBox.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.fontBox.setObjectName("fontBox")
|
||||
self.horizontalLayout_2.addWidget(self.fontBox)
|
||||
self.fontSize = QtWidgets.QComboBox(parent=Dialog)
|
||||
self.fontSize.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.fontSize.setObjectName("fontSize")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.fontSize.addItem("")
|
||||
self.horizontalLayout_2.addWidget(self.fontSize)
|
||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout_2.addItem(spacerItem)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_4)
|
||||
self.gridLayout = QtWidgets.QGridLayout()
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label.setObjectName("label")
|
||||
self.verticalLayout_2 = QVBoxLayout(Dialog)
|
||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||
self.verticalLayout = QVBoxLayout()
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.gridLayout = QGridLayout()
|
||||
self.gridLayout.setObjectName(u"gridLayout")
|
||||
self.label = QLabel(Dialog)
|
||||
self.label.setObjectName(u"label")
|
||||
|
||||
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
|
||||
self.placeholder_list = QtWidgets.QComboBox(parent=Dialog)
|
||||
self.placeholder_list.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.placeholder_list.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents)
|
||||
self.placeholder_list.setObjectName("placeholder_list")
|
||||
|
||||
self.placeholder_list = QComboBox(Dialog)
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.setObjectName(u"placeholder_list")
|
||||
self.placeholder_list.setFocusPolicy(Qt.NoFocus)
|
||||
self.placeholder_list.setSizeAdjustPolicy(QComboBox.AdjustToContents)
|
||||
|
||||
self.gridLayout.addWidget(self.placeholder_list, 1, 0, 1, 1)
|
||||
self.label_2 = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label_2.setObjectName("label_2")
|
||||
|
||||
self.label_2 = QLabel(Dialog)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
|
||||
self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1)
|
||||
self.lineEdit = QtWidgets.QLineEdit(parent=Dialog)
|
||||
|
||||
self.lineEdit = QLineEdit(Dialog)
|
||||
self.lineEdit.setObjectName(u"lineEdit")
|
||||
self.lineEdit.setEnabled(True)
|
||||
self.lineEdit.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.lineEdit.setFocusPolicy(Qt.NoFocus)
|
||||
self.lineEdit.setFrame(False)
|
||||
self.lineEdit.setReadOnly(True)
|
||||
self.lineEdit.setObjectName("lineEdit")
|
||||
|
||||
self.gridLayout.addWidget(self.lineEdit, 1, 1, 1, 1)
|
||||
self.insertPlaceholder = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.insertPlaceholder.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.insertPlaceholder.setObjectName("insertPlaceholder")
|
||||
|
||||
self.insertPlaceholder = QPushButton(Dialog)
|
||||
self.insertPlaceholder.setObjectName(u"insertPlaceholder")
|
||||
self.insertPlaceholder.setFocusPolicy(Qt.NoFocus)
|
||||
|
||||
self.gridLayout.addWidget(self.insertPlaceholder, 1, 2, 1, 1)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.gridLayout)
|
||||
self.label_3 = QtWidgets.QLabel(parent=Dialog)
|
||||
self.label_3.setObjectName("label_3")
|
||||
|
||||
self.label_3 = QLabel(Dialog)
|
||||
self.label_3.setObjectName(u"label_3")
|
||||
|
||||
self.verticalLayout.addWidget(self.label_3)
|
||||
self.subject = QtWidgets.QLineEdit(parent=Dialog)
|
||||
self.subject.setObjectName("subject")
|
||||
|
||||
self.subject = QLineEdit(Dialog)
|
||||
self.subject.setObjectName(u"subject")
|
||||
|
||||
self.verticalLayout.addWidget(self.subject)
|
||||
self.templateEdit = QtWidgets.QTextEdit(parent=Dialog)
|
||||
self.templateEdit.setObjectName("templateEdit")
|
||||
|
||||
self.templateEdit = QTextEdit(Dialog)
|
||||
self.templateEdit.setObjectName(u"templateEdit")
|
||||
|
||||
self.verticalLayout.addWidget(self.templateEdit)
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.testTemplate = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.testTemplate.setObjectName("testTemplate")
|
||||
|
||||
self.horizontalLayout_3 = QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||
self.testTemplate = QPushButton(Dialog)
|
||||
self.testTemplate.setObjectName(u"testTemplate")
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.testTemplate)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout_3.addItem(spacerItem1)
|
||||
|
||||
self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_3.addItem(self.horizontalSpacer_2)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_3)
|
||||
|
||||
|
||||
self.verticalLayout_2.addLayout(self.verticalLayout)
|
||||
self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Discard|QtWidgets.QDialogButtonBox.StandardButton.Save)
|
||||
self.buttonBox.setObjectName("buttonBox")
|
||||
|
||||
self.buttonBox = QDialogButtonBox(Dialog)
|
||||
self.buttonBox.setObjectName(u"buttonBox")
|
||||
self.buttonBox.setOrientation(Qt.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Discard|QDialogButtonBox.Save)
|
||||
|
||||
self.verticalLayout_2.addWidget(self.buttonBox)
|
||||
|
||||
QWidget.setTabOrder(self.subject, self.templateEdit)
|
||||
QWidget.setTabOrder(self.templateEdit, self.testTemplate)
|
||||
QWidget.setTabOrder(self.testTemplate, self.insertPlaceholder)
|
||||
QWidget.setTabOrder(self.insertPlaceholder, self.lineEdit)
|
||||
QWidget.setTabOrder(self.lineEdit, self.placeholder_list)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.fontSize.setCurrentIndex(1)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
Dialog.setTabOrder(self.subject, self.templateEdit)
|
||||
Dialog.setTabOrder(self.templateEdit, self.testTemplate)
|
||||
Dialog.setTabOrder(self.testTemplate, self.insertPlaceholder)
|
||||
Dialog.setTabOrder(self.insertPlaceholder, self.lineEdit)
|
||||
Dialog.setTabOrder(self.lineEdit, self.fontSize)
|
||||
Dialog.setTabOrder(self.fontSize, self.placeholder_list)
|
||||
Dialog.setTabOrder(self.placeholder_list, self.fontBox)
|
||||
|
||||
QMetaObject.connectSlotsByName(Dialog)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
self.bold.setText(_translate("Dialog", "Fett"))
|
||||
self.italic.setText(_translate("Dialog", "Kursiv"))
|
||||
self.underlined.setText(_translate("Dialog", "Unterstrichen"))
|
||||
self.fontSize.setItemText(0, _translate("Dialog", "8"))
|
||||
self.fontSize.setItemText(1, _translate("Dialog", "9"))
|
||||
self.fontSize.setItemText(2, _translate("Dialog", "11"))
|
||||
self.fontSize.setItemText(3, _translate("Dialog", "12"))
|
||||
self.fontSize.setItemText(4, _translate("Dialog", "14"))
|
||||
self.fontSize.setItemText(5, _translate("Dialog", "16"))
|
||||
self.fontSize.setItemText(6, _translate("Dialog", "18"))
|
||||
self.fontSize.setItemText(7, _translate("Dialog", "20"))
|
||||
self.fontSize.setItemText(8, _translate("Dialog", "22"))
|
||||
self.fontSize.setItemText(9, _translate("Dialog", "24"))
|
||||
self.fontSize.setItemText(10, _translate("Dialog", "26"))
|
||||
self.fontSize.setItemText(11, _translate("Dialog", "28"))
|
||||
self.fontSize.setItemText(12, _translate("Dialog", "36"))
|
||||
self.fontSize.setItemText(13, _translate("Dialog", "48"))
|
||||
self.fontSize.setItemText(14, _translate("Dialog", "76"))
|
||||
self.label.setText(_translate("Dialog", "Platzhalter"))
|
||||
self.placeholder_list.setItemText(0, _translate("Dialog", "«Anrede»"))
|
||||
self.placeholder_list.setItemText(1, _translate("Dialog", "«ApparatsName»"))
|
||||
self.placeholder_list.setItemText(2, _translate("Dialog", "«ApparatsFach»"))
|
||||
self.placeholder_list.setItemText(3, _translate("Dialog", "«ApparatsNummer»"))
|
||||
self.placeholder_list.setItemText(4, _translate("Dialog", "«DozentName»"))
|
||||
self.placeholder_list.setItemText(5, _translate("Dialog", "«Signatur»"))
|
||||
self.label_2.setText(_translate("Dialog", "Beschreibung"))
|
||||
self.insertPlaceholder.setText(_translate("Dialog", "An aktiver Position einfügen"))
|
||||
self.label_3.setText(_translate("Dialog", "Betreff"))
|
||||
self.testTemplate.setText(_translate("Dialog", "Template testen"))
|
||||
Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Dialog", None))
|
||||
self.label.setText(QCoreApplication.translate("Dialog", u"Platzhalter", None))
|
||||
self.placeholder_list.setItemText(0, QCoreApplication.translate("Dialog", u"\u00abAnrede\u00bb", None))
|
||||
self.placeholder_list.setItemText(1, QCoreApplication.translate("Dialog", u"\u00abApparatsName\u00bb", None))
|
||||
self.placeholder_list.setItemText(2, QCoreApplication.translate("Dialog", u"\u00abApparatsFach\u00bb", None))
|
||||
self.placeholder_list.setItemText(3, QCoreApplication.translate("Dialog", u"\u00abApparatsNummer\u00bb", None))
|
||||
self.placeholder_list.setItemText(4, QCoreApplication.translate("Dialog", u"\u00abDozentName\u00bb", None))
|
||||
self.placeholder_list.setItemText(5, QCoreApplication.translate("Dialog", u"\u00abSignatur\u00bb", None))
|
||||
|
||||
self.label_2.setText(QCoreApplication.translate("Dialog", u"Beschreibung", None))
|
||||
self.insertPlaceholder.setText(QCoreApplication.translate("Dialog", u"An aktiver Position einf\u00fcgen", None))
|
||||
self.label_3.setText(QCoreApplication.translate("Dialog", u"Betreff", None))
|
||||
self.testTemplate.setText(QCoreApplication.translate("Dialog", u"Template testen", None))
|
||||
# retranslateUi
|
||||
|
||||
|
||||
89
src/ui/dialogs/dialog_sources/order_neweditions.ui
Normal file
89
src/ui/dialogs/dialog_sources/order_neweditions.ui
Normal file
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>808</width>
|
||||
<height>629</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableWidget">
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Bestellen</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Signatur</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Titel</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>ISBN</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Autor</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Auflage</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Standort</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Link</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Bestellen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
92
src/ui/dialogs/dialog_sources/order_neweditions_ui.py
Normal file
92
src/ui/dialogs/dialog_sources/order_neweditions_ui.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'order_neweditions.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.9.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||
QMetaObject, QObject, QPoint, QRect,
|
||||
QSize, QTime, QUrl, Qt)
|
||||
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QApplication, QDialog, QHBoxLayout, QHeaderView,
|
||||
QPushButton, QSizePolicy, QSpacerItem, QTableWidget,
|
||||
QTableWidgetItem, QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
if not Dialog.objectName():
|
||||
Dialog.setObjectName(u"Dialog")
|
||||
Dialog.resize(808, 629)
|
||||
self.verticalLayout = QVBoxLayout(Dialog)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.tableWidget = QTableWidget(Dialog)
|
||||
if (self.tableWidget.columnCount() < 8):
|
||||
self.tableWidget.setColumnCount(8)
|
||||
__qtablewidgetitem = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem)
|
||||
__qtablewidgetitem1 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1)
|
||||
__qtablewidgetitem2 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(2, __qtablewidgetitem2)
|
||||
__qtablewidgetitem3 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(3, __qtablewidgetitem3)
|
||||
__qtablewidgetitem4 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(4, __qtablewidgetitem4)
|
||||
__qtablewidgetitem5 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(5, __qtablewidgetitem5)
|
||||
__qtablewidgetitem6 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(6, __qtablewidgetitem6)
|
||||
__qtablewidgetitem7 = QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(7, __qtablewidgetitem7)
|
||||
self.tableWidget.setObjectName(u"tableWidget")
|
||||
|
||||
self.verticalLayout.addWidget(self.tableWidget)
|
||||
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout.addItem(self.horizontalSpacer)
|
||||
|
||||
self.pushButton = QPushButton(Dialog)
|
||||
self.pushButton.setObjectName(u"pushButton")
|
||||
|
||||
self.horizontalLayout.addWidget(self.pushButton)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
|
||||
QMetaObject.connectSlotsByName(Dialog)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Dialog", None))
|
||||
___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0)
|
||||
___qtablewidgetitem.setText(QCoreApplication.translate("Dialog", u"Bestellen", None));
|
||||
___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1)
|
||||
___qtablewidgetitem1.setText(QCoreApplication.translate("Dialog", u"Signatur", None));
|
||||
___qtablewidgetitem2 = self.tableWidget.horizontalHeaderItem(2)
|
||||
___qtablewidgetitem2.setText(QCoreApplication.translate("Dialog", u"Titel", None));
|
||||
___qtablewidgetitem3 = self.tableWidget.horizontalHeaderItem(3)
|
||||
___qtablewidgetitem3.setText(QCoreApplication.translate("Dialog", u"ISBN", None));
|
||||
___qtablewidgetitem4 = self.tableWidget.horizontalHeaderItem(4)
|
||||
___qtablewidgetitem4.setText(QCoreApplication.translate("Dialog", u"Autor", None));
|
||||
___qtablewidgetitem5 = self.tableWidget.horizontalHeaderItem(5)
|
||||
___qtablewidgetitem5.setText(QCoreApplication.translate("Dialog", u"Auflage", None));
|
||||
___qtablewidgetitem6 = self.tableWidget.horizontalHeaderItem(6)
|
||||
___qtablewidgetitem6.setText(QCoreApplication.translate("Dialog", u"Standort", None));
|
||||
___qtablewidgetitem7 = self.tableWidget.horizontalHeaderItem(7)
|
||||
___qtablewidgetitem7.setText(QCoreApplication.translate("Dialog", u"Link", None));
|
||||
self.pushButton.setText(QCoreApplication.translate("Dialog", u"Bestellen", None))
|
||||
# retranslateUi
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from .dialog_sources.documentprint_ui import Ui_Dialog
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
from src import Icon
|
||||
|
||||
from src.utils.richtext import SemapSchilder, SemesterDocument
|
||||
from src.backend import Semester, Database
|
||||
from natsort import natsorted
|
||||
from PySide6 import QtWidgets
|
||||
|
||||
from src import Icon
|
||||
from src.backend import Database
|
||||
from src.logic import Semester
|
||||
from src.utils.richtext import SemapSchilder, SemesterDocument
|
||||
|
||||
from .dialog_sources.documentprint_ui import Ui_Dialog
|
||||
|
||||
|
||||
class DocumentPrintDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
@@ -23,25 +25,25 @@ class DocumentPrintDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
# Ensure the signal is connected only once
|
||||
try:
|
||||
self.pushButton_2.clicked.disconnect()
|
||||
except TypeError:
|
||||
except (TypeError, RuntimeWarning):
|
||||
pass # Signal was not connected before
|
||||
self.pushButton_2.clicked.connect(self.on_pushButton_2_clicked)
|
||||
|
||||
try:
|
||||
self.pushButton.clicked.disconnect()
|
||||
except TypeError:
|
||||
except (TypeError, RuntimeWarning):
|
||||
pass
|
||||
self.pushButton.clicked.connect(self.on_pushButton_clicked)
|
||||
|
||||
try:
|
||||
self.btn_load_current_apparats.clicked.disconnect()
|
||||
except TypeError:
|
||||
except (TypeError, RuntimeWarning):
|
||||
pass
|
||||
self.btn_load_current_apparats.clicked.connect(self.load_current_clicked)
|
||||
|
||||
try:
|
||||
self.manualCheck.clicked.disconnect()
|
||||
except TypeError:
|
||||
except (TypeError, RuntimeWarning):
|
||||
pass
|
||||
self.manualCheck.clicked.connect(self.manual_request)
|
||||
|
||||
@@ -108,10 +110,10 @@ class DocumentPrintDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
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)
|
||||
apps = natsorted(apps, key=lambda x: x.appnr, reverse=True)
|
||||
for app in apps:
|
||||
prof = self.db.getProfById(app[2])
|
||||
data = (app[4], f"{prof.lastname} ({app[1]})")
|
||||
prof = self.db.getProfById(app.prof_id)
|
||||
data = (app.appnr, f"{prof.lastname} ({app.name})")
|
||||
apparats.append(data)
|
||||
SemesterDocument(
|
||||
semester=self.semester.value,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
from .dialog_sources.Ui_elsa_add_table_entry import Ui_Dialog
|
||||
from src.logic.webrequest import WebRequest, BibTextTransformer
|
||||
from src import Icon
|
||||
from PySide6 import QtWidgets
|
||||
from src.transformers.transformers import DictToTable
|
||||
|
||||
from src import Icon
|
||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||
from src.logic.zotero import ZoteroController
|
||||
from src.transformers.transformers import DictToTable
|
||||
|
||||
from .dialog_sources.elsa_add_table_entry_ui import Ui_Dialog
|
||||
|
||||
zot = ZoteroController()
|
||||
dtt = DictToTable()
|
||||
@@ -174,7 +176,7 @@ class ElsaAddEntry(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.stackedWidget.setCurrentIndex(3)
|
||||
|
||||
def search(self, pages=None):
|
||||
print("searching")
|
||||
# #print("searching")
|
||||
param = self.searchIdent.text()
|
||||
web = WebRequest()
|
||||
web.get_ppn(param)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from .dialog_sources.Ui_elsa_generator_confirm import Ui_Dialog
|
||||
from PySide6 import QtWidgets
|
||||
|
||||
from .dialog_sources.elsa_generator_confirm_ui import Ui_Dialog
|
||||
|
||||
|
||||
class ElsaGenConfirm(QtWidgets.QDialog, Ui_Dialog):
|
||||
def __init__(self, parent=None, data=None):
|
||||
|
||||
@@ -70,7 +70,7 @@ class LoginDialog(Ui_Dialog):
|
||||
def login(self):
|
||||
username = self.lineEdit.text()
|
||||
password = self.lineEdit_2.text()
|
||||
# print(type(username), password)
|
||||
# #print(type(username), password)
|
||||
# Assuming 'Database' is a class to interact with your database
|
||||
|
||||
hashed_password = hashlib.sha256(password.encode()).hexdigest()
|
||||
|
||||
@@ -1,52 +1,72 @@
|
||||
import os
|
||||
import re
|
||||
import smtplib
|
||||
import sys
|
||||
|
||||
from PySide6 import QtWidgets
|
||||
|
||||
from src import Icon, settings as config
|
||||
from src import Icon
|
||||
from src import settings as config
|
||||
from src.shared.logging import log
|
||||
|
||||
|
||||
from .dialog_sources.Ui_mail_preview import Ui_eMailPreview as MailPreviewDialog
|
||||
from .dialog_sources.mail_preview_ui import Ui_eMailPreview as MailPreviewDialog
|
||||
from .mailTemplate import MailTemplateDialog
|
||||
import loguru
|
||||
import sys
|
||||
from src import LOG_DIR
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
CSS_RESET = "<style>html,body{margin:0;padding:0}p{margin:0}</style>"
|
||||
|
||||
empty_signature = """"""
|
||||
|
||||
|
||||
def _escape_braces_in_style(html: str) -> str:
|
||||
"""
|
||||
Double curly braces ONLY inside <style>...</style> blocks so that
|
||||
str.format(...) won't treat CSS as placeholders. The doubled braces
|
||||
will automatically render back to single braces after formatting.
|
||||
"""
|
||||
|
||||
empty_signature = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
def repl(m):
|
||||
start, css, end = m.group(1), m.group(2), m.group(3)
|
||||
css_escaped = css.replace("{", "{{").replace("}", "}}")
|
||||
return f"{start}{css_escaped}{end}"
|
||||
|
||||
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style
|
||||
type="text/css">
|
||||
return re.sub(
|
||||
r"(<style[^>]*>)(.*?)(</style>)",
|
||||
repl,
|
||||
html,
|
||||
flags=re.IGNORECASE | re.DOTALL,
|
||||
)
|
||||
|
||||
p, li { white-space: pre-wrap; }
|
||||
|
||||
hr { height: 1px; border-width: 0; }
|
||||
def _split_eml_headers_body(eml_text: str) -> tuple[str, str]:
|
||||
"""
|
||||
Return (headers, body_html). Robustly split on first blank line.
|
||||
Accepts lines that contain only spaces/tabs as the separator.
|
||||
"""
|
||||
|
||||
li.unchecked::marker { content: "\2610"; }
|
||||
|
||||
li.checked::marker { content: "\2612"; }
|
||||
|
||||
</style></head><body style=" font-family:''Segoe UI''; font-size:9pt; font-weight:400;
|
||||
font-style:normal;">
|
||||
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px;
|
||||
margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>
|
||||
"""
|
||||
parts = re.split(r"\r?\n[ \t]*\r?\n", eml_text, maxsplit=1)
|
||||
if len(parts) == 2:
|
||||
return parts[0], parts[1]
|
||||
# Fallback: try to split right after the Content-Transfer-Encoding line
|
||||
m = re.search(
|
||||
r"(?:^|\r?\n)Content-Transfer-Encoding:.*?(?:\r?\n)",
|
||||
eml_text,
|
||||
flags=re.I | re.S,
|
||||
)
|
||||
if m:
|
||||
return eml_text[: m.end()], eml_text[m.end() :]
|
||||
return "", eml_text # last resort: treat entire content as body
|
||||
|
||||
|
||||
class Mail_Dialog(QtWidgets.QDialog, MailPreviewDialog):
|
||||
def __init__(
|
||||
self,
|
||||
app_id,
|
||||
app_name,
|
||||
app_subject,
|
||||
prof_name,
|
||||
prof_mail,
|
||||
app_id=None,
|
||||
app_name=None,
|
||||
app_subject=None,
|
||||
prof_name=None,
|
||||
prof_mail=None,
|
||||
accepted_books=None,
|
||||
ordered_books=None,
|
||||
parent=None,
|
||||
default_mail="Information zum Semesterapparat",
|
||||
):
|
||||
@@ -58,6 +78,8 @@ class Mail_Dialog(QtWidgets.QDialog, MailPreviewDialog):
|
||||
self.appname = app_name
|
||||
self.subject = app_subject
|
||||
self.profname = prof_name
|
||||
self.books = accepted_books if accepted_books is not None else []
|
||||
self.ordered_books = ordered_books if ordered_books is not None else []
|
||||
self.mail_data = ""
|
||||
self.signature = self.determine_signature()
|
||||
self.prof_mail = prof_mail
|
||||
@@ -65,52 +87,29 @@ class Mail_Dialog(QtWidgets.QDialog, MailPreviewDialog):
|
||||
self.prof_name.setText(prof_name)
|
||||
self.mail_name.setText(self.prof_mail)
|
||||
self.load_mail_templates()
|
||||
# if none of the radio buttons is checked, disable the accept button of the dialog
|
||||
self.setWindowIcon(Icon("mail").icon)
|
||||
self.btn_okay.setEnabled(False)
|
||||
Icon("edit_note", self.newTemplate)
|
||||
self.newTemplate.clicked.connect(self.open_new_template)
|
||||
|
||||
if default_mail is not None:
|
||||
# get the nearest match to the default mail
|
||||
for i in range(self.comboBox.count()):
|
||||
if default_mail in self.comboBox.itemText(i):
|
||||
default_mail = self.comboBox.itemText(i)
|
||||
break
|
||||
self.comboBox.setCurrentText(default_mail)
|
||||
self.comboBox.currentIndexChanged.connect(self.set_mail)
|
||||
|
||||
# re-render when user changes greeting via radio buttons
|
||||
self.gender_female.clicked.connect(self.set_mail)
|
||||
self.gender_male.clicked.connect(self.set_mail)
|
||||
self.gender_non.clicked.connect(self.set_mail)
|
||||
|
||||
# reflect initial state (OK disabled until a greeting is chosen)
|
||||
self._update_ok_button()
|
||||
self.btn_okay.clicked.connect(self.createAndSendMail)
|
||||
|
||||
def open_new_template(self):
|
||||
log.info("Opening new template dialog")
|
||||
# TODO: implement new mail template dialog
|
||||
dialog = MailTemplateDialog()
|
||||
dialog.updateSignal.connect(self.load_mail_templates)
|
||||
dialog.exec()
|
||||
|
||||
pass
|
||||
|
||||
def determine_signature(self):
|
||||
if config.mail.signature is empty_signature or config.mail.signature == "":
|
||||
return """Mit freundlichen Grüßen
|
||||
Ihr Semesterapparatsteam
|
||||
Mail: semesterapparate@ph-freiburg.de
|
||||
Tel.: 0761/682-778 | 07617682-545"""
|
||||
else:
|
||||
return config.mail.signature
|
||||
|
||||
def load_mail_templates(self):
|
||||
# print("loading mail templates")
|
||||
log.info("Loading mail templates")
|
||||
mail_templates = os.listdir("mail_vorlagen")
|
||||
log.info(f"Mail templates: {mail_templates}")
|
||||
self.comboBox.clear()
|
||||
for template in mail_templates:
|
||||
self.comboBox.addItem(template)
|
||||
|
||||
# add these helpers inside Mail_Dialog
|
||||
def get_greeting(self):
|
||||
prof = self.profname.split(" ")[0]
|
||||
if self.gender_male.isChecked():
|
||||
@@ -124,37 +123,104 @@ Tel.: 0761/682-778 | 07617682-545"""
|
||||
name = f"{self.profname.split(' ')[1]} {self.profname.split(' ')[0]}"
|
||||
return f"Guten Tag {name},"
|
||||
|
||||
def _update_ok_button(self):
|
||||
checked = (
|
||||
self.gender_male.isChecked()
|
||||
or self.gender_female.isChecked()
|
||||
or self.gender_non.isChecked()
|
||||
)
|
||||
self.btn_okay.setEnabled(checked)
|
||||
|
||||
def _on_gender_toggled(self, checked: bool):
|
||||
# Only refresh when a button becomes checked
|
||||
if checked:
|
||||
self.set_mail()
|
||||
|
||||
def open_new_template(self):
|
||||
log.info("Opening new template dialog")
|
||||
dialog = MailTemplateDialog()
|
||||
dialog.updateSignal.connect(self.load_mail_templates)
|
||||
dialog.exec()
|
||||
|
||||
def determine_signature(self):
|
||||
# use equality, not identity
|
||||
if (
|
||||
config.mail.signature == empty_signature
|
||||
or config.mail.signature.strip() == ""
|
||||
):
|
||||
return """Mit freundlichen Grüßen
|
||||
Ihr Semesterapparatsteam
|
||||
Mail: semesterapparate@ph-freiburg.de
|
||||
Tel.: 0761/682-778 | 0761/682-545"""
|
||||
else:
|
||||
return config.mail.signature
|
||||
|
||||
def load_mail_templates(self):
|
||||
log.info("Loading mail templates")
|
||||
mail_templates = [
|
||||
f for f in os.listdir("mail_vorlagen") if f.lower().endswith(".eml")
|
||||
]
|
||||
log.info(f"Mail templates: {mail_templates}")
|
||||
self.comboBox.clear()
|
||||
for template in mail_templates:
|
||||
self.comboBox.addItem(template)
|
||||
|
||||
def set_mail(self):
|
||||
log.info("Setting mail")
|
||||
self._update_ok_button() # keep OK enabled state in sync
|
||||
|
||||
email_template = self.comboBox.currentText()
|
||||
if email_template == "":
|
||||
if not email_template:
|
||||
log.debug("No mail template selected")
|
||||
return
|
||||
|
||||
with open(f"mail_vorlagen/{email_template}", "r", encoding="utf-8") as f:
|
||||
mail_template = f.read()
|
||||
eml_text = f.read()
|
||||
|
||||
# header label for UI (unchanged)
|
||||
email_header = email_template.split(".eml")[0]
|
||||
if "{AppNr}" in email_template:
|
||||
email_header = email_template.split(".eml")[0]
|
||||
email_header = email_header.format(AppNr=self.appid, AppName=self.appname)
|
||||
self.mail_header.setText(email_header)
|
||||
self.mail_data = mail_template.split("<html>")[0]
|
||||
mail_html = mail_template.split("<html>")[1]
|
||||
mail_html = "<html>" + mail_html
|
||||
Appname = self.appname
|
||||
mail_html = mail_html.format(
|
||||
Profname=self.profname.split(" ")[0],
|
||||
Appname=Appname,
|
||||
|
||||
headers, body_html = _split_eml_headers_body(eml_text)
|
||||
body_html = _escape_braces_in_style(body_html)
|
||||
|
||||
# compute greeting from the current toggle selection
|
||||
greeting = self.get_greeting()
|
||||
|
||||
try:
|
||||
body_html = body_html.format(
|
||||
Profname=self.profname.split(" ")[
|
||||
0
|
||||
], # last name if your template uses {Profname}
|
||||
Appname=self.appname,
|
||||
AppNr=self.appid,
|
||||
AppSubject=self.subject,
|
||||
greeting=self.get_greeting(),
|
||||
greeting=greeting,
|
||||
signature=self.signature,
|
||||
newEditions="\n".join(
|
||||
[
|
||||
f"- {book.title} (ISBN: {','.join(book.isbn)}, Auflage: {book.edition if book.edition else 'nicht bekannt'}, In Bibliothek: {'ja' if getattr(book, 'signature', None) is not None and 'Handbibliothek' not in str(book.library_location) else 'nein'}, Typ: {book.get_book_type()}) Aktuelle Auflage: {book.old_book.edition if book.old_book and book.old_book.edition else 'nicht bekannt'}"
|
||||
for book in (self.books or [])
|
||||
]
|
||||
)
|
||||
if self.books
|
||||
else "keine neuen Auflagen gefunden",
|
||||
newEditionsOrdered="\n".join(
|
||||
[
|
||||
f" - {book.title}, ISBN: {','.join(book.isbn)}, Bibliotheksstandort : {book.library_location if book.library_location else 'N/A'}, Link: {book.link}"
|
||||
for book in (self.ordered_books or [])
|
||||
]
|
||||
),
|
||||
)
|
||||
except Exception as e:
|
||||
log.error(f"Template formatting failed: {e}")
|
||||
|
||||
self.mail_body.setHtml(mail_html)
|
||||
self.mail_body.setPlainText(body_html)
|
||||
|
||||
def createAndSendMail(self):
|
||||
log.info("Sending mail")
|
||||
import smtplib
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
@@ -168,31 +234,29 @@ Tel.: 0761/682-778 | 07617682-545"""
|
||||
message["From"] = sender_email
|
||||
message["To"] = self.prof_mail
|
||||
message["Subject"] = self.mail_header.text()
|
||||
# include a Fcc to the senders sent folder
|
||||
message["cc"] = "semesterapparate@ph-freiburg.de"
|
||||
message["Cc"] = "semesterapparate@ph-freiburg.de"
|
||||
|
||||
mail_body = self.mail_body.toPlainText()
|
||||
# strange_string = """p, li { white-space: pre-wrap; }
|
||||
# hr { height: 1px; border-width: 0; }
|
||||
# li.unchecked::marker { content: "\2610"; }
|
||||
# li.checked::marker { content: "\2612"; }
|
||||
# """
|
||||
# mail_body.replace(strange_string, "")
|
||||
message.attach(MIMEText(mail_body, "Plain", "utf-8"))
|
||||
|
||||
mail_body = self.mail_body.toHtml()
|
||||
message.attach(MIMEText(mail_body, "html"))
|
||||
mail = message.as_string()
|
||||
|
||||
with smtplib.SMTP_SSL(smtp_server, port) as server:
|
||||
server.connect(smtp_server, port)
|
||||
# server.connect(smtp_server, port)
|
||||
# server.auth(mechanism="PLAIN")
|
||||
server.connect(smtp_server, port) # not needed for SMTP_SSL
|
||||
if config.mail.use_user_name is True:
|
||||
# print(config["mail"]["user_name"])
|
||||
|
||||
server.login(config.mail.user_name, password)
|
||||
else:
|
||||
server.login(sender_email, password)
|
||||
server.sendmail(sender_email, tolist, mail)
|
||||
|
||||
# print("Mail sent")
|
||||
# end active process
|
||||
server.quit()
|
||||
pass
|
||||
log.info("Mail sent, closing connection to server and dialog")
|
||||
# close the dialog
|
||||
|
||||
self.accept()
|
||||
|
||||
|
||||
@@ -217,8 +281,6 @@ def launch_gui(
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
Dialog = QtWidgets.QDialog()
|
||||
ui = Mail_Dialog()
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from PySide6 import QtGui, QtWidgets, QtCore
|
||||
from loguru import logger as log
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
|
||||
from src import Icon
|
||||
|
||||
from .dialog_sources import NewMailTemplateDesignerDialog
|
||||
|
||||
import sys
|
||||
from loguru import logger as log
|
||||
|
||||
logger = log
|
||||
logger.remove()
|
||||
logger.add("logs/application.log", rotation="1 week", retention="1 month", enqueue=True)
|
||||
log.add(
|
||||
f"logs/mail.log",
|
||||
enqueue=True,
|
||||
)
|
||||
|
||||
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
||||
log.add("logs/mail.log", enqueue=True)
|
||||
logger.add(sys.stdout)
|
||||
|
||||
|
||||
@@ -28,35 +23,34 @@ class MailTemplateDialog(QtWidgets.QDialog, NewMailTemplateDesignerDialog):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.setWindowIcon(Icon("edit_note").icon)
|
||||
self.setWindowTitle("Mailvorlage erstellen")
|
||||
self.setWindowTitle("Mailvorlage erstellen (Text)")
|
||||
|
||||
# placeholders UI
|
||||
self.placeholder_list.addItem("")
|
||||
self.placeholder_list.setCurrentText("")
|
||||
self.insertPlaceholder.clicked.connect(self.insert_placeholder)
|
||||
self.placeholder_list.currentTextChanged.connect(self.updateDescription)
|
||||
self.bold.clicked.connect(self.setFontBold)
|
||||
self.italic.clicked.connect(self.setTextFontItalic)
|
||||
self.underlined.clicked.connect(self.setTextFontUnderline)
|
||||
self.testTemplate.clicked.connect(self.test_template)
|
||||
self.fontBox.currentFontChanged.connect(self.setCurrentFont)
|
||||
self.fontSize.currentTextChanged.connect(self.setFontSize)
|
||||
# buttonbox
|
||||
# save button
|
||||
|
||||
# formatting buttons (kept enabled for UX, but saving uses plain text)
|
||||
|
||||
# buttons
|
||||
self.buttonBox.button(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Save
|
||||
).clicked.connect(self.save_template)
|
||||
# discard button
|
||||
self.buttonBox.button(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Discard
|
||||
).clicked.connect(self.discard_changes)
|
||||
# cancel button
|
||||
self.buttonBox.button(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel
|
||||
).clicked.connect(self.closeNow)
|
||||
log.info("Mail template dialog setup complete")
|
||||
log.info("Mail template dialog (plaintext) setup complete")
|
||||
|
||||
def _normalize_newlines(self, s: str) -> str:
|
||||
# Convert any CRLF/CR to LF then back to CRLF for .eml
|
||||
s = s.replace("\\r\\n", "\\n").replace("\\r", "\\n")
|
||||
return s
|
||||
|
||||
def save_template(self):
|
||||
# print("save triggered")
|
||||
# create a dialog to ask for the name of the template
|
||||
dialog = QtWidgets.QInputDialog()
|
||||
dialog.setInputMode(QtWidgets.QInputDialog.InputMode.TextInput)
|
||||
dialog.setLabelText("Bitte geben Sie den Namen des Templates ein:")
|
||||
@@ -66,12 +60,11 @@ class MailTemplateDialog(QtWidgets.QDialog, NewMailTemplateDesignerDialog):
|
||||
dialog.setWindowIcon(Icon("save").icon)
|
||||
save = dialog.exec()
|
||||
template_name = dialog.textValue()
|
||||
log.info("Saving template")
|
||||
log.info("Saving plaintext template")
|
||||
if template_name != "" and save == 1:
|
||||
template = template_name + ".eml"
|
||||
if template in os.listdir("mail_vorlagen"):
|
||||
log.error("Template already exists")
|
||||
# warning dialog
|
||||
dialog = QtWidgets.QMessageBox()
|
||||
dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
||||
Icon("warning", dialog)
|
||||
@@ -87,36 +80,34 @@ class MailTemplateDialog(QtWidgets.QDialog, NewMailTemplateDesignerDialog):
|
||||
ret = dialog.exec()
|
||||
if ret == QtWidgets.QMessageBox.StandardButton.No:
|
||||
return
|
||||
mail = f"""Subject: {self.subject.text()}
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/html; charset="UTF-8"
|
||||
Content-Transfer-Encoding: 8bit
|
||||
{self.templateEdit.toHtml()}"""
|
||||
html_head = """<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
|
||||
# Build plaintext from editor
|
||||
body_text = self.templateEdit.toPlainText()
|
||||
body_text = self._normalize_newlines(body_text)
|
||||
|
||||
# Build EML headers and payload (headers, then one blank line, then body)
|
||||
mail_headers = f"""
|
||||
Subject: {self.subject.text()}
|
||||
"""
|
||||
mail_base = mail.split("<html>")[0]
|
||||
mail_body = mail.split("</head>")[1]
|
||||
mail = mail_base + html_head + mail_body
|
||||
mail = (
|
||||
mail.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace(""", '"')
|
||||
.replace("&", "&")
|
||||
)
|
||||
with open(f"mail_vorlagen/{template}", "w", encoding="utf-8") as f:
|
||||
f.write(mail)
|
||||
mail_body = body_text
|
||||
|
||||
eml = mail_headers + "\n\n" + mail_body
|
||||
eml = re.sub(r" +", " ", eml) # remove multiple spaces
|
||||
eml = re.sub(r"\n +", "\n", eml) #
|
||||
print(eml)
|
||||
|
||||
with open(
|
||||
f"mail_vorlagen/{template}", "w", encoding="utf-8", newline=""
|
||||
) as f:
|
||||
f.write(eml)
|
||||
|
||||
self.updateSignal.emit()
|
||||
self.close()
|
||||
log.success(f"Template {template} saved successfully")
|
||||
# log.success(f"Template {template} saved successfully (plaintext)")
|
||||
else:
|
||||
# warning dialog
|
||||
dialog = QtWidgets.QMessageBox()
|
||||
dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
||||
dialog.setWindowIcon(Icon("warning").icon)
|
||||
|
||||
dialog.setText("Bitte geben Sie einen Namen für das Template ein.")
|
||||
dialog.setWindowTitle("Fehler beim Speichern")
|
||||
dialog.exec()
|
||||
@@ -145,52 +136,20 @@ Content-Transfer-Encoding: 8bit
|
||||
self.close()
|
||||
|
||||
def updateDescription(self):
|
||||
# print("update triggered")
|
||||
# print(self.placeholder_list.currentText())
|
||||
placeholders = {
|
||||
"anrede": "Die Anrede beinhaltet sowohl Person als auch Sehr geehrte/r; dargestellt als: {greeting}",
|
||||
"anrede": "Die Anrede inkl. 'Sehr geehrte/r' oder neutral; dargestellt als: {greeting}",
|
||||
"apparatsfach": "Das Fach, in welchem der Apparat angelegt wurde; dargestellt als: {AppSubject}",
|
||||
"apparatsname": "Der Name des Apparats; dargestellt als: {Appname}",
|
||||
"apparatsnummer": "Die Nummer des Apparats; dargestellt als: {AppNr}",
|
||||
"dozentname": "Der Name des Dozenten / der Dozentin; dargestellt als: {Profname}",
|
||||
"signatur": "Die persönliche / allgemeine Signatur am ende der Mail; dargestellt als: {signature}",
|
||||
"signatur": "Ihre Signatur; dargestellt als: {signature}",
|
||||
"": " ",
|
||||
}
|
||||
for (
|
||||
key,
|
||||
item,
|
||||
) in placeholders.items():
|
||||
for key, item in placeholders.items():
|
||||
if key in self.placeholder_list.currentText().lower():
|
||||
self.lineEdit.setText(item)
|
||||
break
|
||||
|
||||
def setCurrentFont(self):
|
||||
font = self.fontBox.currentFont()
|
||||
font.setPointSize(int(self.fontSize.currentText()))
|
||||
self.templateEdit.setFont(font)
|
||||
|
||||
def setFontSize(self):
|
||||
size = self.fontSize.currentText()
|
||||
self.templateEdit.setFontPointSize(int(size))
|
||||
|
||||
def setFontBold(self):
|
||||
if self.bold.isChecked():
|
||||
self.templateEdit.setFontWeight(QtGui.QFont.Weight.Bold)
|
||||
else:
|
||||
self.templateEdit.setFontWeight(QtGui.QFont.Weight.Normal)
|
||||
|
||||
def setTextFontItalic(self):
|
||||
if self.italic.isChecked():
|
||||
self.templateEdit.setFontItalic(True)
|
||||
else:
|
||||
self.templateEdit.setFontItalic(False)
|
||||
|
||||
def setTextFontUnderline(self):
|
||||
if self.underlined.isChecked():
|
||||
self.templateEdit.setFontUnderline(True)
|
||||
else:
|
||||
self.templateEdit.setFontUnderline(False)
|
||||
|
||||
def test_template(self):
|
||||
placeholders = [
|
||||
"{greeting}",
|
||||
@@ -201,35 +160,29 @@ Content-Transfer-Encoding: 8bit
|
||||
"{signature}",
|
||||
]
|
||||
mail_subject = self.subject.text()
|
||||
mail_body = self.templateEdit.toHtml()
|
||||
mail_body = self.templateEdit.toPlainText()
|
||||
missing_body = []
|
||||
missing_subject = []
|
||||
try:
|
||||
assert placeholders[2] in mail_subject
|
||||
assert "{Appname}" in mail_subject or "{AppName}" in mail_subject
|
||||
except AssertionError:
|
||||
missing_subject.append(placeholders[2])
|
||||
# check if all placeholders are in the mail body
|
||||
missing_subject.append("{Appname}")
|
||||
for placeholder in placeholders:
|
||||
try:
|
||||
assert placeholder in mail_body
|
||||
except AssertionError:
|
||||
missing_body.append(placeholder)
|
||||
if missing_body != []:
|
||||
# warning dialog
|
||||
Icon("template_fail", self.testTemplate)
|
||||
if missing_body:
|
||||
dialog = QtWidgets.QMessageBox()
|
||||
dialog.setWindowIcon(Icon("warning").icon)
|
||||
|
||||
dialog.setText("Folgende Platzhalter fehlen im Template:")
|
||||
|
||||
missing = (
|
||||
"Betreff:\n"
|
||||
+ "\n".join(missing_subject)
|
||||
+ "\n\n"
|
||||
+ "\\n".join(missing_subject)
|
||||
+ "\\n\\n"
|
||||
+ "Mailtext:\n"
|
||||
+ "\n".join(missing_body)
|
||||
+ "\\n".join(missing_body)
|
||||
)
|
||||
|
||||
dialog.setInformativeText(f"{missing}")
|
||||
dialog.setWindowTitle("Fehlende Platzhalter")
|
||||
dialog.exec()
|
||||
@@ -238,21 +191,16 @@ Content-Transfer-Encoding: 8bit
|
||||
self.testTemplate.setText("✔")
|
||||
|
||||
def insert_placeholder(self):
|
||||
placeholder = {
|
||||
placeholder_map = {
|
||||
"anrede": "{greeting}",
|
||||
"apparatsfach": "{AppSubject}",
|
||||
"apparatsname": "{Appname}",
|
||||
"apparatsnummer": "{AppNr}",
|
||||
"dozentname": "{Profname}",
|
||||
"signatur": """<pre class="moz-signature" cols="72">--
|
||||
{signature}
|
||||
</pre>""",
|
||||
"signatur": "{signature}",
|
||||
}
|
||||
cursor = self.templateEdit.textCursor()
|
||||
for (
|
||||
key,
|
||||
item,
|
||||
) in placeholder.items():
|
||||
for key, item in placeholder_map.items():
|
||||
if key in self.placeholder_list.currentText().lower():
|
||||
cursor.insertText(item)
|
||||
break
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from .dialog_sources.medianadder_ui import Ui_Dialog
|
||||
from src import Icon
|
||||
|
||||
from .dialog_sources.medianadder_ui import Ui_Dialog
|
||||
|
||||
|
||||
class MedienAdder(QtWidgets.QDialog, Ui_Dialog):
|
||||
def __init__(self, parent=None):
|
||||
@@ -78,4 +79,4 @@ def launch_gui():
|
||||
dialog = MedienAdder()
|
||||
dialog.show()
|
||||
app.exec()
|
||||
# print(dialog.mode, dialog.data, dialog.result())
|
||||
# #print(dialog.mode, dialog.data, dialog.result())
|
||||
|
||||
109
src/ui/dialogs/newEdition.py
Normal file
109
src/ui/dialogs/newEdition.py
Normal file
@@ -0,0 +1,109 @@
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
|
||||
from src.backend.catalogue import Catalogue
|
||||
from src.backend.database import Database
|
||||
from src.ui.dialogs.mail import Mail_Dialog
|
||||
|
||||
from .dialog_sources.order_neweditions_ui import Ui_Dialog
|
||||
|
||||
|
||||
class NewEditionDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
def __init__(self, app_id, mail_data):
|
||||
super().__init__()
|
||||
self.setupUi(self)
|
||||
self.setWindowTitle("Neuauflagen bestellen")
|
||||
self.db = Database()
|
||||
self.catalogue = Catalogue()
|
||||
self.app_id = app_id
|
||||
self.mail_data = mail_data
|
||||
self.books = self.db.getNewEditionsByApparat(app_id)
|
||||
self.pushButton.clicked.connect(self.orderBooks)
|
||||
self.populateTable()
|
||||
|
||||
def populateTable(self):
|
||||
for book in self.books:
|
||||
# signature not required here; using book.signature directly when needed
|
||||
link_label = QtWidgets.QLabel()
|
||||
link = (
|
||||
book.link
|
||||
if book.link != "SWB"
|
||||
else f"https://www.lehmanns.de/search/quick?mediatype_id=&q={book.isbn[0]}"
|
||||
)
|
||||
|
||||
link_label.setText(f'<a href="{link}">Lehmanns.de</a>')
|
||||
link_label.setOpenExternalLinks(True)
|
||||
link_label.setTextFormat(QtCore.Qt.TextFormat.RichText)
|
||||
link_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||
link_label.setTextInteractionFlags(
|
||||
QtCore.Qt.TextInteractionFlag.TextBrowserInteraction
|
||||
)
|
||||
self.tableWidget.insertRow(0)
|
||||
# first column is checkbox for ordering
|
||||
checkbox = QtWidgets.QCheckBox()
|
||||
checked = True if not book.signature else False
|
||||
if book.library_location is not None:
|
||||
checked = True if "hb" in book.library_location else checked
|
||||
checkbox.setChecked(checked)
|
||||
self.tableWidget.setCellWidget(0, 0, checkbox)
|
||||
self.tableWidget.setItem(
|
||||
0,
|
||||
1,
|
||||
QtWidgets.QTableWidgetItem(
|
||||
str(book.signature if book.signature else "")
|
||||
),
|
||||
)
|
||||
self.tableWidget.setItem(0, 2, QtWidgets.QTableWidgetItem(book.title))
|
||||
isbn = (
|
||||
book.isbn[0]
|
||||
if isinstance(book.isbn, list) and len(book.isbn) > 0
|
||||
else book.isbn
|
||||
)
|
||||
self.tableWidget.setItem(0, 3, QtWidgets.QTableWidgetItem(isbn))
|
||||
self.tableWidget.setItem(0, 4, QtWidgets.QTableWidgetItem(book.author))
|
||||
self.tableWidget.setItem(0, 5, QtWidgets.QTableWidgetItem(book.edition))
|
||||
self.tableWidget.setItem(
|
||||
0, 6, QtWidgets.QTableWidgetItem(book.library_location)
|
||||
)
|
||||
self.tableWidget.setCellWidget(0, 7, link_label)
|
||||
|
||||
def orderBooks(self):
|
||||
ordered_books = []
|
||||
for row in range(self.tableWidget.rowCount()):
|
||||
checkbox = self.tableWidget.cellWidget(row, 0)
|
||||
if checkbox.isChecked():
|
||||
book = self.books[row]
|
||||
book.link = (
|
||||
book.link
|
||||
if book.link != "SWB"
|
||||
else f"https://www.lehmanns.de/search/quick?mediatype_id=&q={book.isbn[0]}"
|
||||
)
|
||||
# print(f"Bestelle Neuauflage für {book.title} ({book.edition})")
|
||||
book.isbn = [book.isbn] if isinstance(book.isbn, str) else book.isbn
|
||||
ordered_books.append(book)
|
||||
# Process ordered_books as needed
|
||||
editionId = self.db.getNewEditionId(book)
|
||||
self.db.setOrdered(editionId)
|
||||
|
||||
self.mail = Mail_Dialog(
|
||||
app_id=self.mail_data.get("app_nr"),
|
||||
prof_name=self.mail_data.get("prof_name"),
|
||||
prof_mail=self.mail_data.get("prof_mail"),
|
||||
app_name=self.mail_data.get("app_name"),
|
||||
default_mail="Bitte um Bestellung",
|
||||
ordered_books=ordered_books,
|
||||
)
|
||||
self.mail.exec()
|
||||
|
||||
|
||||
def launch():
|
||||
app = QtWidgets.QApplication.instance()
|
||||
if app is None:
|
||||
app = QtWidgets.QApplication([])
|
||||
mail_data = {
|
||||
"prof_name": "Erwerbung",
|
||||
"prof_mail": "carola.wiestler@ph-freiburg.de",
|
||||
"app_nr": 131,
|
||||
"app_name": "Beratung und Teamarbeit",
|
||||
}
|
||||
dialog = NewEditionDialog(app_id=18, mail_data=mail_data)
|
||||
dialog.exec()
|
||||
@@ -1,17 +1,19 @@
|
||||
import sys
|
||||
|
||||
import loguru
|
||||
from PySide6 import QtWidgets
|
||||
|
||||
from src import LOG_DIR
|
||||
from src.backend import AutoAdder
|
||||
|
||||
|
||||
from .dialog_sources.parsed_titles_ui import Ui_Form
|
||||
import loguru
|
||||
import sys
|
||||
from src import LOG_DIR
|
||||
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
|
||||
class ParsedTitles(QtWidgets.QWidget, Ui_Form):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
@@ -32,7 +34,7 @@ class ParsedTitles(QtWidgets.QWidget, Ui_Form):
|
||||
self.progressBar.setValue(value)
|
||||
|
||||
def worker_quit(self):
|
||||
# print("Terminating worker")
|
||||
# #print("Terminating worker")
|
||||
self.worker.terminate()
|
||||
self.worker.quit()
|
||||
self.worker.deleteLater()
|
||||
@@ -66,7 +68,7 @@ class ParsedTitles(QtWidgets.QWidget, Ui_Form):
|
||||
def determine_progress(self, signal):
|
||||
# check length of listWidget
|
||||
length = self.listWidget.count()
|
||||
# print(f"Length of listWidget: {length}")
|
||||
# #print(f"Length of listWidget: {length}")
|
||||
if length == 0:
|
||||
log.info("AutoAdder finished")
|
||||
self.buttonBox.accepted.emit()
|
||||
|
||||
@@ -10,7 +10,7 @@ from PySide6 import QtWidgets
|
||||
|
||||
from src import Icon
|
||||
|
||||
from .dialog_sources.Ui_confirm_extend import Ui_extend_confirm
|
||||
from .dialog_sources.confirm_extend_ui import Ui_extend_confirm
|
||||
|
||||
|
||||
class ConfirmDialog(QtWidgets.QDialog, Ui_extend_confirm):
|
||||
|
||||
94
src/ui/dialogs/progress.py
Normal file
94
src/ui/dialogs/progress.py
Normal file
@@ -0,0 +1,94 @@
|
||||
from typing import List, Optional, Set, Union
|
||||
import re
|
||||
|
||||
from PySide6 import QtCore
|
||||
from PySide6.QtWidgets import QDialog, QPushButton, QVBoxLayout
|
||||
from qtqdm import Qtqdm, QtqdmProgressBar
|
||||
|
||||
from src.logic import BookData
|
||||
from src.logic.lehmannsapi import LehmannsClient
|
||||
from src.logic.SRU import SWB
|
||||
|
||||
|
||||
class CheckThread(QtCore.QThread):
|
||||
updateSignal = QtCore.Signal()
|
||||
total_entries_signal = QtCore.Signal(int)
|
||||
resultSignal = QtCore.Signal(str)
|
||||
etaSignal = QtCore.Signal(dict)
|
||||
startSignal = QtCore.Signal()
|
||||
progress = QtCore.Signal(dict)
|
||||
|
||||
def __init__(self, items: list[BookData]):
|
||||
super().__init__()
|
||||
self.items: List[BookData] = items
|
||||
self.results: List[tuple[BookData, List[BookData]]] = []
|
||||
self.total_entries_signal.emit(len(items))
|
||||
|
||||
def _update_callback(self, status):
|
||||
self.progress.emit(status)
|
||||
|
||||
def run(self):
|
||||
tqdm_object = Qtqdm(
|
||||
range(len(self.items)),
|
||||
unit_scale=True,
|
||||
)
|
||||
swb_client = SWB()
|
||||
for i in tqdm_object:
|
||||
book: BookData = self.items[i]
|
||||
author = (
|
||||
book.author.split(";")[0].replace(" ", "")
|
||||
if ";" in book.author
|
||||
else book.author.replace(" ", "")
|
||||
)
|
||||
# title = book.title.split(":")[0].strip()
|
||||
# remove trailing punctuation from title
|
||||
title = book.title.rstrip(" .:,;!?")
|
||||
response: list[BookData] = []
|
||||
response = swb_client.getBooks(
|
||||
[
|
||||
"pica.bib=20735",
|
||||
f"pica.tit={title.split(':')[0].strip()}",
|
||||
# f"pica.per={author}",
|
||||
]
|
||||
)
|
||||
|
||||
# in the response, remove the entry with the same ppn
|
||||
response = [entry for entry in response if entry.ppn != book.ppn]
|
||||
for respo in response:
|
||||
respo.link = "SWB"
|
||||
with LehmannsClient() as client:
|
||||
results = client.search_by_title(title, strict=True)
|
||||
client.enrich_pages(results)
|
||||
if not results:
|
||||
continue
|
||||
for res in results:
|
||||
response.append(BookData().from_LehmannsSearchResult(res))
|
||||
if response == []:
|
||||
continue
|
||||
# check results if lehmanns has a result with the same isbn from the results of swb. if so, if we have a signature, remove, else keep
|
||||
response = filter_prefer_swb(response)
|
||||
|
||||
result = (book, response)
|
||||
|
||||
self.results.append(result)
|
||||
|
||||
|
||||
class ProgressDialog(QDialog):
|
||||
def __init__(self, items: list):
|
||||
super().__init__()
|
||||
self.setWindowTitle("Progress")
|
||||
self.setModal(True)
|
||||
layout = QVBoxLayout(self)
|
||||
self.progress_bar = QtqdmProgressBar(self)
|
||||
self.items: List[BookData] = items
|
||||
layout.addWidget(self.progress_bar)
|
||||
self.results: List[tuple[BookData, List[BookData]]] = []
|
||||
self.start_button = QPushButton("Start Progress", self)
|
||||
self.start_button.hide()
|
||||
self.start_button.clicked.connect(self.start)
|
||||
layout.addWidget(self.start_button)
|
||||
|
||||
def start(self):
|
||||
# Start logic is managed externally; keep method for UI wiring
|
||||
pass
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
from src import Icon, settings
|
||||
from .dialog_sources.settings_ui import Ui_Dialog as _settings
|
||||
from src.ui.widgets.iconLine import IconWidget
|
||||
import loguru
|
||||
import sys
|
||||
from src import LOG_DIR
|
||||
|
||||
import loguru
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from src import LOG_DIR, Icon, settings
|
||||
from src.ui.widgets.iconLine import IconWidget
|
||||
|
||||
from .dialog_sources.settings_ui import Ui_Dialog as _settings
|
||||
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
@@ -12,7 +14,6 @@ log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
|
||||
|
||||
base = """'<!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
|
||||
@@ -220,7 +221,7 @@ class Settings(QtWidgets.QDialog, _settings):
|
||||
|
||||
for color in self.get_colors():
|
||||
settings.icons.colors[color] = self.get_colors()[color]
|
||||
# print(color)
|
||||
# #print(color)
|
||||
for icon in self.get_icons():
|
||||
settings.icons.icons[icon] = self.get_icons()[icon]
|
||||
|
||||
@@ -245,7 +246,7 @@ class Settings(QtWidgets.QDialog, _settings):
|
||||
|
||||
def save(self):
|
||||
config = self.return_data()
|
||||
# #print(config)
|
||||
# ##print(config)
|
||||
|
||||
config.save()
|
||||
self.accept()
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
@@ -68,6 +71,9 @@
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="focusPolicy">
|
||||
@@ -244,227 +250,38 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>180</y>
|
||||
<width>1261</width>
|
||||
<height>511</height>
|
||||
<width>1412</width>
|
||||
<height>531</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="4" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item row="11" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkbx_show_del_media">
|
||||
<property name="text">
|
||||
<string>gel. Medien anzeigen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_reserve">
|
||||
<property name="text">
|
||||
<string>im Apparat?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="add_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_info">
|
||||
<property name="text">
|
||||
<string>Medien werden hinzugefügt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="progress_label">
|
||||
<property name="text">
|
||||
<string>Medium x/y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="avail_layout"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Medien werden geprüft</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="avail_status">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="automation_add_selected_books">
|
||||
<property name="text">
|
||||
<string>Ausgewählte als verfügbar markieren</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QTableWidget" name="tableWidget_apparat_media">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1259</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<widget class="QPushButton" name="add_medium">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Buchtitel</string>
|
||||
<string>Medien hinzufügen</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Es kann sein, dass der Buchtitel leer ist, dies kommt vor, wenn der Titel nicht passend formatiert ist</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Signatur</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Auflage</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Autor</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>im Apparat?</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Diese Angabe ist nicht zuverlässig. Ist das ❌ vorhanden, kann das Medium im Apparat sein, aber aufgrund eines Bugs nicht gefunden worden</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Vorgemerkt</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Link</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
@@ -545,7 +362,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragOnly</enum>
|
||||
<enum>QAbstractItemView::NoDragDrop</enum>
|
||||
</property>
|
||||
<property name="defaultDropAction">
|
||||
<enum>Qt::LinkAction</enum>
|
||||
@@ -1058,23 +875,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="prof_id_adis">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>9</pointsize>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="inputMethodHints">
|
||||
<set>Qt::ImhPreferNumbers</set>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="font">
|
||||
<font>
|
||||
@@ -1090,7 +891,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="apparat_id_adis">
|
||||
<property name="font">
|
||||
<font>
|
||||
@@ -1103,6 +904,22 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="prof_id_adis">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>9</pointsize>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="inputMethodHints">
|
||||
<set>Qt::ImhPreferNumbers</set>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="sem_year">
|
||||
@@ -1532,7 +1349,7 @@
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Die Apparatsdetails werden aus dem Dokument gelesen und eingetragen
|
||||
Einige Angaben müssen ggf angepasst werden</string>
|
||||
Die gewünschten Medien werden automatisch in die Medienliste eingetragen, evtl. unvollständig, da eBooks nicht erfasst werden könnenEinige Angaben müssen ggf angepasst werden</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Daten aus Dokument
|
||||
@@ -1544,23 +1361,247 @@ Einige Angaben müssen ggf angepasst werden</string>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="add_medium">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>3</x>
|
||||
<y>695</y>
|
||||
<width>121</width>
|
||||
<item row="4" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkbx_show_only_wit_neweditions">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>WIP - Broken</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Nur Titel mit Neuauflagen anzeigen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_reserve">
|
||||
<property name="toolTip">
|
||||
<string>Dieser Knopf prüft alle Werke, die mit einem roten X vermerkt sind. Sollten diese inzwischen im Apparat sein, wird dies aktualisiert</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Medien mit ❌ im Apparat?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="add_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_info">
|
||||
<property name="text">
|
||||
<string>Medien werden hinzugefügt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="progress_label">
|
||||
<property name="text">
|
||||
<string>Medium x/y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="avail_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Medien werden geprüft</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_eta">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="avail_status">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="automation_add_selected_books">
|
||||
<property name="text">
|
||||
<string>Ausgewählte als verfügbar markieren</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QTableWidget" name="tableWidget_apparat_media">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1259</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Medien hinzufügen</string>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Buchtitel</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Es kann sein, dass der Buchtitel leer ist, dies kommt vor, wenn der Titel nicht passend formatiert ist</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Signatur</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Auflage</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Autor</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>im Apparat?</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Diese Angabe ist nicht zuverlässig. Ist das ❌ vorhanden, kann das Medium im Apparat sein, aber aufgrund eines Bugs nicht gefunden worden</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Vorgemerkt</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Link</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="search_statistics">
|
||||
@@ -1577,28 +1618,31 @@ Einige Angaben müssen ggf angepasst werden</string>
|
||||
<attribute name="title">
|
||||
<string>Admin</string>
|
||||
</attribute>
|
||||
<widget class="QLabel" name="label_21">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>30</y>
|
||||
<width>47</width>
|
||||
<height>22</height>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1251</width>
|
||||
<height>711</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>Aktion:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="select_action_box">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>60</x>
|
||||
<y>30</y>
|
||||
<width>181</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Nutzer anlegen</string>
|
||||
@@ -1614,16 +1658,15 @@ Einige Angaben müssen ggf angepasst werden</string>
|
||||
<string>Lehrperson bearbeiten</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="admin_action">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>70</y>
|
||||
<width>570</width>
|
||||
<height>291</height>
|
||||
</rect>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Medien bearbeiten</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QGroupBox" name="admin_action">
|
||||
<property name="font">
|
||||
<font>
|
||||
<bold>false</bold>
|
||||
@@ -1639,6 +1682,9 @@ Einige Angaben müssen ggf angepasst werden</string>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -1918,6 +1964,7 @@ Einige Angaben müssen ggf angepasst werden</string>
|
||||
<string>Bearbeiten</string>
|
||||
</property>
|
||||
<addaction name="actionEinstellungen"/>
|
||||
<addaction name="actionMedien_loeschen"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
@@ -1972,6 +2019,11 @@ Einige Angaben müssen ggf angepasst werden</string>
|
||||
<string>F1</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMedien_loeschen">
|
||||
<property name="text">
|
||||
<string>Medien löschen</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>drpdwn_app_nr</tabstop>
|
||||
@@ -1990,10 +2042,8 @@ Einige Angaben müssen ggf angepasst werden</string>
|
||||
<tabstop>check_send_mail</tabstop>
|
||||
<tabstop>btn_apparat_save</tabstop>
|
||||
<tabstop>btn_apparat_apply</tabstop>
|
||||
<tabstop>chkbx_show_del_media</tabstop>
|
||||
<tabstop>btn_reserve</tabstop>
|
||||
<tabstop>select_action_box</tabstop>
|
||||
<tabstop>prof_id_adis</tabstop>
|
||||
<tabstop>apparat_id_adis</tabstop>
|
||||
<tabstop>automation_add_selected_books</tabstop>
|
||||
<tabstop>saveandcreate</tabstop>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'semesterapparat_ui.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.9.1
|
||||
## Created by: Qt User Interface Compiler version 6.9.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
@@ -20,9 +20,9 @@ from PySide6.QtWidgets import (QAbstractItemView, QAbstractScrollArea, QApplicat
|
||||
QComboBox, QFormLayout, QFrame, QGridLayout,
|
||||
QGroupBox, QHBoxLayout, QHeaderView, QLabel,
|
||||
QLineEdit, QMainWindow, QMenu, QMenuBar,
|
||||
QPushButton, QSizePolicy, QSpacerItem, QStatusBar,
|
||||
QTabWidget, QTableWidget, QTableWidgetItem, QToolButton,
|
||||
QVBoxLayout, QWidget)
|
||||
QProgressBar, QPushButton, QSizePolicy, QSpacerItem,
|
||||
QStatusBar, QTabWidget, QTableWidget, QTableWidgetItem,
|
||||
QToolButton, QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
@@ -54,10 +54,13 @@ class Ui_MainWindow(object):
|
||||
self.actionAbout.setMenuRole(QAction.AboutRole)
|
||||
self.actionDokumentation = QAction(MainWindow)
|
||||
self.actionDokumentation.setObjectName(u"actionDokumentation")
|
||||
self.actionMedien_loeschen = QAction(MainWindow)
|
||||
self.actionMedien_loeschen.setObjectName(u"actionMedien_loeschen")
|
||||
self.centralwidget = QWidget(MainWindow)
|
||||
self.centralwidget.setObjectName(u"centralwidget")
|
||||
sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
|
||||
self.centralwidget.setSizePolicy(sizePolicy)
|
||||
self.centralwidget.setAcceptDrops(True)
|
||||
self.verticalLayoutWidget = QWidget(self.centralwidget)
|
||||
self.verticalLayoutWidget.setObjectName(u"verticalLayoutWidget")
|
||||
self.verticalLayoutWidget.setGeometry(QRect(0, 0, 1271, 751))
|
||||
@@ -68,6 +71,7 @@ class Ui_MainWindow(object):
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.gridLayout = QGridLayout()
|
||||
self.gridLayout.setObjectName(u"gridLayout")
|
||||
self.gridLayout.setContentsMargins(3, -1, -1, -1)
|
||||
self.tabWidget = QTabWidget(self.verticalLayoutWidget)
|
||||
self.tabWidget.setObjectName(u"tabWidget")
|
||||
self.tabWidget.setFocusPolicy(Qt.NoFocus)
|
||||
@@ -155,124 +159,24 @@ class Ui_MainWindow(object):
|
||||
self.gridLayoutWidget_2 = QWidget(self.createApparat)
|
||||
self.gridLayoutWidget_2.setObjectName(u"gridLayoutWidget_2")
|
||||
self.gridLayoutWidget_2.setEnabled(True)
|
||||
self.gridLayoutWidget_2.setGeometry(QRect(0, 180, 1261, 511))
|
||||
self.gridLayoutWidget_2.setGeometry(QRect(0, 180, 1412, 531))
|
||||
self.gridLayout_2 = QGridLayout(self.gridLayoutWidget_2)
|
||||
self.gridLayout_2.setObjectName(u"gridLayout_2")
|
||||
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_5 = QHBoxLayout()
|
||||
self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
|
||||
self.horizontalSpacer = QSpacerItem(20, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout_3 = QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||
self.add_medium = QPushButton(self.gridLayoutWidget_2)
|
||||
self.add_medium.setObjectName(u"add_medium")
|
||||
self.add_medium.setFocusPolicy(Qt.NoFocus)
|
||||
|
||||
self.horizontalLayout_5.addItem(self.horizontalSpacer)
|
||||
self.horizontalLayout_3.addWidget(self.add_medium)
|
||||
|
||||
self.chkbx_show_del_media = QCheckBox(self.gridLayoutWidget_2)
|
||||
self.chkbx_show_del_media.setObjectName(u"chkbx_show_del_media")
|
||||
self.horizontalSpacer_5 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.chkbx_show_del_media)
|
||||
|
||||
self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_5.addItem(self.horizontalSpacer_3)
|
||||
|
||||
self.btn_reserve = QPushButton(self.gridLayoutWidget_2)
|
||||
self.btn_reserve.setObjectName(u"btn_reserve")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.btn_reserve)
|
||||
|
||||
self.add_layout = QHBoxLayout()
|
||||
self.add_layout.setObjectName(u"add_layout")
|
||||
self.label_info = QLabel(self.gridLayoutWidget_2)
|
||||
self.label_info.setObjectName(u"label_info")
|
||||
|
||||
self.add_layout.addWidget(self.label_info)
|
||||
|
||||
self.line_2 = QFrame(self.gridLayoutWidget_2)
|
||||
self.line_2.setObjectName(u"line_2")
|
||||
self.line_2.setFrameShape(QFrame.Shape.VLine)
|
||||
self.line_2.setFrameShadow(QFrame.Shadow.Sunken)
|
||||
|
||||
self.add_layout.addWidget(self.line_2)
|
||||
|
||||
self.progress_label = QLabel(self.gridLayoutWidget_2)
|
||||
self.progress_label.setObjectName(u"progress_label")
|
||||
|
||||
self.add_layout.addWidget(self.progress_label)
|
||||
self.horizontalLayout_3.addItem(self.horizontalSpacer_5)
|
||||
|
||||
|
||||
self.horizontalLayout_5.addLayout(self.add_layout)
|
||||
|
||||
self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_5.addItem(self.horizontalSpacer_4)
|
||||
|
||||
self.avail_layout = QHBoxLayout()
|
||||
self.avail_layout.setObjectName(u"avail_layout")
|
||||
|
||||
self.horizontalLayout_5.addLayout(self.avail_layout)
|
||||
|
||||
self.label_20 = QLabel(self.gridLayoutWidget_2)
|
||||
self.label_20.setObjectName(u"label_20")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.label_20)
|
||||
|
||||
self.line_3 = QFrame(self.gridLayoutWidget_2)
|
||||
self.line_3.setObjectName(u"line_3")
|
||||
self.line_3.setFrameShape(QFrame.Shape.VLine)
|
||||
self.line_3.setFrameShadow(QFrame.Shadow.Sunken)
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.line_3)
|
||||
|
||||
self.avail_status = QLabel(self.gridLayoutWidget_2)
|
||||
self.avail_status.setObjectName(u"avail_status")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.avail_status)
|
||||
|
||||
self.automation_add_selected_books = QPushButton(self.gridLayoutWidget_2)
|
||||
self.automation_add_selected_books.setObjectName(u"automation_add_selected_books")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.automation_add_selected_books)
|
||||
|
||||
self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_5.addItem(self.horizontalSpacer_2)
|
||||
|
||||
|
||||
self.gridLayout_2.addLayout(self.horizontalLayout_5, 4, 0, 1, 1)
|
||||
|
||||
self.tableWidget_apparat_media = QTableWidget(self.gridLayoutWidget_2)
|
||||
if (self.tableWidget_apparat_media.columnCount() < 7):
|
||||
self.tableWidget_apparat_media.setColumnCount(7)
|
||||
__qtablewidgetitem6 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(0, __qtablewidgetitem6)
|
||||
__qtablewidgetitem7 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(1, __qtablewidgetitem7)
|
||||
__qtablewidgetitem8 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(2, __qtablewidgetitem8)
|
||||
__qtablewidgetitem9 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(3, __qtablewidgetitem9)
|
||||
__qtablewidgetitem10 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(4, __qtablewidgetitem10)
|
||||
__qtablewidgetitem11 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(5, __qtablewidgetitem11)
|
||||
__qtablewidgetitem12 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(6, __qtablewidgetitem12)
|
||||
self.tableWidget_apparat_media.setObjectName(u"tableWidget_apparat_media")
|
||||
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Expanding)
|
||||
sizePolicy2.setHorizontalStretch(0)
|
||||
sizePolicy2.setVerticalStretch(0)
|
||||
sizePolicy2.setHeightForWidth(self.tableWidget_apparat_media.sizePolicy().hasHeightForWidth())
|
||||
self.tableWidget_apparat_media.setSizePolicy(sizePolicy2)
|
||||
self.tableWidget_apparat_media.setMinimumSize(QSize(1259, 0))
|
||||
self.tableWidget_apparat_media.setFocusPolicy(Qt.NoFocus)
|
||||
self.tableWidget_apparat_media.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.tableWidget_apparat_media.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
|
||||
self.tableWidget_apparat_media.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||
self.tableWidget_apparat_media.setAlternatingRowColors(True)
|
||||
self.tableWidget_apparat_media.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.tableWidget_apparat_media.setSortingEnabled(True)
|
||||
self.tableWidget_apparat_media.horizontalHeader().setCascadingSectionResizes(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.tableWidget_apparat_media, 9, 0, 1, 1)
|
||||
self.gridLayout_2.addLayout(self.horizontalLayout_3, 11, 0, 1, 1)
|
||||
|
||||
self.label = QLabel(self.gridLayoutWidget_2)
|
||||
self.label.setObjectName(u"label")
|
||||
@@ -286,11 +190,11 @@ class Ui_MainWindow(object):
|
||||
self.app_group_box = QGroupBox(self.gridLayoutWidget_2)
|
||||
self.app_group_box.setObjectName(u"app_group_box")
|
||||
self.app_group_box.setEnabled(True)
|
||||
sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
|
||||
sizePolicy3.setHorizontalStretch(0)
|
||||
sizePolicy3.setVerticalStretch(0)
|
||||
sizePolicy3.setHeightForWidth(self.app_group_box.sizePolicy().hasHeightForWidth())
|
||||
self.app_group_box.setSizePolicy(sizePolicy3)
|
||||
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
|
||||
sizePolicy2.setHorizontalStretch(0)
|
||||
sizePolicy2.setVerticalStretch(0)
|
||||
sizePolicy2.setHeightForWidth(self.app_group_box.sizePolicy().hasHeightForWidth())
|
||||
self.app_group_box.setSizePolicy(sizePolicy2)
|
||||
self.app_group_box.setMinimumSize(QSize(0, 210))
|
||||
font1 = QFont()
|
||||
font1.setPointSize(12)
|
||||
@@ -305,17 +209,17 @@ class Ui_MainWindow(object):
|
||||
font2 = QFont()
|
||||
font2.setFamilies([u"Arial"])
|
||||
font2.setPointSize(8)
|
||||
__qtablewidgetitem13 = QTableWidgetItem()
|
||||
__qtablewidgetitem13.setFont(font2);
|
||||
self.document_list.setHorizontalHeaderItem(0, __qtablewidgetitem13)
|
||||
__qtablewidgetitem14 = QTableWidgetItem()
|
||||
__qtablewidgetitem14.setFont(font2);
|
||||
self.document_list.setHorizontalHeaderItem(1, __qtablewidgetitem14)
|
||||
__qtablewidgetitem15 = QTableWidgetItem()
|
||||
__qtablewidgetitem15.setFont(font2);
|
||||
self.document_list.setHorizontalHeaderItem(2, __qtablewidgetitem15)
|
||||
__qtablewidgetitem16 = QTableWidgetItem()
|
||||
self.document_list.setHorizontalHeaderItem(3, __qtablewidgetitem16)
|
||||
__qtablewidgetitem6 = QTableWidgetItem()
|
||||
__qtablewidgetitem6.setFont(font2);
|
||||
self.document_list.setHorizontalHeaderItem(0, __qtablewidgetitem6)
|
||||
__qtablewidgetitem7 = QTableWidgetItem()
|
||||
__qtablewidgetitem7.setFont(font2);
|
||||
self.document_list.setHorizontalHeaderItem(1, __qtablewidgetitem7)
|
||||
__qtablewidgetitem8 = QTableWidgetItem()
|
||||
__qtablewidgetitem8.setFont(font2);
|
||||
self.document_list.setHorizontalHeaderItem(2, __qtablewidgetitem8)
|
||||
__qtablewidgetitem9 = QTableWidgetItem()
|
||||
self.document_list.setHorizontalHeaderItem(3, __qtablewidgetitem9)
|
||||
self.document_list.setObjectName(u"document_list")
|
||||
self.document_list.setGeometry(QRect(780, 20, 321, 181))
|
||||
font3 = QFont()
|
||||
@@ -328,7 +232,7 @@ class Ui_MainWindow(object):
|
||||
self.document_list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
self.document_list.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
|
||||
self.document_list.setDragEnabled(True)
|
||||
self.document_list.setDragDropMode(QAbstractItemView.DragOnly)
|
||||
self.document_list.setDragDropMode(QAbstractItemView.NoDragDrop)
|
||||
self.document_list.setDefaultDropAction(Qt.LinkAction)
|
||||
self.document_list.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
self.document_list.horizontalHeader().setDefaultSectionSize(107)
|
||||
@@ -453,25 +357,25 @@ class Ui_MainWindow(object):
|
||||
|
||||
self.formLayout_3.setWidget(0, QFormLayout.ItemRole.LabelRole, self.label_12)
|
||||
|
||||
self.prof_id_adis = QLineEdit(self.formLayoutWidget_2)
|
||||
self.prof_id_adis.setObjectName(u"prof_id_adis")
|
||||
self.prof_id_adis.setFont(font4)
|
||||
self.prof_id_adis.setInputMethodHints(Qt.ImhPreferNumbers)
|
||||
|
||||
self.formLayout_3.setWidget(0, QFormLayout.ItemRole.FieldRole, self.prof_id_adis)
|
||||
|
||||
self.label_13 = QLabel(self.formLayoutWidget_2)
|
||||
self.label_13.setObjectName(u"label_13")
|
||||
self.label_13.setFont(font4)
|
||||
|
||||
self.formLayout_3.setWidget(1, QFormLayout.ItemRole.LabelRole, self.label_13)
|
||||
self.formLayout_3.setWidget(2, QFormLayout.ItemRole.LabelRole, self.label_13)
|
||||
|
||||
self.apparat_id_adis = QLineEdit(self.formLayoutWidget_2)
|
||||
self.apparat_id_adis.setObjectName(u"apparat_id_adis")
|
||||
self.apparat_id_adis.setFont(font4)
|
||||
self.apparat_id_adis.setInputMethodHints(Qt.ImhPreferNumbers)
|
||||
|
||||
self.formLayout_3.setWidget(1, QFormLayout.ItemRole.FieldRole, self.apparat_id_adis)
|
||||
self.formLayout_3.setWidget(2, QFormLayout.ItemRole.FieldRole, self.apparat_id_adis)
|
||||
|
||||
self.prof_id_adis = QLineEdit(self.formLayoutWidget_2)
|
||||
self.prof_id_adis.setObjectName(u"prof_id_adis")
|
||||
self.prof_id_adis.setFont(font4)
|
||||
self.prof_id_adis.setInputMethodHints(Qt.ImhPreferNumbers)
|
||||
|
||||
self.formLayout_3.setWidget(1, QFormLayout.ItemRole.FieldRole, self.prof_id_adis)
|
||||
|
||||
self.sem_year = QLineEdit(self.app_group_box)
|
||||
self.sem_year.setObjectName(u"sem_year")
|
||||
@@ -558,35 +462,35 @@ class Ui_MainWindow(object):
|
||||
self.verticalLayout_8.setContentsMargins(0, 0, 0, 0)
|
||||
self.btn_add_document = QPushButton(self.verticalLayoutWidget_3)
|
||||
self.btn_add_document.setObjectName(u"btn_add_document")
|
||||
sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.MinimumExpanding)
|
||||
sizePolicy4.setHorizontalStretch(0)
|
||||
sizePolicy4.setVerticalStretch(0)
|
||||
sizePolicy4.setHeightForWidth(self.btn_add_document.sizePolicy().hasHeightForWidth())
|
||||
self.btn_add_document.setSizePolicy(sizePolicy4)
|
||||
sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.MinimumExpanding)
|
||||
sizePolicy3.setHorizontalStretch(0)
|
||||
sizePolicy3.setVerticalStretch(0)
|
||||
sizePolicy3.setHeightForWidth(self.btn_add_document.sizePolicy().hasHeightForWidth())
|
||||
self.btn_add_document.setSizePolicy(sizePolicy3)
|
||||
self.btn_add_document.setFont(font4)
|
||||
|
||||
self.verticalLayout_8.addWidget(self.btn_add_document)
|
||||
|
||||
self.btn_open_document = QPushButton(self.verticalLayoutWidget_3)
|
||||
self.btn_open_document.setObjectName(u"btn_open_document")
|
||||
sizePolicy4.setHeightForWidth(self.btn_open_document.sizePolicy().hasHeightForWidth())
|
||||
self.btn_open_document.setSizePolicy(sizePolicy4)
|
||||
sizePolicy3.setHeightForWidth(self.btn_open_document.sizePolicy().hasHeightForWidth())
|
||||
self.btn_open_document.setSizePolicy(sizePolicy3)
|
||||
self.btn_open_document.setFont(font4)
|
||||
|
||||
self.verticalLayout_8.addWidget(self.btn_open_document)
|
||||
|
||||
self.check_file = QPushButton(self.verticalLayoutWidget_3)
|
||||
self.check_file.setObjectName(u"check_file")
|
||||
sizePolicy4.setHeightForWidth(self.check_file.sizePolicy().hasHeightForWidth())
|
||||
self.check_file.setSizePolicy(sizePolicy4)
|
||||
sizePolicy3.setHeightForWidth(self.check_file.sizePolicy().hasHeightForWidth())
|
||||
self.check_file.setSizePolicy(sizePolicy3)
|
||||
self.check_file.setFont(font4)
|
||||
|
||||
self.verticalLayout_8.addWidget(self.check_file)
|
||||
|
||||
self.btn_extract_data_from_document = QPushButton(self.verticalLayoutWidget_3)
|
||||
self.btn_extract_data_from_document.setObjectName(u"btn_extract_data_from_document")
|
||||
sizePolicy4.setHeightForWidth(self.btn_extract_data_from_document.sizePolicy().hasHeightForWidth())
|
||||
self.btn_extract_data_from_document.setSizePolicy(sizePolicy4)
|
||||
sizePolicy3.setHeightForWidth(self.btn_extract_data_from_document.sizePolicy().hasHeightForWidth())
|
||||
self.btn_extract_data_from_document.setSizePolicy(sizePolicy3)
|
||||
self.btn_extract_data_from_document.setFont(font4)
|
||||
|
||||
self.verticalLayout_8.addWidget(self.btn_extract_data_from_document)
|
||||
@@ -598,10 +502,133 @@ class Ui_MainWindow(object):
|
||||
|
||||
self.gridLayout_2.addWidget(self.app_group_box, 1, 0, 1, 1)
|
||||
|
||||
self.add_medium = QPushButton(self.createApparat)
|
||||
self.add_medium.setObjectName(u"add_medium")
|
||||
self.add_medium.setGeometry(QRect(3, 695, 121, 20))
|
||||
self.add_medium.setFocusPolicy(Qt.NoFocus)
|
||||
self.horizontalLayout_5 = QHBoxLayout()
|
||||
self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
|
||||
self.horizontalSpacer = QSpacerItem(20, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_5.addItem(self.horizontalSpacer)
|
||||
|
||||
self.chkbx_show_only_wit_neweditions = QCheckBox(self.gridLayoutWidget_2)
|
||||
self.chkbx_show_only_wit_neweditions.setObjectName(u"chkbx_show_only_wit_neweditions")
|
||||
self.chkbx_show_only_wit_neweditions.setEnabled(False)
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.chkbx_show_only_wit_neweditions)
|
||||
|
||||
self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_5.addItem(self.horizontalSpacer_3)
|
||||
|
||||
self.btn_reserve = QPushButton(self.gridLayoutWidget_2)
|
||||
self.btn_reserve.setObjectName(u"btn_reserve")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.btn_reserve)
|
||||
|
||||
self.add_layout = QHBoxLayout()
|
||||
self.add_layout.setObjectName(u"add_layout")
|
||||
self.label_info = QLabel(self.gridLayoutWidget_2)
|
||||
self.label_info.setObjectName(u"label_info")
|
||||
|
||||
self.add_layout.addWidget(self.label_info)
|
||||
|
||||
self.line_2 = QFrame(self.gridLayoutWidget_2)
|
||||
self.line_2.setObjectName(u"line_2")
|
||||
self.line_2.setFrameShape(QFrame.Shape.VLine)
|
||||
self.line_2.setFrameShadow(QFrame.Shadow.Sunken)
|
||||
|
||||
self.add_layout.addWidget(self.line_2)
|
||||
|
||||
self.progress_label = QLabel(self.gridLayoutWidget_2)
|
||||
self.progress_label.setObjectName(u"progress_label")
|
||||
|
||||
self.add_layout.addWidget(self.progress_label)
|
||||
|
||||
|
||||
self.horizontalLayout_5.addLayout(self.add_layout)
|
||||
|
||||
self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_5.addItem(self.horizontalSpacer_4)
|
||||
|
||||
self.avail_layout = QHBoxLayout()
|
||||
self.avail_layout.setObjectName(u"avail_layout")
|
||||
self.label_20 = QLabel(self.gridLayoutWidget_2)
|
||||
self.label_20.setObjectName(u"label_20")
|
||||
|
||||
self.avail_layout.addWidget(self.label_20)
|
||||
|
||||
self.progressBar = QProgressBar(self.gridLayoutWidget_2)
|
||||
self.progressBar.setObjectName(u"progressBar")
|
||||
self.progressBar.setValue(24)
|
||||
|
||||
self.avail_layout.addWidget(self.progressBar)
|
||||
|
||||
self.label_eta = QLabel(self.gridLayoutWidget_2)
|
||||
self.label_eta.setObjectName(u"label_eta")
|
||||
|
||||
self.avail_layout.addWidget(self.label_eta)
|
||||
|
||||
|
||||
self.horizontalLayout_5.addLayout(self.avail_layout)
|
||||
|
||||
self.line_3 = QFrame(self.gridLayoutWidget_2)
|
||||
self.line_3.setObjectName(u"line_3")
|
||||
self.line_3.setFrameShape(QFrame.Shape.VLine)
|
||||
self.line_3.setFrameShadow(QFrame.Shadow.Sunken)
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.line_3)
|
||||
|
||||
self.avail_status = QLabel(self.gridLayoutWidget_2)
|
||||
self.avail_status.setObjectName(u"avail_status")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.avail_status)
|
||||
|
||||
self.automation_add_selected_books = QPushButton(self.gridLayoutWidget_2)
|
||||
self.automation_add_selected_books.setObjectName(u"automation_add_selected_books")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.automation_add_selected_books)
|
||||
|
||||
self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_5.addItem(self.horizontalSpacer_2)
|
||||
|
||||
|
||||
self.gridLayout_2.addLayout(self.horizontalLayout_5, 4, 0, 1, 1)
|
||||
|
||||
self.tableWidget_apparat_media = QTableWidget(self.gridLayoutWidget_2)
|
||||
if (self.tableWidget_apparat_media.columnCount() < 7):
|
||||
self.tableWidget_apparat_media.setColumnCount(7)
|
||||
__qtablewidgetitem10 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(0, __qtablewidgetitem10)
|
||||
__qtablewidgetitem11 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(1, __qtablewidgetitem11)
|
||||
__qtablewidgetitem12 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(2, __qtablewidgetitem12)
|
||||
__qtablewidgetitem13 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(3, __qtablewidgetitem13)
|
||||
__qtablewidgetitem14 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(4, __qtablewidgetitem14)
|
||||
__qtablewidgetitem15 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(5, __qtablewidgetitem15)
|
||||
__qtablewidgetitem16 = QTableWidgetItem()
|
||||
self.tableWidget_apparat_media.setHorizontalHeaderItem(6, __qtablewidgetitem16)
|
||||
self.tableWidget_apparat_media.setObjectName(u"tableWidget_apparat_media")
|
||||
sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Expanding)
|
||||
sizePolicy4.setHorizontalStretch(0)
|
||||
sizePolicy4.setVerticalStretch(0)
|
||||
sizePolicy4.setHeightForWidth(self.tableWidget_apparat_media.sizePolicy().hasHeightForWidth())
|
||||
self.tableWidget_apparat_media.setSizePolicy(sizePolicy4)
|
||||
self.tableWidget_apparat_media.setMinimumSize(QSize(1259, 0))
|
||||
self.tableWidget_apparat_media.setFocusPolicy(Qt.NoFocus)
|
||||
self.tableWidget_apparat_media.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.tableWidget_apparat_media.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
|
||||
self.tableWidget_apparat_media.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||
self.tableWidget_apparat_media.setAlternatingRowColors(True)
|
||||
self.tableWidget_apparat_media.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.tableWidget_apparat_media.setSortingEnabled(True)
|
||||
self.tableWidget_apparat_media.horizontalHeader().setCascadingSectionResizes(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.tableWidget_apparat_media, 9, 0, 1, 1)
|
||||
|
||||
self.tabWidget.addTab(self.createApparat, "")
|
||||
self.search_statistics = QWidget()
|
||||
self.search_statistics.setObjectName(u"search_statistics")
|
||||
@@ -611,23 +638,37 @@ class Ui_MainWindow(object):
|
||||
self.tabWidget.addTab(self.elsatab, "")
|
||||
self.admin = QWidget()
|
||||
self.admin.setObjectName(u"admin")
|
||||
self.label_21 = QLabel(self.admin)
|
||||
self.frame = QFrame(self.admin)
|
||||
self.frame.setObjectName(u"frame")
|
||||
self.frame.setGeometry(QRect(0, 0, 1251, 711))
|
||||
self.frame.setFrameShape(QFrame.StyledPanel)
|
||||
self.frame.setFrameShadow(QFrame.Raised)
|
||||
self.formLayout_2 = QFormLayout(self.frame)
|
||||
self.formLayout_2.setObjectName(u"formLayout_2")
|
||||
self.label_21 = QLabel(self.frame)
|
||||
self.label_21.setObjectName(u"label_21")
|
||||
self.label_21.setGeometry(QRect(10, 30, 47, 22))
|
||||
self.select_action_box = QComboBox(self.admin)
|
||||
|
||||
self.formLayout_2.setWidget(0, QFormLayout.ItemRole.LabelRole, self.label_21)
|
||||
|
||||
self.select_action_box = QComboBox(self.frame)
|
||||
self.select_action_box.addItem("")
|
||||
self.select_action_box.addItem("")
|
||||
self.select_action_box.addItem("")
|
||||
self.select_action_box.addItem("")
|
||||
self.select_action_box.setObjectName(u"select_action_box")
|
||||
self.select_action_box.setGeometry(QRect(60, 30, 181, 22))
|
||||
self.admin_action = QGroupBox(self.admin)
|
||||
|
||||
self.formLayout_2.setWidget(0, QFormLayout.ItemRole.FieldRole, self.select_action_box)
|
||||
|
||||
self.admin_action = QGroupBox(self.frame)
|
||||
self.admin_action.setObjectName(u"admin_action")
|
||||
self.admin_action.setGeometry(QRect(10, 70, 570, 291))
|
||||
font5 = QFont()
|
||||
font5.setBold(False)
|
||||
self.admin_action.setFont(font5)
|
||||
self.admin_action.setFlat(True)
|
||||
self.admin_action.setCheckable(False)
|
||||
|
||||
self.formLayout_2.setWidget(1, QFormLayout.ItemRole.FieldRole, self.admin_action)
|
||||
|
||||
self.tabWidget.addTab(self.admin, "")
|
||||
|
||||
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
|
||||
@@ -806,11 +847,9 @@ class Ui_MainWindow(object):
|
||||
QWidget.setTabOrder(self.check_file, self.check_send_mail)
|
||||
QWidget.setTabOrder(self.check_send_mail, self.btn_apparat_save)
|
||||
QWidget.setTabOrder(self.btn_apparat_save, self.btn_apparat_apply)
|
||||
QWidget.setTabOrder(self.btn_apparat_apply, self.chkbx_show_del_media)
|
||||
QWidget.setTabOrder(self.chkbx_show_del_media, self.btn_reserve)
|
||||
QWidget.setTabOrder(self.btn_apparat_apply, self.btn_reserve)
|
||||
QWidget.setTabOrder(self.btn_reserve, self.select_action_box)
|
||||
QWidget.setTabOrder(self.select_action_box, self.prof_id_adis)
|
||||
QWidget.setTabOrder(self.prof_id_adis, self.apparat_id_adis)
|
||||
QWidget.setTabOrder(self.select_action_box, self.apparat_id_adis)
|
||||
QWidget.setTabOrder(self.apparat_id_adis, self.automation_add_selected_books)
|
||||
QWidget.setTabOrder(self.automation_add_selected_books, self.saveandcreate)
|
||||
|
||||
@@ -819,6 +858,7 @@ class Ui_MainWindow(object):
|
||||
self.menubar.addAction(self.menuHelp.menuAction())
|
||||
self.menuDatei.addAction(self.actionBeenden)
|
||||
self.menuEinstellungen.addAction(self.actionEinstellungen)
|
||||
self.menuEinstellungen.addAction(self.actionMedien_loeschen)
|
||||
self.menuHelp.addAction(self.actionAbout)
|
||||
self.menuHelp.addAction(self.actionDokumentation)
|
||||
|
||||
@@ -848,6 +888,7 @@ class Ui_MainWindow(object):
|
||||
#if QT_CONFIG(shortcut)
|
||||
self.actionDokumentation.setShortcut(QCoreApplication.translate("MainWindow", u"F1", None))
|
||||
#endif // QT_CONFIG(shortcut)
|
||||
self.actionMedien_loeschen.setText(QCoreApplication.translate("MainWindow", u"Medien l\u00f6schen", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.create_document.setToolTip(QCoreApplication.translate("MainWindow", u"Erstellt die \u00dcbersicht, welche am Regal ausgeh\u00e4ngt werden kann", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
@@ -866,43 +907,17 @@ class Ui_MainWindow(object):
|
||||
___qtablewidgetitem4.setText(QCoreApplication.translate("MainWindow", u"Dauerapparat", None));
|
||||
___qtablewidgetitem5 = self.tableWidget_apparate.horizontalHeaderItem(5)
|
||||
___qtablewidgetitem5.setText(QCoreApplication.translate("MainWindow", u"KontoNr", None));
|
||||
self.chkbx_show_del_media.setText(QCoreApplication.translate("MainWindow", u"gel. Medien anzeigen", None))
|
||||
self.btn_reserve.setText(QCoreApplication.translate("MainWindow", u"im Apparat?", None))
|
||||
self.label_info.setText(QCoreApplication.translate("MainWindow", u"Medien werden hinzugef\u00fcgt", None))
|
||||
self.progress_label.setText(QCoreApplication.translate("MainWindow", u"Medium x/y", None))
|
||||
self.label_20.setText(QCoreApplication.translate("MainWindow", u"Medien werden gepr\u00fcft", None))
|
||||
self.avail_status.setText(QCoreApplication.translate("MainWindow", u"TextLabel", None))
|
||||
self.automation_add_selected_books.setText(QCoreApplication.translate("MainWindow", u"Ausgew\u00e4hlte als verf\u00fcgbar markieren", None))
|
||||
___qtablewidgetitem6 = self.tableWidget_apparat_media.horizontalHeaderItem(0)
|
||||
___qtablewidgetitem6.setText(QCoreApplication.translate("MainWindow", u"Buchtitel", None));
|
||||
#if QT_CONFIG(tooltip)
|
||||
___qtablewidgetitem6.setToolTip(QCoreApplication.translate("MainWindow", u"Es kann sein, dass der Buchtitel leer ist, dies kommt vor, wenn der Titel nicht passend formatiert ist", None));
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
___qtablewidgetitem7 = self.tableWidget_apparat_media.horizontalHeaderItem(1)
|
||||
___qtablewidgetitem7.setText(QCoreApplication.translate("MainWindow", u"Signatur", None));
|
||||
___qtablewidgetitem8 = self.tableWidget_apparat_media.horizontalHeaderItem(2)
|
||||
___qtablewidgetitem8.setText(QCoreApplication.translate("MainWindow", u"Auflage", None));
|
||||
___qtablewidgetitem9 = self.tableWidget_apparat_media.horizontalHeaderItem(3)
|
||||
___qtablewidgetitem9.setText(QCoreApplication.translate("MainWindow", u"Autor", None));
|
||||
___qtablewidgetitem10 = self.tableWidget_apparat_media.horizontalHeaderItem(4)
|
||||
___qtablewidgetitem10.setText(QCoreApplication.translate("MainWindow", u"im Apparat?", None));
|
||||
#if QT_CONFIG(tooltip)
|
||||
___qtablewidgetitem10.setToolTip(QCoreApplication.translate("MainWindow", u"Diese Angabe ist nicht zuverl\u00e4ssig. Ist das \u274c vorhanden, kann das Medium im Apparat sein, aber aufgrund eines Bugs nicht gefunden worden", None));
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
___qtablewidgetitem11 = self.tableWidget_apparat_media.horizontalHeaderItem(5)
|
||||
___qtablewidgetitem11.setText(QCoreApplication.translate("MainWindow", u"Vorgemerkt", None));
|
||||
___qtablewidgetitem12 = self.tableWidget_apparat_media.horizontalHeaderItem(6)
|
||||
___qtablewidgetitem12.setText(QCoreApplication.translate("MainWindow", u"Link", None));
|
||||
self.add_medium.setText(QCoreApplication.translate("MainWindow", u"Medien hinzuf\u00fcgen", None))
|
||||
self.label.setText(QCoreApplication.translate("MainWindow", u" Medienliste", None))
|
||||
self.app_group_box.setTitle(QCoreApplication.translate("MainWindow", u"SemesterApparatsdetails", None))
|
||||
___qtablewidgetitem13 = self.document_list.horizontalHeaderItem(0)
|
||||
___qtablewidgetitem13.setText(QCoreApplication.translate("MainWindow", u"Dokumentname", None));
|
||||
___qtablewidgetitem14 = self.document_list.horizontalHeaderItem(1)
|
||||
___qtablewidgetitem14.setText(QCoreApplication.translate("MainWindow", u"Dateityp", None));
|
||||
___qtablewidgetitem15 = self.document_list.horizontalHeaderItem(2)
|
||||
___qtablewidgetitem15.setText(QCoreApplication.translate("MainWindow", u"Neu?", None));
|
||||
___qtablewidgetitem16 = self.document_list.horizontalHeaderItem(3)
|
||||
___qtablewidgetitem16.setText(QCoreApplication.translate("MainWindow", u"path", None));
|
||||
___qtablewidgetitem6 = self.document_list.horizontalHeaderItem(0)
|
||||
___qtablewidgetitem6.setText(QCoreApplication.translate("MainWindow", u"Dokumentname", None));
|
||||
___qtablewidgetitem7 = self.document_list.horizontalHeaderItem(1)
|
||||
___qtablewidgetitem7.setText(QCoreApplication.translate("MainWindow", u"Dateityp", None));
|
||||
___qtablewidgetitem8 = self.document_list.horizontalHeaderItem(2)
|
||||
___qtablewidgetitem8.setText(QCoreApplication.translate("MainWindow", u"Neu?", None));
|
||||
___qtablewidgetitem9 = self.document_list.horizontalHeaderItem(3)
|
||||
___qtablewidgetitem9.setText(QCoreApplication.translate("MainWindow", u"path", None));
|
||||
self.appname_mand.setText(QCoreApplication.translate("MainWindow", u"*", None))
|
||||
self.profname_mand.setText(QCoreApplication.translate("MainWindow", u"*", None))
|
||||
self.fach_mand.setText(QCoreApplication.translate("MainWindow", u"*", None))
|
||||
@@ -927,8 +942,8 @@ class Ui_MainWindow(object):
|
||||
self.label_10.setText(QCoreApplication.translate("MainWindow", u"Fach", None))
|
||||
self.prof_mail.setPlaceholderText("")
|
||||
self.label_12.setText(QCoreApplication.translate("MainWindow", u"Prof-ID-aDIS", None))
|
||||
self.prof_id_adis.setText("")
|
||||
self.label_13.setText(QCoreApplication.translate("MainWindow", u"Apparat-ID-aDIS", None))
|
||||
self.prof_id_adis.setText("")
|
||||
self.sem_year.setPlaceholderText(QCoreApplication.translate("MainWindow", u"2023", None))
|
||||
self.check_send_mail.setText(QCoreApplication.translate("MainWindow", u"Mail senden", None))
|
||||
self.sem_winter.setText(QCoreApplication.translate("MainWindow", u"Winter", None))
|
||||
@@ -961,11 +976,44 @@ class Ui_MainWindow(object):
|
||||
" hinzuf\u00fcgen", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.btn_extract_data_from_document.setToolTip(QCoreApplication.translate("MainWindow", u"Die Apparatsdetails werden aus dem Dokument gelesen und eingetragen\n"
|
||||
"Einige Angaben m\u00fcssen ggf angepasst werden", None))
|
||||
"Die gew\u00fcnschten Medien werden automatisch in die Medienliste eingetragen, evtl. unvollst\u00e4ndig, da eBooks nicht erfasst werden k\u00f6nnenEinige Angaben m\u00fcssen ggf angepasst werden", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.btn_extract_data_from_document.setText(QCoreApplication.translate("MainWindow", u"Daten aus Dokument\n"
|
||||
"\u00fcbernehmen", None))
|
||||
self.add_medium.setText(QCoreApplication.translate("MainWindow", u"Medien hinzuf\u00fcgen", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.chkbx_show_only_wit_neweditions.setToolTip(QCoreApplication.translate("MainWindow", u"WIP - Broken", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.chkbx_show_only_wit_neweditions.setText(QCoreApplication.translate("MainWindow", u"Nur Titel mit Neuauflagen anzeigen", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.btn_reserve.setToolTip(QCoreApplication.translate("MainWindow", u"Dieser Knopf pr\u00fcft alle Werke, die mit einem roten X vermerkt sind. Sollten diese inzwischen im Apparat sein, wird dies aktualisiert", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.btn_reserve.setText(QCoreApplication.translate("MainWindow", u"Medien mit \u274c im Apparat?", None))
|
||||
self.label_info.setText(QCoreApplication.translate("MainWindow", u"Medien werden hinzugef\u00fcgt", None))
|
||||
self.progress_label.setText(QCoreApplication.translate("MainWindow", u"Medium x/y", None))
|
||||
self.label_20.setText(QCoreApplication.translate("MainWindow", u"Medien werden gepr\u00fcft", None))
|
||||
self.label_eta.setText("")
|
||||
self.avail_status.setText(QCoreApplication.translate("MainWindow", u"TextLabel", None))
|
||||
self.automation_add_selected_books.setText(QCoreApplication.translate("MainWindow", u"Ausgew\u00e4hlte als verf\u00fcgbar markieren", None))
|
||||
___qtablewidgetitem10 = self.tableWidget_apparat_media.horizontalHeaderItem(0)
|
||||
___qtablewidgetitem10.setText(QCoreApplication.translate("MainWindow", u"Buchtitel", None));
|
||||
#if QT_CONFIG(tooltip)
|
||||
___qtablewidgetitem10.setToolTip(QCoreApplication.translate("MainWindow", u"Es kann sein, dass der Buchtitel leer ist, dies kommt vor, wenn der Titel nicht passend formatiert ist", None));
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
___qtablewidgetitem11 = self.tableWidget_apparat_media.horizontalHeaderItem(1)
|
||||
___qtablewidgetitem11.setText(QCoreApplication.translate("MainWindow", u"Signatur", None));
|
||||
___qtablewidgetitem12 = self.tableWidget_apparat_media.horizontalHeaderItem(2)
|
||||
___qtablewidgetitem12.setText(QCoreApplication.translate("MainWindow", u"Auflage", None));
|
||||
___qtablewidgetitem13 = self.tableWidget_apparat_media.horizontalHeaderItem(3)
|
||||
___qtablewidgetitem13.setText(QCoreApplication.translate("MainWindow", u"Autor", None));
|
||||
___qtablewidgetitem14 = self.tableWidget_apparat_media.horizontalHeaderItem(4)
|
||||
___qtablewidgetitem14.setText(QCoreApplication.translate("MainWindow", u"im Apparat?", None));
|
||||
#if QT_CONFIG(tooltip)
|
||||
___qtablewidgetitem14.setToolTip(QCoreApplication.translate("MainWindow", u"Diese Angabe ist nicht zuverl\u00e4ssig. Ist das \u274c vorhanden, kann das Medium im Apparat sein, aber aufgrund eines Bugs nicht gefunden worden", None));
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
___qtablewidgetitem15 = self.tableWidget_apparat_media.horizontalHeaderItem(5)
|
||||
___qtablewidgetitem15.setText(QCoreApplication.translate("MainWindow", u"Vorgemerkt", None));
|
||||
___qtablewidgetitem16 = self.tableWidget_apparat_media.horizontalHeaderItem(6)
|
||||
___qtablewidgetitem16.setText(QCoreApplication.translate("MainWindow", u"Link", None));
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.createApparat), QCoreApplication.translate("MainWindow", u"Anlegen", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.search_statistics), QCoreApplication.translate("MainWindow", u"Suchen / Statistik", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.elsatab), QCoreApplication.translate("MainWindow", u"ELSA", None))
|
||||
@@ -973,6 +1021,7 @@ class Ui_MainWindow(object):
|
||||
self.select_action_box.setItemText(0, QCoreApplication.translate("MainWindow", u"Nutzer anlegen", None))
|
||||
self.select_action_box.setItemText(1, QCoreApplication.translate("MainWindow", u"Nutzer bearbeiten", None))
|
||||
self.select_action_box.setItemText(2, QCoreApplication.translate("MainWindow", u"Lehrperson bearbeiten", None))
|
||||
self.select_action_box.setItemText(3, QCoreApplication.translate("MainWindow", u"Medien bearbeiten", None))
|
||||
|
||||
self.admin_action.setTitle(QCoreApplication.translate("MainWindow", u"GroupBox", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.admin), QCoreApplication.translate("MainWindow", u"Admin", None))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5,21 +5,25 @@ import sys
|
||||
import tempfile
|
||||
import time
|
||||
import webbrowser
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Union
|
||||
from typing import Any, List, Optional, Tuple, Union
|
||||
|
||||
import loguru
|
||||
from natsort import natsorted
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
from PySide6.QtCore import QThread, Qt
|
||||
from PySide6.QtCore import QThread
|
||||
from PySide6.QtGui import QRegularExpressionValidator
|
||||
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
|
||||
|
||||
from src import LOG_DIR, Icon
|
||||
from src.backend import AvailChecker, BookGrabber, Database, DocumentationThread
|
||||
from src import Icon
|
||||
from src.backend import (
|
||||
AvailChecker,
|
||||
BookGrabber,
|
||||
Database,
|
||||
DocumentationThread,
|
||||
NewEditionCheckerThread,
|
||||
)
|
||||
from src.backend.create_file import recreateFile
|
||||
from src.backend.delete_temp_contents import delete_temp_contents as tempdelete
|
||||
from src.backend.semester import Semester
|
||||
from src.logic import (
|
||||
APP_NRS,
|
||||
Apparat,
|
||||
@@ -27,18 +31,24 @@ from src.logic import (
|
||||
BookData,
|
||||
Prof,
|
||||
SemapDocument,
|
||||
Semester,
|
||||
csv_to_list,
|
||||
eml_to_semap,
|
||||
pdf_to_semap,
|
||||
word_to_semap,
|
||||
)
|
||||
from src.shared.logging import log
|
||||
from src.ui import Ui_Semesterapparat
|
||||
from src.ui.dialogs import (
|
||||
About,
|
||||
ApparatExtendDialog,
|
||||
BookDataUI,
|
||||
DeleteDialog,
|
||||
DocumentPrintDialog,
|
||||
LoginDialog,
|
||||
Mail_Dialog,
|
||||
MedienAdder,
|
||||
NewEditionDialog,
|
||||
ParsedTitles,
|
||||
ReminderDialog,
|
||||
Settings,
|
||||
@@ -51,25 +61,19 @@ from src.ui.widgets import (
|
||||
ElsaDialog,
|
||||
FilePicker,
|
||||
MessageCalendar,
|
||||
NewEditionChecker,
|
||||
NewEditionCheckSelector,
|
||||
SearchStatisticPage,
|
||||
UpdaterThread,
|
||||
UpdateSignatures,
|
||||
UserCreate,
|
||||
)
|
||||
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
log.add(
|
||||
f"{LOG_DIR}/{datetime.now().strftime('%Y-%m-%d')}.log",
|
||||
rotation="1 day",
|
||||
retention="1 month",
|
||||
)
|
||||
log.critical("UI started")
|
||||
log.success("UI started")
|
||||
valid_input = (0, 0, 0, 0, 0, 0)
|
||||
|
||||
|
||||
class Ui(Ui_Semesterapparat):
|
||||
class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
|
||||
# use the Ui_MainWindow class from mainwindow.py
|
||||
def __init__(self, MainWindow, username: str) -> None: # type:ignore
|
||||
log.info("Starting Semesterapparatsmanagement")
|
||||
@@ -78,7 +82,9 @@ class Ui(Ui_Semesterapparat):
|
||||
self.setupUi(MainWindow) # type:ignore
|
||||
self.MainWindow = MainWindow # type:ignore
|
||||
# set the window title
|
||||
MainWindow.setWindowTitle("Semesterapparatsmanagement") # type:ignore
|
||||
MainWindow.setWindowTitle(
|
||||
f"Semesterapparatsmanagement Semester: {Semester().value}"
|
||||
) # type:ignore
|
||||
MainWindow.setWindowIcon(Icon("logo").icon) # type:ignore
|
||||
|
||||
self.db = Database()
|
||||
@@ -121,6 +127,8 @@ class Ui(Ui_Semesterapparat):
|
||||
Icon("offAction", self.actionBeenden)
|
||||
self.actionBeenden.triggered.connect(self.quit) # type:ignore
|
||||
self.actionAbout.triggered.connect(self.open_about) # type:ignore
|
||||
self.actionMedien_loeschen.triggered.connect(self.open_delete_dialog)
|
||||
self.actionMedien_loeschen.setIcon(Icon("trash").icon)
|
||||
|
||||
# set validators
|
||||
self.sem_sommer.clicked.connect(lambda: self.toggleButton(self.sem_winter)) # type:ignore
|
||||
@@ -177,11 +185,11 @@ class Ui(Ui_Semesterapparat):
|
||||
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.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
|
||||
self.chkbx_show_del_media.setEnabled(False)
|
||||
# self.chkbx_show_del_media.setEnabled(False)
|
||||
self.label_info.hide()
|
||||
self.app_group_box.setEnabled(False)
|
||||
self.line_2.hide()
|
||||
@@ -189,8 +197,12 @@ class Ui(Ui_Semesterapparat):
|
||||
self.btn_reserve.hide()
|
||||
self.label_20.hide()
|
||||
self.line_3.hide()
|
||||
self.progressBar.setValue(0)
|
||||
self.progressBar.hide()
|
||||
self.progressBar.setMinimum(0)
|
||||
self.avail_status.hide()
|
||||
self.chkbx_show_del_media.hide()
|
||||
# self.chkbx_show_del_media.hide()
|
||||
self.chkbx_show_only_wit_neweditions.hide()
|
||||
self.automation_add_selected_books.hide()
|
||||
# self.btn_del_select_apparats.setEnabled(False)
|
||||
|
||||
@@ -238,6 +250,7 @@ class Ui(Ui_Semesterapparat):
|
||||
self.availChecker = None
|
||||
self.mail_thread = None
|
||||
self.autoGrabber = None
|
||||
self.newEditionChecker = NewEditionCheckerThread()
|
||||
|
||||
self.elsatab.setLayout(QtWidgets.QVBoxLayout())
|
||||
self.search_statistics.setLayout(QtWidgets.QVBoxLayout())
|
||||
@@ -252,8 +265,69 @@ class Ui(Ui_Semesterapparat):
|
||||
|
||||
self.steps.hide()
|
||||
|
||||
self.player = QMediaPlayer()
|
||||
self.audio_output = QAudioOutput()
|
||||
|
||||
self.status_progress = QtWidgets.QProgressBar()
|
||||
self.statusBar.addWidget(self.status_progress)
|
||||
self.status_progress.hide()
|
||||
self.valid_check_semester.clicked.connect(self.display_valid_semester) # type:ignore
|
||||
|
||||
# allow files to be dragged into document_list
|
||||
self.document_list.setDragDropMode(
|
||||
QtWidgets.QAbstractItemView.DragDropMode.DropOnly
|
||||
)
|
||||
self.document_list.setAcceptDrops(True)
|
||||
self.document_list.viewport().setAcceptDrops(True)
|
||||
self.document_list.installEventFilter(self)
|
||||
self.document_list.viewport().installEventFilter(self)
|
||||
|
||||
def open_delete_dialog(self):
|
||||
# this will open a dialog to select and delete multiple entries. by default, all books will be loaded, and a search bar can be used to fuzzy search the books and select books. on a button press, the selected books will be deleted from the apparat(s) they are part in
|
||||
# raise NotImplementedError("This feature is not yet implemented.")
|
||||
dialog = DeleteDialog()
|
||||
dialog.exec()
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
# Only handle events for document_list and its viewport
|
||||
if obj in (self.document_list, self.document_list.viewport()):
|
||||
et = event.type()
|
||||
if et == QtCore.QEvent.Type.DragEnter:
|
||||
if event.mimeData().hasUrls():
|
||||
event.setDropAction(QtCore.Qt.CopyAction)
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
event.ignore()
|
||||
return True
|
||||
elif et == QtCore.QEvent.Type.DragMove:
|
||||
if event.mimeData().hasUrls():
|
||||
event.setDropAction(QtCore.Qt.CopyAction)
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
event.ignore()
|
||||
return True
|
||||
elif et == QtCore.QEvent.Type.Drop:
|
||||
if not self.app_group_box.isEnabled():
|
||||
self.confirm_popup(
|
||||
"Bitte öffnen Sie zuerst einen Apparat!", title="Fehler"
|
||||
)
|
||||
return True
|
||||
if event.mimeData().hasUrls():
|
||||
for url in event.mimeData().urls():
|
||||
self.add_document(url.toLocalFile())
|
||||
event.setDropAction(QtCore.Qt.CopyAction)
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
event.ignore()
|
||||
return True
|
||||
return super().eventFilter(obj, event)
|
||||
|
||||
def update_eta(self, eta: str):
|
||||
eta = int(eta)
|
||||
# transform seconds eta to HH:MM:SS
|
||||
transformed_eta = f"{eta // 3600}:{(eta % 3600) // 60}:{eta % 60}"
|
||||
self.label_eta.setText(f"Bitte warten... (ETA: {transformed_eta})")
|
||||
|
||||
def create_doc(self):
|
||||
log.debug("Creating document")
|
||||
# open DocumentPrintDialog
|
||||
@@ -295,8 +369,11 @@ class Ui(Ui_Semesterapparat):
|
||||
elif self.select_action_box.currentText() == "Lehrperson bearbeiten":
|
||||
self.setWidget(EditProf())
|
||||
self.admin_action.setTitle("Lehrperson bearbeiten")
|
||||
elif self.select_action_box.currentText() == "Medien bearbeiten":
|
||||
self.setWidget(UpdateSignatures())
|
||||
self.admin_action.setTitle("Medien bearbeiten")
|
||||
else:
|
||||
self.hideWidget()
|
||||
# self.hideWidget()
|
||||
self.admin_action.setTitle("")
|
||||
|
||||
def toggleButton(self, button: QtWidgets.QCheckBox):
|
||||
@@ -312,6 +389,12 @@ class Ui(Ui_Semesterapparat):
|
||||
tempdelete()
|
||||
sys.exit()
|
||||
|
||||
def play_sound(self, sound_file: str):
|
||||
self.player.setAudioOutput(self.audio_output)
|
||||
self.audio_output.setVolume(50)
|
||||
self.player.setSource(QtCore.QUrl.fromLocalFile(f"src/sounds/{sound_file}"))
|
||||
self.player.play()
|
||||
|
||||
def get_apparats(self):
|
||||
alist = self.db.getAllAparats(deleted=0)
|
||||
alist = natsorted(alist, key=lambda x: x.appnr, reverse=True)
|
||||
@@ -340,9 +423,18 @@ class Ui(Ui_Semesterapparat):
|
||||
self.statusBar.showMessage("")
|
||||
|
||||
def update_calendar(self, data: list[dict[str, Any]]):
|
||||
self.calendarWidget.setMessages([data])
|
||||
self.calendarWidget.setMessages(data)
|
||||
self.calendarWidget.updateCells()
|
||||
|
||||
def status_bar_progress(self, current: int, total: int):
|
||||
self.status_progress.setRange(0, total)
|
||||
self.status_progress.setValue(current)
|
||||
if current == total:
|
||||
self.status_progress.hide()
|
||||
self.status_progress.setValue(0)
|
||||
else:
|
||||
self.status_progress.show()
|
||||
|
||||
def tabW1_changed(self):
|
||||
if self.tabWidget.currentIndex() == 1: # Statistics
|
||||
stats_layout = self.search_statistics.layout()
|
||||
@@ -357,6 +449,7 @@ class Ui(Ui_Semesterapparat):
|
||||
statistics.apparat_open.connect(self.open_apparat)
|
||||
statistics.refreshSignal.connect(self.update_apparat_list)
|
||||
statistics.updateCalendar.connect(self.update_calendar)
|
||||
statistics.status_update.connect(self.status_bar_progress)
|
||||
stats_layout.addWidget(statistics)
|
||||
|
||||
# #log.debug("searchpage")
|
||||
@@ -399,7 +492,7 @@ class Ui(Ui_Semesterapparat):
|
||||
else:
|
||||
return f"WiSe {currentYear}/{currentYear + 1}"
|
||||
|
||||
def open_apparat(self, apparat):
|
||||
def open_apparat(self, apparat: Union[int, str]):
|
||||
if self.load_app_data(apparat):
|
||||
# change tab focus to tab 0
|
||||
self.tabWidget.setCurrentIndex(0)
|
||||
@@ -471,7 +564,7 @@ class Ui(Ui_Semesterapparat):
|
||||
self.update_app_media_list()
|
||||
self.cancel_active_selection.click()
|
||||
self.check_send_mail.show()
|
||||
self.chkbx_show_del_media.show()
|
||||
# self.chkbx_show_del_media.show()
|
||||
self.cancel_active_selection.setEnabled(False)
|
||||
self.add_medium.setEnabled(False)
|
||||
# update apparat table
|
||||
@@ -608,17 +701,17 @@ class Ui(Ui_Semesterapparat):
|
||||
self.prof_mail.setText(data.mail)
|
||||
self.app_name.setFocus()
|
||||
|
||||
def get_index_of_value(self, table_widget, value):
|
||||
def get_index_of_value(self, table_widget: QtWidgets.QTableWidget, value: str):
|
||||
for i in range(table_widget.rowCount()):
|
||||
for j in range(table_widget.columnCount()):
|
||||
if (
|
||||
table_widget.item(i, j) is not None
|
||||
and table_widget.item(i, j).text() == value
|
||||
and table_widget.item(i, j).text() == value # type: ignore
|
||||
):
|
||||
return i, j
|
||||
return (None, None)
|
||||
|
||||
def load_app_data(self, app_id=None):
|
||||
def load_app_data(self, app_id: Optional[Union[int, str]] = None):
|
||||
self.cancel_active_selection.setEnabled(True)
|
||||
self.add_medium.setEnabled(True)
|
||||
for child in self.app_group_box.findChildren(QtWidgets.QToolButton):
|
||||
@@ -638,12 +731,12 @@ class Ui(Ui_Semesterapparat):
|
||||
self.sem_winter.setEnabled(False)
|
||||
self.sem_year.setEnabled(False)
|
||||
self.document_list.setRowCount(0)
|
||||
self.chkbx_show_del_media.setEnabled(True)
|
||||
# self.chkbx_show_del_media.setEnabled(True)
|
||||
appdata = self.db.getApparatData(appnr, appname)
|
||||
self.populate_frame(appdata)
|
||||
self.btn_apparat_save.hide()
|
||||
self.btn_reserve.show()
|
||||
self.chkbx_show_del_media.show()
|
||||
# self.chkbx_show_del_media.show()
|
||||
|
||||
self.drpdwn_app_nr.setDisabled(True)
|
||||
self.update_app_media_list()
|
||||
@@ -680,7 +773,7 @@ class Ui(Ui_Semesterapparat):
|
||||
self.sem_year.setEnabled(True)
|
||||
self.sem_sommer.setEnabled(True)
|
||||
self.sem_winter.setEnabled(True)
|
||||
self.chkbx_show_del_media.setEnabled(True)
|
||||
# self.chkbx_show_del_media.setEnabled(True)
|
||||
self.drpdwn_app_nr.setEnabled(True)
|
||||
self.app_fach.setEnabled(True)
|
||||
self.check_send_mail.show()
|
||||
@@ -734,13 +827,14 @@ class Ui(Ui_Semesterapparat):
|
||||
"Bitte mindestens ein Medium hinzufügen!", title="Fehler"
|
||||
)
|
||||
|
||||
app_id = self.active_apparat
|
||||
app_nr = self.db.getId(self.app_name.text())
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
log.debug(prof_id)
|
||||
log.debug(f"{prof_id}, {app_nr}")
|
||||
# check if app_id is in database
|
||||
if self.db.checkApparatExistsById(app_id) is False:
|
||||
if app_nr is None:
|
||||
# create apparat
|
||||
self.btn_save_apparat(False)
|
||||
app_nr = self.db.getId(self.app_name.text())
|
||||
# create a thread that updates the progress label after each medium
|
||||
|
||||
# self.bookGrabber = None
|
||||
@@ -748,7 +842,7 @@ class Ui(Ui_Semesterapparat):
|
||||
bookGrabber.add_values(
|
||||
mode=mode,
|
||||
prof_id=prof_id,
|
||||
app_id=app_id,
|
||||
app_id=app_nr,
|
||||
data=data,
|
||||
any_book=use_any,
|
||||
exact=use_exact,
|
||||
@@ -804,7 +898,7 @@ class Ui(Ui_Semesterapparat):
|
||||
)
|
||||
|
||||
# thread = QThread()
|
||||
appnumber = self.active_apparat
|
||||
appnumber = self.drpdwn_app_nr.currentText()
|
||||
# #log.debug(links)
|
||||
self.availChecker = AvailChecker(links, appnumber, books=books)
|
||||
# availcheck.moveToThread(thread)
|
||||
@@ -825,7 +919,7 @@ class Ui(Ui_Semesterapparat):
|
||||
self.document_list.setRowCount(0)
|
||||
self.app_group_box.setEnabled(False)
|
||||
self.app_fach.setCurrentText("")
|
||||
self.chkbx_show_del_media.hide()
|
||||
# self.chkbx_show_del_media.hide()
|
||||
self.check_send_mail.hide()
|
||||
self.btn_reserve.hide()
|
||||
self.check_eternal_app.setEnabled(False)
|
||||
@@ -847,16 +941,14 @@ class Ui(Ui_Semesterapparat):
|
||||
self.validate_semester()
|
||||
|
||||
def update_app_media_list(self):
|
||||
deleted = 0 if not self.chkbx_show_del_media.isChecked() else 1
|
||||
app_id = self.active_apparat
|
||||
app_id = self.db.getId(self.app_name.text())
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
books: list[dict[int, BookData, int]] = self.db.getBooks(
|
||||
app_id, prof_id, deleted
|
||||
)
|
||||
books: list[dict[int, BookData, int]] = self.db.getBooks(app_id, prof_id, 0)
|
||||
|
||||
# # #log.debug(books)
|
||||
# take the dataclass from the tuple
|
||||
# booklist:list[BookData]=[book[0] for book in books]
|
||||
self.tableWidget_apparat_media.clearContents()
|
||||
self.tableWidget_apparat_media.setRowCount(0)
|
||||
for book in books:
|
||||
book["id"]
|
||||
@@ -889,10 +981,15 @@ class Ui(Ui_Semesterapparat):
|
||||
3,
|
||||
QtWidgets.QTableWidgetItem(book_data.author),
|
||||
)
|
||||
self.tableWidget_apparat_media.setItem(
|
||||
self.tableWidget_apparat_media.rowCount() - 1,
|
||||
6,
|
||||
QtWidgets.QTableWidgetItem(book_data.link),
|
||||
label = QtWidgets.QLabel(f'<a href="{book_data.link}">Katalog</a>')
|
||||
label.setOpenExternalLinks(True)
|
||||
label.setTextFormat(QtCore.Qt.TextFormat.RichText)
|
||||
label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||
label.setTextInteractionFlags(
|
||||
QtCore.Qt.TextInteractionFlag.TextBrowserInteraction
|
||||
)
|
||||
self.tableWidget_apparat_media.setCellWidget(
|
||||
self.tableWidget_apparat_media.rowCount() - 1, 6, label
|
||||
)
|
||||
if availability == 1:
|
||||
# display green checkmark at column 4 in the row
|
||||
@@ -915,10 +1012,6 @@ class Ui(Ui_Semesterapparat):
|
||||
self.tableWidget_apparat_media.rowCount() - 1, 4
|
||||
).setToolTip("Das Medium wurde nicht im Apparat gefunden")
|
||||
|
||||
# make table link clickable
|
||||
# self.tableWidget_apparat_media.itemClicked.connect(self.open_link)
|
||||
# self.tableWidget_apparat_media.
|
||||
|
||||
def open_link(self, item):
|
||||
def __openLink(link):
|
||||
if link == "":
|
||||
@@ -956,8 +1049,9 @@ class Ui(Ui_Semesterapparat):
|
||||
for prof in profs:
|
||||
self.drpdwn_prof_name.addItem(prof)
|
||||
|
||||
def add_document(self):
|
||||
def add_document(self, url: Optional[str] = None):
|
||||
# #log.debug("Add document")
|
||||
if not url:
|
||||
picker = FilePicker()
|
||||
files = picker.pick_files()
|
||||
for file in files:
|
||||
@@ -972,6 +1066,17 @@ class Ui(Ui_Semesterapparat):
|
||||
# set tooltip of row 3 to the file path for each row
|
||||
self.document_list.item(0, 3).setToolTip(file)
|
||||
self.document_list.item(0, 0).setToolTip(filename)
|
||||
else:
|
||||
self.document_list.insertRow(0)
|
||||
filename = url.split("/")[-1]
|
||||
filetype = filename.split(".")[-1]
|
||||
self.document_list.setItem(0, 0, QtWidgets.QTableWidgetItem(filename))
|
||||
self.document_list.setItem(0, 1, QtWidgets.QTableWidgetItem(filetype))
|
||||
self.document_list.setItem(0, 2, QtWidgets.QTableWidgetItem("*"))
|
||||
self.document_list.setItem(0, 3, QtWidgets.QTableWidgetItem(url))
|
||||
# set tooltip of row 3 to the file path for each row
|
||||
self.document_list.item(0, 3).setToolTip(url)
|
||||
self.document_list.item(0, 0).setToolTip(filename)
|
||||
|
||||
def open_document(self):
|
||||
_selected_doc_name = ""
|
||||
@@ -987,7 +1092,7 @@ class Ui(Ui_Semesterapparat):
|
||||
self.document_list.currentRow(), 1
|
||||
).text()
|
||||
except AttributeError:
|
||||
self.confirm_popup("Bitte erst ein document auswählen!", title="Fehler")
|
||||
self.confirm_popup("Bitte erst ein Dokument auswählen!", title="Fehler")
|
||||
return
|
||||
if not _selected_doc_location == "Database":
|
||||
path = Path(_selected_doc_location)
|
||||
@@ -1006,7 +1111,7 @@ class Ui(Ui_Semesterapparat):
|
||||
)
|
||||
|
||||
def add_media_from_file(self):
|
||||
app_id = self.active_apparat
|
||||
app_id = self.db.getId(self.app_name.text())
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
|
||||
def __open_dialog(signatures: list[str]):
|
||||
@@ -1052,17 +1157,24 @@ class Ui(Ui_Semesterapparat):
|
||||
temp_file = tempfile.NamedTemporaryFile(
|
||||
delete=False, suffix="." + file_type
|
||||
)
|
||||
temp_file.write(
|
||||
self.db.getBlob(file_name, int(self.active_apparat))
|
||||
)
|
||||
temp_file.write(self.db.getBlob(file_name, int(app_id)))
|
||||
temp_file.close()
|
||||
file = temp_file.name
|
||||
if file_type == "pdf":
|
||||
# Todo: implement parser here
|
||||
self.confirm_popup(
|
||||
"PDF Dateien werden noch nicht unterstützt!", title="Fehler"
|
||||
)
|
||||
data = pdf_to_semap(file)
|
||||
signatures = data.signatures
|
||||
data = __open_dialog(signatures)
|
||||
# if no data was returned, return
|
||||
if data == []:
|
||||
return
|
||||
for book in data:
|
||||
if not isinstance(book, BookData):
|
||||
continue
|
||||
self.db.addBookToDatabase(
|
||||
bookdata=book,
|
||||
app_id=app_id,
|
||||
prof_id=prof_id,
|
||||
)
|
||||
if file_type == "csv":
|
||||
signatures = csv_to_list(file)
|
||||
data = __open_dialog(signatures)
|
||||
@@ -1086,6 +1198,8 @@ class Ui(Ui_Semesterapparat):
|
||||
self.db.addBookToDatabase(
|
||||
bookdata=book, app_id=app_id, prof_id=prof_id
|
||||
)
|
||||
if file_type == "eml":
|
||||
data = eml_to_semap(file)
|
||||
self.update_app_media_list()
|
||||
# #log.debug(len(signatures))
|
||||
|
||||
@@ -1099,7 +1213,9 @@ class Ui(Ui_Semesterapparat):
|
||||
log.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)
|
||||
file = 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")
|
||||
@@ -1108,12 +1224,14 @@ class Ui(Ui_Semesterapparat):
|
||||
signatures = csv_to_list(file)
|
||||
# add the data to the database
|
||||
return signatures
|
||||
if file_type == "docx":
|
||||
if file_type in ("docx", "doc"):
|
||||
data = word_to_semap(file)
|
||||
log.info("Converted data from semap file")
|
||||
log.debug("Got the data: {}", data)
|
||||
|
||||
return data
|
||||
else:
|
||||
raise ValueError("Dateityp wird nicht unterstützt")
|
||||
|
||||
def import_data_from_document(self):
|
||||
global valid_input
|
||||
@@ -1125,6 +1243,7 @@ class Ui(Ui_Semesterapparat):
|
||||
|
||||
self.prof_mail.setText(data.mail)
|
||||
self.prof_tel_nr.setText(str(data.phoneNumber).replace("-", ""))
|
||||
self.app_name.setText(data.title)
|
||||
if len(data.title_suggestions) > 0:
|
||||
# create a dialog that has a dropdown with the suggestions, and oc and cancel button. on ok return the selected text and set it as title
|
||||
dialog = QtWidgets.QDialog()
|
||||
@@ -1151,10 +1270,11 @@ class Ui(Ui_Semesterapparat):
|
||||
dialog.exec()
|
||||
|
||||
if dialog.result() == QtWidgets.QDialog.DialogCode.Accepted:
|
||||
print("Selected title:", dropdown.currentText())
|
||||
# print("Selected title:", dropdown.currentText())
|
||||
self.app_name.setText(dropdown.currentText().split(" [")[0].strip())
|
||||
else:
|
||||
self.app_name.setText("CHANGEME")
|
||||
|
||||
# self.app_name.setText(data.title)
|
||||
subjects = self.db.getSubjects()
|
||||
subjects = [subject[1] for subject in subjects]
|
||||
@@ -1171,11 +1291,14 @@ class Ui(Ui_Semesterapparat):
|
||||
if data.eternal:
|
||||
self.check_eternal_app.setChecked(True)
|
||||
self.validate_semester()
|
||||
if data.books != []:
|
||||
self.btn_check_file_threaded(data)
|
||||
|
||||
def btn_check_file_threaded(self):
|
||||
def btn_check_file_threaded(self, c_document: Optional[SemapDocument] = None):
|
||||
for runner in self.bookGrabber:
|
||||
if not runner.isRunning():
|
||||
runner.deleteLater()
|
||||
self.bookGrabber.remove(runner)
|
||||
# #log.debug("Checking file")
|
||||
# get active app_id and prof_id
|
||||
self.tableWidget_apparate.setEnabled(False)
|
||||
@@ -1198,7 +1321,7 @@ class Ui(Ui_Semesterapparat):
|
||||
)
|
||||
self.db.createProf(prof)
|
||||
# if app_id not in database, create apparat
|
||||
if not self.db.checkApparatExistsById(app_id):
|
||||
if not app_id:
|
||||
log.info("Apparat does not exist, creating new apparat")
|
||||
# create apparat
|
||||
# #log.debug("Creating apparat")
|
||||
@@ -1218,6 +1341,9 @@ class Ui(Ui_Semesterapparat):
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
|
||||
# log.debug("Prof ID is None", prof_id)
|
||||
document = None
|
||||
|
||||
if c_document is None or not isinstance(c_document, SemapDocument):
|
||||
document = self.extract_document_data()
|
||||
if document is None:
|
||||
log.error("Document is None")
|
||||
@@ -1228,7 +1354,7 @@ class Ui(Ui_Semesterapparat):
|
||||
autoGrabber = BookGrabber()
|
||||
autoGrabber.add_values(
|
||||
mode="ARRAY",
|
||||
app_id=int(app_id),
|
||||
app_id=app_id,
|
||||
prof_id=int(prof_id),
|
||||
data=signatures,
|
||||
any_book=True,
|
||||
@@ -1293,7 +1419,7 @@ class Ui(Ui_Semesterapparat):
|
||||
)
|
||||
prof.title = self.prof_title.text()
|
||||
apparat = Apparat(
|
||||
appnr=self.active_apparat,
|
||||
appnr=int(self.drpdwn_app_nr.currentText()),
|
||||
name=self.app_name.text(),
|
||||
created_semester=self.generateSemester(),
|
||||
eternal=1 if self.check_eternal_app.isChecked() else 0,
|
||||
@@ -1316,7 +1442,8 @@ class Ui(Ui_Semesterapparat):
|
||||
return
|
||||
appdata = self.db.getAllAparats()
|
||||
# merge self.appdata and appdata, remove duplicates
|
||||
self.apparats = list(set(self.apparats + appdata))
|
||||
|
||||
self.apparats = self.__uniques(self.apparats, appdata)
|
||||
self.apparats = natsorted(self.apparats, key=lambda x: x[4], reverse=True)
|
||||
|
||||
self.update_apparat_list()
|
||||
@@ -1335,12 +1462,22 @@ class Ui(Ui_Semesterapparat):
|
||||
self.__clear_fields()
|
||||
return True
|
||||
|
||||
def __uniques(self, list1, list2):
|
||||
seen = set()
|
||||
unique_list = []
|
||||
for item in list1 + list2:
|
||||
identifier = (item.appnr, item.name)
|
||||
if identifier not in seen:
|
||||
seen.add(identifier)
|
||||
unique_list.append(item)
|
||||
return unique_list
|
||||
|
||||
def send_mail_preview(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def active_apparat(self):
|
||||
return self.drpdwn_app_nr.currentText()
|
||||
return self.db.getId(self.app_name.text())
|
||||
|
||||
@property
|
||||
def profdata(self):
|
||||
@@ -1434,10 +1571,18 @@ class Ui(Ui_Semesterapparat):
|
||||
contact_action = menu.addAction("Kontaktieren")
|
||||
delete_action = menu.addAction("Löschen")
|
||||
remind_action = menu.addAction("Erinnerung")
|
||||
new_edition_check = menu.addAction("Auf Neuauflagen prüfen")
|
||||
order_newedition_action = menu.addAction("Neuauflagen bestellen")
|
||||
menu.addAction(extend_action)
|
||||
menu.addActions([contact_action, delete_action, remind_action])
|
||||
extend_action.triggered.connect(self.extend_apparat)
|
||||
remind_action.triggered.connect(self.reminder)
|
||||
menu.addActions(
|
||||
[
|
||||
contact_action,
|
||||
delete_action,
|
||||
remind_action,
|
||||
new_edition_check,
|
||||
order_newedition_action,
|
||||
]
|
||||
)
|
||||
# convert point to row and column
|
||||
row = self.tableWidget_apparate.rowAt(position.y())
|
||||
column = self.tableWidget_apparate.columnAt(position.x())
|
||||
@@ -1447,6 +1592,12 @@ class Ui(Ui_Semesterapparat):
|
||||
app_id = self.tableWidget_apparate.item(row, 0).text()
|
||||
pid = self.db.getProfIDByApparat(app_id)
|
||||
log.debug(app_id, pid)
|
||||
extend_action.triggered.connect(self.extend_apparat)
|
||||
remind_action.triggered.connect(self.reminder)
|
||||
new_edition_check.triggered.connect(lambda: self.check_new_editions())
|
||||
order_newedition_action.triggered.connect(
|
||||
lambda: self.order_new_editions(app_id, pid)
|
||||
)
|
||||
delete_action.triggered.connect(lambda: self.delete_apparat(pos))
|
||||
# pass pos to contact_prof
|
||||
contact_action.triggered.connect(
|
||||
@@ -1454,6 +1605,119 @@ class Ui(Ui_Semesterapparat):
|
||||
)
|
||||
menu.exec(self.tableWidget_apparate.mapToGlobal(position))
|
||||
|
||||
def order_new_editions(self, app_nr, prof_id):
|
||||
log.info("Opening order new editions dialog")
|
||||
app_id = self.db.getId(self.db.getApparatNameByAppNr(app_nr))
|
||||
prof_id = prof_id
|
||||
mail_data = {
|
||||
"prof_name": "Erwerbung",
|
||||
"prof_mail": "erw@ph-freiburg.de",
|
||||
"app_nr": app_nr,
|
||||
"app_name": self.db.getApparatName(app_nr, prof_id),
|
||||
}
|
||||
orderDialog = NewEditionDialog(app_id, mail_data)
|
||||
orderDialog.exec()
|
||||
|
||||
def update_status(self, curr, total):
|
||||
self.avail_status.show()
|
||||
self.label_20.show()
|
||||
self.progressBar.show()
|
||||
self.avail_status.setText(f"{curr}/{total}")
|
||||
self.progressBar.setValue(curr)
|
||||
if curr == total:
|
||||
self.avail_status.hide()
|
||||
self.label_20.hide()
|
||||
self.progressBar.hide()
|
||||
self.progressBar.setValue(0)
|
||||
self.avail_status.setText("0/0")
|
||||
|
||||
def check_new_editions(self):
|
||||
# create a dialog that asks "Prof oder Apparat" with a button for each. based on that either search through the books of the apparat, or all books associated with the prof
|
||||
selector = NewEditionCheckSelector()
|
||||
selector.exec()
|
||||
pick = selector.selection
|
||||
|
||||
app_id = self.tableWidget_apparate.item(
|
||||
self.tableWidget_apparate.currentRow(), 0
|
||||
).text()
|
||||
prof_id: int = self.db.getProfIDByApparat(app_id)
|
||||
app_name = self.tableWidget_apparate.item(
|
||||
self.tableWidget_apparate.currentRow(), 1
|
||||
).text()
|
||||
subject = self.tableWidget_apparate.item(
|
||||
self.tableWidget_apparate.currentRow(), 4
|
||||
).text()
|
||||
if pick == "professor":
|
||||
books = self.db.getBooksByProfId(prof_id)
|
||||
app_name = "Sammelmail"
|
||||
app_id = ", ".join(
|
||||
[str(app.appnr) for app in self.db.getApparatsByProf(prof_id)]
|
||||
)
|
||||
else:
|
||||
apparats_id = self.db.getId(app_name)
|
||||
books = self.db.getBooks(apparats_id, prof_id, deleted=0)
|
||||
searchable_books = []
|
||||
for book in books:
|
||||
b = book["bookdata"]
|
||||
b.in_apparat = True
|
||||
b.library_location = self.db.query_db(
|
||||
"""SELECT s.appnr FROM media AS m
|
||||
JOIN semesterapparat AS s on m.app_id = s.id
|
||||
WHERE m.id = ?""",
|
||||
(book["id"],),
|
||||
one=True,
|
||||
)[0]
|
||||
searchable_books.append(b)
|
||||
|
||||
log.info(f"Checking {len(searchable_books)} for new editions")
|
||||
|
||||
self.newEditionChecker.entries = searchable_books
|
||||
self.newEditionChecker.finished.connect(self.newEditionChecker.reset)
|
||||
self.newEditionChecker.finished.connect(self.reset_eta)
|
||||
|
||||
self.newEditionChecker.etaSignal.connect(self.update_eta)
|
||||
|
||||
self.progressBar.setMaximum(len(searchable_books))
|
||||
self.newEditionChecker.updateSignal.connect(self.update_status)
|
||||
|
||||
self.newEditionChecker.start()
|
||||
while self.newEditionChecker.isRunning():
|
||||
QtWidgets.QApplication.processEvents()
|
||||
results = self.newEditionChecker.results
|
||||
log.success("Finished checking for new editions, got {} results", len(results))
|
||||
if results == []:
|
||||
self.play_sound("error.mp3")
|
||||
return
|
||||
self.play_sound("ding.mp3")
|
||||
log.info(f"Found {len(results)} possible new editions - opening dialog")
|
||||
newEditionChecker = NewEditionChecker(results=results)
|
||||
newEditionChecker.exec()
|
||||
|
||||
accepted_books = newEditionChecker.accepted_books
|
||||
if accepted_books == []:
|
||||
return
|
||||
for book in accepted_books:
|
||||
oldBookId = self.db.getBookIdByPPN(book.old_book.ppn)
|
||||
apparats_id = self.db.getId(
|
||||
self.db.getApparatNameByAppNr(book.old_book.library_location)
|
||||
)
|
||||
self.db.insertNewEdition(book, oldBookId, apparats_id)
|
||||
pass
|
||||
|
||||
self.mail_thread = Mail_Dialog(
|
||||
prof_name=self.db.getSpecificProfData(prof_id, ["fullname"]),
|
||||
prof_mail=self.db.getProfMailById(prof_id),
|
||||
app_id=app_id,
|
||||
app_name=app_name,
|
||||
app_subject=subject,
|
||||
accepted_books=accepted_books,
|
||||
default_mail="Neuauflagen für Semesterapparat",
|
||||
)
|
||||
self.mail_thread.show()
|
||||
|
||||
def reset_eta(self):
|
||||
self.label_eta.setText("")
|
||||
|
||||
def reminder(self):
|
||||
log.info("Opening reminder dialog")
|
||||
reminder = ReminderDialog()
|
||||
@@ -1522,11 +1786,17 @@ class Ui(Ui_Semesterapparat):
|
||||
apparat_add_action = QtGui.QAction("Zum Apparat hinzufügen")
|
||||
apparat_move_action = QtGui.QAction("In Apparat verschieben")
|
||||
apparat_copy_action = QtGui.QAction("In Apparat kopieren")
|
||||
replace_old_editions = QtGui.QAction("Neuauflagen ersetzen")
|
||||
|
||||
apparatmenu = menu.addMenu("Apparate")
|
||||
generalmenu = menu.addMenu("Allgemeines")
|
||||
apparatmenu.addActions( # type: ignore
|
||||
[apparat_add_action, apparat_copy_action, apparat_move_action]
|
||||
[
|
||||
apparat_add_action,
|
||||
apparat_copy_action,
|
||||
apparat_move_action,
|
||||
replace_old_editions,
|
||||
]
|
||||
)
|
||||
generalmenu.addActions([edit_action, delete_action, update_data_action]) # type: ignore
|
||||
# disable apparat_add_action
|
||||
@@ -1537,11 +1807,77 @@ class Ui(Ui_Semesterapparat):
|
||||
apparat_copy_action.triggered.connect(self.copy_to_apparat) # type: ignore
|
||||
apparat_move_action.triggered.connect(self.move_to_apparat) # type: ignore
|
||||
update_data_action.triggered.connect(self.update_data) # type: ignore
|
||||
replace_old_editions.triggered.connect(self.replace_old_edition) # type: ignore
|
||||
menu.exec(self.tableWidget_apparat_media.mapToGlobal(position)) # type: ignore
|
||||
|
||||
def replace_old_edition(self):
|
||||
# open dialog
|
||||
dialog = QtWidgets.QDialog()
|
||||
dialog.setWindowTitle("Neuauflagen:")
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
label = QtWidgets.QLabel("Folgende Medien haben Neuauflagen:")
|
||||
layout.addWidget(label)
|
||||
table = QtWidgets.QTableWidget()
|
||||
table.setColumnCount(4)
|
||||
table.setHorizontalHeaderLabels(["Titel", "Auflage", "Signatur", "Neues Werk"])
|
||||
table.horizontalHeader().setStretchLastSection(True)
|
||||
new_editions = self.db.getBooksWithNewEditions(
|
||||
self.active_apparat,
|
||||
)
|
||||
for book in new_editions:
|
||||
table.insertRow(0)
|
||||
table.setItem(0, 0, QtWidgets.QTableWidgetItem(book[0].title))
|
||||
table.setItem(0, 1, QtWidgets.QTableWidgetItem(str(book[0].edition)))
|
||||
table.setItem(0, 2, QtWidgets.QTableWidgetItem(book[0].signature))
|
||||
new_ed_data = (
|
||||
f"{book[1].title} (Auflage {book[1].edition}, {book[1].signature})"
|
||||
)
|
||||
table.setItem(0, 3, QtWidgets.QTableWidgetItem(new_ed_data))
|
||||
|
||||
layout.addWidget(table)
|
||||
dialog.setLayout(layout)
|
||||
dialog.exec()
|
||||
|
||||
def update_data(self):
|
||||
# TODO: use link in table, parse data and if needed, update location / signature
|
||||
pass
|
||||
signatures = [
|
||||
self.tableWidget_apparat_media.item(row, 1).text()
|
||||
for row in range(self.tableWidget_apparat_media.rowCount())
|
||||
] # type: ignore
|
||||
prof_id = self.db.getProfId(self.profdata) # type: ignore
|
||||
app_id = self.db.getId(self.app_name.text()) # type: ignore
|
||||
books: List[Tuple[int, BookData]] = []
|
||||
for signature in signatures:
|
||||
book = self.db.getBookBasedOnSignature(
|
||||
app_id=app_id,
|
||||
signature=signature,
|
||||
prof_id=prof_id,
|
||||
)
|
||||
book_id = self.db.getBookIdBasedOnSignature(
|
||||
app_id,
|
||||
prof_id,
|
||||
signature,
|
||||
)
|
||||
books.append((book_id, book))
|
||||
# self.autoUpdater.entries = books
|
||||
# self.autoUpdater.finished.connect(self.autoUpdater.reset)
|
||||
self.updater = UpdaterThread()
|
||||
u_books = []
|
||||
for book_id, book in books:
|
||||
u_books.append({"id": book_id, "bookdata": book})
|
||||
self.updater.books = u_books
|
||||
self.progressBar.setMaximum(len(books))
|
||||
self.updater.finished.connect(self.updater.deleteLater)
|
||||
self.updater.finished.connect(self.update_app_media_list)
|
||||
self.updater.currtot.connect(self.update_status)
|
||||
self.updater.start()
|
||||
# ppn = book.link.split("kid=")[-1]
|
||||
# result = cat.get_book(ppn)
|
||||
# if result:
|
||||
# book.signature = result.signature
|
||||
# book.in_apparat = True
|
||||
# #print(book)
|
||||
# self.db.updateBookdata(book_id, book)
|
||||
# self.update_app_media_list()
|
||||
|
||||
def copy_to_apparat(self):
|
||||
selected_rows = self.tableWidget_apparat_media.selectionModel().selectedRows() # type: ignore
|
||||
@@ -1587,7 +1923,7 @@ class Ui(Ui_Semesterapparat):
|
||||
def confirm_action_dialog(self, message, title="Bestätigung"):
|
||||
appnrs = self.db.getUnavailableApparatNumbers()
|
||||
appnrs = [str(i) for i in appnrs]
|
||||
appnrs.remove(self.active_apparat)
|
||||
appnrs.remove(self.drpdwn_app_nr.currentText())
|
||||
if len(appnrs) == 0:
|
||||
# create a warning dialog, saying no apparats present
|
||||
self.confirm_popup("Keine weiteren Apparate vorhanden", title="Fehler")
|
||||
@@ -1639,12 +1975,12 @@ class Ui(Ui_Semesterapparat):
|
||||
).text()
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
data = self.db.getBookBasedOnSignature(
|
||||
app_id=self.active_apparat,
|
||||
app_id=self.db.getId(self.app_name.text()),
|
||||
signature=book,
|
||||
prof_id=prof_id,
|
||||
)
|
||||
book_id = self.db.getBookIdBasedOnSignature(
|
||||
self.active_apparat,
|
||||
self.db.getId(self.app_name.text()),
|
||||
prof_id,
|
||||
book,
|
||||
)
|
||||
@@ -1668,9 +2004,7 @@ class Ui(Ui_Semesterapparat):
|
||||
pass
|
||||
|
||||
def delete_medium(self):
|
||||
selected_apparat_id = self.tableWidget_apparate.item(
|
||||
self.tableWidget_apparate.currentRow(), 0
|
||||
).text()
|
||||
selected_apparat_id = self.active_apparat
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
# check how many rows are selected
|
||||
selected_rows = self.tableWidget_apparat_media.selectionModel().selectedRows()
|
||||
@@ -1732,10 +2066,18 @@ class Ui(Ui_Semesterapparat):
|
||||
else:
|
||||
return
|
||||
|
||||
def __contact_dialog(self, apparat, location: tuple | str, mail=None, pid=""):
|
||||
def __contact_dialog(
|
||||
self,
|
||||
apparat,
|
||||
location: tuple | str,
|
||||
mail=None,
|
||||
pid="",
|
||||
accepted_books=None,
|
||||
app_id="",
|
||||
):
|
||||
log.debug(
|
||||
"Got these values apparat: {}, location: {}, mail: {}, pid: {}".format(
|
||||
apparat, location, mail, pid
|
||||
"Got these values apparat: {}, location: {}, mail: {}, pid: {}, accepted_books: {}, app_id: {}".format(
|
||||
apparat, location, mail, pid, accepted_books, app_id
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1798,10 +2140,16 @@ class Ui(Ui_Semesterapparat):
|
||||
if state == 1:
|
||||
log.debug("Deleting apparat {}", selected_apparat_id)
|
||||
pid = self.db.getProfIDByApparat(selected_apparat_id)
|
||||
self.db.deleteApparat(selected_apparat_id, Semester().value)
|
||||
apparat = Apparat(
|
||||
appnr=int(selected_apparat_id),
|
||||
name=self.tableWidget_apparate.item(
|
||||
self.tableWidget_apparate.currentRow(), 1
|
||||
).text(),
|
||||
)
|
||||
self.db.deleteApparat(apparat=apparat, semester=Semester().value)
|
||||
# delete the corresponding entry from self.apparats
|
||||
for apparat in self.apparats:
|
||||
if apparat[4] == int(selected_apparat_id):
|
||||
if apparat.appnr == int(selected_apparat_id):
|
||||
self.apparats.remove(apparat)
|
||||
break
|
||||
self.old_apparats = self.apparats
|
||||
@@ -1842,6 +2190,7 @@ def launch_gui():
|
||||
) # if that thread uses an event loop
|
||||
app.aboutToQuit.connect(aui.docu.terminate) # our new slot
|
||||
app.aboutToQuit.connect(aui.docu.wait)
|
||||
app.aboutToQuit.connect(aui.newEditionChecker.terminate)
|
||||
atexit.register(tempdelete)
|
||||
# atexit.register(aui.validate_thread.quit)
|
||||
# atexit.register(aui.docu.quit)
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import darkdetect
|
||||
import loguru
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
from PySide6.QtCore import QDate
|
||||
from PySide6.QtGui import QColor, QPen
|
||||
|
||||
from src import LOG_DIR
|
||||
from src.backend import Database
|
||||
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
from src.shared.logging import log
|
||||
|
||||
color = "#ddfb00" if darkdetect.isDark() else "#2204ff"
|
||||
pen = QPen(QColor(color))
|
||||
@@ -43,9 +35,7 @@ class MessageCalendar(QtWidgets.QCalendarWidget):
|
||||
|
||||
def setMessages(self, messages: list[dict[str, Any]]):
|
||||
# remove all drawn circles
|
||||
|
||||
for message in messages:
|
||||
# print(message)
|
||||
# Convert the date string to a QDate object
|
||||
date = QDate.fromString(message["remind_at"], "yyyy-MM-dd")
|
||||
# Store the message for the date
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
__all__ = [
|
||||
"LoginWidget",
|
||||
"RegisterWidget",
|
||||
"DataQtGraph",
|
||||
"StatusWidget",
|
||||
"FilePicker",
|
||||
"DataGraph",
|
||||
"CalendarEntry",
|
||||
"MessageCalendar",
|
||||
"SearchStatisticPage",
|
||||
@@ -12,16 +10,23 @@ __all__ = [
|
||||
"EditUser",
|
||||
"EditProf",
|
||||
"IconWidget",
|
||||
"NewEditionChecker",
|
||||
"NewEditionCheckSelector",
|
||||
"UpdateSignatures",
|
||||
"UpdaterThread"
|
||||
]
|
||||
|
||||
from .admin_create_user import UserCreate
|
||||
from .admin_edit_prof import EditProf
|
||||
from .admin_edit_user import EditUser
|
||||
from .calendar_entry import CalendarEntry
|
||||
from .collapse import StatusWidget
|
||||
from .elsa_main import ElsaDialog
|
||||
from .filepicker import FilePicker
|
||||
from .graph import DataQtGraph
|
||||
from .calendar_entry import CalendarEntry
|
||||
from .MessageCalendar import MessageCalendar
|
||||
from .searchPage import SearchStatisticPage
|
||||
from .elsa_main import ElsaDialog
|
||||
from .admin_create_user import UserCreate
|
||||
from .admin_edit_user import EditUser
|
||||
from .admin_edit_prof import EditProf
|
||||
from .iconLine import IconWidget
|
||||
from .MessageCalendar import MessageCalendar
|
||||
from .new_edition_check import NewEditionChecker, NewEditionCheckSelector
|
||||
from .searchPage import SearchStatisticPage
|
||||
from .signature_update import UpdateSignatures, UpdaterThread
|
||||
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
from .widget_sources.admin_edit_prof_ui import Ui_Dialog #
|
||||
import sys
|
||||
|
||||
import loguru
|
||||
from PySide6 import QtWidgets
|
||||
|
||||
from src.logic import Prof
|
||||
from src.backend import Database
|
||||
import loguru
|
||||
import sys
|
||||
from src import LOG_DIR
|
||||
from src.backend import Database
|
||||
from src.logic import Prof
|
||||
|
||||
from .widget_sources.admin_edit_prof_ui import Ui_Dialog #
|
||||
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
|
||||
|
||||
class EditProf(QtWidgets.QDialog, Ui_Dialog):
|
||||
def __init__(self):
|
||||
super(EditProf, self).__init__()
|
||||
@@ -55,11 +57,11 @@ class EditProf(QtWidgets.QDialog, Ui_Dialog):
|
||||
# get the selected member
|
||||
name = self.edit_faculty_member_select_member.currentText()
|
||||
fullname = name.replace(",", "")
|
||||
# print(fullname, name)
|
||||
# #print(fullname, name)
|
||||
# get the data for the selected member
|
||||
data = self.db.getProfByName(fullname)
|
||||
# set the data
|
||||
# print(data)
|
||||
# #print(data)
|
||||
if data is None:
|
||||
self.edit_faculty_member_title.setText("")
|
||||
self.faculty_member_old_telnr.setText("")
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from .widget_sources.admin_edit_user_ui import Ui_Dialog
|
||||
from PySide6 import QtWidgets
|
||||
from src.backend import Database
|
||||
from src.backend import AdminCommands
|
||||
|
||||
from src.backend import AdminCommands, Database
|
||||
|
||||
from .widget_sources.admin_edit_user_ui import Ui_Dialog
|
||||
|
||||
admin = AdminCommands()
|
||||
|
||||
@@ -51,7 +52,7 @@ class EditUser(QtWidgets.QDialog, Ui_Dialog):
|
||||
"role": role,
|
||||
}
|
||||
data = {key: value for key, value in data.items() if value is not None}
|
||||
# print(data)
|
||||
# #print(data)
|
||||
self.db.updateUser(username=username, data=data)
|
||||
self.user_delete_frame_user_select.setCurrentText("")
|
||||
self.user_edit_frame_new_password.clear()
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from .widget_sources.admin_query_ui import Ui_Form
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
from src import Icon
|
||||
from src.backend import Database
|
||||
|
||||
from .widget_sources. import Ui_Form
|
||||
|
||||
|
||||
class AdminQueryWidget(QtWidgets.QWidget, Ui_Form):
|
||||
def __init__(self, parent=None):
|
||||
@@ -22,7 +23,7 @@ class AdminQueryWidget(QtWidgets.QWidget, Ui_Form):
|
||||
return
|
||||
|
||||
data = self.db.query_db(request_text)
|
||||
print(data)
|
||||
# print(data)
|
||||
table_names = (
|
||||
request_text.lower().split("select")[1].split("from")[0].split(",")
|
||||
)
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from .widget_sources.calendar_entry_ui import Ui_Dialog
|
||||
from PySide6 import QtWidgets
|
||||
from PySide6.QtCore import Signal
|
||||
from src.backend.database import Database
|
||||
|
||||
from src import Icon
|
||||
from src.backend.database import Database
|
||||
|
||||
from .widget_sources.calendar_entry_ui import Ui_Dialog
|
||||
|
||||
|
||||
class CalendarEntry(QtWidgets.QDialog, Ui_Dialog):
|
||||
@@ -36,12 +38,12 @@ class CalendarEntry(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
def delete_message(self):
|
||||
value = self.spin_select_message.value()
|
||||
# print(value)
|
||||
# #print(value)
|
||||
if value > 0:
|
||||
value = value - 1
|
||||
message = self.messages[value]
|
||||
id = self.__get_id(message)
|
||||
# print("id", id)
|
||||
# #print("id", id)
|
||||
# del self.messages[value - 1]
|
||||
self.spin_select_message.setMaximum(len(self.messages))
|
||||
self.message_box.clear()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# import pysignal pyslot
|
||||
from PySide6.QtCore import Signal as Signal
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication,
|
||||
QTreeWidget,
|
||||
QTreeWidgetItem,
|
||||
QVBoxLayout,
|
||||
@@ -30,7 +29,7 @@ class StatusWidget(QWidget):
|
||||
while parent:
|
||||
parent_depth += 1
|
||||
parent = parent.parent()
|
||||
# print(parent_depth)
|
||||
# #print(parent_depth)
|
||||
# Emit the person_double_clicked signal with the name of the person and the parent depth
|
||||
self.person_double_clicked.emit(self.header, item.text(column), parent_depth)
|
||||
|
||||
@@ -61,17 +60,3 @@ class StatusWidget(QWidget):
|
||||
|
||||
# Make the action entry collapsible
|
||||
action_item.setExpanded(True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
data = {"test": {"test2": ["test3", "test4"]}}
|
||||
widget = StatusWidget(data, "test")
|
||||
|
||||
widget.show()
|
||||
# detect emit signal
|
||||
widget.person_double_clicked.connect(lambda x: print(x))
|
||||
|
||||
sys.exit(app.exec())
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
import os
|
||||
from .widget_sources.elsa_maindialog_ui import Ui_Dialog
|
||||
from PySide6 import QtCore, QtWidgets, QtGui
|
||||
from PySide6.QtGui import QRegularExpressionValidator
|
||||
from PySide6.QtCore import QDate
|
||||
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, DataQtGraph
|
||||
from src.backend import recreateElsaFile
|
||||
import loguru
|
||||
import sys
|
||||
from src import LOG_DIR
|
||||
log = loguru.logger
|
||||
log.remove()
|
||||
log.add(sys.stdout, level="INFO")
|
||||
log.add(f"{LOG_DIR}/application.log", rotation="1 MB", retention="10 days")
|
||||
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
from PySide6.QtCore import QDate
|
||||
from PySide6.QtGui import QRegularExpressionValidator
|
||||
|
||||
from src import Icon
|
||||
from src.backend import Database, recreateElsaFile
|
||||
from src.logic import Prof, Semester, elsa_word_to_csv
|
||||
from src.shared.logging import log
|
||||
from src.ui.dialogs import ElsaAddEntry, popus_confirm
|
||||
from src.ui.widgets.filepicker import FilePicker
|
||||
from src.ui.widgets.graph import DataQtGraph
|
||||
|
||||
from .widget_sources.elsa_maindialog_ui import Ui_Dialog
|
||||
|
||||
|
||||
class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
@@ -240,7 +236,7 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
if prof_id is None:
|
||||
self.db.createProf(profdata)
|
||||
prof_id = self.db.getProfId(prof)
|
||||
prof_id = self.db.getProfId(profdata)
|
||||
self.profs.append(
|
||||
"f{}, {}".format(profdata.lastname, profdata.firstname), prof_id
|
||||
)
|
||||
@@ -397,6 +393,7 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
# get the file path of the selected file based on it's row
|
||||
row = self.dokument_list_elsa.currentRow()
|
||||
file = self.dokument_list_elsa.item(row, 3).text()
|
||||
file_location = file
|
||||
if file == "Database":
|
||||
filename = self.dokument_list_elsa.item(row, 0).text()
|
||||
filetype = self.dokument_list_elsa.item(row, 1).text()
|
||||
@@ -413,6 +410,17 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
log.debug(
|
||||
f"elsa_id: {elsa_id}, prof: {self.elsa_prof.currentText()}, semester: {self.elsa_semester.text()}, date: {self.elsa_date.text()}"
|
||||
)
|
||||
if file_location != "Database":
|
||||
self.db.insertElsaFile(
|
||||
[
|
||||
{
|
||||
"name": file.split("/")[-1],
|
||||
"path": file,
|
||||
"type": file.split(".")[-1],
|
||||
}
|
||||
],
|
||||
elsa_id,
|
||||
)
|
||||
for row in data:
|
||||
if self.seperateEntries.isChecked():
|
||||
if ";" in row["pages"]:
|
||||
@@ -426,6 +434,7 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
else:
|
||||
self.setElsaRow(row)
|
||||
self.db.addElsaMedia(row, elsa_id)
|
||||
|
||||
self.quote_entry.setEnabled(True)
|
||||
|
||||
def openDocumentElsa(self):
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user