From ecc38972a885b07f9537afca0f3dd545b6ebd10d Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Sun, 29 Sep 2024 16:17:48 +0100 Subject: [PATCH] Added TableModels Doc --- TermTk/TTkAbstract/abstracttablemodel.py | 35 ++++++++++++++++- .../TTkWidgets/TTkModelView/tablemodelcsv.py | 30 +++++++------- .../TTkWidgets/TTkModelView/tablemodellist.py | 39 ++++++++++++------- TermTk/TTkWidgets/TTkModelView/tablewidget.py | 6 +-- tests/t.ui/test.ui.032.table.07.py | 2 +- 5 files changed, 77 insertions(+), 35 deletions(-) diff --git a/TermTk/TTkAbstract/abstracttablemodel.py b/TermTk/TTkAbstract/abstracttablemodel.py index 71fc2bd9..27b2470e 100644 --- a/TermTk/TTkAbstract/abstracttablemodel.py +++ b/TermTk/TTkAbstract/abstracttablemodel.py @@ -27,7 +27,38 @@ from TermTk.TTkCore.string import TTkString from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot class TTkAbstractTableModel(): - '''TTkAbstractTableModel''' + ''' + :class:`TTkAbstractTableModel` provides a standard interface for + models that represent their data as a two-dimensional array of items. + It is not used directly, but must be subclassed. + + Since the model provides a more specialized interface than QAbstractItemModel, + it is not suitable for use with tree views, although it can be used to provide data to a QListView. + If you need to represent a simple list of items, and only need a model to contain a single column of data, + subclassing the QAbstractListModel may be more appropriate. + + The rowCount() and columnCount() functions return the dimensions of the table. + To retrieve a model index corresponding to an item in the model, + use index() and provide only the row and column numbers. + + **Subclassing** + + When subclassing QAbstractTableModel, you must implement :meth:`rowCount`, :meth:`columnCount`, and :meth:`data`. + Well behaved models will also implement :meth:`headerData`. + + Editable models need to implement :meth:`setData`. + + Models that provide interfaces to resizable data structures can provide implementations of + insertRows(), removeRows(), insertColumns(), and removeColumns(). + + **Built-In Implementation** + + :class:`~TermTk.TTkWidgets.TTkModelView.tablemodellist.TTkTableModelList` basic subclass implementing a 2d list as data structure + + :class:`~TermTk.TTkWidgets.TTkModelView.tablemodelcsv.TTkTableModelCSV` subclass of :class:`~TermTk.TTkWidgets.TTkModelView.tablemodellist.TTkTableModelList` including the api to import csv data + + :class:`~TermTk.TTkWidgets.TTkModelView.tablemodeljson.TTkTableModelJson` subclass of :class:`~TermTk.TTkWidgets.TTkModelView.tablemodellist.TTkTableModelList` with a focus on json data structures + ''' __slots__ = ( # Signals 'dataChanged' @@ -42,7 +73,7 @@ class TTkAbstractTableModel(): raise NotImplementedError() def data(self, row:int, col:int) -> object: - return TTkString() + raise NotImplementedError() def ttkStringData(self, row:int, col:int) -> TTkString: data = self.data(row,col) diff --git a/TermTk/TTkWidgets/TTkModelView/tablemodelcsv.py b/TermTk/TTkWidgets/TTkModelView/tablemodelcsv.py index bb7ccd82..f1269d98 100644 --- a/TermTk/TTkWidgets/TTkModelView/tablemodelcsv.py +++ b/TermTk/TTkWidgets/TTkModelView/tablemodelcsv.py @@ -28,34 +28,34 @@ from TermTk.TTkCore.constant import TTkK from TermTk.TTkWidgets.TTkModelView.tablemodellist import TTkTableModelList class TTkTableModelCSV(TTkTableModelList): - def __init__(self, *, filename='', fd=None): - ml, head, idx = [[]], [], [] + def __init__(self, *, filename=None, fd=None): + data, head, idx = [[]], [], [] if filename: with open(filename, "r") as fd: - ml, head, idx = self._csvImport(fd) + data, head, idx = self._csvImport(fd) elif fd: - ml, head, idx = self._csvImport(fd) - super().__init__(list=ml,header=head,indexes=idx) + data, head, idx = self._csvImport(fd) + super().__init__(data=data,header=head,indexes=idx) def _csvImport(self, fd) -> tuple[list,list,list[list]]: - ml, head, idx = [], [], [] + data, head, idx = [], [], [] sniffer = csv.Sniffer() has_header = sniffer.has_header(fd.read(2048)) fd.seek(0) csvreader = csv.reader(fd) for row in csvreader: - ml.append(row) + data.append(row) if has_header: - head = ml.pop(0) + head = data.pop(0) # check if the first column include an index: - if self._checkIndexColumn(ml): + if self._checkIndexColumn(data): head.pop(0) - for l in ml: + for l in data: idx.append(l.pop(0)) - return ml, head, idx + return data, head, idx - def _checkIndexColumn(self, ml:list[list]) -> bool: - if all(l[0].isdigit() for l in ml): - num = int(ml[0][0]) - return all(num+i==int(l[0]) for i,l in enumerate(ml)) + def _checkIndexColumn(self, data:list[list]) -> bool: + if all(l[0].isdigit() for l in data): + num = int(data[0][0]) + return all(num+i==int(l[0]) for i,l in enumerate(data)) return False diff --git a/TermTk/TTkWidgets/TTkModelView/tablemodellist.py b/TermTk/TTkWidgets/TTkModelView/tablemodellist.py index 8539081f..5c46e8be 100644 --- a/TermTk/TTkWidgets/TTkModelView/tablemodellist.py +++ b/TermTk/TTkWidgets/TTkModelView/tablemodellist.py @@ -26,31 +26,44 @@ from TermTk.TTkCore.constant import TTkK from TermTk.TTkAbstract.abstracttablemodel import TTkAbstractTableModel class TTkTableModelList(TTkAbstractTableModel): - __slots__ = ('_list','_listOriginal', '_hheader', '_vheader') - def __init__(self, *, list=[], header=[], indexes=[]): - self._list = self._listOriginal = list if list else [['']] + ''' + :class:`TTkTableModelList` extends :class:`¬TermTk.TTkAbstract.abstracttablemodel.TTkAbstractTableModel`, + including a basic model with a 2d list data structure + + :param data: the 2D List model for the view to present. + :type data: list[list] + + :param header: the header labels, defaults to the column number. + :type header: list[str], optional. + + :param indexes: the index labels, defaults to the line number. + :type indexes: list[str], optional. + ''' + __slots__ = ('_data','_dataOriginal', '_hheader', '_vheader') + def __init__(self, *, data=[], header=[], indexes=[]): + self._data = self._dataOriginal = data if data else [['']] self._hheader = header self._vheader = indexes super().__init__() def modelList(self) -> list[list]: - return self._list + return self._data def setModelList(self, modelList:list[list]) -> None: - if modelList == self._list: return - self._list = modelList + if modelList == self._data: return + self._data = modelList def rowCount(self) -> int: - return len(self._list) + return len(self._data) def columnCount(self) -> int: - return len(self._list[0]) if self._list else 0 + return len(self._data[0]) if self._data else 0 def data(self, row:int, col:int) -> None: - return self._list[row][col] + return self._data[row][col] def setData(self, row:int, col:int, data:object) -> None: - self._list[row][col] = data + self._data[row][col] = data def headerData(self, num:int, orientation:int): if orientation == TTkK.HORIZONTAL: @@ -63,9 +76,9 @@ class TTkTableModelList(TTkAbstractTableModel): def sort(self, column:int, order:TTkK.SortOrder) -> None: if column == -1: - self._list = self._listOriginal + self._data = self._dataOriginal else: try: - self._list = sorted(self._listOriginal, key=lambda x:x[column], reverse=order==TTkK.SortOrder.DescendingOrder) + self._data = sorted(self._dataOriginal, key=lambda x:x[column], reverse=order==TTkK.SortOrder.DescendingOrder) except TypeError as _: - self._list = sorted(self._listOriginal, key=lambda x:str(x[column]), reverse=order==TTkK.SortOrder.DescendingOrder) + self._data = sorted(self._dataOriginal, key=lambda x:str(x[column]), reverse=order==TTkK.SortOrder.DescendingOrder) diff --git a/TermTk/TTkWidgets/TTkModelView/tablewidget.py b/TermTk/TTkWidgets/TTkModelView/tablewidget.py index 9d8e6c6c..765baff4 100644 --- a/TermTk/TTkWidgets/TTkModelView/tablewidget.py +++ b/TermTk/TTkWidgets/TTkModelView/tablewidget.py @@ -67,7 +67,8 @@ class TTkHeaderView(): return self._visible class TTkTableWidget(TTkAbstractScrollView): - '''TTkTableWidget + ''' + A :class:`TTkTableWidget` implements a table view that displays items from a model. :: @@ -85,9 +86,6 @@ class TTkTableWidget(TTkAbstractScrollView): 6 │2d08FB17EE273F4 │Aimee │Downs │Steele Group │Chavezborough │ ╾╌╌┴────────────────┴───────────┴────────────┴────────────────────────────────┴────────────────────┘ - - A :class:`TTkTableWidget` implements a table view that displays items from a model. - The :class:`TTkTableWidget` class is one of the Model/View Classes and is part of TermTk's model/view framework. :class:`TTkTableWidget` implements the methods to allow it to display data provided by models derived from the :class:`~TermTk.TTkAbstract.abstracttablemodel.TTkAbstractTableModel` class. diff --git a/tests/t.ui/test.ui.032.table.07.py b/tests/t.ui/test.ui.032.table.07.py index b4bcd944..15a1c524 100755 --- a/tests/t.ui/test.ui.032.table.07.py +++ b/tests/t.ui/test.ui.032.table.07.py @@ -123,7 +123,7 @@ class CustomColorModifier(ttk.TTkAlternateColor): class MyTableModel(ttk.TTkTableModelList): def __init__(self, mylist, size=None): self.size=size - super().__init__(list=mylist) + super().__init__(data=mylist) def rowCount(self): return super().rowCount() if not self.size else self.size[0] def columnCount(self): return super().columnCount() if not self.size else self.size[1]