159 lines
5.1 KiB
Python
159 lines
5.1 KiB
Python
#!/usr/bin/env python
|
|
#coding:utf-8
|
|
# Purpose: table-row container
|
|
# Created: 02.02.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 .xmlns import CN, etree
|
|
from .nodestructuretags import TABLE_COLUMNS, TABLE_PRELUDE
|
|
from .nodeorganizer import PreludeTagBlock
|
|
from .tableutils import is_table, RepetitionAttribute
|
|
from .conf import config
|
|
|
|
def new_empty_column():
|
|
return etree.Element(CN('table:table-column'))
|
|
|
|
class _ExpandAll(object):
|
|
def expand_element(self, count, xmlnode):
|
|
while count > 1:
|
|
clone = copy.deepcopy(xmlnode)
|
|
xmlnode.addnext(clone)
|
|
count -= 1
|
|
|
|
def expand_column(self, xmlcolumn, maxcols):
|
|
repeat = RepetitionAttribute(xmlcolumn)
|
|
count = repeat.cols
|
|
if count > 1:
|
|
del repeat.cols
|
|
self.expand_element(count, xmlcolumn)
|
|
|
|
def expand_columns(self, xmlcolumns, maxcols):
|
|
for xmlcolumn in xmlcolumns:
|
|
self.expand_column(xmlcolumn, maxcols)
|
|
|
|
class _ExpandAllButLast(_ExpandAll):
|
|
def do_not_expand_column(self, xmlcolumn):
|
|
repeat = RepetitionAttribute(xmlcolumn)
|
|
if repeat.cols > 1:
|
|
del repeat.cols
|
|
|
|
def expand_columns(self, xmlcolumns, maxcols):
|
|
for xmlcolumn in xmlcolumns[:-1]:
|
|
self.expand_column(xmlcolumn, maxcols)
|
|
if len(xmlcolumns):
|
|
self.do_not_expand_column(xmlcolumns[-1])
|
|
|
|
class _ExpandAllLessMaxCount(_ExpandAll):
|
|
def expand_column(self, xmlcolumn, maxcols):
|
|
repeat = RepetitionAttribute(xmlcolumn)
|
|
count = repeat.cols
|
|
if 1 < count < maxcols:
|
|
del repeat.cols
|
|
self.expand_element(count, xmlcolumn)
|
|
elif count >= maxcols:
|
|
del repeat.cols # column just appears only one time
|
|
|
|
expand_strategies = {
|
|
'all': _ExpandAll(),
|
|
'all_but_last': _ExpandAllButLast(),
|
|
'all_less_maxcount': _ExpandAllLessMaxCount(),
|
|
}
|
|
|
|
class TableColumnController(object):
|
|
def __init__(self, xmlnode):
|
|
if not is_table(xmlnode):
|
|
raise ValueError('invalid xmlnode')
|
|
self.xmlnode = xmlnode
|
|
self._expand_repeated_content()
|
|
self.update()
|
|
|
|
def update(self):
|
|
self._columns = self.xmlnode.findall('.//'+CN('table:table-column'))
|
|
|
|
def reset(self, ncols):
|
|
if ncols < 1:
|
|
raise ValueError('ncols has to be >= 1.')
|
|
self._remove_existing_columns()
|
|
insert_position = PreludeTagBlock(self.xmlnode, TABLE_PRELUDE).insert_position_after()
|
|
for _ in range(ncols):
|
|
self.xmlnode.insert(insert_position, new_empty_column())
|
|
self.update()
|
|
|
|
def _remove_existing_columns(self):
|
|
for child in self.xmlnode.getchildren():
|
|
if child.tag in TABLE_COLUMNS:
|
|
self.xmlnode.remove(child)
|
|
|
|
def _expand_repeated_content(self):
|
|
maxcols = config.table_expand_strategy.get_maxcols()
|
|
expand = config.table_expand_strategy.get_strategy()
|
|
try:
|
|
strategy = expand_strategies[expand]
|
|
except KeyError:
|
|
raise TypeError("Unknown expand strategy: %s" % expand)
|
|
strategy.expand_columns(self.xmlnode.findall('.//'+CN('table:table-column')), maxcols)
|
|
|
|
def __len__(self):
|
|
return len(self._columns)
|
|
|
|
def __getitem__(self, pos):
|
|
return self._columns[pos]
|
|
|
|
def __setitem__(self, pos, element):
|
|
self._check_column_type(element)
|
|
oldcolumn = self._columns[pos]
|
|
newcolumn = copy.deepcopy(element)
|
|
oldcolumn.getparent().replace(oldcolumn, newcolumn)
|
|
self._columns[pos] = newcolumn
|
|
|
|
def _check_column_type(self, column):
|
|
if column.tag != CN('table:table-column'):
|
|
raise TypeError('element-tag is not <table:table-column>')
|
|
|
|
def get_table_column(self, index):
|
|
return self._columns[index]
|
|
|
|
def is_consistent(self):
|
|
# just for testing
|
|
xmlcols = self.xmlnode.findall('.//'+CN('table:table-column'))
|
|
if len(xmlcols) != len(self):
|
|
return False
|
|
for col1, col2 in zip(self._columns, xmlcols):
|
|
if col1 != col2:
|
|
return False
|
|
return True
|
|
|
|
def append(self, count=1):
|
|
if count < 1:
|
|
raise ValueError('count < 1')
|
|
for _ in range(count):
|
|
column = new_empty_column()
|
|
self._columns[-1].addnext(column)
|
|
self._columns.append(column)
|
|
|
|
def insert(self, index, count=1):
|
|
if count < 1:
|
|
raise ValueError('count < 1')
|
|
if index < 0:
|
|
index += len(self)
|
|
for _ in range(count):
|
|
column = new_empty_column()
|
|
insertpos = self._columns[index]
|
|
insertpos.addprevious(column)
|
|
self._columns.insert(index, column)
|
|
|
|
def delete(self, index, count=1):
|
|
if count < 1:
|
|
raise ValueError('count < 1')
|
|
if index < 0:
|
|
index += len(self)
|
|
for _ in range(count):
|
|
column = self._columns[index]
|
|
column.getparent().remove(column)
|
|
del self._columns[index]
|