]> danix's work - publisher.git/commitdiff
feat: taxonomy view with IT/EN pair table and orphan detection
authorDanilo M. <redacted>
Sun, 3 May 2026 08:44:13 +0000 (10:44 +0200)
committerDanilo M. <redacted>
Sun, 3 May 2026 08:44:13 +0000 (10:44 +0200)
ui/main_window.py
ui/taxonomy_view.py [new file with mode: 0644]

index 463c3dca6528bd18a58e2c388eecf846ee0d5889..61d74e41f9c7382bdcef285aa1f03a387cab9769 100644 (file)
@@ -104,8 +104,14 @@ class MainWindow(QMainWindow):
         self._stack.addWidget(self._hugo_panel)
         self._page_hugo = self._stack.count() - 1
 
+        from ui.taxonomy_view import TaxonomyView
+
+        self._taxonomy_view = TaxonomyView(Path(self.config.blog_repo), parent=self)
+        self._stack.addWidget(self._taxonomy_view)
+        self._page_taxonomy = self._stack.count() - 1
+
         # Remaining placeholders
-        for name in ["taxonomy", "media"]:
+        for name in ["media"]:
             w = QLabel(f"[{name}]")
             w.setAlignment(Qt.AlignmentFlag.AlignCenter)
             self._stack.addWidget(w)
diff --git a/ui/taxonomy_view.py b/ui/taxonomy_view.py
new file mode 100644 (file)
index 0000000..f7b450b
--- /dev/null
@@ -0,0 +1,131 @@
+from __future__ import annotations
+from pathlib import Path
+from PyQt6.QtWidgets import (
+    QWidget, QVBoxLayout, QHBoxLayout, QTabWidget,
+    QTableWidget, QTableWidgetItem, QPushButton,
+    QLabel, QDialog, QFormLayout, QLineEdit, QMessageBox,
+)
+from PyQt6.QtCore import Qt
+from PyQt6.QtGui import QColor
+from core.taxonomy import TaxonomyModel, load_taxonomy, save_taxonomy
+
+class AddTermDialog(QDialog):
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.setWindowTitle("Aggiungi termine")
+        layout = QVBoxLayout(self)
+        form = QFormLayout()
+        self._it = QLineEdit()
+        self._en = QLineEdit()
+        form.addRow("IT:", self._it)
+        form.addRow("EN:", self._en)
+        layout.addLayout(form)
+        btns = QHBoxLayout()
+        ok = QPushButton("Aggiungi")
+        ok.clicked.connect(self.accept)
+        cancel = QPushButton("Annulla")
+        cancel.clicked.connect(self.reject)
+        btns.addStretch()
+        btns.addWidget(cancel)
+        btns.addWidget(ok)
+        layout.addLayout(btns)
+
+    @property
+    def it_term(self) -> str:
+        return self._it.text().strip()
+
+    @property
+    def en_term(self) -> str:
+        return self._en.text().strip()
+
+class TaxonomyView(QWidget):
+    def __init__(self, blog_root: Path, parent=None):
+        super().__init__(parent)
+        self._blog_root = blog_root
+        self._tags_it = blog_root / "docs" / "tags-it.txt"
+        self._tags_en = blog_root / "docs" / "tags-en.txt"
+        self._model: TaxonomyModel | None = None
+        self._build_ui()
+        self.load()
+
+    def _build_ui(self):
+        layout = QVBoxLayout(self)
+
+        tabs = QTabWidget()
+
+        tags_tab = QWidget()
+        tl = QVBoxLayout(tags_tab)
+        self._tags_table = QTableWidget(0, 2)
+        self._tags_table.setHorizontalHeaderLabels(["๐Ÿ‡ฎ๐Ÿ‡น Italiano", "๐Ÿ‡ฌ๐Ÿ‡ง English"])
+        self._tags_table.horizontalHeader().setStretchLastSection(True)
+        tl.addWidget(self._tags_table)
+        tag_btns = QHBoxLayout()
+        add_tag_btn = QPushButton("โž• Aggiungi termine")
+        add_tag_btn.clicked.connect(self._add_term)
+        save_tags_btn = QPushButton("๐Ÿ’พ Salva")
+        save_tags_btn.clicked.connect(self._save)
+        tag_btns.addWidget(add_tag_btn)
+        tag_btns.addStretch()
+        tag_btns.addWidget(save_tags_btn)
+        tl.addLayout(tag_btns)
+        tabs.addTab(tags_tab, "๐Ÿท Tags")
+
+        layout.addWidget(tabs)
+
+        self._status = QLabel("")
+        self._status.setStyleSheet("color:#888;font-size:10px;padding:4px;")
+        layout.addWidget(self._status)
+
+    def load(self):
+        if not self._tags_it.exists():
+            self._status.setText("tags-it.txt non trovato.")
+            return
+        self._model = load_taxonomy(self._tags_it, self._tags_en)
+        self._populate_table()
+
+    def _populate_table(self):
+        if not self._model:
+            return
+        self._tags_table.setRowCount(0)
+        for it_term, en_term in sorted(self._model.it_to_en.items()):
+            row = self._tags_table.rowCount()
+            self._tags_table.insertRow(row)
+            self._tags_table.setItem(row, 0, QTableWidgetItem(it_term))
+            self._tags_table.setItem(row, 1, QTableWidgetItem(en_term))
+
+        for orphan in self._model.orphans_it:
+            row = self._tags_table.rowCount()
+            self._tags_table.insertRow(row)
+            it_item = QTableWidgetItem(orphan)
+            it_item.setForeground(QColor("#ff6b6b"))
+            en_item = QTableWidgetItem("โš  mancante")
+            en_item.setForeground(QColor("#ff6b6b"))
+            self._tags_table.setItem(row, 0, it_item)
+            self._tags_table.setItem(row, 1, en_item)
+
+        self._status.setText(
+            f"{len(self._model.it_to_en)} coppie ยท {len(self._model.orphans_it)} IT orfani ยท {len(self._model.orphans_en)} EN orfani"
+        )
+
+    def _add_term(self):
+        dlg = AddTermDialog(self)
+        if dlg.exec() and dlg.it_term and dlg.en_term:
+            if self._model:
+                self._model.it_to_en[dlg.it_term] = dlg.en_term
+                self._populate_table()
+
+    def _save(self):
+        if not self._model:
+            return
+        updated: dict[str, str] = {}
+        for row in range(self._tags_table.rowCount()):
+            it_item = self._tags_table.item(row, 0)
+            en_item = self._tags_table.item(row, 1)
+            if it_item and en_item:
+                it_val = it_item.text().strip()
+                en_val = en_item.text().strip()
+                if it_val and en_val and en_val != "โš  mancante":
+                    updated[it_val] = en_val
+        self._model.it_to_en = updated
+        save_taxonomy(self._model, self._tags_it, self._tags_en)
+        self._status.setText("Salvato.")