diff --git a/DocuMentor.wxs b/DocuMentor.wxs index ff33c83..604871e 100644 --- a/DocuMentor.wxs +++ b/DocuMentor.wxs @@ -4,7 +4,7 @@ tuple[str, str]: """ Konvertiert den Abhängigkeitsgraph in vis.js-kompatible JSON-Strukturen. + Knoten werden in drei Kategorien eingeteilt: + - Kategorie 1 (blau): Nur im Verzeichnis, nicht im Projekt + - Kategorie 2 (grün): Im Projekt und im Verzeichnis + - Kategorie 3 (rot): Im Projekt referenziert, aber Datei fehlt + Returns: tuple[str, str]: (nodes_json, edges_json) """ # Direkten Graph verwenden (nicht transitiv) direct_graph = self.dependency_graph.build_direct_graph(self.xsl_root_dir) - # Pfad → ID Mapping - all_paths = sorted(direct_graph.keys(), key=lambda p: self._rel_path(p).lower()) - path_to_id: dict[Path, int] = {path: idx for idx, path in enumerate(all_paths)} + # Dateisystem-Pfade (Kategorie 1 und 2) + fs_paths = sorted(direct_graph.keys(), key=lambda p: self._rel_path(p).lower()) + path_to_id: dict[Path, int] = {path: idx for idx, path in enumerate(fs_paths)} + + # Kategorie 3: Im Projekt referenziert, aber nicht im Dateisystem + ghost_paths = sorted( + self._project_xsl_paths - set(direct_graph.keys()), + key=lambda p: p.name.lower(), + ) + ghost_offset = len(fs_paths) + for idx, path in enumerate(ghost_paths): + path_to_id[path] = ghost_offset + idx + + # Farb-Definitionen pro Kategorie + color_fs_only = {"background": "#4a90d9", "border": "#2c5f9e"} # Kat. 1: nur Verzeichnis + color_in_project = {"background": "#4caf50", "border": "#2e7d32"} # Kat. 2: Projekt + Verzeichnis + color_ghost = {"background": "#e74c3c", "border": "#c0392b"} # Kat. 3: Projekt, Datei fehlt - # Nodes nodes = [] - for path, node_id in path_to_id.items(): + + # Kategorie 1 und 2: Dateien die im Verzeichnis existieren + for path in fs_paths: + node_id = path_to_id[path] rel = self._rel_path(path) label = path.name direct_deps = len(direct_graph.get(path, set())) reverse_count = len(self._reverse_map.get(path, set())) - title = f"{rel}
Importiert: {direct_deps}
Importiert von: {reverse_count}" - # Knotengröße basierend auf Verbindungsanzahl - value = direct_deps + reverse_count + value = max(direct_deps + reverse_count, 1) + in_project = path in self._project_xsl_paths + title = ( + f"{rel}
" + f"Importiert: {direct_deps}
" + f"Importiert von: {reverse_count}
" + f"Im Projekt: {'Ja' if in_project else 'Nein'}" + ) + + node: dict = { + "id": node_id, + "label": label, + "title": title, + "value": value, + "color": color_in_project if in_project else color_fs_only, + "borderWidth": 3 if in_project else 1, + } + nodes.append(node) + + # Kategorie 3: Ghost-Knoten (im Projekt, aber Datei fehlt im Verzeichnis) + for path in ghost_paths: + rel = self._rel_path(path) + title = f"{rel}
Datei nicht gefunden
Im Projekt: Ja" nodes.append( { - "id": node_id, - "label": label, + "id": path_to_id[path], + "label": path.name, "title": title, - "value": max(value, 1), + "value": 1, + "color": color_ghost, + "borderWidth": 2, + "shapeProperties": {"borderDashes": [5, 5]}, } ) - # Edges (nur direkte Abhängigkeiten) + # Edges (nur zwischen Dateisystem-Knoten — Ghost-Knoten haben keine bekannten Abhängigkeiten) edges = [] for path, deps in direct_graph.items(): from_id = path_to_id.get(path) @@ -757,6 +809,28 @@ class XslDependencyDialog(QDialog): font-size: 13px !important; box-shadow: 2px 2px 6px rgba(0,0,0,0.3) !important; }} + #graph-legend {{ + position: absolute; + bottom: 16px; + left: 16px; + background: {bg_hex}cc; + border: 1px solid #888; + border-radius: 6px; + padding: 10px 14px; + font-size: 12px; + color: {text_hex}; + z-index: 10; + line-height: 1.8; + pointer-events: none; + }} + .legend-dot {{ + display: inline-block; + width: 12px; + height: 12px; + border-radius: 50%; + margin-right: 6px; + vertical-align: middle; + }}