Source code for ooodev.write.table.write_table_cell_range

from __future__ import annotations
from typing import Any, overload, Generator, TYPE_CHECKING, Tuple, Sequence

try:
    # python 3.12+
    from typing import override  # noqa # type: ignore
except ImportError:
    from typing_extensions import override  # noqa # type: ignore

from com.sun.star.lang import IndexOutOfBoundsException

# from ooodev.mock import mock_g
from ooodev.adapter.style.character_properties_partial import CharacterPropertiesPartial
from ooodev.adapter.style.paragraph_properties_partial import ParagraphPropertiesPartial
from ooodev.adapter.table.cell_partial import CellPartial
from ooodev.adapter.text.cell_range_comp import CellRangeComp
from ooodev.format.inner.style_partial import StylePartial
from ooodev.utils import gen_util as mGenUtil
from ooodev.utils.data_type.cell_values import CellValues
from ooodev.utils.data_type.range_obj import RangeObj
from ooodev.utils.partial.lo_inst_props_partial import LoInstPropsPartial
from ooodev.utils.partial.prop_partial import PropPartial
from ooodev.utils.partial.qi_partial import QiPartial
from ooodev.write.partial.write_doc_prop_partial import WriteDocPropPartial
from ooodev.write.table.partial.write_table_prop_partial import WriteTablePropPartial
from ooodev.write.table.write_table_cell import WriteTableCell

if TYPE_CHECKING:
    from com.sun.star.table import XCellRange
    from com.sun.star.table import CellAddress
    from com.sun.star.table import XCell
    from com.sun.star.table import CellRangeAddress
    from ooodev.utils.data_type.range_values import RangeValues
    from ooodev.proto.component_proto import ComponentT
    from ooodev.utils.data_type.cell_obj import CellObj


[docs]class WriteTableCellRange( WriteDocPropPartial, WriteTablePropPartial, CellRangeComp, CellPartial, CharacterPropertiesPartial, ParagraphPropertiesPartial, LoInstPropsPartial, PropPartial, StylePartial, QiPartial, ): """Represents writer table rows."""
[docs] def __init__(self, owner: ComponentT, component: XCellRange, range_obj: RangeObj) -> None: """ Constructor Args: component (TextTableRow): UNO object that supports ``om.sun.star.text.TextTableRow`` service. """ if not isinstance(owner, WriteTablePropPartial): raise ValueError("owner must be a WriteTablePropPartial instance.") WriteTablePropPartial.__init__(self, obj=owner.write_table) WriteDocPropPartial.__init__(self, obj=owner.write_doc) # type: ignore LoInstPropsPartial.__init__(self, lo_inst=self.write_doc.lo_inst) CellRangeComp.__init__(self, component=component) # type: ignore CellPartial.__init__(self, component=component, interface=None) # type: ignore CharacterPropertiesPartial.__init__(self, component=component) # type: ignore ParagraphPropertiesPartial.__init__(self, component=component) # type: ignore PropPartial.__init__(self, component=component, lo_inst=self.lo_inst) StylePartial.__init__(self, component=component) QiPartial.__init__(self, component=component, lo_inst=self.lo_inst) self._owner = owner self._range_obj = range_obj self._parent = None
[docs] def __getitem__(self, key: Any) -> WriteTableCell: """ Returns the Write Table Cell. Args: key (Any): Key. can be a Tuple of (col, row) or a string such as "A1" or a CellObj. Returns: WriteTableCell: Table Cell Object. Example: .. code-block:: python >>> table = doc.tables[0] >>> rng = table.get_cell_range_by_name("A1:D10") >>> cell = rng["D3"] >>> print(cell, cell.value) WriteTableCell(cell_name=C4) Sean Connery See Also: - :meth:`get_cell` """ return self.get_cell(key)
[docs] def __iter__(self) -> Generator[WriteTableCell, Any, Any]: """ Iterates through the cells. The iteration is done in a column-major order, meaning that the cells are iterated over by column, then by row. Example: .. code-block:: python >>> rng = table.get_cell_range_by_name("A1:C3") >>> for cell in rng: >>> print(cell, cell.value) WriteTableCell(cell_name=A1) Title WriteTableCell(cell_name=B1) Year WriteTableCell(cell_name=C1) Actor WriteTableCell(cell_name=A2) Dr. No WriteTableCell(cell_name=B2) 1962 WriteTableCell(cell_name=C2) Sean Connery WriteTableCell(cell_name=A3) From Russia with Love WriteTableCell(cell_name=B3) 1963 WriteTableCell(cell_name=C3) Sean Connery """ for cell in self.range_obj: yield self.get_cell(cell)
def __repr__(self) -> str: return f"{self.__class__.__name__}(range={self.range_obj})" # region CellRangeDataPartial overrides
[docs] @override def set_data_array(self, array: Sequence[Sequence[Any]]) -> None: """ Fills the cell range with values from an array. The size of the array must be the same as the size of the cell range. Each element of the array must contain a float or a string. Warning: The size of the array must be the same as the size of the cell range. This means when setting table data the table must be the same size as the data. When setting a table range the array must be the same size as the range. """ self.component.setDataArray(array) # type: ignore
# endregion CellRangeDataPartial overrides # region get_cell() @overload def get_cell(self, cell_obj: CellObj) -> WriteTableCell: """ Gets the cell as WriteTableCell. Args: cell_obj (CellObj): Cell Object. Returns: WriteTableCell: Cell Object. """ ... @overload def get_cell(self, values: Tuple[int, int]) -> WriteTableCell: """ Gets the cell as WriteTableCell. Args: val (Tuple[int, int]): Cell values. Tuple of (col, row). Values are Zero Based. Returns: WriteTableCell: Cell Object. """ ... @overload def get_cell(self, col: int, row: int) -> WriteTableCell: """ Gets the cell as WriteTableCell from column and row. Args: col (int): Column. Zero Based column index. row (int): Row. Zero Based row index. Returns: WriteTableCell: Cell Object. """ ... @overload def get_cell(self, addr: CellAddress) -> WriteTableCell: """ Gets the cell as WriteTableCell from a cell address. Args: addr (CellAddress): Cell Address. Returns: WriteTableCell: Cell Object. """ ... @overload def get_cell(self, cell: XCell) -> WriteTableCell: """ Gets the cell as WriteTableCell from a cell. Args: cell (XCell): Cell. Returns: WriteTableCell: Cell Object. """ ... @overload def get_cell(self, val: CellValues) -> WriteTableCell: """ Gets the cell as WriteTableCell from CellValues. Args: val (CellValues): Cell values. Returns: WriteTableCell: Cell Object. Hint: - ``CellValues`` can be imported from ``ooodev.utils.data_type.cell_values`` """ ... @overload def get_cell(self, name: str) -> WriteTableCell: """ Gets the cell as WriteTableCell from a cell name. Args: name (str): Cell name such as as ``A23`` or ``Sheet1.A23`` Returns: WriteTableCell: Cell Object. """ ...
[docs] def get_cell(self, *args, **kwargs) -> WriteTableCell: """Returns a single cell within the range.""" cell_obj = self.write_table.range_converter.get_cell_obj(*args, **kwargs) col_index = cell_obj.col_obj.index row_index = cell_obj.row - 1 return self.get_cell_by_position(col=col_index, row=row_index)
# endregion get_cell() # region get Table Cell Range @overload def get_cell_range(self, cell_obj: CellObj) -> WriteTableCellRange: """ Gets a range Object representing a range. Args: cell_obj (CellObj): Cell Object. Returns: WriteTableCellRange: Range object. """ ... @overload def get_cell_range(self, range_obj: RangeObj) -> WriteTableCellRange: """ Gets a range object. Returns the same object. Args: range_obj (RangeObj): Range Object Returns: WriteTableCellRange: Range object. """ ... @overload def get_cell_range( self, col_start: int, row_start: int, col_end: int, row_end: int, sheet_idx: int = ... ) -> WriteTableCellRange: """ Gets a range Object representing a range. Args: col_start (int): Zero-based start column index. row_start (int): Zero-based start row index. col_end (int): Zero-based end column index. row_end (int): Zero-based end row index. sheet_idx (int, optional): Zero-based sheet index that this range value belongs to. Default is -1. Returns: WriteTableCellRange: Range object. """ ... @overload def get_cell_range(self, addr: CellRangeAddress) -> WriteTableCellRange: """ Gets a range Object representing a range from a cell range address. Args: addr (CellRangeAddress): Cell Range Address. Returns: WriteTableCellRange: Range object. """ ... @overload def get_cell_range(self, rng: RangeValues) -> WriteTableCellRange: """ Gets a range Object representing a range from a cell range address. Args: rng (RangeValues): Cell Range Values. Returns: WriteTableCellRange: Range object. Hint: - ``RangeValues`` can be imported from ``ooodev.utils.data_type.range_values`` """ ... @overload def get_cell_range(self, rng_name: str) -> WriteTableCellRange: """ Gets a range Object representing a range. Args: rng_name (str): Range as string such as ``Sheet1.A1:C125`` or ``A1:C125`` Returns: WriteTableCellRange: Range object. """ ...
[docs] def get_cell_range(self, *args, **kwargs) -> WriteTableCellRange: """ Gets a range Object representing a range. Args: rng_name (str): Range as string such as ``Sheet1.A1:C125`` or ``A1:C125`` Returns: WriteTableCellRange: Range object. """ rng = self.write_table.range_converter.get_range_obj(*args, **kwargs) return self.get_cell_range_by_name(str(rng))
# endregion get Table Cell Range # region Get Row or Column
[docs] def get_column_range(self, col: int | str, start_row_idx: int = 0) -> WriteTableCellRange: """ Returns a sub-range of cells within the range. Args: col (int, str): Zero Based column index or a Colum Letter such as ``A``. If integer then can also be a negative value to get from end. start_row_idx (int, optional): Start Row Index. Zero Based. Can be negative to get from end. Defaults to ``0``. Returns: WriteTableCellRange: Range object. """ if isinstance(col, int): col_count = self.range_obj.col_count index = mGenUtil.Util.get_index(col, col_count) col_rng = self.range_obj.get_col(index) else: col_rng = self.range_obj.get_col(col) if start_row_idx > 0: if start_row_idx >= col_rng.row_count: raise IndexError(f"Index out of range: start_row_idx={start_row_idx}") rv = col_rng.get_range_values() col_rng = self.write_table.range_converter.rng_from_position( col_start=rv.col_start, row_start=start_row_idx, col_end=rv.col_end, row_end=rv.row_end, ) return self.get_cell_range_by_name(str(col_rng))
[docs] def get_row_range(self, row: int) -> WriteTableCellRange: """ Returns a sub-range of cells within the range for a given row. Args: row (int): Row Index. Zero Based. Can be negative to get from end. Returns: WriteTableCellRange: Range object. """ row_count = self.range_obj.row_count index = mGenUtil.Util.get_index(row, row_count) row_rng = self.range_obj.get_row(index) return self.get_cell_range_by_name(str(row_rng))
# endregion Get Row or Column # region CellRangePartial Overrides
[docs] @override def get_cell_by_position(self, col: int, row: int) -> WriteTableCell: # type: ignore """ Returns a single cell within the range. Args: col (int): Column. Zero Based column index. Can be negative to get from end. row (int): Row. Zero Based row index. Can be negative to get from end. Raises: IndexError: If the index is out of range. Returns: WriteTableCell: Cell Object. """ # in a sub-range of cells within the range. Cell Names and indexes do not match up. # if the origin range is A1:C4 and the sub-range is A2:C2, then the cell at A2 is at column 0, row 0 # There is no GetCellByName so some conversion is needed. try: row_count = self.range_obj.row_count row_index = mGenUtil.Util.get_index(row, row_count) col_count = self.range_obj.col_count col_index = mGenUtil.Util.get_index(col, col_count) cell_obj = self.write_table.range_converter.get_cell_obj(values=(col_index, row_index)) return WriteTableCell( owner=self, component=self.component.getCellByPosition(col, row), cell_obj=cell_obj, ) except IndexOutOfBoundsException as e: raise IndexError(f"Index out of range. column={col}, row={row}") from e
[docs] @override def get_cell_range_by_name(self, rng: str) -> WriteTableCellRange: # type: ignore """ Returns a sub-range of cells within the range. The sub-range is specified by its name. The format of the range name is dependent of the context of the table. In spreadsheets valid names may be ``A1:C5`` or ``$B$2`` or even defined names for cell ranges such as ``MySpecialCell``. Returns: WriteTableCell: Cell Object. Note: This method returns a sub range of cells within the range. Sub-ranges cell names and indexes **do not** match up with the parent range. If a sub-ranges is ``A3:D6`` then ``sub_rng["A1"]`` is at column 0, row 0 of the sub-range but has a cell name of ``A3``. Example: .. code-block:: python >>> rng = table.get_cell_range_by_name("A1:D10") >>> sub1 = rng.get_cell_range_by_name("A3:D6") >>> print("Sub1 cell A1") >>> print(cell, cell.value) Sub1 cell A1 WriteTableCell(cell_name=A3) From Russia with Love >>> sub2 = sub1.get_cell_range_by_name("A4:D5") >>> print("Sub1") >>> for cell in sub2: >>> print(cell, cell.value) Sub2 WriteTableCell(cell_name=A4) Goldfinger WriteTableCell(cell_name=B4) 1964 WriteTableCell(cell_name=C4) Sean Connery WriteTableCell(cell_name=D4) Guy Hamilton WriteTableCell(cell_name=A5) Thunderball WriteTableCell(cell_name=B5) 1965 WriteTableCell(cell_name=C5) Sean Connery WriteTableCell(cell_name=D5) Terence Young """ # pylint: disable=protected-access rng_obj = self.write_table.range_converter.rng_from_str(rng) rv = rng_obj.get_range_values() # for some reason the getCellRangeByName always does not work with the range name # when I called this method during WriteTableRow.get_row_data() it crashed badly. The bridge was disposed. result = WriteTableCellRange( owner=self, # component=self.component.getCellRangeByName(rng), # can crash the bridge for unknown reasons. component=self.component.getCellRangeByPosition(rv.col_start, rv.row_start, rv.col_end, rv.row_end), range_obj=self.write_table.range_converter.get_offset_range_obj(rng_obj), ) result._parent = self return result
[docs] @override def get_cell_range_by_position(self, left: int, top: int, right: int, bottom: int) -> WriteTableCellRange: # type: ignore """ Returns a sub-range of cells within the range. Raises: IndexError: If the index is out of range. Returns: WriteTableCell: Cell Object. Note: This method returns a sub-range of cells within the range. Sub-ranges cell names and indexes **do not** match up with the parent range. If a sub-ranges is ``A3:D6`` then ``sub_rng[(0,0)]`` is at column 0, row 0 of the sub-range but has a cell name of ``A3``. """ # pylint: disable=protected-access try: range_obj = self.write_table.range_converter.rng_from_position( col_start=left, row_start=top, col_end=right, row_end=bottom, ) result = WriteTableCellRange( owner=self, component=self.component.getCellRangeByPosition(left, top, right, bottom), range_obj=self.write_table.range_converter.get_offset_range_obj(range_obj), ) result._parent = self return result except IndexOutOfBoundsException as e: raise IndexError(f"Index out of range: left:{left}, top:{top}, right:{right}, bottom:{bottom}") from e
# endregion CellRangePartial Overrides
[docs] def get_row_data(self, idx: int, as_floats: bool = False) -> Tuple[float | str | None, ...]: """ Gets the row data. Args: idx (int): Index of the row. Zero Based. Can be negative to get from end. as_floats (bool, optional): If ``True`` then get all values as floats. If the cell is not a number then it is converted to ``0.0``. Defaults to ``False``. Returns: Tuple[float | str | None, ...]: Tuple of values. """ range_row = self.get_row_range(idx) data = range_row.get_data() if as_floats else range_row.get_data_array() return data[0] if len(data) == 1 else data # type: ignore
[docs] def get_column_data( self, idx: int, as_floats: bool = False, start_row_idx: int = 0 ) -> Tuple[float | str | None, ...]: """ Gets the column data. Args: idx (int): Index of the column. Zero Based. Can be negative to get from end. as_floats (bool, optional): If ``True`` then get all values as floats. If the cell is not a number then it is converted to ``0.0``. Defaults to ``False``. start_row_idx (int, optional): Start Row Index. Zero Based. Can be negative to get from end. Defaults to ``0``. Returns: Tuple[float | str | None, ...]: Tuple of values. """ range_col = self.get_column_range(idx, start_row_idx) data_arr = range_col.get_data() if as_floats else range_col.get_data_array() data = [row[0] for row in data_arr] return tuple(data)
[docs] def get_table_row_index(self, idx: int) -> int: """ Gets the table row index from the range relative index. The range index is the index of the row within this range. A range can be a subset of the table. This method returns the table row index from the range index. Args: idx (int): Row index within this range. Zero Based. Can be negative to get from end. Returns: int: Table Row Index. Zero Based. """ row_count = self.range_obj.row_count index = mGenUtil.Util.get_index(idx, row_count) # get the first cell of the row cell = self.get_cell_by_position(0, index) cv = self.write_table.range_converter.get_cell_values(cell.cell_name) return cv.row
[docs] def get_table_column_index(self, idx: int) -> int: """ Gets the table row index from the range relative index. The range index is the index of the row within this range. A range can be a subset of the table. This method returns the table row index from the range index. Args: idx (int): Column index within this range. Zero Based. Can be negative to get from end. Returns: int: Table Row Index. Zero Based. """ col_count = self.range_obj.col_count index = mGenUtil.Util.get_index(idx, col_count) # get the first cell of the col cell = self.get_cell_by_position(index, 0) cv = self.write_table.range_converter.get_cell_values(cell.cell_name) return cv.col
[docs] def get_table_range_obj(self, col_idx: int, row_idx: int) -> CellObj: """ Gets a cell object that contains column and row where the cell is located in the actual table. Args: col_idx (int): Column index within this range. Zero Based. Can be negative to get from end. row_idx (int): Row index within this range. Zero Based. Can be negative to get from end. Returns: CellObj: _description_ """ col_count = self.range_obj.col_count col_index = mGenUtil.Util.get_index(col_idx, col_count) row_count = self.range_obj.row_count row_index = mGenUtil.Util.get_index(row_idx, row_count) cell = self.get_cell_by_position(col_index, row_index) return self.write_table.range_converter.get_cell_obj(cell.cell_name)
@property def owner(self) -> ComponentT: """Owner of this component.""" return self._owner @property def range_obj(self) -> RangeObj: """ Range Object that represents this cell range. Note: The ``RangeObj`` returned from this property is a sub-range of the parent range or Table. This means the ``RangeObj`` contains relative values to the parent range or table. For this reason the cell names and indexes **do not** match up with the parent range. If a sub-ranges is ``A3:D6`` then ``sub_rng[(0,0)]`` is at column 0, row 0 of the sub-range but has a cell name of ``A3``. The ``RangeObj`` will always start with ``A1`` (column 0 and row 0). """ return self._range_obj @property def parent(self) -> WriteTableCellRange | None: """Parent of this table cell range.""" return self._parent