so-gui/widgets/drag_tree_widget.py

151 lines
5.9 KiB
Python
Raw Permalink Normal View History

2025-02-01 18:16:23 +01:00
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 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