Meshroom/meshroom/ui/components/csvData.py
Fabien Castan b295242576 [ui] Camera Response Function display: make it safer
More checks on file content and catch exception.
Check nbColumns using a slot instead of using the property.
Use a workaround on the CVS loader to avoid a crash (do not set active
to False).
2020-08-24 11:33:26 +02:00

125 lines
No EOL
3.8 KiB
Python

from meshroom.common.qt import QObjectListModel
from PySide2.QtCore import QObject, Slot, Signal, Property, Qt
from PySide2.QtCharts import QtCharts
import csv
import os
import logging
class CsvData(QObject):
"""Store data from a CSV file."""
def __init__(self, parent=None):
"""Initialize the object without any parameter."""
super(CsvData, self).__init__(parent=parent)
self._filepath = ""
self._data = QObjectListModel(parent=self) # List of CsvColumn
self._ready = False
self.filepathChanged.connect(self.updateData)
@Slot(int, result=QObject)
def getColumn(self, index):
return self._data.at(index)
@Slot(result=str)
def getFilepath(self):
return self._filepath
@Slot(result=int)
def getNbColumns(self):
if self._ready:
return len(self._data)
else:
return 0
@Slot(str)
def setFilepath(self, filepath):
if self._filepath == filepath:
return
self.setReady(False)
self._filepath = filepath
self.filepathChanged.emit()
def setReady(self, ready):
if self._ready == ready:
return
self._ready = ready
self.readyChanged.emit()
@Slot()
def updateData(self):
self.setReady(False)
self._data.clear()
newColumns = self.read()
if newColumns:
self._data.setObjectList(newColumns)
self.setReady(True)
def read(self):
"""Read the CSV file and return a list containing CsvColumn objects."""
if not self._filepath or not self._filepath.lower().endswith(".csv") or not os.path.isfile(self._filepath):
return []
dataList = []
try:
csvRows = []
with open(self._filepath, "r") as fp:
reader = csv.reader(fp)
for row in reader:
csvRows.append(row)
# Create the objects in dataList
# with the first line elements as objects' title
for elt in csvRows[0]:
dataList.append(CsvColumn(elt)) # , parent=self._data
# Populate the content attribute
for elt in csvRows[1:]:
for idx, value in enumerate(elt):
dataList[idx].appendValue(value)
except:
logging.error("CsvData: Failed to load file: {}".format(self._filepath))
return dataList
filepathChanged = Signal()
filepath = Property(str, getFilepath, setFilepath, notify=filepathChanged)
readyChanged = Signal()
ready = Property(bool, lambda self: self._ready, notify=readyChanged)
data = Property(QObject, lambda self: self._data, notify=readyChanged)
nbColumns = Property(int, getNbColumns, notify=readyChanged)
class CsvColumn(QObject):
"""Store content of a CSV column."""
def __init__(self, title="", parent=None):
"""Initialize the object with optional column title parameter."""
super(CsvColumn, self).__init__(parent=parent)
self._title = title
self._content = []
def appendValue(self, value):
self._content.append(value)
@Slot(result=str)
def getFirst(self):
if not self._content:
return ""
return self._content[0]
@Slot(result=str)
def getLast(self):
if not self._content:
return ""
return self._content[-1]
@Slot(QtCharts.QXYSeries)
def fillChartSerie(self, serie):
"""Fill XYSerie used for displaying QML Chart."""
if not serie:
return
serie.clear()
for index, value in enumerate(self._content):
serie.append(float(index), float(value))
title = Property(str, lambda self: self._title, constant=True)
content = Property("QStringList", lambda self: self._content, constant=True)