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
|