151 lines
5.9 KiB
Python
151 lines
5.9 KiB
Python
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
|