2025-10-10 09:46:41 +02:00

202 lines
6.6 KiB
Python

#!/usr/bin/env python
#coding:utf-8
# Purpose: table objects
# Created: 03.01.2011
# Copyright (C) 2011, Manfred Moitzi
# License: MIT license
from __future__ import unicode_literals, print_function, division
__author__ = "mozman <mozman@gmx.at>"
import copy
from .compatibility import is_string
from .xmlns import register_class, CN, wrap, etree
from . import wrapcache
from .base import GenericWrapper
from .protection import random_protection_key
from .propertymixins import TableVisibilityMixin
from .propertymixins import StringProperty, BooleanProperty
from .tableutils import address_to_index, get_cell_index
from .tablerowcontroller import TableRowController
from .tablecolumncontroller import TableColumnController
from .cellspancontroller import CellSpanController
@register_class
class Table(GenericWrapper):
TAG = CN('table:table')
style_name = StringProperty(CN('table:style-name'))
print_ = BooleanProperty(CN('table:print'))
def __init__(self, name='NEWTABLE', size=(10, 10), xmlnode=None):
def init_attributes_by_xmlnode():
self._cellmatrix = TableRowController(self.xmlnode)
self._columns_info = TableColumnController(self.xmlnode)
self._cell_span_controller = CellSpanController(self._cellmatrix)
def set_new_table_metrics():
self.name = name
self._cellmatrix.reset(size)
self._columns_info.reset(size[1])
super(Table, self).__init__(xmlnode=xmlnode)
init_attributes_by_xmlnode()
if xmlnode is None:
set_new_table_metrics()
wrapcache.add(self)
def __getitem__(self, key):
if isinstance(key, int):
return self.get_child(key)
else:
return self.get_cell(get_cell_index(key))
def __setitem__(self, key, cell):
if isinstance(key, int):
self.set_child(key, cell)
else:
self.set_cell(get_cell_index(key), cell)
@property
def name(self):
return self.get_attr(CN('table:name'))
@name.setter
def name(self, value):
return self.set_attr(CN('table:name'), self._normalize_sheet_name(value))
@staticmethod
def _normalize_sheet_name(name):
for subst in "\t\r'\"":
name = name.replace(subst, ' ')
return name.strip()
@property
def protected(self):
return self.get_bool_attr(CN('table:protected'))
@protected.setter
def protected(self, value):
self.set_bool_attr(CN('table:protected'), value)
if self.protected:
self.set_attr(CN('table:protection-key'), random_protection_key())
def nrows(self):
""" Count of table rows. """
return self._cellmatrix.nrows()
def ncols(self):
""" Count of table columns. """
return self._cellmatrix.ncols()
def reset(self, size=(10, 10)):
preserve_name = self.name
super(Table, self).clear()
self.name = preserve_name
self._cellmatrix.reset(size)
self._columns_info.reset(size[1])
def clear(self):
size = (self.nrows(), self.ncols())
self.reset(size)
def copy(self, newname=None):
newtable = Table(xmlnode=copy.deepcopy(self.xmlnode))
if newname is None:
newname = 'CopyOf' + self.name
newtable.name = newname
return newtable
def get_cell(self, pos):
""" Get cell at position 'pos', where 'pos' is a tuple (row, column). """
return wrap(self._cellmatrix.get_cell(pos))
def set_cell(self, pos, cell):
""" Set cell at position 'pos', where 'pos' is a tuple (row, column). """
if not hasattr(cell, 'kind') or cell.kind != 'Cell':
raise TypeError("invalid type of 'cell'.")
self._cellmatrix.set_cell(pos, cell.xmlnode)
def itercells(self):
""" Iterate over all cells, returns tuples (pos, cell). """
for irow, row in enumerate(self.rows()):
for icol, cell in enumerate(row):
yield ((irow, icol), cell)
def row(self, index):
if is_string(index):
index, column = address_to_index(index)
return [wrap(e) for e in self._cellmatrix.row(index)]
def rows(self):
for index in range(self.nrows()):
yield self.row(index)
def column(self, index):
if is_string(index):
row, index = address_to_index(index)
return [wrap(e) for e in self._cellmatrix.column(index)]
def columns(self):
for index in range(self.ncols()):
yield self.column(index)
def row_info(self, index):
if is_string(index):
index, column = address_to_index(index)
return wrap(self._cellmatrix.row(index))
def column_info(self, index):
if is_string(index):
row, index = address_to_index(index)
return wrap(self._columns_info.get_table_column(index))
def append_rows(self, count=1):
self._cellmatrix.append_rows(count)
def insert_rows(self, index, count=1):
# CAUTION: this will break refernces in formulas!
self._cellmatrix.insert_rows(index, count)
def delete_rows(self, index, count=1):
# CAUTION: this will break refernces in formulas!
self._cellmatrix.delete_rows(index, count)
def append_columns(self, count=1):
self._cellmatrix.append_columns(count)
self._columns_info.append(count)
def insert_columns(self, index, count=1):
# CAUTION: this will break refernces in formulas!
self._cellmatrix.insert_columns(index, count)
self._columns_info.insert(index, count)
def delete_columns(self, index, count=1):
# CAUTION: this will break refernces in formulas!
self._cellmatrix.delete_columns(index, count)
self._columns_info.delete(index, count)
def set_cell_span(self, pos, size):
self._cell_span_controller.set_span(get_cell_index(pos), size)
def remove_cell_span(self, pos):
self._cell_span_controller.remove_span(get_cell_index(pos))
@register_class
class TableColumn(GenericWrapper, TableVisibilityMixin):
TAG = CN('table:table-column')
style_name = StringProperty(CN('table:style-name'))
default_cell_style_name = StringProperty(CN('table:default-cell-style-name'))
@register_class
class TableRow(TableColumn):
TAG = CN('table:table-row')
def __init__(self, ncols=10, xmlnode=None):
super(TableRow, self).__init__(xmlnode=xmlnode)
if xmlnode is None:
self._setup(ncols)
def _setup(self, ncols):
for col in range(ncols):
self.xmlnode.append(etree.Element(CN('table:table-cell')))