import json from PySide6.QtWidgets import ( QTreeWidget, QTreeWidgetItem, QAbstractItemView, QApplication ) from PySide6.QtCore import QPoint, Qt, QMimeData from PySide6.QtGui import QDrag, QMouseEvent class DragTreeWidget(QTreeWidget): """ Drzewo źródłowe (drag source). Umożliwia przeciąganie wybranych węzłów w formacie JSON do DropTreeWidget. """ def __init__(self, parent=None): super().__init__(parent) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setDragEnabled(True) # Edycja np. double-click lub kliknięcie wybranego self.setEditTriggers(QAbstractItemView.DoubleClicked | QAbstractItemView.SelectedClicked) self._drag_start_pos = QPoint() self._drag_in_progress = False # Flaga kontroli przeciągania def handle_item_click(self, item, column): """ Po kliknięciu w węzeł kopiuje do schowka JSON zawierający ścieżkę (rodzice) od korzenia do tego węzła – ale BEZ dzieci! """ chain_json = self.item_to_json_parents_no_children(item) print("[LOG] Copied item + parents (NO children) to clipboard:") print(chain_json) from PySide6.QtWidgets import QApplication QApplication.clipboard().setText(chain_json) def item_to_json_parents_no_children(self, item: QTreeWidgetItem) -> str: """ Buduje strukturę JSON (jako string) dla pojedynczej ścieżki 'korzeń -> ... -> item', bez dzieci. Każdy węzeł ma 'children': []. """ import json # Zacznij od zaznaczonego węzła node_dict = self.item_to_dict_no_children(item) # Idź w górę, owijając node_dict w kolejnych rodziców current = item.parent() while current is not None: parent_dict = self.item_to_dict_no_children(current) parent_dict["children"] = [node_dict] node_dict = parent_dict current = current.parent() # Zamień na ładny, sformatowany JSON return json.dumps(node_dict, ensure_ascii=False, indent=2) def item_to_dict_no_children(self, item: QTreeWidgetItem) -> dict: """ Zwraca słownik z polami (punkty, obowiązkowe, nr, opis), ale 'children' zawsze jest pustą listą. """ return { "punkty": item.text(0), "obowiązkowe": item.text(1), "nr": item.text(2), "opis": item.text(3), "children": [] } def mousePressEvent(self, event: QMouseEvent): item = self.itemAt(event.position().toPoint()) if item: # 1) Alt + LPM: kopiowanie do schowka (łańcuch bez dzieci) if (event.button() == Qt.LeftButton) and (event.modifiers() & Qt.ShiftModifier): chain_json = self.item_to_json_parents_no_children(item) from PySide6.QtWidgets import QApplication QApplication.clipboard().setText(chain_json) return # Nie zaznaczaj już tego węzła # 2) Shift + LPM: kopiowanie *tylko* opisu (kolumna 3) klikniętego węzła if (event.button() == Qt.LeftButton) and (event.modifiers() & Qt.AltModifier): from PySide6.QtWidgets import QApplication opis = item.text(3).strip() # kolumna 3 QApplication.clipboard().setText(opis) return # Nie zaznaczaj już tego węzła # Poniższa logika pozostaje bez zmian (drag, normalne zaznaczenie itp.) if event.button() == Qt.LeftButton: self._drag_start_pos = event.position().toPoint() self._drag_in_progress = False super().mousePressEvent(event) def mouseMoveEvent(self, event: QMouseEvent): if event.buttons() & Qt.LeftButton: dist = (event.position().toPoint() - self._drag_start_pos).manhattanLength() if dist > QApplication.startDragDistance() and not self._drag_in_progress: self._drag_in_progress = True self.startDrag() super().mouseMoveEvent(event) def startDrag(self, supportedActions=Qt.MoveAction): if self._drag_in_progress: selected_items = self.selectedItems() if not selected_items: self._drag_in_progress = False return # Konwertujemy zaznaczone elementy na listę JSON (uwzględniamy hierarchię) data_list = [self.item_to_dict_with_parents(item) for item in selected_items] formatted_json = json.dumps(data_list, ensure_ascii=False, indent=4) drag = QDrag(self) mime = QMimeData() mime.setText(formatted_json) drag.setMimeData(mime) result = drag.exec(Qt.CopyAction) self._drag_in_progress = False def item_to_dict_with_parents(self, item: QTreeWidgetItem) -> dict: """ Buduje pełną hierarchię rodziców i dzieci od wybranego elementu aż do korzenia. """ current_item = item full_hierarchy = None while current_item is not None: node = self.item_to_dict_subtree(current_item) if full_hierarchy is not None: node["children"] = [full_hierarchy] full_hierarchy = node current_item = current_item.parent() return full_hierarchy def item_to_dict_subtree(self, item: QTreeWidgetItem) -> dict: """Rekurencyjnie przekształca węzeł i jego dzieci w słownik.""" node_data = { "punkty": item.text(0).strip(), "obowiązkowe": item.text(1).strip(), "nr": item.text(2).strip(), "opis": item.text(3).strip(), "children": [] } for i in range(item.childCount()): child = item.child(i) node_data["children"].append(self.item_to_dict_subtree(child)) return node_data