easymacro/source/easymacro/easycalc.py

498 lines
13 KiB
Python

#!/usr/bin/env python3
from typing import Any, Union
from .easymain import log, BaseObject, Color, dict_to_property, run_in_thread
from .easydoc import LODocument
from .easyevents import EventsRangeSelectionListener, LOEvents
class LOCalcRange():
CELL = 'ScCellObj'
def __init__(self, obj):
self._obj = obj
self._is_cell = obj.ImplementationName == self.CELL
def __getitem__(self, index):
return LOCalcRange(self.obj[index])
def __iter__(self):
self._r = 0
self._c = 0
return self
def __next__(self):
try:
rango = self[self._r, self._c]
except Exception as e:
raise StopIteration
self._c += 1
if self._c == self.obj.Columns.Count:
self._c = 0
self._r +=1
return rango
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
def __len__(self):
ra = self.range_address
rows = ra.EndRow - ra.StartRow + 1
cols = ra.EndColumn - ra.StartColumn + 1
return rows, cols
def __str__(self):
s = f'Range: {self.name}'
if self.is_cell:
s = f'Cell: {self.name}'
return s
@property
def obj(self):
return self._obj
@property
def is_cell(self):
return self._is_cell
@property
def name(self):
return self.obj.AbsoluteName
@property
def address(self):
return self.obj.CellAddress
@property
def range_address(self):
return self.obj.RangeAddress
@property
def sheet(self):
return LOCalcSheet(self.obj.Spreadsheet)
@property
def doc(self):
doc = self.obj.Spreadsheet.DrawPage.Forms.Parent
return LODocCalc(doc)
@property
def cursor(self):
cursor = self.obj.Spreadsheet.createCursorByRange(self.obj)
return cursor
def offset(self, rows=0, cols=1):
ra = self.range_address
col = ra.EndColumn + cols
row = ra.EndRow + rows
return LOCalcRange(self.sheet[row, col].obj)
@property
def style(self):
return self.obj.CellStyle
@style.setter
def style(self, value):
self.obj.CellStyle = value
@property
def string(self):
return self.obj.String
@string.setter
def string(self, value):
self.obj.setString(value)
@property
def data(self):
return self.obj.getDataArray()
@data.setter
def data(self, values):
if self._is_cell:
self.to_size(len(values[0]), len(values)).data = values
else:
self.obj.setDataArray(values)
@property
def current_region(self):
cursor = self.cursor
cursor.collapseToCurrentRegion()
rango = self.obj.Spreadsheet[cursor.AbsoluteName]
return LOCalcRange(rango)
def to_size(self, cols: int, rows: int):
cursor = self.cursor
cursor.collapseToSize(cols, rows)
rango = self.obj.Spreadsheet[cursor.AbsoluteName]
return LOCalcRange(rango)
class LOCalcSheet(BaseObject):
def __init__(self, obj):
super().__init__(obj)
def __getitem__(self, index):
return LOCalcRange(self.obj[index])
def __exit__(self, exc_type, exc_value, traceback):
pass
def __str__(self):
return f'Sheet: {self.name}'
@property
def doc(self):
return LOCalc(self.obj.DrawPage.Forms.Parent)
@property
def name(self):
return self._obj.Name
@name.setter
def name(self, value):
self._obj.Name = value
@property
def code_name(self):
return self._obj.CodeName
@code_name.setter
def code_name(self, value):
self._obj.CodeName = value
@property
def visible(self):
return self._obj.IsVisible
@visible.setter
def visible(self, value):
self._obj.IsVisible = value
@property
def color(self):
return self._obj.TabColor
@color.setter
def color(self, value):
self._obj.TabColor = Color()(value)
@property
def used_area(self):
cursor = self.create_cursor()
cursor.gotoEndOfUsedArea(True)
return self[cursor.AbsoluteName]
@property
def is_protected(self):
return self._obj.isProtected()
@property
def password(self):
return ''
@password.setter
def password(self, value):
self.obj.protect(value)
@property
def events(self):
return LOEvents(self.obj.Events)
def protect(self, value):
self.obj.protect(value)
return
def unprotect(self, value):
try:
self.obj.unprotect(value)
return True
except:
pass
return False
def move(self, pos: int=-1):
index = pos
if pos < 0:
index = len(self.doc)
self.doc.move(self.name, index)
return
def remove(self):
self.doc.remove(self.name)
return
def copy(self, new_name: str='', pos: int=-1):
index = pos
if pos < 0:
index = len(self.doc)
new_sheet = self.doc.copy_sheet(self.name, new_name, index)
return new_sheet
def copy_to(self, doc: Any, target: str='', pos: int=-1):
"""Copy sheet to other document.
"""
index = pos
if pos < 0:
index = len(doc)
new_name = target or self.name
sheet = doc.copy_from(self.doc, self.name, new_name, index)
return sheet
def activate(self):
self.doc.activate(self.obj)
return
def create_cursor(self, rango: Any=None):
if rango is None:
cursor = self.obj.createCursor()
else:
obj = rango
if hasattr(rango, 'obj'):
obj = rango.obj
cursor = self.obj.createCursorByRange(obj)
return cursor
class LOCalc(LODocument):
"""Classe for Calc module"""
TYPE_RANGES = ('ScCellObj', 'ScCellRangeObj')
RANGES = 'ScCellRangesObj'
SHAPE = 'com.sun.star.drawing.SvxShapeCollection'
_type = 'calc'
def __init__(self, obj):
super().__init__(obj)
self._sheets = obj.Sheets
self._listener_range_selection = None
def __getitem__(self, index):
"""Index access"""
return LOCalcSheet(self._sheets[index])
def __setitem__(self, key: str, value: Any):
"""Insert new sheet"""
self._sheets[key] = value
def __len__(self):
return self._sheets.Count
def __contains__(self, item):
return item in self._sheets
def __iter__(self):
self._i = 0
return self
def __next__(self):
try:
sheet = LOCalcSheet(self._sheets[self._i])
except Exception as e:
raise StopIteration
self._i += 1
return sheet
def __str__(self):
return f'Calc: {self.title}'
@property
def headers(self):
"""Get true if is visible columns/rows headers"""
return self._cc.ColumnRowHeaders
@headers.setter
def headers(self, value):
"""Set visible columns/rows headers"""
self._cc.ColumnRowHeaders = value
@property
def tabs(self):
"""Get true if is visible tab sheets"""
return self._cc.SheetTabs
@tabs.setter
def tabs(self, value):
"""Set visible tab sheets"""
self._cc.SheetTabs = value
@property
def selection(self):
sel = self.obj.CurrentSelection
type_obj = sel.ImplementationName
if type_obj in self.TYPE_RANGES:
sel = LOCalcRange(sel)
elif type_obj == self.RANGES:
sel = LOCalcRanges(sel)
elif type_obj == self.SHAPE:
if len(sel) == 1:
sel = LOShape(sel[0])
else:
sel = LOShapes(sel)
else:
log.debug(type_obj)
return sel
@property
def active(self):
"""Get active sheet"""
return LOCalcSheet(self._cc.ActiveSheet)
@property
def names(self):
"""Get all sheet names"""
names = self.obj.Sheets.ElementNames
return names
@property
def events(self):
return LOEvents(self.obj.Events)
def new_sheet(self):
s = self._create_instance('com.sun.star.sheet.Spreadsheet')
return s
def select(self, rango: Any):
obj = rango
if hasattr(rango, 'obj'):
obj = rango.obj
self._cc.select(obj)
return
@run_in_thread
def start_range_selection(self, controllers: Any, args: dict={}):
"""Start select range selection by user
`See Api RangeSelectionArguments <https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1sheet_1_1RangeSelectionArguments.html>`_
"""
if args:
args['CloseOnMouseRelease'] = args.get('CloseOnMouseRelease', True)
else:
args = dict(
Title = 'Please select a range',
CloseOnMouseRelease = True)
properties = dict_to_property(args)
self._listener_range_selection = EventsRangeSelectionListener(controllers(self))
self._cc.addRangeSelectionListener(self._listener_range_selection)
self._cc.startRangeSelection(properties)
return
def remove_range_selection_listener(self):
if not self._listener_range_selection is None:
self._cc.removeRangeSelectionListener(self._listener_range_selection)
return
def activate(self, sheet: Union[str, LOCalcSheet]):
"""Activate sheet
:param sheet: Sheet to activate
:type sheet: str, pyUno or LOCalcSheet
"""
obj = sheet
if isinstance(sheet, LOCalcSheet):
obj = sheet.obj
elif isinstance(sheet, str):
obj = self._sheets[sheet]
self._cc.setActiveSheet(obj)
return
def insert(self, name: Union[str, list, tuple]):
"""Insert new sheet
:param name: Name new sheet, or iterable with names.
:type name: str, list or tuple
:return: New last instance sheet.
:rtype: LOCalcSheet
"""
names = name
if isinstance(name, str):
names = (name,)
for n in names:
self._sheets[n] = self._create_instance('com.sun.star.sheet.Spreadsheet')
return LOCalcSheet(self._sheets[n])
def move(self, sheet: Union[str, LOCalcSheet], pos: int=-1):
"""Move sheet name to position
:param sheet: Instance or Name sheet to move
:type sheet: LOCalcSheet or str
:param pos: New position, if pos=-1 move to end
:type pos: int
"""
name = sheet
index = pos
if pos < 0:
index = len(self)
if isinstance(sheet, LOCalcSheet):
name = sheet.name
self._sheets.moveByName(name, index)
return
def remove(self, sheet: Union[str, LOCalcSheet]):
"""Remove sheet by name
:param sheet: Instance or Name sheet to move
:type sheet: LOCalcSheet or str
"""
name = sheet
if isinstance(sheet, LOCalcSheet):
name = sheet.name
self._sheets.removeByName(name)
return
def _get_new_name_sheet(self, name):
i = 1
new_name = f'{name}_{i}'
while new_name in self:
i += 1
new_name = f'{name}_{i}'
return new_name
def copy_sheet(self, sheet: Union[str, LOCalcSheet], new_name: str='', pos: int=-1):
"""Copy sheet
"""
name = sheet
if isinstance(sheet, LOCalcSheet):
name = sheet.name
index = pos
if pos < 0:
index = len(self)
if not new_name:
new_name = self._get_new_name_sheet(name)
self._sheets.copyByName(name, new_name, index)
return LOCalcSheet(self._sheets[new_name])
def copy_from(self, doc: Any, source: Any=None, target: Any=None, pos: int=-1):
"""Copy sheet from document
"""
index = pos
if pos < 0:
index = len(self)
names = source
if not source:
names = doc.names
elif isinstance(source, str):
names = (source,)
elif isinstance(source, LOCalcSheet):
names = (source.name,)
new_names = target
if not target:
new_names = names
elif isinstance(target, str):
new_names = (target,)
for i, name in enumerate(names):
self._sheets.importSheet(doc.obj, name, index + i)
self[index + i].name = new_names[i]
return LOCalcSheet(self._sheets[index])
def sort(self, reverse=False):
"""Sort sheets by name
:param reverse: For order in reverse
:type reverse: bool
"""
names = sorted(self.names, reverse=reverse)
for i, n in enumerate(names):
self.move(n, i)
return