# Copyright (c) 2025-2026 macro-qgis-plugin contributors.
#
#
# This file is part of macro-qgis-plugin.
#
# macro-qgis-plugin is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# macro-qgis-plugin is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with macro-qgis-plugin. If not, see <https://www.gnu.org/licenses/>.
"""Qt table model for displaying macros in the macro panel."""
from typing import ClassVar
from qgis.PyQt.QtCore import NULL, QAbstractTableModel, QModelIndex, Qt, QVariant
from qgis_macros.macro import Macro
from qgis_plugin_tools.tools.i18n import tr
[docs]
class MacroTableModel(QAbstractTableModel):
"""Table model for a list of :class:`~qgis_macros.macro.Macro` objects."""
headers: ClassVar[dict[int, str]] = {0: tr("Macro")}
def __init__(self) -> None:
"""Initialize the model with an empty macro list."""
super().__init__()
self.macros: list[Macro] = []
[docs]
def add_macro(self, macro: Macro) -> None:
"""Append a macro and notify attached views."""
row = len(self.macros)
self.beginInsertRows(QModelIndex(), row, row)
self.macros.append(macro)
# Notify the view that rows have been added
self.endInsertRows()
[docs]
def remove_macro(self, row: int) -> None:
"""Remove the macro at *row* and notify attached views."""
self.beginRemoveRows(QModelIndex(), row, row)
self.macros.pop(row)
self.endRemoveRows()
[docs]
def reset_macros(self, macros: list[Macro]) -> None:
"""Replace the entire macro list and reset the model."""
self.beginResetModel()
self.macros = macros
self.endResetModel()
[docs]
def rowCount(self, parent: QModelIndex) -> int: # noqa: N802, D102
valid = parent.isValid()
return 0 if valid else len(self.macros)
[docs]
def columnCount(self, parent: QModelIndex) -> int: # noqa: N802, D102
return 0 if parent.isValid() else len(self.headers)
[docs]
def flags(self, index: QModelIndex) -> Qt.ItemFlag:
"""Return the flags for the given index."""
default_flags = super().flags(index)
if index.isValid():
return default_flags | Qt.ItemFlag.ItemIsEditable
return default_flags
[docs]
def data(
self, index: QModelIndex, role: Qt.ItemDataRole = Qt.ItemDataRole.DisplayRole
) -> QVariant:
"""Return the data for the given index and role."""
row = index.row()
if not index.isValid():
return NULL
if role == Qt.ItemDataRole.TextAlignmentRole:
return Qt.AlignmentFlag.AlignLeft
if role in (
Qt.ItemDataRole.DisplayRole,
Qt.ItemDataRole.ToolTipRole,
Qt.ItemDataRole.EditRole,
):
return QVariant(self.macros[row].name)
return NULL
[docs]
def setData( # noqa: N802
self,
index: QModelIndex,
value: str,
role: Qt.ItemDataRole = Qt.ItemDataRole.EditRole,
) -> bool:
"""Set the data for the given index and role."""
if not index.isValid() or role != Qt.ItemDataRole.EditRole:
return False
row = index.row()
name = value.strip()
if not name:
return False
self.macros[row].name = name
self.dataChanged.emit(index, index, [role])
return True