Files
2026-05-15 17:27:26 +02:00

193 lines
7.2 KiB
Python

from PySide6.QtWidgets import QCheckBox, QApplication, QMainWindow, QTableView, QVBoxLayout, QWidget, QPushButton, QAbstractItemView
from PySide6.QtGui import QStandardItemModel, QStandardItem
from PySide6.QtCore import QModelIndex, Signal
import random
import json
import os
import uuid
DEBUG_MODE = False
class JsonTableWidget(QTableView):
header_double_clicked = Signal(object)
def __init__(self, parent=None, dataset_name=""):
super().__init__(parent)
self.model = QStandardItemModel()
# self.model.itemChanged.connect(self.save_data)
self.setModel(self.model)
self.setSelectionMode(QAbstractItemView.ExtendedSelection)
if dataset_name == "":
self.dataset_name = str(uuid.uuid4())
self._save_path = os.path.join(os.path.dirname(__file__), "../../",f"{self.dataset_name}.save.json")
# Ajout entêtes de colonne basique
self.headers = [ ]
self.refresh_columns_headers()
self.verticalHeader().sectionDoubleClicked.connect(self.row_double_clicked)
self.emit_double_click_on_header = False
def refresh_columns_headers(self):
for col, header in enumerate(self.headers):
item = QStandardItem(header)
self.model.setHorizontalHeaderItem(col, item)
def add_new_column(self, title= None):
# Ajouter une nouvelle colonne à la fin du modèle
num_cols = self.model.columnCount()
new_header_text = title or f"New Column {num_cols + 1}"
# print(f"adding new column: {new_header_text}")
# Créer le nouvel en-tête pour la colonne
header_item = QStandardItem(new_header_text)
# Insérer une nouvelle colonne à la fin du modèle
self.model.insertColumn(num_cols-1)
header_labels = []
for i in range(self.model.columnCount()):
header_item = self.model.horizontalHeaderItem(i)
if header_item is not None:
header_labels.append(header_item.text())
header_labels.insert(len(header_labels) - 1, new_header_text)
self.model.setHorizontalHeaderLabels(header_labels)
# self.reset_checkbox()
def add_new_row(self, data = None):
# print(f"tableview state : \nRows -> {self.model.rowCount()}\nCols -> {self.model.columnCount()}")
valid_data = self.check_incoming_data(data)
if( valid_data is None):
# print("No insertion possible. Aborting !!!")
#Remplir la nouvelle ligne avec des données (par exemple, des nombres aléatoires)
if DEBUG_MODE:
# random int insertion
self.add_new_row({"random": random.randint(1,1000)})
return
# Ajouter une nouvelle colonne à la fin du modèle si elle n'existe pas
for keys, values in valid_data.items():
if (keys not in self.headers):
self.headers.insert(len(self.headers), keys)
# refraichir les headers
self.refresh_columns_headers()
# Ajouter une nouvelle ligne à la fin du modèle
num_rows = self.model.rowCount()
self.model.insertRow(num_rows)
# print (f"valid data: {valid_data}")
# Remplir la nouvelle ligne avec les données de datas :
for col in range(self.model.columnCount()):
if self.headers[col] not in valid_data.keys():
# print(f"{self.headers[col]} not in {valid_data.keys()}")
continue
if DEBUG_MODE :
# print(f"key: {self.headers[col]}")
continue
item = QStandardItem(str(valid_data[self.headers[col]]))
self.model.setItem(num_rows, col, item)
# delete all rows
def delete_all(self):
while self.model.rowCount() > 0:
self.model.removeRow(0)
def del_row(self, row_id):
if isinstance(row_id, int):
self.model.removeRow(row_id)
elif isinstance(row_id, QModelIndex):
self.model.removeRow(row_id.row())
else:
# print(f"Invalid type {type(row_id)}")
return
self.clearSelection()
def delete_selected_rows(self):
selection = self.selectionModel().selectedRows()
for row in selection:
# print(f"delete row: {row}")
self.del_row(row)
def check_incoming_data(self, data) -> object:
if isinstance(data, dict):
return data
elif isinstance(data, str):
try:
return json.loads(data)
except json.JSONDecodeError:
return {"data": data}
else:
# print(f"invalid data type : {type(data)}")
return None
def save_data(self, path=None):
# Récupérez toutes les données du modèle
data = self.get_all_data()
if path is None:
path = self._save_path
# print(f"data {data}")
try:
# Serialisez les données en JSON et sauvegardez-les dans un fichier
with open(path, 'w') as file:
try:
json.dump(data, file, indent=4)
except Exception as json_e:
print(f"Json exception {json_e}")
except Exception as e:
print(f"Exception {type(e)} while saving data \n\"{e}\"")
def append_data(self, data):
try:
# Serialisez les données en JSON et sauvegardez-les dans un fichier
with open(self._save_path, 'a') as file:
json.dump(data, file, indent=4)
except Exception as e:
print(f"Exception while appending data {e}")
def get_all_data(self):
data = []
for row in range(self.model.rowCount()):
row_data = {}
for col in range(self.model.columnCount()):
item = self.model.item(row, col)
if item is not None:
row_data[self.headers[col]] = item.text()
data.append(row_data)
return data
def row_double_clicked(self, index: int):
if(not self.emit_double_click_on_header):
return
# Copier le contenu de la ligne
print(f"index = {index}")
row_data = {}
# obtenir le row à l'index
# obtenir les textes des colonnes pour cette ligne
for col in range(self.model.columnCount()):
item = self.model.item(index, col)
if item is not None:
data = item.text()
data = data.replace("'", "\"")
data = data.replace("False", "false")
data = data.replace("True", "true")
try:
data = json.loads(data)
print(f"can be json: {data}")
except Exception as e:
print(f"not a json: {e} {data}")
row_data[self.headers[col]] = data
print(f"Row data: {row_data}") # Ajouté pour déboguer
# obtenir les textes des colonnes
#remplir le dictionnaire data avec pour clefs les noms des colonnes et pour valeurs les élément du row
self.header_double_clicked.emit(row_data)