3 Commits

Author SHA1 Message Date
info ec753a5770 Version 1.7.0: Feather Icons via Qt-Ressourcensystem eingebunden
Alle QIcon.fromTheme()-Aufrufe durch eingebettete Feather Icons ersetzt,
die unter Windows zuverlässig funktionieren. Icons passen sich automatisch
der Palette-Farbe des aktiven Themes an (QSvgRenderer + currentColor).

- scripts/download_icons.py: lädt 20 Feather-SVGs von GitHub
- src/res/icons/: 20 SVG-Dateien (MIT-Lizenz, stroke=currentColor)
- src/res/resources.qrc + resources_rc.py: Qt-Ressourcensystem
- src/icons.py: icon()-Hilfsfunktion mit Palette-Farb-Injection
- MainWindow, AppSettings, XslDependencyDialog, tree_manager,
  XsltParamsEditDialog, ProjectXsltParamsDialog: Icons gesetzt
- Theme-Wechsel aktualisiert Icons und Tree-Items sofort
- THIRD_PARTY_LICENSES.txt: Feather Icons (MIT) eingetragen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 16:13:22 +02:00
info bf2db92040 Version 1.6.6: Versionsanzeige im Info-Dialog bei PyInstaller-Bundle gefixt
Im PyInstaller-Bundle fehlten .dist-info-Metadaten, wodurch importlib.metadata
keine Paketversionen liefern konnte. Lösung: DocuMentor.spec erzeugt beim Build
einen Versions-Snapshot (versions.json) der ins Bundle eingebettet wird.
license_parser.py liest diesen Snapshot im Bundle-Modus statt importlib.metadata.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 13:54:27 +02:00
info 19f7deec20 build_msi.py: Klare Fehlermeldung bei fehlendem wix-Befehl
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 13:34:30 +02:00
39 changed files with 973 additions and 61 deletions
+20
View File
@@ -4,7 +4,10 @@ PyInstaller Konfiguration für DocuMentor
Erstellt eine eigenständige Windows-Executable ohne Python-Installation Erstellt eine eigenständige Windows-Executable ohne Python-Installation
""" """
import json
import sys import sys
from importlib.metadata import PackageNotFoundError
from importlib.metadata import version as pkg_version
from pathlib import Path from pathlib import Path
from PyInstaller.utils.hooks import collect_all from PyInstaller.utils.hooks import collect_all
@@ -14,6 +17,22 @@ block_cipher = None
project_root = Path(SPECPATH) project_root = Path(SPECPATH)
src_path = project_root / 'src' src_path = project_root / 'src'
# Versions-Snapshot erzeugen und ins Bundle einbetten
_packages_to_snapshot = [
"PySide6", "pydantic", "pydantic-settings", "pydantic-yaml",
"polars", "connectorx", "pyarrow", "psutil", "lxml",
"ruff", "pyinstaller", "pillow",
]
_versions_snapshot: dict[str, str] = {}
for _pkg in _packages_to_snapshot:
try:
_versions_snapshot[_pkg.lower()] = pkg_version(_pkg)
except PackageNotFoundError:
_versions_snapshot[_pkg.lower()] = ""
_versions_file = project_root / "versions.json"
_versions_file.write_text(json.dumps(_versions_snapshot), encoding="utf-8")
# connectorx komplett sammeln (Python-Code, native .pyd und Metadaten) # connectorx komplett sammeln (Python-Code, native .pyd und Metadaten)
# PyInstaller erkennt connectorx nicht automatisch, da es zur Laufzeit # PyInstaller erkennt connectorx nicht automatisch, da es zur Laufzeit
# von polars per importlib.import_module() geladen wird # von polars per importlib.import_module() geladen wird
@@ -36,6 +55,7 @@ a = Analysis(
datas=ui_files + res_files + cx_datas + [ datas=ui_files + res_files + cx_datas + [
(str(project_root / 'pyproject.toml'), '.'), (str(project_root / 'pyproject.toml'), '.'),
(str(project_root / 'THIRD_PARTY_LICENSES.txt'), '.'), (str(project_root / 'THIRD_PARTY_LICENSES.txt'), '.'),
(str(_versions_file), '.'),
(str(project_root / 'resources' / 'icon.ico'), 'resources'), (str(project_root / 'resources' / 'icon.ico'), 'resources'),
], ],
hiddenimports=[ hiddenimports=[
+1 -1
View File
@@ -4,7 +4,7 @@
<!-- Paket-Definition (ersetzt Product in v4) --> <!-- Paket-Definition (ersetzt Product in v4) -->
<Package <Package
Name="DocuMentor" Name="DocuMentor"
Version="1.6.5" Version="1.7.0"
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"
+11 -1
View File
@@ -115,6 +115,16 @@ Diese Bibliotheken sind direkt im Quellcode von DocuMentor enthalten.
Datei: src/res/vis-network.min.js Datei: src/res/vis-network.min.js
Hinweis: Wird inline in QWebEngineView für den XSL-Abhängigkeitsgraph verwendet Hinweis: Wird inline in QWebEngineView für den XSL-Abhängigkeitsgraph verwendet
2. Feather Icons
Version: 4.29.2
Lizenz: MIT License
Webseite: https://feathericons.com
GitHub: https://github.com/feathericons/feather
Beschreibung: Simply beautiful open source icons
Copyright: Copyright (c) 2013-2017 Cole Bemis
Datei: src/res/icons/, src/res/resources_rc.py
Hinweis: SVG-Icons werden via Qt-Ressourcensystem eingebettet; Farbe wird zur Laufzeit aus der Qt-Palette gesetzt
================================================================================ ================================================================================
Externe Tools (nicht eingebettet) Externe Tools (nicht eingebettet)
================================================================================ ================================================================================
@@ -253,5 +263,5 @@ HINWEISE
================================================================================ ================================================================================
Stand: April 2026 Stand: April 2026
Erstellt für: DocuMentor v1.6.5 Erstellt für: DocuMentor v1.7.0
================================================================================ ================================================================================
+13 -4
View File
@@ -48,10 +48,19 @@ def build_msi():
# Schritt 2: MSI kompilieren mit WiX v6 # Schritt 2: MSI kompilieren mit WiX v6
print("Schritt 2/2: Kompiliere MSI-Installer...") print("Schritt 2/2: Kompiliere MSI-Installer...")
result = subprocess.run( try:
["wix", "build", "DocuMentor.wxs", "ProductFiles.wxs", "-o", str(msi_output)], result = subprocess.run(
check=False, ["wix", "build", "DocuMentor.wxs", "ProductFiles.wxs", "-o", str(msi_output)],
) check=False,
)
except FileNotFoundError:
print("\nFEHLER: 'wix' wurde nicht gefunden!")
print("WiX v6 muss installiert sein. Installationsschritte:")
print(" 1. .NET SDK installieren: https://dot.net")
print(" 2. WiX als dotnet tool installieren:")
print(" dotnet tool install --global wix --version 6.*")
print(" 3. Neues Terminal öffnen (PATH aktualisieren)")
sys.exit(1)
if result.returncode != 0: if result.returncode != 0:
print("\nFEHLER: MSI-Kompilierung fehlgeschlagen!") print("\nFEHLER: MSI-Kompilierung fehlgeschlagen!")
+1 -1
View File
@@ -10,7 +10,7 @@
; Build-Befehl: iscc installer.iss ; Build-Befehl: iscc installer.iss
#define MyAppName "DocuMentor" #define MyAppName "DocuMentor"
#define MyAppVersion "1.6.5" #define MyAppVersion "1.7.0"
#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
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "DocuMentor" name = "DocuMentor"
version = "1.6.5" version = "1.7.0"
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"}
+76
View File
@@ -0,0 +1,76 @@
"""
Lädt Feather Icons (MIT-Lizenz) von GitHub herunter und speichert sie in src/res/icons/.
Stroke-Farbe wird auf #444444 gesetzt für bessere Sichtbarkeit in hellen und dunklen Themes.
Ausführung: uv run python scripts/download_icons.py
"""
import urllib.request
from pathlib import Path
ICONS = [
"folder-plus",
"log-out",
"settings",
"folder",
"refresh-cw",
"plus-circle",
"minus-circle",
"play-circle",
"file",
"check-circle",
"info",
"git-branch",
"file-text",
"code",
"chevron-down",
"chevron-up",
"trash-2",
"file-plus",
"columns",
"sliders",
"folder-open",
]
BASE_URL = "https://raw.githubusercontent.com/feathericons/feather/master/icons/{name}.svg"
OUTPUT_DIR = Path(__file__).parent.parent / "src" / "res" / "icons"
def download_icons():
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
success = 0
failed = []
for name in ICONS:
url = BASE_URL.format(name=name)
dest = OUTPUT_DIR / f"{name}.svg"
if dest.exists():
print(f" [OK] {name}.svg (bereits vorhanden)")
success += 1
continue
try:
with urllib.request.urlopen(url, timeout=10) as response:
content = response.read().decode("utf-8")
content = content.replace('stroke="#000000"', 'stroke="#444444"')
content = content.replace("stroke='#000000'", "stroke='#444444'")
dest.write_text(content, encoding="utf-8")
print(f" [OK] {name}.svg")
success += 1
except Exception as e:
print(f" [FEHLER] {name}.svg: {e}")
failed.append(name)
print(f"\n{success}/{len(ICONS)} Icons heruntergeladen nach {OUTPUT_DIR}")
if failed:
print(f"Fehlgeschlagen: {', '.join(failed)}")
if __name__ == "__main__":
print(f"Lade {len(ICONS)} Feather Icons herunter ...")
download_icons()
+72
View File
@@ -0,0 +1,72 @@
import logging
from PySide6.QtCore import QByteArray, QFile, Qt
from PySide6.QtGui import QIcon, QPainter, QPixmap, QPalette
from PySide6.QtSvg import QSvgRenderer
from PySide6.QtWidgets import QApplication
logger = logging.getLogger(__name__)
_ICON_MAP: dict[str, str] = {
"folder-plus": ":/icons/folder-plus.svg",
"log-out": ":/icons/log-out.svg",
"settings": ":/icons/settings.svg",
"folder": ":/icons/folder.svg",
"refresh-cw": ":/icons/refresh-cw.svg",
"plus-circle": ":/icons/plus-circle.svg",
"minus-circle": ":/icons/minus-circle.svg",
"play-circle": ":/icons/play-circle.svg",
"file": ":/icons/file.svg",
"check-circle": ":/icons/check-circle.svg",
"info": ":/icons/info.svg",
"git-branch": ":/icons/git-branch.svg",
"file-text": ":/icons/file-text.svg",
"code": ":/icons/code.svg",
"chevron-down": ":/icons/chevron-down.svg",
"chevron-up": ":/icons/chevron-up.svg",
"trash-2": ":/icons/trash-2.svg",
"file-plus": ":/icons/file-plus.svg",
"columns": ":/icons/columns.svg",
"sliders": ":/icons/sliders.svg",
}
def icon(name: str) -> QIcon:
"""
Lädt ein Icon aus dem Qt-Ressource-System und färbt es mit der aktuellen Palette-Farbe.
Args:
name: Feather-Icon-Name (z.B. "folder-plus", "settings")
Returns:
QIcon in der Textfarbe des aktiven Themes, oder leerer QIcon bei unbekanntem Namen
"""
path = _ICON_MAP.get(name)
if path is None:
logger.warning(f"Unbekannter Icon-Name: {name!r}")
return QIcon()
app = QApplication.instance()
if app is None:
return QIcon(path)
color = app.palette().color(QPalette.ColorRole.WindowText).name().encode()
f = QFile(path)
if not f.open(QFile.OpenModeFlag.ReadOnly):
logger.warning(f"Icon konnte nicht geöffnet werden: {path}")
return QIcon(path)
svg_data = QByteArray(bytes(f.readAll()).replace(b"currentColor", color))
f.close()
renderer = QSvgRenderer(svg_data)
result = QIcon()
for size in (16, 24, 32):
pixmap = QPixmap(size, size)
pixmap.fill(Qt.GlobalColor.transparent)
painter = QPainter(pixmap)
renderer.render(painter)
painter.end()
result.addPixmap(pixmap)
return result
+24 -1
View File
@@ -2,8 +2,10 @@
Parser für THIRD_PARTY_LICENSES.txt. Parser für THIRD_PARTY_LICENSES.txt.
Extrahiert strukturierte Lizenzinformationen und ergänzt sie Extrahiert strukturierte Lizenzinformationen und ergänzt sie
mit den tatsächlich installierten Paketversionen via importlib.metadata. mit den tatsächlich installierten Paketversionen via importlib.metadata
oder (im PyInstaller-Bundle) aus der mitgebündelten versions.json.
""" """
import json
import logging import logging
import re import re
import sys import sys
@@ -71,8 +73,29 @@ def _normalize_package_name(display_name: str) -> str:
return display_name.lower().split("(")[0].strip() return display_name.lower().split("(")[0].strip()
_bundled_versions: dict[str, str] | None = None
def _load_bundled_versions() -> dict[str, str]:
"""Lädt den Versions-Snapshot aus der mitgebündelten versions.json (nur im PyInstaller-Bundle)."""
global _bundled_versions
if _bundled_versions is None:
if hasattr(sys, "_MEIPASS"):
versions_file = Path(sys._MEIPASS) / "versions.json" # type: ignore[attr-defined]
if versions_file.exists():
_bundled_versions = json.loads(versions_file.read_text(encoding="utf-8"))
else:
_bundled_versions = {}
else:
_bundled_versions = {}
return _bundled_versions
def _get_installed_version(package_name: str) -> str: def _get_installed_version(package_name: str) -> str:
"""Ermittelt die installierte Version eines Pakets.""" """Ermittelt die installierte Version eines Pakets."""
bundled = _load_bundled_versions()
if bundled:
return bundled.get(package_name.lower(), "")
try: try:
return version(package_name) return version(package_name)
except PackageNotFoundError: except PackageNotFoundError:
+3
View File
@@ -98,6 +98,9 @@ def main():
if icon_path.exists(): if icon_path.exists():
app.setWindowIcon(QIcon(str(icon_path))) app.setWindowIcon(QIcon(str(icon_path)))
# Qt-Ressourcen registrieren (Icons)
import res.resources_rc # noqa: F401
# Hauptfenster erstellen # Hauptfenster erstellen
window = MainWindow() window = MainWindow()
+1
View File
@@ -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"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>

After

Width:  |  Height:  |  Size: 275 B

+1
View File
@@ -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="6 9 12 15 18 9"/></svg>

After

Width:  |  Height:  |  Size: 222 B

+1
View File
@@ -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="18 15 12 9 6 15"/></svg>

After

Width:  |  Height:  |  Size: 223 B

+1
View File
@@ -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="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>

After

Width:  |  Height:  |  Size: 258 B

+1
View File
@@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3h7a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-7m0-18H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h7m0-18v18"/></svg>

After

Width:  |  Height:  |  Size: 288 B

+1
View File
@@ -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"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="12" y1="18" x2="12" y2="12"/><line x1="9" y1="15" x2="15" y2="15"/></svg>

After

Width:  |  Height:  |  Size: 369 B

+1
View File
@@ -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"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>

After

Width:  |  Height:  |  Size: 401 B

+1
View File
@@ -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"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>

After

Width:  |  Height:  |  Size: 292 B

+1
View File
@@ -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"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/><line x1="12" y1="11" x2="12" y2="17"/><line x1="9" y1="14" x2="15" y2="14"/></svg>

After

Width:  |  Height:  |  Size: 351 B

+1
View File
@@ -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"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>

After

Width:  |  Height:  |  Size: 274 B

+1
View File
@@ -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"><line x1="6" y1="3" x2="6" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>

After

Width:  |  Height:  |  Size: 314 B

+1
View File
@@ -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"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>

After

Width:  |  Height:  |  Size: 298 B

+1
View File
@@ -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"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>

After

Width:  |  Height:  |  Size: 313 B

+1
View File
@@ -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"><circle cx="12" cy="12" r="10"/><line x1="8" y1="12" x2="16" y2="12"/></svg>

After

Width:  |  Height:  |  Size: 257 B

+1
View File
@@ -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"><circle cx="12" cy="12" r="10"/><polygon points="10 8 16 12 10 16 10 8"/></svg>

After

Width:  |  Height:  |  Size: 260 B

+1
View File
@@ -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"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></svg>

After

Width:  |  Height:  |  Size: 295 B

+1
View File
@@ -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="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>

After

Width:  |  Height:  |  Size: 339 B

+1
View File
@@ -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"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>

After

Width:  |  Height:  |  Size: 964 B

+1
View File
@@ -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"><line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/></svg>

After

Width:  |  Height:  |  Size: 525 B

+1
View File
@@ -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="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg>

After

Width:  |  Height:  |  Size: 388 B

+25
View File
@@ -0,0 +1,25 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/">
<file>icons/folder-plus.svg</file>
<file>icons/log-out.svg</file>
<file>icons/settings.svg</file>
<file>icons/folder.svg</file>
<file>icons/refresh-cw.svg</file>
<file>icons/plus-circle.svg</file>
<file>icons/minus-circle.svg</file>
<file>icons/play-circle.svg</file>
<file>icons/file.svg</file>
<file>icons/check-circle.svg</file>
<file>icons/info.svg</file>
<file>icons/git-branch.svg</file>
<file>icons/file-text.svg</file>
<file>icons/code.svg</file>
<file>icons/chevron-down.svg</file>
<file>icons/chevron-up.svg</file>
<file>icons/trash-2.svg</file>
<file>icons/file-plus.svg</file>
<file>icons/columns.svg</file>
<file>icons/sliders.svg</file>
</qresource>
</RCC>
+634
View File
@@ -0,0 +1,634 @@
# Resource object code (Python 3)
# Created by: object code
# Created by: The Resource Compiler for Qt version 6.11.1
# WARNING! All changes made in this file will be lost!
from PySide6 import QtCore
qt_resource_data = b"\
\x00\x00\x01\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><circle cx=\x22\
12\x22 cy=\x2212\x22 r=\x221\
0\x22/><line x1=\x228\x22\
y1=\x2212\x22 x2=\x2216\x22\
y2=\x2212\x22/></svg>\
\
\x00\x00\x02\x0d\
<\
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><line x1=\x224\x22\
y1=\x2221\x22 x2=\x224\x22 \
y2=\x2214\x22/><line x\
1=\x224\x22 y1=\x2210\x22 x2\
=\x224\x22 y2=\x223\x22/><li\
ne x1=\x2212\x22 y1=\x222\
1\x22 x2=\x2212\x22 y2=\x221\
2\x22/><line x1=\x2212\
\x22 y1=\x228\x22 x2=\x2212\x22\
y2=\x223\x22/><line x\
1=\x2220\x22 y1=\x2221\x22 x\
2=\x2220\x22 y2=\x2216\x22/>\
<line x1=\x2220\x22 y1\
=\x2212\x22 x2=\x2220\x22 y2\
=\x223\x22/><line x1=\x22\
1\x22 y1=\x2214\x22 x2=\x227\
\x22 y2=\x2214\x22/><line\
x1=\x229\x22 y1=\x228\x22 x\
2=\x2215\x22 y2=\x228\x22/><\
line x1=\x2217\x22 y1=\
\x2216\x22 x2=\x2223\x22 y2=\
\x2216\x22/></svg>\
\x00\x00\x01\x04\
<\
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><circle cx=\x22\
12\x22 cy=\x2212\x22 r=\x221\
0\x22/><polygon poi\
nts=\x2210 8 16 12 \
10 16 10 8\x22/></s\
vg>\
\x00\x00\x01 \
<\
svg width=\x2224\x22 h\
eight=\x2224\x22 viewB\
ox=\x220 0 24 24\x22 x\
mlns=\x22http://www\
.w3.org/2000/svg\
\x22 fill=\x22none\x22 st\
roke=\x22currentCol\
or\x22 stroke-width\
=\x222\x22 stroke-line\
cap=\x22round\x22 stro\
ke-linejoin=\x22rou\
nd\x22><path d=\x22M12\
3h7a2 2 0 0 1 2\
2v14a2 2 0 0 1-\
2 2h-7m0-18H5a2 \
2 0 0 0-2 2v14a2\
2 0 0 0 2 2h7m0\
-18v18\x22/></svg>\
\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><path d=\x22M22\
19a2 2 0 0 1-2 \
2H4a2 2 0 0 1-2-\
2V5a2 2 0 0 1 2-\
2h5l2 3h9a2 2 0 \
0 1 2 2z\x22/><line\
x1=\x2212\x22 y1=\x2211\x22\
x2=\x2212\x22 y2=\x2217\x22\
/><line x1=\x229\x22 y\
1=\x2214\x22 x2=\x2215\x22 y\
2=\x2214\x22/></svg>\
\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><path d=\x22M13\
2H6a2 2 0 0 0-2\
2v16a2 2 0 0 0 \
2 2h12a2 2 0 0 0\
2-2V9z\x22/><polyl\
ine points=\x2213 2\
13 9 20 9\x22/></s\
vg>\
\x00\x00\x01S\
<\
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=\x2223 4 23 10\
17 10\x22/><polyli\
ne points=\x221 20 \
1 14 7 14\x22/><pat\
h d=\x22M3.51 9a9 9\
0 0 1 14.85-3.3\
6L23 10M1 14l4.6\
4 4.36A9 9 0 0 0\
20.49 15\x22/></sv\
g>\
\x00\x00\x01\x12\
<\
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><path d=\x22M22\
19a2 2 0 0 1-2 \
2H4a2 2 0 0 1-2-\
2V5a2 2 0 0 1 2-\
2h5l2 3h9a2 2 0 \
0 1 2 2z\x22/></svg\
>\
\x00\x00\x00\xde\
<\
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=\x226 9 12 15 \
18 9\x22/></svg>\
\x00\x00\x03\xc4\
<\
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><circle cx=\x22\
12\x22 cy=\x2212\x22 r=\x223\
\x22/><path d=\x22M19.\
4 15a1.65 1.65 0\
0 0 .33 1.82l.0\
6.06a2 2 0 0 1 0\
2.83 2 2 0 0 1-\
2.83 0l-.06-.06a\
1.65 1.65 0 0 0-\
1.82-.33 1.65 1.\
65 0 0 0-1 1.51V\
21a2 2 0 0 1-2 2\
2 2 0 0 1-2-2v-\
.09A1.65 1.65 0 \
0 0 9 19.4a1.65 \
1.65 0 0 0-1.82.\
33l-.06.06a2 2 0\
0 1-2.83 0 2 2 \
0 0 1 0-2.83l.06\
-.06a1.65 1.65 0\
0 0 .33-1.82 1.\
65 1.65 0 0 0-1.\
51-1H3a2 2 0 0 1\
-2-2 2 2 0 0 1 2\
-2h.09A1.65 1.65\
0 0 0 4.6 9a1.6\
5 1.65 0 0 0-.33\
-1.82l-.06-.06a2\
2 0 0 1 0-2.83 \
2 2 0 0 1 2.83 0\
l.06.06a1.65 1.6\
5 0 0 0 1.82.33H\
9a1.65 1.65 0 0 \
0 1-1.51V3a2 2 0\
0 1 2-2 2 2 0 0\
1 2 2v.09a1.65 \
1.65 0 0 0 1 1.5\
1 1.65 1.65 0 0 \
0 1.82-.33l.06-.\
06a2 2 0 0 1 2.8\
3 0 2 2 0 0 1 0 \
2.83l-.06.06a1.6\
5 1.65 0 0 0-.33\
1.82V9a1.65 1.6\
5 0 0 0 1.51 1H2\
1a2 2 0 0 1 2 2 \
2 2 0 0 1-2 2h-.\
09a1.65 1.65 0 0\
0-1.51 1z\x22/></s\
vg>\
\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><circle cx=\x22\
12\x22 cy=\x2212\x22 r=\x221\
0\x22/><line x1=\x2212\
\x22 y1=\x228\x22 x2=\x2212\x22\
y2=\x2216\x22/><line \
x1=\x228\x22 y1=\x2212\x22 x\
2=\x2216\x22 y2=\x2212\x22/>\
</svg>\
\x00\x00\x019\
<\
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><path d=\x22M9 \
21H5a2 2 0 0 1-2\
-2V5a2 2 0 0 1 2\
-2h4\x22/><polyline\
points=\x2216 17 2\
1 12 16 7\x22/><lin\
e x1=\x2221\x22 y1=\x2212\
\x22 x2=\x229\x22 y2=\x2212\x22\
/></svg>\
\x00\x00\x01\x13\
<\
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><path d=\x22M22\
11.08V12a10 10 \
0 1 1-5.93-9.14\x22\
/><polyline poin\
ts=\x2222 4 12 14.0\
1 9 11.01\x22/></sv\
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><circle cx=\x22\
12\x22 cy=\x2212\x22 r=\x221\
0\x22/><line x1=\x2212\
\x22 y1=\x2216\x22 x2=\x2212\
\x22 y2=\x2212\x22/><line\
x1=\x2212\x22 y1=\x228\x22 \
x2=\x2212.01\x22 y2=\x228\
\x22/></svg>\
\x00\x00\x00\xdf\
<\
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=\x2218 15 12 9\
6 15\x22/></svg>\
\x00\x00\x01\x91\
<\
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><path d=\x22M14\
2H6a2 2 0 0 0-2\
2v16a2 2 0 0 0 \
2 2h12a2 2 0 0 0\
2-2V8z\x22/><polyl\
ine points=\x2214 2\
14 8 20 8\x22/><li\
ne x1=\x2216\x22 y1=\x221\
3\x22 x2=\x228\x22 y2=\x2213\
\x22/><line x1=\x2216\x22\
y1=\x2217\x22 x2=\x228\x22 \
y2=\x2217\x22/><polyli\
ne points=\x2210 9 \
9 9 8 9\x22/></svg>\
\
\x00\x00\x01q\
<\
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><path d=\x22M14\
2H6a2 2 0 0 0-2\
2v16a2 2 0 0 0 \
2 2h12a2 2 0 0 0\
2-2V8z\x22/><polyl\
ine points=\x2214 2\
14 8 20 8\x22/><li\
ne x1=\x2212\x22 y1=\x221\
8\x22 x2=\x2212\x22 y2=\x221\
2\x22/><line x1=\x229\x22\
y1=\x2215\x22 x2=\x2215\x22\
y2=\x2215\x22/></svg>\
\
\x00\x00\x01\x02\
<\
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=\x2216 18 22 1\
2 16 6\x22/><polyli\
ne points=\x228 6 2\
12 8 18\x22/></svg\
>\
\x00\x00\x01\x84\
<\
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=\x223 6 5 6 21\
6\x22/><path d=\x22M1\
9 6v14a2 2 0 0 1\
-2 2H7a2 2 0 0 1\
-2-2V6m3 0V4a2 2\
0 0 1 2-2h4a2 2\
0 0 1 2 2v2\x22/><\
line x1=\x2210\x22 y1=\
\x2211\x22 x2=\x2210\x22 y2=\
\x2217\x22/><line x1=\x22\
14\x22 y1=\x2211\x22 x2=\x22\
14\x22 y2=\x2217\x22/></s\
vg>\
\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><line x1=\x226\x22\
y1=\x223\x22 x2=\x226\x22 y\
2=\x2215\x22/><circle \
cx=\x2218\x22 cy=\x226\x22 r\
=\x223\x22/><circle cx\
=\x226\x22 cy=\x2218\x22 r=\x22\
3\x22/><path d=\x22M18\
9a9 9 0 0 1-9 9\
\x22/></svg>\
"
qt_resource_name = b"\
\x00\x05\
\x00o\xa6S\
\x00i\
\x00c\x00o\x00n\x00s\
\x00\x10\
\x02\xfe\x1a\xa7\
\x00m\
\x00i\x00n\x00u\x00s\x00-\x00c\x00i\x00r\x00c\x00l\x00e\x00.\x00s\x00v\x00g\
\x00\x0b\
\x0cb\x05\x87\
\x00s\
\x00l\x00i\x00d\x00e\x00r\x00s\x00.\x00s\x00v\x00g\
\x00\x0f\
\x0b\xa3Gg\
\x00p\
\x00l\x00a\x00y\x00-\x00c\x00i\x00r\x00c\x00l\x00e\x00.\x00s\x00v\x00g\
\x00\x0b\
\x04\x82\x9dG\
\x00c\
\x00o\x00l\x00u\x00m\x00n\x00s\x00.\x00s\x00v\x00g\
\x00\x0f\
\x06\x9fG\xa7\
\x00f\
\x00o\x00l\x00d\x00e\x00r\x00-\x00p\x00l\x00u\x00s\x00.\x00s\x00v\x00g\
\x00\x08\
\x00(Wg\
\x00f\
\x00i\x00l\x00e\x00.\x00s\x00v\x00g\
\x00\x0e\
\x04\x1b\xd7\x87\
\x00r\
\x00e\x00f\x00r\x00e\x00s\x00h\x00-\x00c\x00w\x00.\x00s\x00v\x00g\
\x00\x0a\
\x0a\xc8\xf6\x87\
\x00f\
\x00o\x00l\x00d\x00e\x00r\x00.\x00s\x00v\x00g\
\x00\x10\
\x0e\x17\x06\x87\
\x00c\
\x00h\x00e\x00v\x00r\x00o\x00n\x00-\x00d\x00o\x00w\x00n\x00.\x00s\x00v\x00g\
\x00\x0c\
\x0b\xdf,\xc7\
\x00s\
\x00e\x00t\x00t\x00i\x00n\x00g\x00s\x00.\x00s\x00v\x00g\
\x00\x0f\
\x02\xe3G'\
\x00p\
\x00l\x00u\x00s\x00-\x00c\x00i\x00r\x00c\x00l\x00e\x00.\x00s\x00v\x00g\
\x00\x0b\
\x06!\xeeG\
\x00l\
\x00o\x00g\x00-\x00o\x00u\x00t\x00.\x00s\x00v\x00g\
\x00\x10\
\x0d\xfd\xe1'\
\x00c\
\x00h\x00e\x00c\x00k\x00-\x00c\x00i\x00r\x00c\x00l\x00e\x00.\x00s\x00v\x00g\
\x00\x08\
\x04\xd2T\xc7\
\x00i\
\x00n\x00f\x00o\x00.\x00s\x00v\x00g\
\x00\x0e\
\x09Xl\x87\
\x00c\
\x00h\x00e\x00v\x00r\x00o\x00n\x00-\x00u\x00p\x00.\x00s\x00v\x00g\
\x00\x0d\
\x06\xf2R'\
\x00f\
\x00i\x00l\x00e\x00-\x00t\x00e\x00x\x00t\x00.\x00s\x00v\x00g\
\x00\x0d\
\x09\xc3S\x87\
\x00f\
\x00i\x00l\x00e\x00-\x00p\x00l\x00u\x00s\x00.\x00s\x00v\x00g\
\x00\x08\
\x05\xa8W\x87\
\x00c\
\x00o\x00d\x00e\x00.\x00s\x00v\x00g\
\x00\x0b\
\x0b\xf2K\xe7\
\x00t\
\x00r\x00a\x00s\x00h\x00-\x002\x00.\x00s\x00v\x00g\
\x00\x0e\
\x04|qG\
\x00g\
\x00i\x00t\x00-\x00b\x00r\x00a\x00n\x00c\x00h\x00.\x00s\x00v\x00g\
"
qt_resource_struct = b"\
\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\x02\x00\x00\x00\x14\x00\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\x06\xa5\
\x00\x00\x01\x9ey\x0c6\xfa\
\x00\x00\x01L\x00\x00\x00\x00\x00\x01\x00\x00\x0e\xe4\
\x00\x00\x01\x9ey\x0c3\x89\
\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x01\x9ey\x0c4\x94\
\x00\x00\x00\xcc\x00\x00\x00\x00\x00\x01\x00\x00\x07\xcd\
\x00\x00\x01\x9ey\x0c2\xb4\
\x00\x00\x02\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x1a\x0c\
\x00\x00\x01\x9ey\x0c:\x95\
\x00\x00\x00v\x00\x00\x00\x00\x00\x01\x00\x00\x04\x1e\
\x00\x00\x01\x9ey\x0cB\x90\
\x00\x00\x01\xb2\x00\x00\x00\x00\x00\x01\x00\x00\x12c\
\x00\x00\x01\x9ey\x0c9c\
\x00\x00\x02*\x00\x00\x00\x00\x00\x01\x00\x00\x17~\
\x00\x00\x01\x9ey\x0c<\x93\
\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\x01\x9ey\x0c1c\
\x00\x00\x00R\x00\x00\x00\x00\x00\x01\x00\x00\x03\x16\
\x00\x00\x01\x9ey\x0c5\xc9\
\x00\x00\x01.\x00\x00\x00\x00\x00\x01\x00\x00\x0b\x1c\
\x00\x00\x01\x9ey\x0c00\
\x00\x00\x02@\x00\x00\x00\x00\x00\x01\x00\x00\x18\x84\
\x00\x00\x01\x9ey\x0c?\xdf\
\x00\x00\x006\x00\x00\x00\x00\x00\x01\x00\x00\x01\x05\
\x00\x00\x01\x9ey\x0cC\xc7\
\x00\x00\x01\x8c\x00\x00\x00\x00\x00\x01\x00\x00\x11L\
\x00\x00\x01\x9ey\x0c8.\
\x00\x00\x01\x08\x00\x00\x00\x00\x00\x01\x00\x00\x0a:\
\x00\x00\x01\x9ey\x0c=\xc8\
"
def qInitResources():
QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
def qCleanupResources():
QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
qInitResources()
+11
View File
@@ -1,6 +1,7 @@
from PySide6.QtWidgets import QDialog, QTableWidgetItem, QHeaderView, QAbstractItemView from PySide6.QtWidgets import QDialog, QTableWidgetItem, QHeaderView, QAbstractItemView
from PySide6.QtCore import Qt from PySide6.QtCore import Qt
from pathlib import Path from pathlib import Path
from icons import icon
from ui.AppSettings_ui import Ui_Dialog from ui.AppSettings_ui import Ui_Dialog
from ui.JavaVmConfigDialog import JavaVmConfigDialog from ui.JavaVmConfigDialog import JavaVmConfigDialog
@@ -36,11 +37,21 @@ class AppSettingsDlg(QDialog):
self.temp_pdf_projects = self.settings.pdf_projects.copy() self.temp_pdf_projects = self.settings.pdf_projects.copy()
self.temp_postgresql_dbs = self.settings.postgresql_dbs.copy() self.temp_postgresql_dbs = self.settings.postgresql_dbs.copy()
self._setup_icons()
self._connect_signals() self._connect_signals()
self._setup_tables() self._setup_tables()
self._populate_tables() self._populate_tables()
self._populate_performance_tab() self._populate_performance_tab()
def _setup_icons(self):
"""Setzt Feather Icons für alle Hinzufügen/Entfernen-Buttons."""
add = icon("plus-circle")
remove = icon("minus-circle")
for btn_name in ("addXsl", "addJavaVm", "addSaxon", "addApacheFop", "addDiffPdf", "addPostgreSql", "addProject"):
getattr(self.ui, btn_name).setIcon(add)
for btn_name in ("removeXsl", "removeJavaVm", "removeSaxon", "removeApacheFop", "removeDiffPdf", "removePostgreSql", "removeProject"):
getattr(self.ui, btn_name).setIcon(remove)
# --- Generische Helfer --- # --- Generische Helfer ---
def _update_remove_button(self, table, button): def _update_remove_button(self, table, button):
+22 -4
View File
@@ -25,6 +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 pathlib import Path from pathlib import Path
@@ -140,9 +141,27 @@ 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)
self._setup_icons()
# Gespeicherte UI-Zustände wiederherstellen # Gespeicherte UI-Zustände wiederherstellen
self._restore_ui_state() self._restore_ui_state()
def _setup_icons(self):
"""Setzt Feather Icons für alle Menü-Aktionen und Buttons."""
self.ui.actionNeu.setIcon(icon("folder-plus"))
self.ui.actionBeenden.setIcon(icon("log-out"))
self.ui.actionEinstellungen.setIcon(icon("settings"))
self.ui.actionVorhandene_Projekte.setIcon(icon("folder"))
self.ui.actionAlle_XML_Dateien_neu_transformieren_force.setIcon(icon("refresh-cw"))
self.ui.view_ref_pdf.setIcon(icon("file"))
self.ui.view_new_pdf.setIcon(icon("file"))
self.ui.accept_changes.setIcon(icon("check-circle"))
if hasattr(self, "action_xsl_dependencies"):
self.action_xsl_dependencies.setIcon(icon("git-branch"))
if hasattr(self, "action_info"):
self.action_info.setIcon(icon("info"))
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)."""
global app_settings global app_settings
@@ -339,6 +358,9 @@ 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()
if hasattr(self, "pdf_project") and self.pdf_project:
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")
@@ -385,10 +407,7 @@ class MainWindow(
self.ui.menuProjekt.addAction(self.action_worker_metrics) self.ui.menuProjekt.addAction(self.action_worker_metrics)
# Menü-Aktion "Abhängigkeitsgraph" zum Aktion-Menü hinzufügen # Menü-Aktion "Abhängigkeitsgraph" zum Aktion-Menü hinzufügen
from PySide6.QtGui import QIcon as _QIcon
self.action_xsl_dependencies = QAction("XSL-Abhängigkeitsgraph", self) self.action_xsl_dependencies = QAction("XSL-Abhängigkeitsgraph", self)
self.action_xsl_dependencies.setIcon(_QIcon(_QIcon.fromTheme("view-list-tree")))
self.action_xsl_dependencies.triggered.connect(self._show_xsl_dependency_dialog) self.action_xsl_dependencies.triggered.connect(self._show_xsl_dependency_dialog)
self.ui.menuAktion.addSeparator() self.ui.menuAktion.addSeparator()
self.ui.menuAktion.addAction(self.action_xsl_dependencies) self.ui.menuAktion.addAction(self.action_xsl_dependencies)
@@ -406,7 +425,6 @@ class MainWindow(
# Hilfe-Menü programmatisch erstellen # Hilfe-Menü programmatisch erstellen
self.menu_hilfe = QMenu("Hilfe", self) self.menu_hilfe = QMenu("Hilfe", self)
self.action_info = QAction("Info ...", self) self.action_info = QAction("Info ...", self)
self.action_info.setIcon(_QIcon(_QIcon.fromTheme("help-about")))
self.action_info.triggered.connect(self._show_about_dialog) self.action_info.triggered.connect(self._show_about_dialog)
self.menu_hilfe.addAction(self.action_info) self.menu_hilfe.addAction(self.action_info)
self.ui.menubar.addMenu(self.menu_hilfe) self.ui.menubar.addMenu(self.menu_hilfe)
+4
View File
@@ -1,5 +1,6 @@
from PySide6.QtWidgets import QDialog, QTableWidgetItem from PySide6.QtWidgets import QDialog, QTableWidgetItem
from ui.ProjectXsltParamsDialog_ui import Ui_ProjectXsltParamsDialog from ui.ProjectXsltParamsDialog_ui import Ui_ProjectXsltParamsDialog
from icons import icon
class ProjectXsltParamsDialog(QDialog): class ProjectXsltParamsDialog(QDialog):
@@ -11,6 +12,9 @@ class ProjectXsltParamsDialog(QDialog):
self.ui = Ui_ProjectXsltParamsDialog() self.ui = Ui_ProjectXsltParamsDialog()
self.ui.setupUi(self) self.ui.setupUi(self)
self.ui.addParamButton.setIcon(icon("plus-circle"))
self.ui.removeParamButton.setIcon(icon("minus-circle"))
self.ui.addParamButton.clicked.connect(self._add_parameter) self.ui.addParamButton.clicked.connect(self._add_parameter)
self.ui.removeParamButton.clicked.connect(self._remove_parameter) self.ui.removeParamButton.clicked.connect(self._remove_parameter)
+5 -4
View File
@@ -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 PySide6.QtGui import QIcon from icons import icon
from PySide6.QtWidgets import ( from PySide6.QtWidgets import (
QComboBox, QComboBox,
QDialog, QDialog,
@@ -154,6 +154,7 @@ class XslDependencyDialog(QDialog):
# Sidebar initial ausblenden # Sidebar initial ausblenden
self.ui.sidebarWidget.setVisible(False) self.ui.sidebarWidget.setVisible(False)
self.ui.mainSplitter.setSizes([1000, 0]) self.ui.mainSplitter.setSizes([1000, 0])
self.ui.settingsButton.setIcon(icon("sliders"))
self.ui.settingsButton.clicked.connect(self._toggle_sidebar) self.ui.settingsButton.clicked.connect(self._toggle_sidebar)
# Netzwerkgraph-Tab ausblenden wenn WebEngine nicht verfügbar # Netzwerkgraph-Tab ausblenden wenn WebEngine nicht verfügbar
@@ -220,7 +221,7 @@ class XslDependencyDialog(QDialog):
"""Befüllt den Dateibaum mit allen XSL-Dateien und Abhängigkeitszahlen.""" """Befüllt den Dateibaum mit allen XSL-Dateien und Abhängigkeitszahlen."""
self.ui.fileTree.clear() self.ui.fileTree.clear()
xsl_icon = QIcon.fromTheme("text-x-generic") xsl_icon = icon("file-text")
for xsl_file in sorted(self._full_graph.keys(), key=lambda p: self._rel_path(p).lower()): for xsl_file in sorted(self._full_graph.keys(), key=lambda p: self._rel_path(p).lower()):
deps_count = len(self._full_graph.get(xsl_file, set())) deps_count = len(self._full_graph.get(xsl_file, set()))
@@ -260,8 +261,8 @@ class XslDependencyDialog(QDialog):
rel_name = self._rel_path(xsl_file) rel_name = self._rel_path(xsl_file)
self.ui.rightLabel.setText(f"Abhängigkeiten: {rel_name}") self.ui.rightLabel.setText(f"Abhängigkeiten: {rel_name}")
import_icon = QIcon.fromTheme("go-down") import_icon = icon("chevron-down")
imported_by_icon = QIcon.fromTheme("go-up") imported_by_icon = icon("chevron-up")
# Sektion: "Importiert" (forward dependencies) # Sektion: "Importiert" (forward dependencies)
deps = self._full_graph.get(xsl_file, set()) deps = self._full_graph.get(xsl_file, set())
+4
View File
@@ -1,5 +1,6 @@
from PySide6.QtWidgets import QDialog, QTableWidgetItem, QMessageBox from PySide6.QtWidgets import QDialog, QTableWidgetItem, QMessageBox
from PySide6.QtCore import Qt from PySide6.QtCore import Qt
from icons import icon
class XsltParamsEditDialog(QDialog): class XsltParamsEditDialog(QDialog):
@@ -14,6 +15,9 @@ class XsltParamsEditDialog(QDialog):
self.node = node self.node = node
self.parent_params = parent_params or {} self.parent_params = parent_params or {}
self.ui.addParamButton.setIcon(icon("plus-circle"))
self.ui.removeParamButton.setIcon(icon("minus-circle"))
self.ui.addParamButton.clicked.connect(self.add_parameter) self.ui.addParamButton.clicked.connect(self.add_parameter)
self.ui.removeParamButton.clicked.connect(self.remove_parameter) self.ui.removeParamButton.clicked.connect(self.remove_parameter)
+25 -43
View File
@@ -15,7 +15,7 @@ from enum import Enum, auto
from pathlib import Path from pathlib import Path
from PySide6.QtCore import Qt from PySide6.QtCore import Qt
from PySide6.QtGui import QAction, QIcon from PySide6.QtGui import QAction
from PySide6.QtWidgets import ( from PySide6.QtWidgets import (
QMenu, QMenu,
QTreeWidgetItem, QTreeWidgetItem,
@@ -28,6 +28,7 @@ from PySide6.QtWidgets import (
) )
from conf import TreeNode, XslFile, XmlFile from conf import TreeNode, XslFile, XmlFile
from icons import icon
from ui.TreeNodeEditDialog import TreeNodeEditDialog from ui.TreeNodeEditDialog import TreeNodeEditDialog
from ui.XslFileEditDialog import XslFileEditDialog from ui.XslFileEditDialog import XslFileEditDialog
from ui.XmlToXslAssignDialog import XmlToXslAssignDialog from ui.XmlToXslAssignDialog import XmlToXslAssignDialog
@@ -319,7 +320,7 @@ class TreeManagerMixin:
if node_type == ItemType.TREE_NODE: if node_type == ItemType.TREE_NODE:
# Kontextmenü für TreeNode # Kontextmenü für TreeNode
action_edit = QAction("Bearbeiten", self) action_edit = QAction("Bearbeiten", self)
action_edit.setIcon(QIcon(QIcon.fromTheme(QIcon.ThemeIcon.DocumentProperties))) action_edit.setIcon(icon("settings"))
action_edit.triggered.connect(lambda: self._edit_tree_node(item)) action_edit.triggered.connect(lambda: self._edit_tree_node(item))
font = action_edit.font() font = action_edit.font()
font.setBold(True) font.setBold(True)
@@ -330,12 +331,12 @@ class TreeManagerMixin:
menu.addSeparator() menu.addSeparator()
action_add_child = QAction("Unterknoten hinzufügen", self) action_add_child = QAction("Unterknoten hinzufügen", self)
action_add_child.setIcon(QIcon(QIcon.fromTheme("folder-new"))) action_add_child.setIcon(icon("folder-plus"))
action_add_child.triggered.connect(lambda: self._add_tree_node_child(item)) action_add_child.triggered.connect(lambda: self._add_tree_node_child(item))
menu.addAction(action_add_child) menu.addAction(action_add_child)
action_add_xsl = QAction("XSL-Datei hinzufügen", self) action_add_xsl = QAction("XSL-Datei hinzufügen", self)
action_add_xsl.setIcon(QIcon(QIcon.fromTheme("document-new"))) action_add_xsl.setIcon(icon("file-plus"))
action_add_xsl.triggered.connect(lambda: self._add_xsl_file_to_node(item)) action_add_xsl.triggered.connect(lambda: self._add_xsl_file_to_node(item))
menu.addAction(action_add_xsl) menu.addAction(action_add_xsl)
@@ -346,13 +347,13 @@ class TreeManagerMixin:
has_xml_files = bool(tree_node_obj and self._has_xml_files_recursive(tree_node_obj)) has_xml_files = bool(tree_node_obj and self._has_xml_files_recursive(tree_node_obj))
action_transform = QAction("Alle XML-Dateien transformieren", self) action_transform = QAction("Alle XML-Dateien transformieren", self)
action_transform.setIcon(QIcon(QIcon.fromTheme("system-run"))) action_transform.setIcon(icon("play-circle"))
action_transform.triggered.connect(lambda: self._transform_tree_node(item)) action_transform.triggered.connect(lambda: self._transform_tree_node(item))
action_transform.setEnabled(has_xml_files) action_transform.setEnabled(has_xml_files)
menu.addAction(action_transform) menu.addAction(action_transform)
action_transform_force = QAction("Alle XML-Dateien neu transformieren (force)", self) action_transform_force = QAction("Alle XML-Dateien neu transformieren (force)", self)
action_transform_force.setIcon(QIcon(QIcon.fromTheme("view-refresh"))) action_transform_force.setIcon(icon("refresh-cw"))
action_transform_force.triggered.connect(lambda: self._transform_tree_node(item, force=True)) action_transform_force.triggered.connect(lambda: self._transform_tree_node(item, force=True))
action_transform_force.setEnabled(has_xml_files) action_transform_force.setEnabled(has_xml_files)
menu.addAction(action_transform_force) menu.addAction(action_transform_force)
@@ -364,7 +365,7 @@ class TreeManagerMixin:
has_diff_pdfs = len(diff_pdfs) > 0 has_diff_pdfs = len(diff_pdfs) > 0
action_accept_all = QAction("Alle Änderungen übernehmen", self) action_accept_all = QAction("Alle Änderungen übernehmen", self)
action_accept_all.setIcon(QIcon(QIcon.fromTheme("emblem-default"))) action_accept_all.setIcon(icon("check-circle"))
action_accept_all.triggered.connect(lambda: self._accept_all_changes_under_node(item)) action_accept_all.triggered.connect(lambda: self._accept_all_changes_under_node(item))
action_accept_all.setEnabled(has_diff_pdfs) action_accept_all.setEnabled(has_diff_pdfs)
menu.addAction(action_accept_all) menu.addAction(action_accept_all)
@@ -372,14 +373,14 @@ class TreeManagerMixin:
menu.addSeparator() menu.addSeparator()
action_delete = QAction("Löschen", self) action_delete = QAction("Löschen", self)
action_delete.setIcon(QIcon(QIcon.fromTheme(QIcon.ThemeIcon.EditDelete))) action_delete.setIcon(icon("trash-2"))
action_delete.triggered.connect(lambda: self._delete_tree_node(item)) action_delete.triggered.connect(lambda: self._delete_tree_node(item))
menu.addAction(action_delete) menu.addAction(action_delete)
elif node_type == ItemType.XSL_FILE: elif node_type == ItemType.XSL_FILE:
# Kontextmenü für XslFile # Kontextmenü für XslFile
action_edit = QAction("Bearbeiten", self) action_edit = QAction("Bearbeiten", self)
action_edit.setIcon(QIcon(QIcon.fromTheme(QIcon.ThemeIcon.DocumentProperties))) action_edit.setIcon(icon("settings"))
action_edit.triggered.connect(lambda: self._edit_xsl_file(item)) action_edit.triggered.connect(lambda: self._edit_xsl_file(item))
font = action_edit.font() font = action_edit.font()
font.setBold(True) font.setBold(True)
@@ -390,7 +391,7 @@ class TreeManagerMixin:
menu.addSeparator() menu.addSeparator()
action_add_xml = QAction("XML-Datei hinzufügen", self) action_add_xml = QAction("XML-Datei hinzufügen", self)
action_add_xml.setIcon(QIcon(QIcon.fromTheme("document-new"))) action_add_xml.setIcon(icon("file-plus"))
action_add_xml.triggered.connect(lambda: self._add_xml_file_to_xsl(item)) action_add_xml.triggered.connect(lambda: self._add_xml_file_to_xsl(item))
menu.addAction(action_add_xml) menu.addAction(action_add_xml)
@@ -401,13 +402,13 @@ class TreeManagerMixin:
has_xml_files = bool(xsl_file_obj and xsl_file_obj.xmls) has_xml_files = bool(xsl_file_obj and xsl_file_obj.xmls)
action_transform = QAction("Alle XML-Dateien transformieren", self) action_transform = QAction("Alle XML-Dateien transformieren", self)
action_transform.setIcon(QIcon(QIcon.fromTheme("system-run"))) action_transform.setIcon(icon("play-circle"))
action_transform.triggered.connect(lambda: self._transform_xsl_file(item)) action_transform.triggered.connect(lambda: self._transform_xsl_file(item))
action_transform.setEnabled(has_xml_files) action_transform.setEnabled(has_xml_files)
menu.addAction(action_transform) menu.addAction(action_transform)
action_transform_force = QAction("Alle XML-Dateien neu transformieren (force)", self) action_transform_force = QAction("Alle XML-Dateien neu transformieren (force)", self)
action_transform_force.setIcon(QIcon(QIcon.fromTheme("view-refresh"))) action_transform_force.setIcon(icon("refresh-cw"))
action_transform_force.triggered.connect(lambda: self._transform_xsl_file(item, force=True)) action_transform_force.triggered.connect(lambda: self._transform_xsl_file(item, force=True))
action_transform_force.setEnabled(has_xml_files) action_transform_force.setEnabled(has_xml_files)
menu.addAction(action_transform_force) menu.addAction(action_transform_force)
@@ -419,7 +420,7 @@ class TreeManagerMixin:
has_diff_pdfs = len(diff_pdfs) > 0 has_diff_pdfs = len(diff_pdfs) > 0
action_accept_all = QAction("Alle Änderungen übernehmen", self) action_accept_all = QAction("Alle Änderungen übernehmen", self)
action_accept_all.setIcon(QIcon(QIcon.fromTheme("emblem-default"))) action_accept_all.setIcon(icon("check-circle"))
action_accept_all.triggered.connect(lambda: self._accept_all_changes_under_node(item)) action_accept_all.triggered.connect(lambda: self._accept_all_changes_under_node(item))
action_accept_all.setEnabled(has_diff_pdfs) action_accept_all.setEnabled(has_diff_pdfs)
menu.addAction(action_accept_all) menu.addAction(action_accept_all)
@@ -427,21 +428,21 @@ class TreeManagerMixin:
menu.addSeparator() menu.addSeparator()
action_deps = QAction("Abhängigkeiten anzeigen", self) action_deps = QAction("Abhängigkeiten anzeigen", self)
action_deps.setIcon(QIcon(QIcon.fromTheme("view-list-tree"))) action_deps.setIcon(icon("git-branch"))
action_deps.triggered.connect(lambda: self._show_xsl_dependencies(item)) action_deps.triggered.connect(lambda: self._show_xsl_dependencies(item))
menu.addAction(action_deps) menu.addAction(action_deps)
menu.addSeparator() menu.addSeparator()
action_delete = QAction("Löschen", self) action_delete = QAction("Löschen", self)
action_delete.setIcon(QIcon(QIcon.fromTheme(QIcon.ThemeIcon.EditDelete))) action_delete.setIcon(icon("trash-2"))
action_delete.triggered.connect(lambda: self._delete_xsl_file(item)) action_delete.triggered.connect(lambda: self._delete_xsl_file(item))
menu.addAction(action_delete) menu.addAction(action_delete)
elif node_type == ItemType.XML_FILE: elif node_type == ItemType.XML_FILE:
# Kontextmenü für XmlFile # Kontextmenü für XmlFile
action_edit = QAction("Bearbeiten", self) action_edit = QAction("Bearbeiten", self)
action_edit.setIcon(QIcon(QIcon.fromTheme(QIcon.ThemeIcon.DocumentProperties))) action_edit.setIcon(icon("settings"))
action_edit.triggered.connect(lambda: self._edit_xml_file(item)) action_edit.triggered.connect(lambda: self._edit_xml_file(item))
font = action_edit.font() font = action_edit.font()
font.setBold(True) font.setBold(True)
@@ -453,26 +454,26 @@ class TreeManagerMixin:
# Transformations-Aktionen # Transformations-Aktionen
action_transform = QAction("Transformieren", self) action_transform = QAction("Transformieren", self)
action_transform.setIcon(QIcon(QIcon.fromTheme("system-run"))) action_transform.setIcon(icon("play-circle"))
action_transform.triggered.connect(lambda: self._transform_xml_file(item)) action_transform.triggered.connect(lambda: self._transform_xml_file(item))
menu.addAction(action_transform) menu.addAction(action_transform)
action_transform_force = QAction("Neu transformieren (force)", self) action_transform_force = QAction("Neu transformieren (force)", self)
action_transform_force.setIcon(QIcon(QIcon.fromTheme("view-refresh"))) action_transform_force.setIcon(icon("refresh-cw"))
action_transform_force.triggered.connect(lambda: self._transform_xml_file(item, force=True)) action_transform_force.triggered.connect(lambda: self._transform_xml_file(item, force=True))
menu.addAction(action_transform_force) menu.addAction(action_transform_force)
menu.addSeparator() menu.addSeparator()
action_delete = QAction("Löschen", self) action_delete = QAction("Löschen", self)
action_delete.setIcon(QIcon(QIcon.fromTheme(QIcon.ThemeIcon.EditDelete))) action_delete.setIcon(icon("trash-2"))
action_delete.triggered.connect(lambda: self._delete_xml_file(item)) action_delete.triggered.connect(lambda: self._delete_xml_file(item))
menu.addAction(action_delete) menu.addAction(action_delete)
else: else:
# Unbekannter Typ oder leerer Bereich - Menü für Root-Elemente # Unbekannter Typ oder leerer Bereich - Menü für Root-Elemente
action_add_tree_node = QAction("Unterknoten hinzufügen", self) action_add_tree_node = QAction("Unterknoten hinzufügen", self)
action_add_tree_node.setIcon(QIcon(QIcon.fromTheme("folder-new"))) action_add_tree_node.setIcon(icon("folder-plus"))
action_add_tree_node.triggered.connect(lambda: self._add_root_tree_node()) action_add_tree_node.triggered.connect(lambda: self._add_root_tree_node())
menu.addAction(action_add_tree_node) menu.addAction(action_add_tree_node)
@@ -656,17 +657,9 @@ class TreeManagerMixin:
# Setze Icon basierend auf Node-Typ # Setze Icon basierend auf Node-Typ
if isinstance(node, TreeNode): if isinstance(node, TreeNode):
# TreeNode: Ordner-Icon item.setIcon(0, icon("folder"))
folder_icon = QIcon.fromTheme(QIcon.ThemeIcon.FolderOpen)
if folder_icon.isNull():
folder_icon = QIcon.fromTheme("folder")
item.setIcon(0, folder_icon)
elif isinstance(node, XslFile): elif isinstance(node, XslFile):
# XslFile: Code/Script-Icon für XSL-Dateien item.setIcon(0, icon("file-text"))
xsl_icon = QIcon.fromTheme("text-x-script")
if xsl_icon.isNull():
xsl_icon = QIcon.fromTheme("text-x-generic")
item.setIcon(0, xsl_icon)
if isinstance(node, TreeNode): if isinstance(node, TreeNode):
# Speichere zusätzlich die Node-ID in UserRole+1 für Kompatibilität # Speichere zusätzlich die Node-ID in UserRole+1 für Kompatibilität
@@ -729,12 +722,7 @@ class TreeManagerMixin:
xml_item.setData(0, Qt.ItemDataRole.UserRole + 2, xsl_id_str) xml_item.setData(0, Qt.ItemDataRole.UserRole + 2, xsl_id_str)
# Setze XML-Icon # Setze XML-Icon
xml_icon = QIcon.fromTheme("text-xml") xml_item.setIcon(0, icon("code"))
if xml_icon.isNull():
xml_icon = QIcon.fromTheme("application-xml")
if xml_icon.isNull():
xml_icon = QIcon.fromTheme("text-x-generic")
xml_item.setIcon(0, xml_icon)
# Prüfe ob XML-Datei existiert und deaktiviere Knoten falls nicht # Prüfe ob XML-Datei existiert und deaktiviere Knoten falls nicht
# Wenn XSL-Datei fehlt, deaktiviere auch alle untergeordneten XML-Knoten # Wenn XSL-Datei fehlt, deaktiviere auch alle untergeordneten XML-Knoten
@@ -812,13 +800,7 @@ class TreeManagerMixin:
# Icon-Label # Icon-Label
icon_label = QLabel() icon_label = QLabel()
# Icon für Diff-View mit Fallbacks icon_label.setPixmap(icon("columns").pixmap(16, 16))
icon = QIcon.fromTheme("view-split-left-right")
if icon.isNull():
icon = QIcon.fromTheme("vcs-diff")
if icon.isNull():
icon = QIcon.fromTheme("system-search") # Letzter Fallback
icon_label.setPixmap(icon.pixmap(16, 16))
icon_label.setToolTip("Diff-PDF vorhanden (wird automatisch geladen bei Selektion)") icon_label.setToolTip("Diff-PDF vorhanden (wird automatisch geladen bei Selektion)")
layout.addWidget(icon_label) layout.addWidget(icon_label)
Generated
+1 -1
View File
@@ -39,7 +39,7 @@ wheels = [
[[package]] [[package]]
name = "documentor" name = "documentor"
version = "1.6.5" version = "1.7.0"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "connectorx" }, { name = "connectorx" },