Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 789fb5d77f | |||
| d19c36191c | |||
| 3e20b186c7 |
@@ -4,7 +4,7 @@ Spreche mit mir auf Deutsch! (Communicate with me in German!)
|
|||||||
|
|
||||||
## Projektübersicht
|
## Projektübersicht
|
||||||
|
|
||||||
DocuMentor (ehemals xsl-validator) ist eine PySide6-basierte Desktop-Anwendung zur Verwaltung und Validierung von XSL-Transformationen mit XML-Dateien. Sie bietet eine GUI zur Konfiguration von Transformations-Toolchains (Saxon, Apache FOP, diff-pdf) und zur Verwaltung von PDF-Generierungsprojekten mit PostgreSQL-Datenbankintegration.
|
DocuMentor ist eine PySide6-basierte Desktop-Anwendung zur Verwaltung und Validierung von XSL-Transformationen mit XML-Dateien. Sie bietet eine GUI zur Konfiguration von Transformations-Toolchains (Saxon, Apache FOP, diff-pdf) und zur Verwaltung von PDF-Generierungsprojekten mit PostgreSQL-Datenbankintegration.
|
||||||
|
|
||||||
## Anvisiertes Nutzungsszenario
|
## Anvisiertes Nutzungsszenario
|
||||||
Der primäre Einsatz ist die kontinuierliche Weiterentwicklung von PDF-Dokumenten in Flexnow (Software zur Prüfungsverwaltung). Dabei handelt es sich beispielsweise um amtliche Urkunden, Zeugnisse und Bescheide.
|
Der primäre Einsatz ist die kontinuierliche Weiterentwicklung von PDF-Dokumenten in Flexnow (Software zur Prüfungsverwaltung). Dabei handelt es sich beispielsweise um amtliche Urkunden, Zeugnisse und Bescheide.
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<!-- Paket-Definition (ersetzt Product in v4) -->
|
<!-- Paket-Definition (ersetzt Product in v4) -->
|
||||||
<Package
|
<Package
|
||||||
Name="DocuMentor"
|
Name="DocuMentor"
|
||||||
Version="1.7.1"
|
Version="1.7.3"
|
||||||
Manufacturer="Vitali Graf / Software- und Datenbankentwicklung"
|
Manufacturer="Vitali Graf / Software- und Datenbankentwicklung"
|
||||||
UpgradeCode="F498B66C-726D-44AA-95F4-CB4FBDCEF26E"
|
UpgradeCode="F498B66C-726D-44AA-95F4-CB4FBDCEF26E"
|
||||||
Language="1031"
|
Language="1031"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
**Professionelle XSL-Transformations-Verwaltung und PDF-Generierung**
|
**Professionelle XSL-Transformations-Verwaltung und PDF-Generierung**
|
||||||
|
|
||||||
DocuMentor (ehemals xsl-validator) ist eine leistungsstarke PySide6-basierte Desktop-Anwendung zur Verwaltung und Validierung von XSL-Transformationen mit automatischer PDF-Generierung. Die Anwendung bietet eine intuitive GUI zur Konfiguration von Transformations-Toolchains (Saxon, Apache FOP, diff-pdf) und zur Verwaltung komplexer PDF-Generierungsprojekte mit PostgreSQL-Datenbankintegration.
|
DocuMentor ist eine leistungsstarke PySide6-basierte Desktop-Anwendung zur Verwaltung und Validierung von XSL-Transformationen mit automatischer PDF-Generierung. Die Anwendung bietet eine intuitive GUI zur Konfiguration von Transformations-Toolchains (Saxon, Apache FOP, diff-pdf) und zur Verwaltung komplexer PDF-Generierungsprojekte mit PostgreSQL-Datenbankintegration.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ DocuMentor (ehemals xsl-validator) ist eine leistungsstarke PySide6-basierte Des
|
|||||||
### ⚡ Asynchrone Batch-Verarbeitung
|
### ⚡ Asynchrone Batch-Verarbeitung
|
||||||
- Verarbeiten Sie große Mengen von XML-Dateien im Hintergrund
|
- Verarbeiten Sie große Mengen von XML-Dateien im Hintergrund
|
||||||
- Fortschrittsanzeige für lange Transformationen
|
- Fortschrittsanzeige für lange Transformationen
|
||||||
- 4x schnellere XSLT-Transformationen durch Worker-Pool-Architektur
|
- Parallelisierte XSLT-Transformationen durch eine Worker-Pool-Architektur
|
||||||
|
|
||||||
### 🔍 Intelligente Duplikatserkennung
|
### 🔍 Intelligente Duplikatserkennung
|
||||||
- Automatische Hash-basierte Erkennung von identischen XML-Dateien (Blake2b)
|
- Automatische Hash-basierte Erkennung von identischen XML-Dateien (Blake2b)
|
||||||
@@ -37,7 +37,7 @@ DocuMentor (ehemals xsl-validator) ist eine leistungsstarke PySide6-basierte Des
|
|||||||
- Plattformübergreifende Unterstützung (Linux, Windows, macOS)
|
- Plattformübergreifende Unterstützung (Linux, Windows, macOS)
|
||||||
|
|
||||||
### 🎨 Modernes UI
|
### 🎨 Modernes UI
|
||||||
- Dark-Theme-Unterstützung via `qdarktheme`
|
- Dark/Light-Theme-Unterstützung
|
||||||
- Drag-and-Drop für XML-Dateien
|
- Drag-and-Drop für XML-Dateien
|
||||||
- Responsive und intuitive Benutzeroberfläche
|
- Responsive und intuitive Benutzeroberfläche
|
||||||
|
|
||||||
@@ -58,13 +58,14 @@ uv sync
|
|||||||
pip install -e .
|
pip install -e .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Externe Tools (optional)
|
### Externe Tools
|
||||||
|
|
||||||
Für die volle Funktionalität benötigen Sie:
|
Für die volle Funktionalität benötigen Sie:
|
||||||
|
|
||||||
- **Saxon-HE**: XSLT 3.0 Prozessor ([Download](https://www.saxonica.com/download/))
|
- **Saxon-HE**: XSLT 3.0 Prozessor ([Download](https://www.saxonica.com/download/))
|
||||||
- **Apache FOP**: PDF-Generierung aus XSL-FO ([Download](https://xmlgraphics.apache.org/fop/download.html))
|
- **Apache FOP**: PDF-Generierung aus XSL-FO ([Download](https://xmlgraphics.apache.org/fop/download.html))
|
||||||
- **diff-pdf**: PDF-Vergleich ([GitHub](https://github.com/vslavik/diff-pdf))
|
- **diff-pdf**: PDF-Vergleich ([GitHub](https://github.com/vslavik/diff-pdf))
|
||||||
|
- **OpenJDK/JRE**: für Saxon und Apache FOP. JDK empfohlen für Worker-Pools ([Eclipse Temurin](https://adoptium.net))
|
||||||
|
|
||||||
## Verwendung
|
## Verwendung
|
||||||
|
|
||||||
@@ -74,12 +75,14 @@ Für die volle Funktionalität benötigen Sie:
|
|||||||
uv run python src/main.py
|
uv run python src/main.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Erste Start
|
||||||
|
Konfigurieren Sie Ihre Tools (Saxon, Apache FOP, diff-pdf) in den Einstellungen
|
||||||
|
|
||||||
### Projekt erstellen
|
### Projekt erstellen
|
||||||
|
|
||||||
1. Legen Sie ein neues Projekt an
|
1. Legen Sie ein neues Projekt an
|
||||||
2. Konfigurieren Sie Ihre Tools (Saxon, Apache FOP) in den Einstellungen
|
2. Organisieren Sie XSL-Stylesheets und XML-Dateien in der Baumstruktur
|
||||||
3. Organisieren Sie XSL-Stylesheets und XML-Dateien in der Baumstruktur
|
3. Führen Sie Transformationen aus
|
||||||
4. Führen Sie Transformationen aus
|
|
||||||
|
|
||||||
### Konfiguration
|
### Konfiguration
|
||||||
|
|
||||||
|
|||||||
@@ -263,5 +263,5 @@ HINWEISE
|
|||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
Stand: Mai 2026
|
Stand: Mai 2026
|
||||||
Erstellt für: DocuMentor v1.7.1
|
Erstellt für: DocuMentor v1.7.3
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
; Build-Befehl: iscc installer.iss
|
; Build-Befehl: iscc installer.iss
|
||||||
|
|
||||||
#define MyAppName "DocuMentor"
|
#define MyAppName "DocuMentor"
|
||||||
#define MyAppVersion "1.7.1"
|
#define MyAppVersion "1.7.3"
|
||||||
#define MyAppPublisher "Ihr Name/Organisation"
|
#define MyAppPublisher "Ihr Name/Organisation"
|
||||||
#define MyAppURL "https://github.com/yourusername/xsl-validator"
|
#define MyAppURL "https://github.com/yourusername/xsl-validator"
|
||||||
#define MyAppExeName "DocuMentor.exe"
|
#define MyAppExeName "DocuMentor.exe"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "DocuMentor"
|
name = "DocuMentor"
|
||||||
version = "1.7.1"
|
version = "1.7.3"
|
||||||
description = "Professionelle XSL-Transformations-Verwaltung und PDF-Generierung"
|
description = "Professionelle XSL-Transformations-Verwaltung und PDF-Generierung"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = {text = "MIT"}
|
license = {text = "MIT"}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ ICONS = [
|
|||||||
"file-plus",
|
"file-plus",
|
||||||
"columns",
|
"columns",
|
||||||
"sliders",
|
"sliders",
|
||||||
|
"database",
|
||||||
|
"activity",
|
||||||
]
|
]
|
||||||
|
|
||||||
BASE_URL = "https://raw.githubusercontent.com/feathericons/feather/master/icons/{name}.svg"
|
BASE_URL = "https://raw.githubusercontent.com/feathericons/feather/master/icons/{name}.svg"
|
||||||
|
|||||||
+57
-9
@@ -1,5 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
from PySide6.QtCore import QByteArray, QFile, Qt
|
from PySide6.QtCore import QByteArray, QEvent, QFile, Qt
|
||||||
from PySide6.QtGui import QIcon, QPainter, QPixmap, QPalette
|
from PySide6.QtGui import QIcon, QPainter, QPixmap, QPalette
|
||||||
from PySide6.QtSvg import QSvgRenderer
|
from PySide6.QtSvg import QSvgRenderer
|
||||||
from PySide6.QtWidgets import QApplication
|
from PySide6.QtWidgets import QApplication
|
||||||
@@ -7,6 +7,10 @@ import res.resources_rc # noqa: F401 # registriert die Qt-Ressourcen (Icons) b
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Basisgröße für das einmalige Rendern; Qt skaliert daraus die benötigten Icon-Größen
|
||||||
|
# (16/24/32 px in Menüs, Bäumen, Buttons). 64 px bietet genug Reserve auch für HiDPI.
|
||||||
|
_RENDER_SIZE = 64
|
||||||
|
|
||||||
# Cache: (Icon-Name, Theme-Textfarbe) → fertig gerendertes QIcon.
|
# Cache: (Icon-Name, Theme-Textfarbe) → fertig gerendertes QIcon.
|
||||||
# Der Farb-Anteil im Schlüssel sorgt dafür, dass ein Theme-Wechsel automatisch
|
# Der Farb-Anteil im Schlüssel sorgt dafür, dass ein Theme-Wechsel automatisch
|
||||||
# neue Einträge erzeugt, ohne dass der Cache explizit geleert werden muss.
|
# neue Einträge erzeugt, ohne dass der Cache explizit geleert werden muss.
|
||||||
@@ -44,14 +48,58 @@ def icon(name: str) -> QIcon:
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
renderer = QSvgRenderer(svg_data)
|
renderer = QSvgRenderer(svg_data)
|
||||||
result = QIcon()
|
pixmap = QPixmap(_RENDER_SIZE, _RENDER_SIZE)
|
||||||
for size in (16, 24, 32):
|
pixmap.fill(Qt.GlobalColor.transparent)
|
||||||
pixmap = QPixmap(size, size)
|
painter = QPainter(pixmap)
|
||||||
pixmap.fill(Qt.GlobalColor.transparent)
|
renderer.render(painter)
|
||||||
painter = QPainter(pixmap)
|
painter.end()
|
||||||
renderer.render(painter)
|
|
||||||
painter.end()
|
|
||||||
result.addPixmap(pixmap)
|
|
||||||
|
|
||||||
|
result = QIcon(pixmap)
|
||||||
_ICON_CACHE[cache_key] = result
|
_ICON_CACHE[cache_key] = result
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class IconRefreshMixin:
|
||||||
|
"""
|
||||||
|
Mischklasse für Top-Level-Widgets, deren Icons sich beim Theme-Wechsel automatisch neu einfärben.
|
||||||
|
|
||||||
|
Voraussetzungen für die nutzende Klasse:
|
||||||
|
- Sie stellt eine Methode ``_setup_icons()`` bereit, die alle ihre Icons neu setzt.
|
||||||
|
- Nach abgeschlossener Initialisierung setzt sie ``self._icons_ready = True``
|
||||||
|
(idealerweise zusammen mit ``self._last_icon_color``, siehe ``mark_icons_ready()``).
|
||||||
|
|
||||||
|
Bei einem Style-/Palette-Wechsel wird – nur wenn sich die Theme-Textfarbe tatsächlich
|
||||||
|
geändert hat – ``_on_icon_theme_changed()`` aufgerufen (Standard: ``_setup_icons()``).
|
||||||
|
Unterklassen können ``_on_icon_theme_changed()`` überschreiben, um zusätzlich z.B.
|
||||||
|
Baum-Icons neu zu zeichnen.
|
||||||
|
|
||||||
|
Hinweis: ``IconRefreshMixin`` muss in der Klassenbasis VOR der Qt-Basisklasse
|
||||||
|
(``QMainWindow``/``QDialog``) stehen, damit das überschriebene ``changeEvent`` greift.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_icons_ready: bool = False
|
||||||
|
_last_icon_color: str | None = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _current_text_color() -> str | None:
|
||||||
|
app = QApplication.instance()
|
||||||
|
if app is None:
|
||||||
|
return None
|
||||||
|
return app.palette().color(QPalette.ColorRole.WindowText).name()
|
||||||
|
|
||||||
|
def mark_icons_ready(self):
|
||||||
|
"""Schaltet die Theme-Reaktivität scharf (nach dem ersten ``_setup_icons()`` aufrufen)."""
|
||||||
|
self._last_icon_color = self._current_text_color()
|
||||||
|
self._icons_ready = True
|
||||||
|
|
||||||
|
def changeEvent(self, event):
|
||||||
|
if event.type() in (QEvent.Type.PaletteChange, QEvent.Type.StyleChange) and self._icons_ready:
|
||||||
|
color = self._current_text_color()
|
||||||
|
if color is not None and color != self._last_icon_color:
|
||||||
|
self._last_icon_color = color
|
||||||
|
self._on_icon_theme_changed()
|
||||||
|
super().changeEvent(event)
|
||||||
|
|
||||||
|
def _on_icon_theme_changed(self):
|
||||||
|
"""Reaktion auf eine geänderte Theme-Textfarbe. Standard: alle Icons neu setzen."""
|
||||||
|
self._setup_icons()
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
|
||||||
|
After Width: | Height: | Size: 239 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>
|
||||||
|
After Width: | Height: | Size: 318 B |
@@ -21,5 +21,7 @@
|
|||||||
<file>icons/file-plus.svg</file>
|
<file>icons/file-plus.svg</file>
|
||||||
<file>icons/columns.svg</file>
|
<file>icons/columns.svg</file>
|
||||||
<file>icons/sliders.svg</file>
|
<file>icons/sliders.svg</file>
|
||||||
|
<file>icons/database.svg</file>
|
||||||
|
<file>icons/activity.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
+85
-34
@@ -168,6 +168,28 @@ h d=\x22M3.51 9a9 9\
|
|||||||
4 4.36A9 9 0 0 0\
|
4 4.36A9 9 0 0 0\
|
||||||
20.49 15\x22/></sv\
|
20.49 15\x22/></sv\
|
||||||
g>\
|
g>\
|
||||||
|
\x00\x00\x01>\
|
||||||
|
<\
|
||||||
|
svg xmlns=\x22http:\
|
||||||
|
//www.w3.org/200\
|
||||||
|
0/svg\x22 width=\x2224\
|
||||||
|
\x22 height=\x2224\x22 vi\
|
||||||
|
ewBox=\x220 0 24 24\
|
||||||
|
\x22 fill=\x22none\x22 st\
|
||||||
|
roke=\x22currentCol\
|
||||||
|
or\x22 stroke-width\
|
||||||
|
=\x222\x22 stroke-line\
|
||||||
|
cap=\x22round\x22 stro\
|
||||||
|
ke-linejoin=\x22rou\
|
||||||
|
nd\x22><ellipse cx=\
|
||||||
|
\x2212\x22 cy=\x225\x22 rx=\x22\
|
||||||
|
9\x22 ry=\x223\x22/><path\
|
||||||
|
d=\x22M21 12c0 1.6\
|
||||||
|
6-4 3-9 3s-9-1.3\
|
||||||
|
4-9-3\x22/><path d=\
|
||||||
|
\x22M3 5v14c0 1.66 \
|
||||||
|
4 3 9 3s9-1.34 9\
|
||||||
|
-3V5\x22/></svg>\
|
||||||
\x00\x00\x01\x12\
|
\x00\x00\x01\x12\
|
||||||
<\
|
<\
|
||||||
svg xmlns=\x22http:\
|
svg xmlns=\x22http:\
|
||||||
@@ -395,6 +417,23 @@ y2=\x2217\x22/><polyli\
|
|||||||
ne points=\x2210 9 \
|
ne points=\x2210 9 \
|
||||||
9 9 8 9\x22/></svg>\
|
9 9 8 9\x22/></svg>\
|
||||||
\
|
\
|
||||||
|
\x00\x00\x00\xef\
|
||||||
|
<\
|
||||||
|
svg xmlns=\x22http:\
|
||||||
|
//www.w3.org/200\
|
||||||
|
0/svg\x22 width=\x2224\
|
||||||
|
\x22 height=\x2224\x22 vi\
|
||||||
|
ewBox=\x220 0 24 24\
|
||||||
|
\x22 fill=\x22none\x22 st\
|
||||||
|
roke=\x22currentCol\
|
||||||
|
or\x22 stroke-width\
|
||||||
|
=\x222\x22 stroke-line\
|
||||||
|
cap=\x22round\x22 stro\
|
||||||
|
ke-linejoin=\x22rou\
|
||||||
|
nd\x22><polyline po\
|
||||||
|
ints=\x2222 12 18 1\
|
||||||
|
2 15 21 9 3 6 12\
|
||||||
|
2 12\x22/></svg>\
|
||||||
\x00\x00\x01q\
|
\x00\x00\x01q\
|
||||||
<\
|
<\
|
||||||
svg xmlns=\x22http:\
|
svg xmlns=\x22http:\
|
||||||
@@ -524,6 +563,10 @@ qt_resource_name = b"\
|
|||||||
\x04\x1b\xd7\x87\
|
\x04\x1b\xd7\x87\
|
||||||
\x00r\
|
\x00r\
|
||||||
\x00e\x00f\x00r\x00e\x00s\x00h\x00-\x00c\x00w\x00.\x00s\x00v\x00g\
|
\x00e\x00f\x00r\x00e\x00s\x00h\x00-\x00c\x00w\x00.\x00s\x00v\x00g\
|
||||||
|
\x00\x0c\
|
||||||
|
\x05\xc9\x15\xc7\
|
||||||
|
\x00d\
|
||||||
|
\x00a\x00t\x00a\x00b\x00a\x00s\x00e\x00.\x00s\x00v\x00g\
|
||||||
\x00\x0a\
|
\x00\x0a\
|
||||||
\x0a\xc8\xf6\x87\
|
\x0a\xc8\xf6\x87\
|
||||||
\x00f\
|
\x00f\
|
||||||
@@ -560,6 +603,10 @@ qt_resource_name = b"\
|
|||||||
\x06\xf2R'\
|
\x06\xf2R'\
|
||||||
\x00f\
|
\x00f\
|
||||||
\x00i\x00l\x00e\x00-\x00t\x00e\x00x\x00t\x00.\x00s\x00v\x00g\
|
\x00i\x00l\x00e\x00-\x00t\x00e\x00x\x00t\x00.\x00s\x00v\x00g\
|
||||||
|
\x00\x0c\
|
||||||
|
\x0cQ;g\
|
||||||
|
\x00a\
|
||||||
|
\x00c\x00t\x00i\x00v\x00i\x00t\x00y\x00.\x00s\x00v\x00g\
|
||||||
\x00\x0d\
|
\x00\x0d\
|
||||||
\x09\xc3S\x87\
|
\x09\xc3S\x87\
|
||||||
\x00f\
|
\x00f\
|
||||||
@@ -581,48 +628,52 @@ qt_resource_name = b"\
|
|||||||
qt_resource_struct = b"\
|
qt_resource_struct = b"\
|
||||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x14\x00\x00\x00\x02\
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x16\x00\x00\x00\x02\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\x06\xa5\
|
\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\x06\xa5\
|
||||||
\x00\x00\x01\x9ey\x0c6\xfa\
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
\x00\x00\x01L\x00\x00\x00\x00\x00\x01\x00\x00\x0e\xe4\
|
\x00\x00\x01j\x00\x00\x00\x00\x00\x01\x00\x00\x10&\
|
||||||
\x00\x00\x01\x9ey\x0c3\x89\
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
||||||
\x00\x00\x01\x9ey\x0c4\x94\
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
\x00\x00\x00\xcc\x00\x00\x00\x00\x00\x01\x00\x00\x07\xcd\
|
\x00\x00\x00\xcc\x00\x00\x00\x00\x00\x01\x00\x00\x07\xcd\
|
||||||
\x00\x00\x01\x9ey\x0c2\xb4\
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
\x00\x00\x02\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x1a\x0c\
|
\x00\x00\x02\x98\x00\x00\x00\x00\x00\x01\x00\x00\x1cA\
|
||||||
\x00\x00\x01\x9ey\x0c:\x95\
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
\x00\x00\x00v\x00\x00\x00\x00\x00\x01\x00\x00\x04\x1e\
|
\x00\x00\x00v\x00\x00\x00\x00\x00\x01\x00\x00\x04\x1e\
|
||||||
\x00\x00\x01\x9ey\x0cB\x90\
|
\x00\x00\x01\x9ez2\xf1\x11\
|
||||||
\x00\x00\x01\xb2\x00\x00\x00\x00\x00\x01\x00\x00\x12c\
|
\x00\x00\x01\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x13\xa5\
|
||||||
\x00\x00\x01\x9ey\x0c9c\
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
\x00\x00\x02*\x00\x00\x00\x00\x00\x01\x00\x00\x17~\
|
\x00\x00\x02f\x00\x00\x00\x00\x00\x01\x00\x00\x19\xb3\
|
||||||
\x00\x00\x01\x9ey\x0c<\x93\
|
\x00\x00\x01\x9ez2\xf1\x11\
|
||||||
\x00\x00\x01p\x00\x00\x00\x00\x00\x01\x00\x00\x10\x0f\
|
|
||||||
\x00\x00\x01\x9ey\x0c.\xf3\
|
|
||||||
\x00\x00\x00\x92\x00\x00\x00\x00\x00\x01\x00\x00\x05B\
|
|
||||||
\x00\x00\x01\x9ey\x0c-\x81\
|
|
||||||
\x00\x00\x01\xea\x00\x00\x00\x00\x00\x01\x00\x00\x14t\
|
|
||||||
\x00\x00\x01\x9ey\x0c;i\
|
|
||||||
\x00\x00\x01\xc8\x00\x00\x00\x00\x00\x01\x00\x00\x13\x91\
|
|
||||||
\x00\x00\x01\x9ey\x0c>\xf8\
|
|
||||||
\x00\x00\x02\x0a\x00\x00\x00\x00\x00\x01\x00\x00\x16\x09\
|
|
||||||
\x00\x00\x01\x9ey\x0cA`\
|
|
||||||
\x00\x00\x00\xee\x00\x00\x00\x00\x00\x01\x00\x00\x09$\
|
\x00\x00\x00\xee\x00\x00\x00\x00\x00\x01\x00\x00\x09$\
|
||||||
\x00\x00\x01\x9ey\x0c1c\
|
\x00\x00\x01\x9e}\xa1\x91F\
|
||||||
|
\x00\x00\x01\x8e\x00\x00\x00\x00\x00\x01\x00\x00\x11Q\
|
||||||
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
|
\x00\x00\x00\x92\x00\x00\x00\x00\x00\x01\x00\x00\x05B\
|
||||||
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
|
\x00\x00\x02\x08\x00\x00\x00\x00\x00\x01\x00\x00\x15\xb6\
|
||||||
|
\x00\x00\x01\x9ez2\xf1\x11\
|
||||||
|
\x00\x00\x01\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x14\xd3\
|
||||||
|
\x00\x00\x01\x9ez2\xf1\x11\
|
||||||
|
\x00\x00\x02F\x00\x00\x00\x00\x00\x01\x00\x00\x18>\
|
||||||
|
\x00\x00\x01\x9ez2\xf1\x11\
|
||||||
|
\x00\x00\x01\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x0af\
|
||||||
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
\x00\x00\x00R\x00\x00\x00\x00\x00\x01\x00\x00\x03\x16\
|
\x00\x00\x00R\x00\x00\x00\x00\x00\x01\x00\x00\x03\x16\
|
||||||
\x00\x00\x01\x9ey\x0c5\xc9\
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
\x00\x00\x01.\x00\x00\x00\x00\x00\x01\x00\x00\x0b\x1c\
|
\x00\x00\x01L\x00\x00\x00\x00\x00\x01\x00\x00\x0c^\
|
||||||
\x00\x00\x01\x9ey\x0c00\
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
\x00\x00\x02@\x00\x00\x00\x00\x00\x01\x00\x00\x18\x84\
|
\x00\x00\x02|\x00\x00\x00\x00\x00\x01\x00\x00\x1a\xb9\
|
||||||
\x00\x00\x01\x9ey\x0c?\xdf\
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
|
\x00\x00\x02(\x00\x00\x00\x00\x00\x01\x00\x00\x17K\
|
||||||
|
\x00\x00\x01\x9e}\xa1\x92!\
|
||||||
\x00\x00\x006\x00\x00\x00\x00\x00\x01\x00\x00\x01\x05\
|
\x00\x00\x006\x00\x00\x00\x00\x00\x01\x00\x00\x01\x05\
|
||||||
\x00\x00\x01\x9ey\x0cC\xc7\
|
\x00\x00\x01\x9ez2\xf1\x12\
|
||||||
\x00\x00\x01\x8c\x00\x00\x00\x00\x00\x01\x00\x00\x11L\
|
\x00\x00\x01\xaa\x00\x00\x00\x00\x00\x01\x00\x00\x12\x8e\
|
||||||
\x00\x00\x01\x9ey\x0c8.\
|
\x00\x00\x01\x9ez2\xf1\x11\
|
||||||
\x00\x00\x01\x08\x00\x00\x00\x00\x00\x01\x00\x00\x0a:\
|
\x00\x00\x01&\x00\x00\x00\x00\x00\x01\x00\x00\x0b|\
|
||||||
\x00\x00\x01\x9ey\x0c=\xc8\
|
\x00\x00\x01\x9ez2\xf1\x11\
|
||||||
"
|
"
|
||||||
|
|
||||||
def qInitResources():
|
def qInitResources():
|
||||||
|
|||||||
+19
-9
@@ -25,7 +25,7 @@ from ui.mixins import (
|
|||||||
TransformationMixin,
|
TransformationMixin,
|
||||||
)
|
)
|
||||||
from conf import app_settings, Project, ProjectData, TreeNode, XslFile
|
from conf import app_settings, Project, ProjectData, TreeNode, XslFile
|
||||||
from icons import icon
|
from icons import icon, IconRefreshMixin
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class MainWindow(
|
class MainWindow(
|
||||||
|
IconRefreshMixin,
|
||||||
QMainWindow,
|
QMainWindow,
|
||||||
TreeManagerMixin,
|
TreeManagerMixin,
|
||||||
PdfViewerMixin,
|
PdfViewerMixin,
|
||||||
@@ -141,8 +142,11 @@ class MainWindow(
|
|||||||
# Zoom per Mausrad (STRG+Mausrad) für PDF-Viewer aktivieren
|
# Zoom per Mausrad (STRG+Mausrad) für PDF-Viewer aktivieren
|
||||||
self._setup_scroll_area_zoom()
|
self._setup_scroll_area_zoom()
|
||||||
|
|
||||||
# Icons setzen (überschreibt fromTheme()-Icons aus _ui.py)
|
# Icons setzen (überschreibt fromTheme()-Icons aus _ui.py). Läuft nach
|
||||||
|
# _connect_signals(), daher existieren auch die programmatisch erzeugten Aktionen.
|
||||||
self._setup_icons()
|
self._setup_icons()
|
||||||
|
# Ab hier reagiert das Fenster auf Theme-Wechsel (siehe IconRefreshMixin)
|
||||||
|
self.mark_icons_ready()
|
||||||
|
|
||||||
# Gespeicherte UI-Zustände wiederherstellen
|
# Gespeicherte UI-Zustände wiederherstellen
|
||||||
self._restore_ui_state()
|
self._restore_ui_state()
|
||||||
@@ -153,14 +157,21 @@ class MainWindow(
|
|||||||
self.ui.actionBeenden.setIcon(icon("log-out"))
|
self.ui.actionBeenden.setIcon(icon("log-out"))
|
||||||
self.ui.actionEinstellungen.setIcon(icon("settings"))
|
self.ui.actionEinstellungen.setIcon(icon("settings"))
|
||||||
self.ui.actionVorhandene_Projekte.setIcon(icon("folder"))
|
self.ui.actionVorhandene_Projekte.setIcon(icon("folder"))
|
||||||
|
self.ui.actionAlle_XML_Dateien_transformieren.setIcon(icon("play-circle"))
|
||||||
self.ui.actionAlle_XML_Dateien_neu_transformieren_force.setIcon(icon("refresh-cw"))
|
self.ui.actionAlle_XML_Dateien_neu_transformieren_force.setIcon(icon("refresh-cw"))
|
||||||
|
self.ui.actionAus_Datenbank_laden.setIcon(icon("database"))
|
||||||
self.ui.view_ref_pdf.setIcon(icon("file"))
|
self.ui.view_ref_pdf.setIcon(icon("file"))
|
||||||
self.ui.view_new_pdf.setIcon(icon("file"))
|
self.ui.view_new_pdf.setIcon(icon("file"))
|
||||||
self.ui.accept_changes.setIcon(icon("check-circle"))
|
self.ui.accept_changes.setIcon(icon("check-circle"))
|
||||||
if hasattr(self, "action_xsl_dependencies"):
|
self.action_worker_metrics.setIcon(icon("activity"))
|
||||||
self.action_xsl_dependencies.setIcon(icon("git-branch"))
|
self.action_xsl_dependencies.setIcon(icon("git-branch"))
|
||||||
if hasattr(self, "action_info"):
|
self.action_info.setIcon(icon("info"))
|
||||||
self.action_info.setIcon(icon("info"))
|
|
||||||
|
def _on_icon_theme_changed(self):
|
||||||
|
"""Theme-Wechsel: Icons neu einfärben und – falls ein Projekt offen ist – die Baum-Icons."""
|
||||||
|
self._setup_icons()
|
||||||
|
if getattr(self, "pdf_project", None):
|
||||||
|
self._load_nodes_to_tree()
|
||||||
|
|
||||||
def _restore_ui_state(self):
|
def _restore_ui_state(self):
|
||||||
"""Stellt die gespeicherten UI-Zustände wieder her (Fenstergeometrie, Splitter, TreeWidget-Spalten)."""
|
"""Stellt die gespeicherten UI-Zustände wieder her (Fenstergeometrie, Splitter, TreeWidget-Spalten)."""
|
||||||
@@ -358,9 +369,8 @@ class MainWindow(
|
|||||||
logger.info(f"Theme erfolgreich gewechselt zu: {theme_name}")
|
logger.info(f"Theme erfolgreich gewechselt zu: {theme_name}")
|
||||||
app_settings.theme = theme_name
|
app_settings.theme = theme_name
|
||||||
app_settings.save()
|
app_settings.save()
|
||||||
self._setup_icons()
|
# Icons/Baum werden über changeEvent (PaletteChange/StyleChange) neu eingefärbt,
|
||||||
if hasattr(self, "pdf_project") and self.pdf_project:
|
# siehe IconRefreshMixin._on_icon_theme_changed()
|
||||||
self._load_nodes_to_tree()
|
|
||||||
else:
|
else:
|
||||||
logger.error(f"Fehler: Theme '{theme_name}' konnte nicht erstellt werden")
|
logger.error(f"Fehler: Theme '{theme_name}' konnte nicht erstellt werden")
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import tempfile
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from PySide6.QtCore import QUrl, Qt
|
from PySide6.QtCore import QUrl, Qt
|
||||||
from icons import icon
|
from icons import icon, IconRefreshMixin
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QComboBox,
|
QComboBox,
|
||||||
QDialog,
|
QDialog,
|
||||||
@@ -120,7 +120,7 @@ except ImportError:
|
|||||||
logger.warning("PySide6-WebEngine nicht verfügbar — Netzwerkgraph-Tab deaktiviert")
|
logger.warning("PySide6-WebEngine nicht verfügbar — Netzwerkgraph-Tab deaktiviert")
|
||||||
|
|
||||||
|
|
||||||
class XslDependencyDialog(QDialog):
|
class XslDependencyDialog(IconRefreshMixin, QDialog):
|
||||||
"""Dialog zur Anzeige des vollständigen XSL-Abhängigkeitsgraphen."""
|
"""Dialog zur Anzeige des vollständigen XSL-Abhängigkeitsgraphen."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -185,6 +185,25 @@ class XslDependencyDialog(QDialog):
|
|||||||
self._build_layout_controls()
|
self._build_layout_controls()
|
||||||
self._restore_graph_layout_settings()
|
self._restore_graph_layout_settings()
|
||||||
|
|
||||||
|
# Ab hier auf Theme-Wechsel reagieren (siehe IconRefreshMixin)
|
||||||
|
self.mark_icons_ready()
|
||||||
|
|
||||||
|
def _setup_icons(self):
|
||||||
|
"""Färbt alle Icons gemäß aktuellem Theme neu ein (Button und Baum-Icons)."""
|
||||||
|
self.ui.settingsButton.setIcon(icon("sliders"))
|
||||||
|
|
||||||
|
# Datei-Baum neu einfärben, dabei die aktuelle Auswahl erhalten
|
||||||
|
current = self.ui.fileTree.currentItem()
|
||||||
|
current_path = current.data(0, Qt.ItemDataRole.UserRole) if current else None
|
||||||
|
self._populate_file_tree()
|
||||||
|
if current_path is not None:
|
||||||
|
for i in range(self.ui.fileTree.topLevelItemCount()):
|
||||||
|
item = self.ui.fileTree.topLevelItem(i)
|
||||||
|
if item.data(0, Qt.ItemDataRole.UserRole) == current_path:
|
||||||
|
# Setzt die Auswahl → _on_file_selected zeichnet den Abhängigkeitsbaum neu ein
|
||||||
|
self.ui.fileTree.setCurrentItem(item)
|
||||||
|
break
|
||||||
|
|
||||||
def reject(self):
|
def reject(self):
|
||||||
"""Speichert Layout-Einstellungen und räumt temporäre Dateien und QWebEngineView auf."""
|
"""Speichert Layout-Einstellungen und räumt temporäre Dateien und QWebEngineView auf."""
|
||||||
self._save_graph_layout_settings()
|
self._save_graph_layout_settings()
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "documentor"
|
name = "documentor"
|
||||||
version = "1.7.1"
|
version = "1.7.3"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "connectorx" },
|
{ name = "connectorx" },
|
||||||
|
|||||||
+4
-4
@@ -1873,8 +1873,8 @@
|
|||||||
<span class="download-card-badge">EMPFOHLEN</span>
|
<span class="download-card-badge">EMPFOHLEN</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="download-card-desc">Windows-Installer mit automatischer Einrichtung. Erstellt Startmenü-Einträge und ermöglicht saubere Deinstallation über die Systemsteuerung.</p>
|
<p class="download-card-desc">Windows-Installer mit automatischer Einrichtung. Erstellt Startmenü-Einträge und ermöglicht saubere Deinstallation über die Systemsteuerung.</p>
|
||||||
<span class="download-card-meta">DocuMentor-1.7.0.msi — ca. 255 MB</span>
|
<span class="download-card-meta">DocuMentor-1.7.3.msi — ca. 255 MB</span>
|
||||||
<a href="https://code.vitaligraf.de/info/xsl-validator/releases/download/v1.7.0/DocuMentor-1.7.0.msi" class="btn-download">▼ MSI herunterladen</a>
|
<a href="https://code.vitaligraf.de/info/xsl-validator/releases/download/v1.7.3/DocuMentor-1.7.3.msi" class="btn-download">▼ MSI herunterladen</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="download-card corner-brackets">
|
<div class="download-card corner-brackets">
|
||||||
<div class="download-card-header">
|
<div class="download-card-header">
|
||||||
@@ -1882,8 +1882,8 @@
|
|||||||
<span class="download-card-badge">PORTABEL</span>
|
<span class="download-card-badge">PORTABEL</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="download-card-desc">Portable Version ohne Installation. Entpacken und direkt starten — ideal für eingeschränkte Umgebungen ohne Administratorrechte.</p>
|
<p class="download-card-desc">Portable Version ohne Installation. Entpacken und direkt starten — ideal für eingeschränkte Umgebungen ohne Administratorrechte.</p>
|
||||||
<span class="download-card-meta">DocuMentor-1.7.0.zip — ca. 315 MB</span>
|
<span class="download-card-meta">DocuMentor-1.7.3.zip — ca. 315 MB</span>
|
||||||
<a href="https://code.vitaligraf.de/info/xsl-validator/releases/download/v1.7.0/DocuMentor-1.7.0.zip" class="btn-download">▼ ZIP herunterladen</a>
|
<a href="https://code.vitaligraf.de/info/xsl-validator/releases/download/v1.7.3/DocuMentor-1.7.3.zip" class="btn-download">▼ ZIP herunterladen</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user