diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 724965e8..c66b14dd 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -11,6 +11,24 @@ on: branches: [ main ] jobs: + test-autogen: + runs-on: self-hosted + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.sha }} + - run: | + PYTHONPATH=libs/pyTermTk tools/autogenForwarded.py --apply + if [[ $(git status --porcelain) ]] ; then + git diff + echo "❌ PR failed due to missing release files:" + echo " - run: PYTHONPATH=libs/pyTermTk tools/autogenForwarded.py --apply" + echo " and push the generated files" + exit 1 + else + echo "✅ - Release Clean" + fi + build: # runs-on: ubuntu-latest runs-on: self-hosted diff --git a/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py b/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py index de1efa96..be06e8aa 100644 --- a/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py +++ b/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py @@ -164,16 +164,16 @@ def setup(app: Sphinx) -> ExtensionMetadata: def _getSignalsForwarded(_obj): ret = {} - if hasattr(_obj,'_forwardedSignals'): - ret['baseClass'] = _obj._forwardWidget.__name__ - ret['signals'] = sorted(_obj._forwardedSignals) + if hasattr(_obj,'_ttk_forward'): + ret['baseClass'] = _obj._ttk_forward.forwardClass.__name__ + ret['signals'] = sorted(_obj._ttk_forward.signals) return ret def _getMethodsForwarded(_obj): ret = {} - if hasattr(_obj,'_forwardedMethods'): - ret['baseClass'] = _obj._forwardWidget.__name__ - ret['methods'] = sorted(_obj._forwardedMethods) + if hasattr(_obj,'_ttk_forward'): + ret['baseClass'] = _obj._ttk_forward.forwardClass.__name__ + ret['methods'] = sorted(_obj._ttk_forward.methods) return ret def _parseModules(_mod): @@ -278,10 +278,10 @@ def setup(app: Sphinx) -> ExtensionMetadata: print(ttk.TTkString(f"[{_name}] Params in the class docstring", ttk.TTkColor.BG_RED + ttk.TTkColor.FG_YELLOW).toAnsi()) if hasattr(_obj,'__init__'): _obj.__doc__ = _mergeDoc(_obj.__doc__, _obj.__init__.__doc__) - if hasattr(_obj,'_forwardWidget') and hasattr(_obj._forwardWidget,'__init__'): + if hasattr(_obj,'_ttk_forward') and hasattr(_obj._ttk_forward.forwardClass,'__init__'): _obj.__doc__ = _mergeDoc(_obj.__doc__, - _obj._forwardWidget.__init__.__doc__, - f"\n:py:class:`{_obj._forwardWidget.__name__}`'s forwarded init params:\n") + _obj._ttk_forward.forwardClass.__init__.__doc__, + f"\n:py:class:`{_obj._ttk_forward.forwardClass.__name__}`'s forwarded init params:\n") for _iname in ttkInherited[_name]: if _iname not in ttkClasses: continue diff --git a/libs/pyTermTk/TermTk/TTkAbstract/abstractscrollarea.py b/libs/pyTermTk/TermTk/TTkAbstract/abstractscrollarea.py index 398d4857..c3a816cd 100644 --- a/libs/pyTermTk/TermTk/TTkAbstract/abstractscrollarea.py +++ b/libs/pyTermTk/TermTk/TTkAbstract/abstractscrollarea.py @@ -22,6 +22,9 @@ __all__ = ['TTkAbstractScrollArea'] +from dataclasses import dataclass +from typing import List,Any,Type + from TermTk.TTkCore.constant import TTkK # from TermTk.TTkCore.log import TTkLog from TermTk.TTkCore.signal import pyTTkSlot @@ -31,6 +34,13 @@ from TermTk.TTkWidgets.scrollbar import TTkScrollBar from TermTk.TTkLayouts.gridlayout import TTkGridLayout from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollViewInterface +@dataclass +class _ForwardData(): + forwardClass: Type + instance: str + signals: List[str] + methods: List[str] + class TTkAbstractScrollArea(TTkContainer): __slots__ = ( '_processing', # this flag is required to avoid unnecessary loop on edge cases diff --git a/libs/pyTermTk/TermTk/TTkGui/textdocument.py b/libs/pyTermTk/TermTk/TTkGui/textdocument.py index b71dacbb..81972c5d 100644 --- a/libs/pyTermTk/TermTk/TTkGui/textdocument.py +++ b/libs/pyTermTk/TermTk/TTkGui/textdocument.py @@ -22,7 +22,7 @@ __all__ = ['TTkTextDocument'] -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Optional, Union from threading import Lock from TermTk.TTkCore.log import TTkLog @@ -237,7 +237,7 @@ class TTkTextDocument(): def characterCount(self): return sum([len[x] for x in self._dataLines])+self.lineCount() - def setText(self, text): + def setText(self, text:Union[str,TTkString]): remLines = len(self._dataLines) if not isinstance(text, str) and not isinstance(text,TTkString): text=str(text) diff --git a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetree.py b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetree.py index b00e4790..3c93578d 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetree.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetree.py @@ -22,8 +22,13 @@ __all__ = ['TTkFileTree'] +from TermTk.TTkCore.constant import TTkK +from TermTk.TTkCore.string import TTkString +from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal from TermTk.TTkWidgets.TTkModelView.tree import TTkTree from TermTk.TTkWidgets.TTkModelView.filetreewidget import TTkFileTreeWidget +from TermTk.TTkWidgets.TTkModelView.treewidgetitem import TTkTreeWidgetItem +from TermTk.TTkAbstract.abstractscrollarea import _ForwardData class TTkFileTree(TTkTree): __doc__ = ''' @@ -31,17 +36,19 @@ class TTkFileTree(TTkTree): ''' + TTkFileTreeWidget.__doc__ - __slots__ = tuple( - ['_fileTreeWidget'] + - (_forwardedSignals:=[# Forwarded Signals from TTkFileTreeWidget - *TTkTree._forwardedSignals, - 'fileClicked', 'folderClicked', 'fileDoubleClicked', 'folderDoubleClicked', 'fileActivated', 'folderActivated']) + - (_forwardedMethods:=[# Forwarded Methods From TTkTreeWidget - *TTkTree._forwardedMethods, - 'openPath', 'getOpenPath', - 'setFilter']) + _ttk_forward = _ForwardData( + forwardClass=TTkFileTreeWidget, + instance="self._fileTreeWidget", + signals=[# Forwarded Signals from TTkFileTreeWidget + *TTkTree._ttk_forward.signals, + 'fileClicked', 'folderClicked', 'fileDoubleClicked', 'folderDoubleClicked', 'fileActivated', 'folderActivated'], + methods=[# Forwarded Methods From TTkTreeWidget + *TTkTree._ttk_forward.methods, + 'openPath', 'getOpenPath', + 'setFilter'] ) - _forwardWidget = TTkFileTreeWidget + + __slots__ = ('_fileTreeWidget', *_ttk_forward.signals) def __init__(self, **kwargs) -> None: wkwargs = kwargs.copy() @@ -51,5 +58,140 @@ class TTkFileTree(TTkTree): super().__init__(**kwargs, treeWidget=self._fileTreeWidget) - for _attr in self._forwardedSignals+self._forwardedMethods: + for _attr in self._ttk_forward.signals: setattr(self,_attr,getattr(self._fileTreeWidget,_attr)) + + #--FORWARD-AUTOGEN-START--# + def setHeaderLabels(self, labels:TTkString) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.setHeaderLabels` + + setHeaderLabels + ''' + return self._fileTreeWidget.setHeaderLabels(labels=labels) + def setColumnWidth(self, column:int, width: int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.setColumnWidth` + + setColumnWidth + ''' + return self._fileTreeWidget.setColumnWidth(column=column, width=width) + def resizeColumnToContents(self, column:int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.resizeColumnToContents` + + resizeColumnToContents + ''' + return self._fileTreeWidget.resizeColumnToContents(column=column) + def sortColumn(self): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.sortColumn` + + Returns the column used to sort the contents of the widget. + ''' + return self._fileTreeWidget.sortColumn() + def sortItems(self, col:int, order:TTkK.SortOrder) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.sortItems` + + Sorts the items in the widget in the specified order by the values in the given column. + ''' + return self._fileTreeWidget.sortItems(col=col, order=order) + def dragDropMode(self): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.dragDropMode` + + dragDropMode + ''' + return self._fileTreeWidget.dragDropMode() + def setDragDropMode(self, dndMode): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.setDragDropMode` + + setDragDropMode + ''' + return self._fileTreeWidget.setDragDropMode(dndMode=dndMode) + @pyTTkSlot() + def expandAll(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.expandAll` + + expandAll + ''' + return self._fileTreeWidget.expandAll() + @pyTTkSlot() + def collapseAll(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.collapseAll` + + collapseAll + ''' + return self._fileTreeWidget.collapseAll() + def addTopLevelItem(self, item:TTkTreeWidgetItem) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.addTopLevelItem` + + addTopLevelItem + ''' + return self._fileTreeWidget.addTopLevelItem(item=item) + def addTopLevelItems(self, items:TTkTreeWidgetItem) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.addTopLevelItems` + + addTopLevelItems + ''' + return self._fileTreeWidget.addTopLevelItems(items=items) + def takeTopLevelItem(self, index) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.takeTopLevelItem` + + takeTopLevelItem + ''' + return self._fileTreeWidget.takeTopLevelItem(index=index) + def topLevelItem(self, index) -> TTkTreeWidgetItem: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.topLevelItem` + + topLevelItem + ''' + return self._fileTreeWidget.topLevelItem(index=index) + def indexOfTopLevelItem(self, item:TTkTreeWidgetItem) -> int: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.indexOfTopLevelItem` + + indexOfTopLevelItem + ''' + return self._fileTreeWidget.indexOfTopLevelItem(item=item) + def selectedItems(self) -> list[TTkTreeWidgetItem]: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.selectedItems` + + selectedItems + ''' + return self._fileTreeWidget.selectedItems() + def clear(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.clear` + + clear + ''' + return self._fileTreeWidget.clear() + def openPath(self, path): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.openPath` + + ''' + return self._fileTreeWidget.openPath(path=path) + def getOpenPath(self): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.getOpenPath` + + ''' + return self._fileTreeWidget.getOpenPath() + def setFilter(self, filter): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkFileTreeWidget.setFilter` + + ''' + return self._fileTreeWidget.setFilter(filter=filter) + #--FORWARD-AUTOGEN-END--# \ No newline at end of file diff --git a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/table.py b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/table.py index b2fb7bad..c6bd6531 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/table.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/table.py @@ -24,8 +24,8 @@ __all__ = ['TTkTable'] from TermTk.TTkCore.constant import TTkK from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot -from TermTk.TTkWidgets.TTkModelView.tablewidget import TTkTableWidget -from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea +from TermTk.TTkWidgets.TTkModelView.tablewidget import TTkTableWidget, TTkHeaderView +from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea, _ForwardData from TermTk.TTkAbstract.abstracttablemodel import TTkAbstractTableModel class TTkTable(TTkAbstractScrollArea): @@ -36,15 +36,16 @@ class TTkTable(TTkAbstractScrollArea): classStyle = TTkTableWidget.classStyle - __slots__ = tuple( - ['_tableView'] + - (_forwardedSignals:=[ # Forwarded Signals From TTkTable + _ttk_forward = _ForwardData( + forwardClass=TTkTableWidget , + instance="self._tableView", + signals=[ # Forwarded Signals From TTkTable # 'cellActivated', 'cellChanged', 'cellClicked', 'cellDoubleClicked', 'cellEntered', # 'cellPressed', - 'currentCellChanged']) + - (_forwardedMethods:=[ # Forwarded Methods From TTkTable + 'currentCellChanged'], + methods=[ # Forwarded Methods From TTkTable 'undo', 'redo', 'isUndoAvailable','isRedoAvailable', 'copy', 'cut', 'paste', @@ -56,9 +57,10 @@ class TTkTable(TTkAbstractScrollArea): 'hSeparatorVisibility', 'vSeparatorVisibility', 'setHSeparatorVisibility', 'setVSeparatorVisibility', 'model', 'setModel', 'setColumnWidth', 'resizeColumnToContents', 'resizeColumnsToContents', - 'setRowHeight', 'resizeRowToContents', 'resizeRowsToContents']) - ) - _forwardWidget = TTkTableWidget + 'setRowHeight', 'resizeRowToContents', 'resizeRowsToContents'] + ) + + __slots__ = ('_tableView', *_ttk_forward.signals) def __init__(self, *, tableWidget:TTkTableWidget=None, @@ -88,7 +90,7 @@ class TTkTable(TTkAbstractScrollArea): self.setViewport(self._tableView) # self.setFocusPolicy(TTkK.ClickFocus) - for _attr in self._forwardedSignals+self._forwardedMethods: + for _attr in self._ttk_forward.signals: setattr(self,_attr,getattr(self._tableView,_attr)) def style(self): @@ -104,4 +106,378 @@ class TTkTable(TTkAbstractScrollArea): def mergeStyle(self, style): if self._tableView: self._tableView.mergeStyle(style) - return super().mergeStyle(style) \ No newline at end of file + return super().mergeStyle(style) + + #--FORWARD-AUTOGEN-START--# + @pyTTkSlot() + def undo(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.undo` + + Undoes the last operation if undo is available. + ''' + return self._tableView.undo() + @pyTTkSlot() + def redo(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.redo` + + Redoes the last operation if redo is available. + ''' + return self._tableView.redo() + def isUndoAvailable(self) -> bool: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.isUndoAvailable` + + isUndoAvailable + + :return: bool + ''' + return self._tableView.isUndoAvailable() + def isRedoAvailable(self) -> bool: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.isRedoAvailable` + + isRedoAvailable + + :return: bool + ''' + return self._tableView.isRedoAvailable() + @pyTTkSlot() + def copy(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.copy` + + Copies any selected cells to the clipboard. + ''' + return self._tableView.copy() + @pyTTkSlot() + def cut(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.cut` + + Copies the selected ccells to the clipboard and deletes them from the table. + ''' + return self._tableView.cut() + @pyTTkSlot() + def paste(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.paste` + + Pastes the text/cells from the clipboard into the table at the current cursor position. + ''' + return self._tableView.paste() + @pyTTkSlot(bool) + def setSortingEnabled(self, enable:bool) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.setSortingEnabled` + + If enable is true, enables sorting for the table and immediately trigger a + call to :meth:`sortByColumn` + with the current sort section and order + + **Note**: Setter function for property sortingEnabled. + + :param enable: the availability of undo + :type enable: bool + ''' + return self._tableView.setSortingEnabled(enable=enable) + def isSortingEnabled(self) -> bool: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.isSortingEnabled` + + This property holds whether sorting is enabled + If this property is true, sorting is enabled for the table. + If this property is false, sorting is not enabled. The default value is false. + + **Note**: . Setting the property to true with :meth:`setSortingEnabled` + immediately triggers a call to :meth:`sortByColumn` + with the current sort section and order. + + :return: bool + ''' + return self._tableView.isSortingEnabled() + @pyTTkSlot(int, TTkK.SortOrder) + def sortByColumn(self, column:int, order:TTkK.SortOrder) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.sortByColumn` + + Sorts the model by the values in the given column and order. + + column may be -1, in which case no sort indicator will be shown and the model will return to its natural, unsorted order. + Note that not all models support this and may even crash in this case. + + :param column: the column used for the sorting, -1 to keep the table unsorted + :type column: bool + + :param order: the sort order + :type order: :py:class:`TTkK.SortOrder` + ''' + return self._tableView.sortByColumn(column=column, order=order) + def clearSelection(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.clearSelection` + + Deselects all selected items. + The current index will not be changed. + ''' + return self._tableView.clearSelection() + def selectAll(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.selectAll` + + Selects all items in the view. + This function will use the selection behavior set on the view when selecting. + ''' + return self._tableView.selectAll() + def setSelection(self, pos:tuple[int,int], size:tuple[int,int], flags:TTkK.TTkItemSelectionModel) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.setSelection` + + Selects the items within the given rect and in accordance with the specified selection flags. + + :param pos: the x,y position of the rect + :type pos: tuple[int,int] + :param size: the width,height of the rect used for the selection + :type size: tuple[int,int] + :param flags: the selection model used (i.e. :py:class:`TTkItemSelectionModel.Select`) + :type flags: :py:class:`TTkItemSelectionModel` + ''' + return self._tableView.setSelection(pos=pos, size=size, flags=flags) + def selectRow(self, row:int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.selectRow` + + Selects the given row in the table view + + :param row: the row to be selected + :type row: int + ''' + return self._tableView.selectRow(row=row) + def selectColumn(self, col:int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.selectColumn` + + Selects the given column in the table view + + :param col: the column to be selected + :type col: int + ''' + return self._tableView.selectColumn(col=col) + def unselectRow(self, row:int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.unselectRow` + + Unselects the given row in the table view + + :param row: the row to be unselected + :type row: int + ''' + return self._tableView.unselectRow(row=row) + def unselectColumn(self, column:int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.unselectColumn` + + Unselects the given column in the table view + + :param column: the column to be unselected + :type column: int + ''' + return self._tableView.unselectColumn(column=column) + def rowCount(self) -> int: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.rowCount` + + Returns the number of rows. + + :return: int + ''' + return self._tableView.rowCount() + def currentRow(self) -> int: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.currentRow` + + Returns the row of the current item. + + :return: int + ''' + return self._tableView.currentRow() + def columnCount(self) -> int: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.columnCount` + + Returns the number of columns. + + :return: int + ''' + return self._tableView.columnCount() + def currentColumn(self) -> int: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.currentColumn` + + Returns the column of the current item. + + :return: int + ''' + return self._tableView.currentColumn() + def verticalHeader(self) -> TTkHeaderView: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.verticalHeader` + + Returns the table view's vertical header. + + :return: :py:class:`TTkHeaderView` + ''' + return self._tableView.verticalHeader() + def horizontalHeader(self) -> TTkHeaderView: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.horizontalHeader` + + Returns the table view's horizontal header. + + :return: :py:class:`TTkHeaderView` + ''' + return self._tableView.horizontalHeader() + def hSeparatorVisibility(self) -> bool: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.hSeparatorVisibility` + + Returns the visibility status of the horizontal separator + + :return: bool + ''' + return self._tableView.hSeparatorVisibility() + def vSeparatorVisibility(self) -> bool: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.vSeparatorVisibility` + + Returns the visibility status of the vertical separator + + :return: bool + ''' + return self._tableView.vSeparatorVisibility() + def setHSeparatorVisibility(self, visibility:bool) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.setHSeparatorVisibility` + + Set the the visibility of the horizontal separators (lines) + + :: + + Customer Id First Name Last Name Company + 1 │ DD37Cf93aecA6Dc Sheryl Baxter Rasmussen Group + ╾╌╌┼─────────────────────────────────────────────────────────── + 2 │ 1Ef7b82A4CAAD10 Preston Lozano Vega-Gentry + ╾╌╌┼─────────────────────────────────────────────────────────── + 3 │ 6F94879bDAfE5a6 Roy Berry Murillo-Perry + ╾╌╌┼─────────────────────────────────────────────────────────── + + :param visibility: the visibility status + :type visibility: bool + ''' + return self._tableView.setHSeparatorVisibility(visibility=visibility) + def setVSeparatorVisibility(self, visibility:bool): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.setVSeparatorVisibility` + + Set the the visibility of the vertical separators (lines) + + :: + + Customer Id ╿First Name ╿Last Name ╿Company ╿ + 1 │ DD37Cf93aecA6Dc │Sheryl │Baxter │Rasmussen Group │ + 2 │ 1Ef7b82A4CAAD10 │Preston │Lozano │Vega-Gentry │ + 3 │ 6F94879bDAfE5a6 │Roy │Berry │Murillo-Perry │ + 4 │ 5Cef8BFA16c5e3c │Linda │Olsen │Dominguez, Mcmillan and Don │ + 5 │ 053d585Ab6b3159 │Joanna │Bender │Martin, Lang and Andrade │ + 6 │ 2d08FB17EE273F4 │Aimee │Downs │Steele Group │ + + :param visibility: the visibility status + :type visibility: bool + ''' + return self._tableView.setVSeparatorVisibility(visibility=visibility) + def model(self) -> TTkAbstractTableModel: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.model` + + Returns the model that this view is presenting. + + :return: :py:class:`TTkAbstractTableModel` + ''' + return self._tableView.model() + def setModel(self, model:TTkAbstractTableModel) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.setModel` + + Sets the model for the view to present. + + :param model: + :type model: :py:class:`TTkAbstractTableModel` + ''' + return self._tableView.setModel(model=model) + @pyTTkSlot(int,int) + def setColumnWidth(self, column:int, width: int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.setColumnWidth` + + Sets the width of the given column. + + :param column: the column + :type column: int + :param width: its width + :type width: int + ''' + return self._tableView.setColumnWidth(column=column, width=width) + @pyTTkSlot(int) + def resizeColumnToContents(self, column:int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.resizeColumnToContents` + + Resizes the given column based on the size hints of the delegate used to render each item in the column. + + :param column: the column to be resized + :type column: int + ''' + return self._tableView.resizeColumnToContents(column=column) + @pyTTkSlot() + def resizeColumnsToContents(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.resizeColumnsToContents` + + Resizes all columns based on the size hints of the delegate used to render each item in the columns. + ''' + return self._tableView.resizeColumnsToContents() + @pyTTkSlot(int,int) + def setRowHeight(self, row:int, height: int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.setRowHeight` + + Sets the height of the given row. + + :param row: the row + :type row: int + :param height: its height + :type height: int + ''' + return self._tableView.setRowHeight(row=row, height=height) + @pyTTkSlot(int) + def resizeRowToContents(self, row:int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.resizeRowToContents` + + Resizes the given row based on the size hints of the delegate used to render each item in the row. + + :param row: the row to be resized + :type row: int + ''' + return self._tableView.resizeRowToContents(row=row) + @pyTTkSlot() + def resizeRowsToContents(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTableWidget.resizeRowsToContents` + + Resizes all rows based on the size hints of the delegate used to render each item in the rows. + ''' + return self._tableView.resizeRowsToContents() + #--FORWARD-AUTOGEN-END--# + diff --git a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/tree.py b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/tree.py index 02682e6b..f847ca49 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/tree.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/tree.py @@ -23,30 +23,33 @@ __all__ = ['TTkTree'] from TermTk.TTkCore.constant import TTkK +from TermTk.TTkCore.string import TTkString from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot from TermTk.TTkWidgets.TTkModelView.treewidget import TTkTreeWidget -from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea - +from TermTk.TTkWidgets.TTkModelView.treewidgetitem import TTkTreeWidgetItem +from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea, _ForwardData class TTkTree(TTkAbstractScrollArea): __doc__ = ''' :py:class:`TTkTree` is a container widget which place :py:class:`TTkTreeWidget` in a scrolling area with on-demand scroll bars. ''' + TTkTreeWidget.__doc__ - __slots__ = tuple( - ['_treeView'] + - (_forwardedSignals:=[# Forwarded Signals From TTkTreeWidget - 'itemActivated', 'itemChanged', 'itemClicked', 'itemExpanded', 'itemCollapsed', 'itemDoubleClicked']) + - (_forwardedMethods:=[# Forwarded Methods From TTkTreeWidget + _ttk_forward = _ForwardData( + forwardClass=TTkTreeWidget , + instance="self._treeView", + signals=[# Forwarded Signals From TTkTreeWidget + 'itemActivated', 'itemChanged', 'itemClicked', 'itemExpanded', 'itemCollapsed', 'itemDoubleClicked'], + methods=[# Forwarded Methods From TTkTreeWidget 'setHeaderLabels', 'setColumnWidth', 'resizeColumnToContents', 'sortColumn', 'sortItems', 'dragDropMode', 'setDragDropMode', 'expandAll', 'collapseAll', # 'appendItem', 'setAlignment', 'setColumnColors', 'setColumnSize', 'setHeader', - 'addTopLevelItem', 'addTopLevelItems', 'takeTopLevelItem', 'topLevelItem', 'indexOfTopLevelItem', 'selectedItems', 'clear']) - ) - _forwardWidget = TTkTreeWidget + 'addTopLevelItem', 'addTopLevelItems', 'takeTopLevelItem', 'topLevelItem', 'indexOfTopLevelItem', 'selectedItems', 'clear'] + ) + + __slots__ = ('_treeView', *_ttk_forward.signals) def __init__(self, *, treeWidget:TTkTreeWidget=None, @@ -62,5 +65,122 @@ class TTkTree(TTkAbstractScrollArea): self.setViewport(self._treeView) self.setFocusPolicy(TTkK.ClickFocus) - for _attr in self._forwardedSignals+self._forwardedMethods: + for _attr in self._ttk_forward.signals: setattr(self,_attr,getattr(self._treeView,_attr)) + + #--FORWARD-AUTOGEN-START--# + def setHeaderLabels(self, labels:TTkString) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.setHeaderLabels` + + setHeaderLabels + ''' + return self._treeView.setHeaderLabels(labels=labels) + def setColumnWidth(self, column:int, width: int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.setColumnWidth` + + setColumnWidth + ''' + return self._treeView.setColumnWidth(column=column, width=width) + def resizeColumnToContents(self, column:int) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.resizeColumnToContents` + + resizeColumnToContents + ''' + return self._treeView.resizeColumnToContents(column=column) + def sortColumn(self): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.sortColumn` + + Returns the column used to sort the contents of the widget. + ''' + return self._treeView.sortColumn() + def sortItems(self, col:int, order:TTkK.SortOrder) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.sortItems` + + Sorts the items in the widget in the specified order by the values in the given column. + ''' + return self._treeView.sortItems(col=col, order=order) + def dragDropMode(self): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.dragDropMode` + + dragDropMode + ''' + return self._treeView.dragDropMode() + def setDragDropMode(self, dndMode): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.setDragDropMode` + + setDragDropMode + ''' + return self._treeView.setDragDropMode(dndMode=dndMode) + @pyTTkSlot() + def expandAll(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.expandAll` + + expandAll + ''' + return self._treeView.expandAll() + @pyTTkSlot() + def collapseAll(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.collapseAll` + + collapseAll + ''' + return self._treeView.collapseAll() + def addTopLevelItem(self, item:TTkTreeWidgetItem) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.addTopLevelItem` + + addTopLevelItem + ''' + return self._treeView.addTopLevelItem(item=item) + def addTopLevelItems(self, items:TTkTreeWidgetItem) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.addTopLevelItems` + + addTopLevelItems + ''' + return self._treeView.addTopLevelItems(items=items) + def takeTopLevelItem(self, index) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.takeTopLevelItem` + + takeTopLevelItem + ''' + return self._treeView.takeTopLevelItem(index=index) + def topLevelItem(self, index) -> TTkTreeWidgetItem: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.topLevelItem` + + topLevelItem + ''' + return self._treeView.topLevelItem(index=index) + def indexOfTopLevelItem(self, item:TTkTreeWidgetItem) -> int: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.indexOfTopLevelItem` + + indexOfTopLevelItem + ''' + return self._treeView.indexOfTopLevelItem(item=item) + def selectedItems(self) -> list[TTkTreeWidgetItem]: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.selectedItems` + + selectedItems + ''' + return self._treeView.selectedItems() + def clear(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTreeWidget.clear` + + clear + ''' + return self._treeView.clear() + #--FORWARD-AUTOGEN-END--# \ No newline at end of file diff --git a/libs/pyTermTk/TermTk/TTkWidgets/TTkTerminal/terminal.py b/libs/pyTermTk/TermTk/TTkWidgets/TTkTerminal/terminal.py index 504cd717..c249bc03 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/TTkTerminal/terminal.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/TTkTerminal/terminal.py @@ -24,7 +24,7 @@ __all__ = ['TTkTerminal'] from TermTk.TTkCore.constant import TTkK from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot -from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea +from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea, _ForwardData from TermTk.TTkWidgets.TTkTerminal.terminalview import TTkTerminalView class TTkTerminal(TTkAbstractScrollArea): @@ -33,15 +33,17 @@ class TTkTerminal(TTkAbstractScrollArea): ''' + TTkTerminalView.__doc__ - __slots__ = tuple( - ['_terminalView'] + - (_forwardedSignals:=[# Forwarded Signals From TTkTreeWidget + _ttk_forward = _ForwardData( + forwardClass=TTkTerminalView , + instance="self._terminalView", + signals=[# Forwarded Signals From TTkTreeWidget 'bell', 'titleChanged', 'terminalClosed', 'textSelected', - 'termData', 'termResized']) + - (_forwardedMethods:=[# Forwarded Methods From TTkTreeWidget - 'termWrite', 'termSize']) - ) - _forwardWidget = TTkTerminalView + 'termData', 'termResized'], + methods=[# Forwarded Methods From TTkTreeWidget + 'termWrite', 'termSize'] + ) + + __slots__ = ('_terminalView', *_ttk_forward.signals) def __init__(self, **kwargs) -> None: super().__init__(**kwargs) @@ -51,7 +53,7 @@ class TTkTerminal(TTkAbstractScrollArea): self.setFocusPolicy(TTkK.ClickFocus) self.setViewport(self._terminalView) - for _attr in self._forwardedSignals+self._forwardedMethods: + for _attr in self._ttk_forward.signals: setattr(self,_attr,getattr(self._terminalView,_attr)) self.terminalClosed = pyTTkSignal(TTkTerminal) @@ -61,3 +63,25 @@ class TTkTerminal(TTkAbstractScrollArea): self._terminalView.close() return super().close() + #--FORWARD-AUTOGEN-START--# + def termWrite(self, data:str) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTerminalView.termWrite` + + Write data to the terminal. + + :params data: the data to write + :type data: str + ''' + return self._terminalView.termWrite(data=data) + def termSize(self) -> tuple[int,int]: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTerminalView.termSize` + + This property holds the size of the terminal + + :return: a tuple of 2 integers (width, height) + :rtype: tuple + ''' + return self._terminalView.termSize() + #--FORWARD-AUTOGEN-END--# \ No newline at end of file diff --git a/libs/pyTermTk/TermTk/TTkWidgets/list_.py b/libs/pyTermTk/TermTk/TTkWidgets/list_.py index 83d2c9c4..4bf96671 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/list_.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/list_.py @@ -23,8 +23,8 @@ __all__ = ['TTkList'] from TermTk.TTkCore.constant import TTkK -from TermTk.TTkWidgets.listwidget import TTkListWidget -from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea +from TermTk.TTkWidgets.listwidget import TTkListWidget, TTkAbstractListItem +from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea, _ForwardData class TTkList(TTkAbstractScrollArea): __doc__ = ''' @@ -32,11 +32,12 @@ class TTkList(TTkAbstractScrollArea): ''' + TTkListWidget.__doc__ - __slots__ = tuple( - ['_listView'] + - (_forwardedSignals:=[ # Forwarded Signals From TTkTable - 'itemClicked', 'textClicked', 'searchModified']) + - (_forwardedMethods:=[ # Forwarded Methods From TTkTable + _ttk_forward = _ForwardData( + forwardClass=TTkListWidget , + instance="self._listView", + signals=[ # Forwarded Signals From TTkTable + 'itemClicked', 'textClicked', 'searchModified'], + methods=[ 'items', 'dragDropMode', 'setDragDropMode', 'addItem', 'addItemAt', 'addItems', 'addItemsAt', @@ -44,9 +45,11 @@ class TTkList(TTkAbstractScrollArea): 'removeAt', 'removeItem', 'removeItems', 'selectionMode', 'setSelectionMode', 'selectedItems', 'selectedLabels', 'search', 'setSearch', 'searchVisibility', 'setSearchVisibility', - 'setCurrentRow', 'setCurrentItem']) - ) - _forwardWidget = TTkListWidget + 'setCurrentRow', 'setCurrentItem' + ] + ) + + __slots__ = ('_listView', *_ttk_forward.signals) def __init__(self, *, listWidget:TTkListWidget=None, @@ -66,6 +69,169 @@ class TTkList(TTkAbstractScrollArea): super().__init__(**kwargs) self.setViewport(self._listView) - for _attr in self._forwardedSignals+self._forwardedMethods: + for _attr in self._ttk_forward.signals: setattr(self,_attr,getattr(self._listView,_attr)) + #--FORWARD-AUTOGEN-START--# + def items(self) -> list[TTkAbstractListItem]: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.items` + + items + ''' + return self._listView.items() + def dragDropMode(self): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.dragDropMode` + + dragDropMode + ''' + return self._listView.dragDropMode() + def setDragDropMode(self, dndMode): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.setDragDropMode` + + setDragDropMode + ''' + return self._listView.setDragDropMode(dndMode=dndMode) + def addItem(self, item, data=None): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.addItem` + + addItem + ''' + return self._listView.addItem(item=item, data=data) + def addItemAt(self, item, pos, data=None): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.addItemAt` + + addItemAt + ''' + return self._listView.addItemAt(item=item, pos=pos, data=data) + def addItems(self, items): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.addItems` + + addItems + ''' + return self._listView.addItems(items=items) + def addItemsAt(self, items, pos): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.addItemsAt` + + addItemsAt + ''' + return self._listView.addItemsAt(items=items, pos=pos) + def indexOf(self, item): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.indexOf` + + indexOf + ''' + return self._listView.indexOf(item=item) + def itemAt(self, pos): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.itemAt` + + itemAt + ''' + return self._listView.itemAt(pos=pos) + def moveItem(self, fr, to): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.moveItem` + + moveItem + ''' + return self._listView.moveItem(fr=fr, to=to) + def removeAt(self, pos): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.removeAt` + + removeAt + ''' + return self._listView.removeAt(pos=pos) + def removeItem(self, item): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.removeItem` + + removeItem + ''' + return self._listView.removeItem(item=item) + def removeItems(self, items): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.removeItems` + + removeItems + ''' + return self._listView.removeItems(items=items) + def selectionMode(self): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.selectionMode` + + selectionMode + ''' + return self._listView.selectionMode() + def setSelectionMode(self, mode): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.setSelectionMode` + + setSelectionMode + ''' + return self._listView.setSelectionMode(mode=mode) + def selectedItems(self): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.selectedItems` + + selectedItems + ''' + return self._listView.selectedItems() + def selectedLabels(self): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.selectedLabels` + + selectedLabels + ''' + return self._listView.selectedLabels() + def search(self) -> str: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.search` + + search + ''' + return self._listView.search() + def setSearch(self, search:str) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.setSearch` + + setSearch + ''' + return self._listView.setSearch(search=search) + def searchVisibility(self) -> bool: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.searchVisibility` + + searchVisibility + ''' + return self._listView.searchVisibility() + def setSearchVisibility(self, visibility:bool) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.setSearchVisibility` + + setSearchVisibility + ''' + return self._listView.setSearchVisibility(visibility=visibility) + def setCurrentRow(self, row): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.setCurrentRow` + + setCurrentRow + ''' + return self._listView.setCurrentRow(row=row) + def setCurrentItem(self, item): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkListWidget.setCurrentItem` + + setCurrentItem + ''' + return self._listView.setCurrentItem(item=item) + #--FORWARD-AUTOGEN-END--# \ No newline at end of file diff --git a/libs/pyTermTk/TermTk/TTkWidgets/texedit.py b/libs/pyTermTk/TermTk/TTkWidgets/texedit.py index 2918132b..c0d3ec65 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/texedit.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/texedit.py @@ -22,6 +22,7 @@ __all__ = ['TTkTextEditView', 'TTkTextEdit', 'TTkTextEditRuler'] +from typing import Optional,Union,Dict,Any from TermTk.TTkCore.log import TTkLog from TermTk.TTkCore.cfg import TTkCfg @@ -40,7 +41,7 @@ from TermTk.TTkGui.textdocument import TTkTextDocument from TermTk.TTkWidgets.widget import TTkWidget -from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea +from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea, _ForwardData from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView, TTkAbstractScrollViewGridLayout class TTkTextEditRuler(TTkAbstractScrollView): @@ -483,10 +484,14 @@ class TTkTextEditView(TTkAbstractScrollView): self._textWrap.wrapChanged.connect(self.update) # forward textWrap Methods - def wrapWidth(self, *args, **kwargs) -> None: return self._textWrap.wrapWidth(*args, **kwargs) - def setWrapWidth(self, *args, **kwargs) -> None: return self._textWrap.setWrapWidth(*args, **kwargs) - def wordWrapMode(self, *args, **kwargs) -> None: return self._textWrap.wordWrapMode(*args, **kwargs) - def setWordWrapMode(self, *args, **kwargs) -> None: return self._textWrap.setWordWrapMode(*args, **kwargs) + def wrapWidth(self, *args, **kwargs) -> None: + return self._textWrap.wrapWidth(*args, **kwargs) + def setWrapWidth(self, *args, **kwargs) -> None: + return self._textWrap.setWrapWidth(*args, **kwargs) + def wordWrapMode(self, *args, **kwargs) -> None: + return self._textWrap.wordWrapMode(*args, **kwargs) + def setWordWrapMode(self, *args, **kwargs) -> None: + return self._textWrap.setWordWrapMode(*args, **kwargs) def extraSelections(self) -> list[ExtraSelection]: ''' @@ -514,7 +519,7 @@ class TTkTextEditView(TTkAbstractScrollView): def isReadOnly(self) -> bool: return self._readOnly - def setReadOnly(self, ro) -> None: + def setReadOnly(self, ro:bool) -> None: self._readOnly = ro self.disableWidgetCursor(ro) @@ -535,7 +540,7 @@ class TTkTextEditView(TTkAbstractScrollView): self._textWrap.rewrap() @pyTTkSlot(str) - def setText(self, text) -> None: + def setText(self, text:Union[str,TTkString]) -> None: self.viewMoveTo(0, 0) self._textDocument.setText(text) self._updateSize() @@ -922,31 +927,35 @@ class TTkTextEdit(TTkAbstractScrollArea): ExtraSelection = TTkTextEditView.ExtraSelection - __slots__ = ( - ['_textEditView', - '_lineNumberView', '_lineNumber'] + - (_forwardedSignals:=[ # Forwarded Signals From TTkTexteditView - # Signals + _ttk_forward:_ForwardData = _ForwardData( + forwardClass=TTkTextEditView , + instance="self._textEditView", + signals=[ # Forwarded Signals From TTkTexteditView 'focusChanged', 'currentColorChanged', 'cursorPositionChanged', 'undoAvailable', 'redoAvailable', - 'textChanged']) + - (_forwardedMethods:=[ # Forwarded Methods From TTkTexteditView - # Forwarded Methods - 'clear', 'setText', 'append', 'isReadOnly', 'setReadOnly', 'document', - 'wrapWidth', 'setWrapWidth', - 'multiLine', - 'lineWrapMode', 'setLineWrapMode', - 'wordWrapMode', 'setWordWrapMode', - 'textCursor', 'setFocus', 'setColor', - 'extraSelections', 'setExtraSelections', - 'cut', 'copy', 'paste', - 'undo', 'redo', 'isUndoAvailable', 'isRedoAvailable', - 'find', 'ensureCursorVisible', + 'textChanged'], + methods=[ + # Forwarded Methods From TTkTexteditView + "clear", "setText", "append", "isReadOnly", "setReadOnly", "document", + "wrapWidth", "setWrapWidth", + "multiLine", + "lineWrapMode", "setLineWrapMode", + "wordWrapMode", "setWordWrapMode", + "textCursor", "setFocus", "setColor", + "extraSelections", "setExtraSelections", + "cut", "copy", "paste", + "undo", "redo", "isUndoAvailable", "isRedoAvailable", + "find", "ensureCursorVisible", # Export Methods, - 'toAnsi', 'toRawText', 'toPlainText', # 'toHtml', 'toMarkdown', - ]) + "toAnsi", "toRawText", "toPlainText" # , "toHtml", "toMarkdown", + ] + ) + + __slots__ = ( + '_textEditView', + '_lineNumberView', '_lineNumber', + *_ttk_forward.signals ) - _forwardWidget = TTkTextEditView def __init__(self, *, # TTkWidget init @@ -984,7 +993,7 @@ class TTkTextEdit(TTkAbstractScrollArea): textEditLayout.addWidget(self._lineNumberView,0,0) self.setViewport(textEditLayout) - for _attr in self._forwardedSignals+self._forwardedMethods: + for _attr in self._ttk_forward.signals: setattr(self,_attr,getattr(self._textEditView,_attr)) def ruler(self) -> TTkTextEditRuler: @@ -1018,3 +1027,215 @@ class TTkTextEdit(TTkAbstractScrollArea): '''setDocument''' self._textEditView.setDocument(document) self._lineNumberView.setTextWrap(self._textEditView._textWrap) + + #--FORWARD-AUTOGEN-START--# + @pyTTkSlot() + def clear(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.clear` + + ''' + return self._textEditView.clear() + @pyTTkSlot(str) + def setText(self, text:Union[str,TTkString]) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setText` + + ''' + return self._textEditView.setText(text=text) + @pyTTkSlot(str) + def append(self, text) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.append` + + ''' + return self._textEditView.append(text=text) + def isReadOnly(self) -> bool: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.isReadOnly` + + ''' + return self._textEditView.isReadOnly() + def setReadOnly(self, ro:bool) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setReadOnly` + + ''' + return self._textEditView.setReadOnly(ro=ro) + def document(self) -> TTkTextDocument: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.document` + + document + ''' + return self._textEditView.document() + def wrapWidth(self, *args, **kwargs) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.wrapWidth` + + ''' + return self._textEditView.wrapWidth(*args, **kwargs) + def setWrapWidth(self, *args, **kwargs) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setWrapWidth` + + ''' + return self._textEditView.setWrapWidth(*args, **kwargs) + def multiLine(self) -> bool: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.multiLine` + + multiline + ''' + return self._textEditView.multiLine() + def lineWrapMode(self) -> TTkK.LineWrapMode: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.lineWrapMode` + + ''' + return self._textEditView.lineWrapMode() + def setLineWrapMode(self, mode:TTkK.LineWrapMode): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setLineWrapMode` + + ''' + return self._textEditView.setLineWrapMode(mode=mode) + def wordWrapMode(self, *args, **kwargs) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.wordWrapMode` + + ''' + return self._textEditView.wordWrapMode(*args, **kwargs) + def setWordWrapMode(self, *args, **kwargs) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setWordWrapMode` + + ''' + return self._textEditView.setWordWrapMode(*args, **kwargs) + def textCursor(self) -> TTkTextCursor: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.textCursor` + + ''' + return self._textEditView.textCursor() + @pyTTkSlot() + def setFocus(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setFocus` + + Focus the widget + ''' + return self._textEditView.setFocus() + @pyTTkSlot(TTkColor) + def setColor(self, color:TTkColor) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setColor` + + ''' + return self._textEditView.setColor(color=color) + def extraSelections(self) -> list[ExtraSelection]: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.extraSelections` + + Returns previously set extra selections. + + :rtype: list[:py:class:`ExtraSelection`] + ''' + return self._textEditView.extraSelections() + def setExtraSelections(self, extraSelections:list[ExtraSelection]) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setExtraSelections` + + This function allows temporarily marking certain regions in the document with a given color, + specified as selections. This can be useful for example in a programming editor to mark a + whole line of text with a given background color to indicate the existence of a breakpoint. + + :param extraSelections: the list of extra selections. + :type extraSelections: list[:py:class:`ExtraSelection`] + ''' + return self._textEditView.setExtraSelections(extraSelections=extraSelections) + @pyTTkSlot() + def cut(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.cut` + + ''' + return self._textEditView.cut() + @pyTTkSlot() + def copy(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.copy` + + ''' + return self._textEditView.copy() + @pyTTkSlot() + def paste(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.paste` + + ''' + return self._textEditView.paste() + @pyTTkSlot() + def undo(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.undo` + + ''' + return self._textEditView.undo() + @pyTTkSlot() + def redo(self) -> None: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.redo` + + ''' + return self._textEditView.redo() + def isUndoAvailable(self) -> bool: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.isUndoAvailable` + + isUndoAvailable + ''' + return self._textEditView.isUndoAvailable() + def isRedoAvailable(self) -> bool: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.isRedoAvailable` + + isRedoAvailable + ''' + return self._textEditView.isRedoAvailable() + @pyTTkSlot(TTkString) + def find(self, exp): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.find` + + ''' + return self._textEditView.find(exp=exp) + @pyTTkSlot() + def ensureCursorVisible(self): + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.ensureCursorVisible` + + ''' + return self._textEditView.ensureCursorVisible() + def toAnsi(self) -> str: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.toAnsi` + + toAnsi + ''' + return self._textEditView.toAnsi() + def toRawText(self) -> TTkString: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.toRawText` + + toRawText + ''' + return self._textEditView.toRawText() + def toPlainText(self) ->str: + ''' + .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.toPlainText` + + toPlainText + ''' + return self._textEditView.toPlainText() + #--FORWARD-AUTOGEN-END--# \ No newline at end of file diff --git a/tools/autogenForwarded.py b/tools/autogenForwarded.py new file mode 100755 index 00000000..5f29284f --- /dev/null +++ b/tools/autogenForwarded.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +# MIT License +# +# Copyright (c) 2025 Eugenio Parodi +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import re +import json +import argparse +import inspect +from typing import List, Optional, Dict, Tuple, Any + +def read_file_to_lines(file_path: str) -> List[str]: + """ + Reads a file and returns a list of strings, one for each line. + + Args: + file_path (str): The path to the file. + + Returns: + list: A list of strings, where each string is a line from the file. + Returns None if the file cannot be opened. + """ + with open(file_path, 'r') as f: + lines: List[str] = f.readlines() + return lines + raise Exception() + +def write_lines_to_file(lines: List[str], output_path: str) -> bool: + """ + Writes a list of strings to a file, one string per line. + + Args: + lines (list): The list of strings to write. + output_path (str): The path to the output file. + + Returns: + bool: True if the write was successful, False otherwise. + """ + try: + with open(output_path, 'w') as f: + for line in lines: + f.write(line) + return True + except Exception as e: + print(f"Error: An error occurred while writing to the file: {e}") + return False + +def _index_of(_m:str, lines:List[str]) -> int: + for i,l in enumerate(lines): + if _m in l: + return i + raise ValueError(f"End Delimiter '{_m}' not found in the filtered lines") + +marker_start = "#--FORWARD-AUTOGEN-START--#" +marker_end = "#--FORWARD-AUTOGEN-END--#" + +from TermTk.TTkAbstract.abstractscrollarea import _ForwardData +def autogen_methods(data: _ForwardData) -> List[str]: + """ + Generates a list of method signatures and return types for a given class. + + Args: + data (Dict[str, Any]): A dictionary containing the class name and a list of methods. + Example: {'class': 'TTkTexteditView', 'methods': ['clear', 'setText', ...]} + + Returns: + List[str]: A list of strings, where each string is a method signature and return type. + """ + import TermTk as ttk + + class_name = data.forwardClass.__name__ + signatures: List[str] = [] + + for method_name in data.methods: + try: + # Get the method from the class + method = getattr(data.forwardClass, method_name) + sig = inspect.signature(method) + doc = inspect.getdoc(method) + return_type = sig.return_annotation + params = ', '.join([f"{_p}={_p}" for _p in sig.parameters.keys() if _p != 'self']) + + source = inspect.getsource(method) + # Extract the first line, which should be the method definition + lines = source.splitlines() + index_func = _index_of(' def ',lines) + lines = lines[:index_func+1] + doc_indent = " " + lines.extend([ + doc_indent + f"'''", + doc_indent + f".. seealso:: this method is forwarded to :py:meth:`{class_name}.{method_name}`\n", + ]) + if doc: + lines.extend([doc_indent + _l for _l in doc.split('\n')]) + lines.append(doc_indent + "'''") + # Format the signature string + signatures.extend([ + *[f"{_l}\n" for _l in lines], + # f" def {method_name}{sig}:", + ]) + if '=kwargs' in params and '=args' in params: + signatures.append(f" return {data.instance}.{method_name}(*args, **kwargs)\n") + elif '=kwargs' in params: + signatures.append(f" return {data.instance}.{method_name}(**kwargs)\n") + elif '=args' in params: + signatures.append(f" return {data.instance}.{method_name}(*args)\n") + else: + signatures.append(f" return {data.instance}.{method_name}({params})\n") + + except AttributeError: + print(f"Error: Method '{method_name}' not found in class '{class_name}'.") + except Exception as e: + print(f"Error: An error occurred while processing method '{method_name}': {e}") + + return signatures + +def get_classes_with_source_from_module(module) -> List[Dict[str, Any]]: + classes_with_source: List[Dict[str, Any]] = [] + + for name, obj in inspect.getmembers(module): + if inspect.isclass(obj) and hasattr(obj,'_ttk_forward'): + try: + source = inspect.getsource(obj) + filename = inspect.getfile(obj) + classes_with_source.append({ + 'class': obj, + 'name': name, + 'forward': obj._ttk_forward, + 'module': module.__name__, + 'filename': filename, + 'source': source + }) + except OSError as e: + print(f"Could not get source for class {name}: {e}") + except Exception as e: + print(f"Unexpected error getting source for class {name}: {e}") + + return classes_with_source + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Read a file and write its lines to another file.") + parser.add_argument('--apply', action='store_true', help='Apply the changes') + args = parser.parse_args() + + import TermTk as ttk + classes = get_classes_with_source_from_module(ttk) + args = parser.parse_args() + if classes: + for class_data in classes: + print(f"Class Name: {class_data['name']}") + print(f" Class: {class_data['class']}") + print(f" Forward: {class_data['forward']}") + print(f" Module: {class_data['module']}") + print(f" Filename: {class_data['filename']}") + # print(f" Source:\n{class_data['source']}") + autogenenerated = autogen_methods(class_data['forward']) + if args.apply: + lines = read_file_to_lines(class_data['filename']) + index_start = _index_of(marker_start,lines) + index_end = _index_of(marker_end,lines) + lines[index_start+1:index_end] = autogenenerated + write_lines_to_file(lines,class_data['filename']) + else: + print(''.join(autogenenerated)) + else: + print("No classes found in the module.") \ No newline at end of file