2020-11-01 14:33:37 -06:00
|
|
|
# ~ FILTER_PDF = '/org.openoffice.Office.Common/Filter/PDF/Export/'
|
|
|
|
|
2020-11-07 22:37:58 -06:00
|
|
|
# ~ If location="document" Then
|
|
|
|
# ~ sp = ThisComponent.getScriptProvider()
|
2020-11-01 14:33:37 -06:00
|
|
|
|
|
|
|
|
|
|
|
class FormControlBase(object):
|
|
|
|
EVENTS = {
|
|
|
|
'action': 'actionPerformed',
|
|
|
|
'click': 'mousePressed',
|
|
|
|
}
|
|
|
|
TYPES = {
|
|
|
|
'actionPerformed': 'XActionListener',
|
|
|
|
'mousePressed': 'XMouseListener',
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
self._obj = obj
|
|
|
|
self._index = -1
|
|
|
|
self._rules = {}
|
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self.obj.Name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def form(self):
|
|
|
|
return self.obj.getParent()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def index(self):
|
|
|
|
return self._index
|
|
|
|
@index.setter
|
|
|
|
def index(self, value):
|
|
|
|
self._index = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def events(self):
|
|
|
|
return self.form.getScriptEvents(self.index)
|
|
|
|
|
|
|
|
def remove_event(self, name=''):
|
|
|
|
for ev in self.events:
|
|
|
|
if name and \
|
|
|
|
ev.EventMethod == self.EVENTS[name] and \
|
|
|
|
ev.ListenerType == self.TYPES[ev.EventMethod]:
|
|
|
|
self.form.revokeScriptEvent(self.index,
|
|
|
|
ev.ListenerType, ev.EventMethod, ev.AddListenerParam)
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
self.form.revokeScriptEvent(self.index,
|
|
|
|
ev.ListenerType, ev.EventMethod, ev.AddListenerParam)
|
|
|
|
return
|
|
|
|
|
|
|
|
def add_event(self, name, macro):
|
|
|
|
if not 'name' in macro:
|
|
|
|
macro['name'] = '{}_{}'.format(self.name, name)
|
|
|
|
|
|
|
|
event = ScriptEventDescriptor()
|
|
|
|
event.AddListenerParam = ''
|
|
|
|
event.EventMethod = self.EVENTS[name]
|
|
|
|
event.ListenerType = self.TYPES[event.EventMethod]
|
|
|
|
event.ScriptCode = _get_url_script(macro)
|
|
|
|
event.ScriptType = 'Script'
|
|
|
|
|
|
|
|
for ev in self.events:
|
|
|
|
if ev.EventMethod == event.EventMethod and \
|
|
|
|
ev.ListenerType == event.ListenerType:
|
|
|
|
self.form.revokeScriptEvent(self.index,
|
|
|
|
event.ListenerType, event.EventMethod, event.AddListenerParam)
|
|
|
|
break
|
|
|
|
|
|
|
|
self.form.registerScriptEvent(self.index, event)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class FormButton(FormControlBase):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
|
|
|
|
|
|
|
|
class LOForm(ObjectBase):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
self._init_controls()
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
if isinstance(index, int):
|
|
|
|
return self._controls[index]
|
|
|
|
else:
|
|
|
|
return getattr(self, index)
|
|
|
|
|
|
|
|
def _get_type_control(self, name):
|
|
|
|
types = {
|
|
|
|
# ~ 'stardiv.Toolkit.UnoFixedTextControl': 'label',
|
|
|
|
'com.sun.star.form.OButtonModel': 'formbutton',
|
|
|
|
# ~ 'stardiv.Toolkit.UnoEditControl': 'text',
|
|
|
|
# ~ 'stardiv.Toolkit.UnoRoadmapControl': 'roadmap',
|
|
|
|
# ~ 'stardiv.Toolkit.UnoFixedHyperlinkControl': 'link',
|
|
|
|
# ~ 'stardiv.Toolkit.UnoListBoxControl': 'listbox',
|
|
|
|
}
|
|
|
|
return types[name]
|
|
|
|
|
|
|
|
def _init_controls(self):
|
|
|
|
self._controls = []
|
|
|
|
for i, c in enumerate(self.obj.ControlModels):
|
|
|
|
tipo = self._get_type_control(c.ImplementationName)
|
|
|
|
control = get_custom_class(tipo, c)
|
|
|
|
control.index = i
|
|
|
|
self._controls.append(control)
|
|
|
|
setattr(self, c.Name, control)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self._obj.getName()
|
|
|
|
@name.setter
|
|
|
|
def name(self, value):
|
|
|
|
self._obj.setName(value)
|
|
|
|
|
|
|
|
|
|
|
|
class LOForms(ObjectBase):
|
|
|
|
|
|
|
|
def __init__(self, obj, doc):
|
|
|
|
self._doc = doc
|
|
|
|
super().__init__(obj)
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
form = super().__getitem__(index)
|
|
|
|
return LOForm(form)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def doc(self):
|
|
|
|
return self._doc
|
|
|
|
|
|
|
|
@property
|
|
|
|
def count(self):
|
|
|
|
return self.obj.getCount()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def names(self):
|
|
|
|
return self.obj.getElementNames()
|
|
|
|
|
|
|
|
def exists(self, name):
|
|
|
|
return name in self.names
|
|
|
|
|
|
|
|
def insert(self, name):
|
|
|
|
form = self.doc.create_instance('com.sun.star.form.component.Form')
|
|
|
|
self.obj.insertByName(name, form)
|
|
|
|
return self[name]
|
|
|
|
|
|
|
|
def remove(self, index):
|
|
|
|
if isinstance(index, int):
|
|
|
|
self.obj.removeByIndex(index)
|
|
|
|
else:
|
|
|
|
self.obj.removeByName(index)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class LOCalcSheet(object):
|
|
|
|
|
|
|
|
def __init__(self, obj, doc):
|
|
|
|
self._obj = obj
|
|
|
|
self._init_values()
|
|
|
|
|
|
|
|
def _init_values(self):
|
|
|
|
self._events = None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def forms(self):
|
|
|
|
return LOForms(self._dp.getForms(), self.doc)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def events(self):
|
|
|
|
return self._events
|
|
|
|
@events.setter
|
|
|
|
def events(self, controllers):
|
|
|
|
self._events = controllers
|
|
|
|
self._connect_listeners()
|
|
|
|
|
|
|
|
def _connect_listeners(self):
|
|
|
|
if self.events is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
listeners = {
|
|
|
|
'addModifyListener': EventsModify,
|
|
|
|
}
|
|
|
|
for key, value in listeners.items():
|
|
|
|
getattr(self.obj, key)(listeners[key](self.events))
|
|
|
|
print('add_listener')
|
|
|
|
return
|
|
|
|
|
|
|
|
def find(self, search_string, rango=None):
|
|
|
|
if rango is None:
|
|
|
|
ra = self.obj.getPrintAreas()[0]
|
|
|
|
rango = self.get_range_by_address(ra)
|
|
|
|
|
|
|
|
cell = rango.find(search_string)
|
|
|
|
|
|
|
|
return cell
|
|
|
|
|
|
|
|
|
|
|
|
class LOWriter(LODocument):
|
|
|
|
|
|
|
|
def write(self, data, cursor=None):
|
|
|
|
cursor = cursor or self.selection.cursor.getEnd()
|
|
|
|
if data.startswith('\n'):
|
|
|
|
c = data.split('\n')
|
|
|
|
for i in range(len(c)-1):
|
|
|
|
self.text.insertControlCharacter(cursor, PARAGRAPH_BREAK, False)
|
|
|
|
else:
|
|
|
|
self.text.insertString(cursor, data, False)
|
|
|
|
return
|
|
|
|
|
|
|
|
def insert_table(self, data, cursor=None):
|
|
|
|
cursor = cursor or self.selection.cursor.getEnd()
|
|
|
|
table = self.obj.createInstance('com.sun.star.text.TextTable')
|
|
|
|
rows = len(data)
|
|
|
|
cols = len(data[0])
|
|
|
|
table.initialize(rows, cols)
|
|
|
|
self.insert_content(cursor, table)
|
|
|
|
table.DataArray = data
|
|
|
|
return WriterTable(table)
|
|
|
|
|
|
|
|
def create_chart(self, tipo, cursor=None):
|
|
|
|
cursor = cursor or self.selection.cursor.getEnd()
|
|
|
|
chart = LOChart(None, tipo)
|
|
|
|
chart.cursor = cursor
|
|
|
|
chart.doc = self
|
|
|
|
return chart
|
|
|
|
|
|
|
|
def insert_content(self, cursor, data, replace=False):
|
|
|
|
self.text.insertTextContent(cursor, data, replace)
|
|
|
|
return
|
|
|
|
|
|
|
|
# ~ f = doc.createInstance('com.sun.star.text.TextFrame')
|
|
|
|
# ~ f.setSize(Size(10000, 500))
|
|
|
|
|
|
|
|
def insert_image(self, path, **kwargs):
|
|
|
|
cursor = kwargs.get('cursor', self.selection.cursor.getEnd())
|
|
|
|
w = kwargs.get('width', 1000)
|
|
|
|
h = kwargs.get('Height', 1000)
|
|
|
|
image = self.create_instance('com.sun.star.text.GraphicObject')
|
|
|
|
image.GraphicURL = _path_url(path)
|
|
|
|
image.AnchorType = AS_CHARACTER
|
|
|
|
image.Width = w
|
|
|
|
image.Height = h
|
|
|
|
self.insert_content(cursor, image)
|
|
|
|
return
|
|
|
|
|
|
|
|
def go_start(self):
|
|
|
|
cursor = self._cc.getViewCursor()
|
|
|
|
cursor.gotoStart(False)
|
|
|
|
return cursor
|
|
|
|
|
|
|
|
def go_end(self):
|
|
|
|
cursor = self._cc.getViewCursor()
|
|
|
|
cursor.gotoEnd(False)
|
|
|
|
return cursor
|
|
|
|
|
|
|
|
def select(self, text):
|
|
|
|
self._cc.select(text)
|
|
|
|
return
|
|
|
|
|
|
|
|
def search(self, options):
|
|
|
|
descriptor = self.obj.createSearchDescriptor()
|
|
|
|
descriptor.setSearchString(options.get('Search', ''))
|
|
|
|
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
|
|
|
|
descriptor.SearchWords = options.get('Words', False)
|
|
|
|
if 'Attributes' in options:
|
|
|
|
attr = dict_to_property(options['Attributes'])
|
|
|
|
descriptor.setSearchAttributes(attr)
|
|
|
|
if hasattr(descriptor, 'SearchRegularExpression'):
|
|
|
|
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
|
|
|
|
if hasattr(descriptor, 'SearchType') and 'Type' in options:
|
|
|
|
descriptor.SearchType = options['Type']
|
|
|
|
|
|
|
|
if options.get('First', False):
|
|
|
|
found = self.obj.findFirst(descriptor)
|
|
|
|
else:
|
|
|
|
found = self.obj.findAll(descriptor)
|
|
|
|
|
|
|
|
return found
|
|
|
|
|
|
|
|
def replace(self, options):
|
|
|
|
descriptor = self.obj.createReplaceDescriptor()
|
|
|
|
descriptor.setSearchString(options['Search'])
|
|
|
|
descriptor.setReplaceString(options['Replace'])
|
|
|
|
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
|
|
|
|
descriptor.SearchWords = options.get('Words', False)
|
|
|
|
if 'Attributes' in options:
|
|
|
|
attr = dict_to_property(options['Attributes'])
|
|
|
|
descriptor.setSearchAttributes(attr)
|
|
|
|
if hasattr(descriptor, 'SearchRegularExpression'):
|
|
|
|
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
|
|
|
|
if hasattr(descriptor, 'SearchType') and 'Type' in options:
|
|
|
|
descriptor.SearchType = options['Type']
|
|
|
|
found = self.obj.replaceAll(descriptor)
|
|
|
|
return found
|
|
|
|
|
|
|
|
|
|
|
|
class LOTextRange(object):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
self._obj = obj
|
|
|
|
self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph'
|
|
|
|
self._is_table = self.obj.ImplementationName == 'SwXTextTable'
|
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_paragraph(self):
|
|
|
|
return self._is_paragraph
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_table(self):
|
|
|
|
return self._is_table
|
|
|
|
|
|
|
|
@property
|
|
|
|
def string(self):
|
|
|
|
return self.obj.String
|
|
|
|
|
|
|
|
@property
|
|
|
|
def text(self):
|
|
|
|
return self.obj.getText()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def cursor(self):
|
|
|
|
return self.text.createTextCursorByRange(self.obj)
|
|
|
|
|
|
|
|
|
|
|
|
class LOBase(object):
|
|
|
|
TYPES = {
|
|
|
|
str: 'setString',
|
|
|
|
int: 'setInt',
|
|
|
|
float: 'setFloat',
|
|
|
|
bool: 'setBoolean',
|
|
|
|
Date: 'setDate',
|
|
|
|
Time: 'setTime',
|
|
|
|
DateTime: 'setTimestamp',
|
|
|
|
}
|
|
|
|
# ~ setArray
|
|
|
|
# ~ setBinaryStream
|
|
|
|
# ~ setBlob
|
|
|
|
# ~ setByte
|
|
|
|
# ~ setBytes
|
|
|
|
# ~ setCharacterStream
|
|
|
|
# ~ setClob
|
|
|
|
# ~ setNull
|
|
|
|
# ~ setObject
|
|
|
|
# ~ setObjectNull
|
|
|
|
# ~ setObjectWithInfo
|
|
|
|
# ~ setPropertyValue
|
|
|
|
# ~ setRef
|
|
|
|
def __init__(self, name, path='', **kwargs):
|
|
|
|
self._name = name
|
|
|
|
self._path = path
|
|
|
|
self._dbc = create_instance('com.sun.star.sdb.DatabaseContext')
|
|
|
|
if path:
|
|
|
|
path_url = _path_url(path)
|
|
|
|
db = self._dbc.createInstance()
|
|
|
|
db.URL = 'sdbc:embedded:firebird'
|
|
|
|
db.DatabaseDocument.storeAsURL(path_url, ())
|
|
|
|
if not self.exists:
|
|
|
|
self._dbc.registerDatabaseLocation(name, path_url)
|
|
|
|
else:
|
|
|
|
if name.startswith('odbc:'):
|
|
|
|
self._con = self._odbc(name, kwargs)
|
|
|
|
else:
|
|
|
|
db = self._dbc.getByName(name)
|
|
|
|
self.path = _path_system(self._dbc.getDatabaseLocation(name))
|
|
|
|
self._con = db.getConnection('', '')
|
|
|
|
|
|
|
|
if self._con is None:
|
|
|
|
msg = 'Not connected to: {}'.format(name)
|
|
|
|
else:
|
|
|
|
msg = 'Connected to: {}'.format(name)
|
|
|
|
debug(msg)
|
|
|
|
|
|
|
|
def _odbc(self, name, kwargs):
|
|
|
|
dm = create_instance('com.sun.star.sdbc.DriverManager')
|
|
|
|
args = dict_to_property(kwargs)
|
|
|
|
try:
|
|
|
|
con = dm.getConnectionWithInfo('sdbc:{}'.format(name), args)
|
|
|
|
return con
|
|
|
|
except Exception as e:
|
|
|
|
error(str(e))
|
|
|
|
return None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self._name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def connection(self):
|
|
|
|
return self._con
|
|
|
|
|
|
|
|
@property
|
|
|
|
def path(self):
|
|
|
|
return self._path
|
|
|
|
@path.setter
|
|
|
|
def path(self, value):
|
|
|
|
self._path = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def exists(self):
|
|
|
|
return self._dbc.hasRegisteredDatabase(self.name)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def register(self, path, name):
|
|
|
|
if not self._dbc.hasRegisteredDatabase(name):
|
|
|
|
self._dbc.registerDatabaseLocation(name, _path_url(path))
|
|
|
|
return
|
|
|
|
|
|
|
|
def revoke(self, name):
|
|
|
|
self._dbc.revokeDatabaseLocation(name)
|
|
|
|
return True
|
|
|
|
|
|
|
|
def save(self):
|
|
|
|
# ~ self._db.connection.commit()
|
|
|
|
# ~ self._db.connection.getTables().refresh()
|
|
|
|
# ~ oDisp.executeDispatch(oFrame,".uno:DBRefreshTables", "", 0, Array())
|
|
|
|
self._obj.DatabaseDocument.store()
|
|
|
|
self.refresh()
|
|
|
|
return
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self._con.close()
|
|
|
|
return
|
|
|
|
|
|
|
|
def refresh(self):
|
|
|
|
self._con.getTables().refresh()
|
|
|
|
return
|
|
|
|
|
|
|
|
def get_tables(self):
|
|
|
|
tables = self._con.getTables()
|
|
|
|
tables = [tables.getByIndex(i) for i in range(tables.Count)]
|
|
|
|
return tables
|
|
|
|
|
|
|
|
def cursor(self, sql, params):
|
|
|
|
cursor = self._con.prepareStatement(sql)
|
|
|
|
for i, v in enumerate(params, 1):
|
|
|
|
if not type(v) in self.TYPES:
|
|
|
|
error('Type not support')
|
|
|
|
debug((i, type(v), v, self.TYPES[type(v)]))
|
|
|
|
getattr(cursor, self.TYPES[type(v)])(i, v)
|
|
|
|
return cursor
|
|
|
|
|
|
|
|
def execute(self, sql, params):
|
|
|
|
debug(sql)
|
|
|
|
if params:
|
|
|
|
cursor = self.cursor(sql, params)
|
|
|
|
cursor.execute()
|
|
|
|
else:
|
|
|
|
cursor = self._con.createStatement()
|
|
|
|
cursor.execute(sql)
|
|
|
|
# ~ resulset = cursor.executeQuery(sql)
|
|
|
|
# ~ rows = cursor.executeUpdate(sql)
|
|
|
|
self.save()
|
|
|
|
return cursor
|
|
|
|
|
|
|
|
|
|
|
|
class LOCellRange(object):
|
|
|
|
|
|
|
|
def __contains__(self, item):
|
|
|
|
return item.in_range(self)
|
|
|
|
|
|
|
|
def copy(self, source):
|
|
|
|
self.sheet.obj.copyRange(self.address, source.range_address)
|
|
|
|
return
|
|
|
|
|
|
|
|
def transpose(self, formula=False):
|
|
|
|
data = self.data
|
|
|
|
if formula:
|
|
|
|
data = self.formula
|
|
|
|
data = tuple(zip(*data))
|
|
|
|
self.clear(1023)
|
|
|
|
self[0,0].copy_from(data, formula=formula)
|
|
|
|
return
|
|
|
|
|
|
|
|
def transpose2(self):
|
|
|
|
# ~ 'Flags': 'A',
|
|
|
|
# ~ 'FormulaCommand': 0,
|
|
|
|
# ~ 'SkipEmptyCells': False,
|
|
|
|
# ~ 'AsLink': False,
|
|
|
|
# ~ 'MoveMode': 4,
|
|
|
|
args = {
|
|
|
|
'Transpose': True,
|
|
|
|
}
|
|
|
|
args = dict_to_property(args)
|
|
|
|
self.select()
|
|
|
|
copy()
|
|
|
|
self.clear(1023)
|
|
|
|
self[0,0].select()
|
|
|
|
call_dispatch(self._doc, '.uno:InsertContents', args)
|
|
|
|
set_clipboard('')
|
|
|
|
return
|
|
|
|
|
|
|
|
@property
|
|
|
|
def merged_area(self):
|
|
|
|
cursor = self.sheet.get_cursor(self.obj[0,0])
|
|
|
|
cursor.collapseToMergedArea()
|
|
|
|
return LOCellRange(self.sheet[cursor.AbsoluteName].obj, self.doc)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def empty(self):
|
|
|
|
cursor = self.sheet.get_cursor(self.obj)
|
|
|
|
rangos = [LOCellRange(self.sheet[r.AbsoluteName].obj, self.doc)
|
|
|
|
for r in cursor.queryEmptyCells()]
|
|
|
|
return tuple(rangos)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def cell_style(self):
|
|
|
|
return self.obj.CellStyle
|
|
|
|
@cell_style.setter
|
|
|
|
def cell_style(self, value):
|
|
|
|
self.obj.CellStyle = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def auto_format(self):
|
|
|
|
return self.obj.CellStyle
|
|
|
|
@auto_format.setter
|
|
|
|
def auto_format(self, value):
|
|
|
|
self.obj.autoFormat(value)
|
|
|
|
|
|
|
|
def in_range(self, rango):
|
|
|
|
if isinstance(rango, LOCellRange):
|
|
|
|
address = rango.address
|
|
|
|
else:
|
|
|
|
address = rango.getRangeAddress()
|
|
|
|
cursor = self.sheet.get_cursor(self.obj)
|
|
|
|
result = cursor.queryIntersection(address)
|
|
|
|
return bool(result.Count)
|
|
|
|
|
|
|
|
def fill(self, source=1):
|
|
|
|
self.obj.fillAuto(0, source)
|
|
|
|
return
|
|
|
|
|
|
|
|
def get_column(self, index=0, first=False):
|
|
|
|
ca = self.address
|
|
|
|
ra = self.current_region.address
|
|
|
|
if hasattr(ca, 'Column'):
|
|
|
|
col = ca.Column
|
|
|
|
else:
|
|
|
|
col = ca.StartColumn + index
|
|
|
|
start = 1
|
|
|
|
if first:
|
|
|
|
start = 0
|
|
|
|
if hasattr(ra, 'Row'):
|
|
|
|
row_start = ra.Row + start
|
|
|
|
row_end = ra.Row + 1
|
|
|
|
else:
|
|
|
|
row_start = ra.StartRow + start
|
|
|
|
row_end = ra.EndRow + 1
|
|
|
|
return LOCellRange(self.sheet[row_start:row_end, col:col+1].obj, self.doc)
|
|
|
|
|
|
|
|
def import_csv(self, path, **kwargs):
|
|
|
|
data = import_csv(path, **kwargs)
|
|
|
|
self.copy_from(data)
|
|
|
|
return
|
|
|
|
|
|
|
|
def export_csv(self, path, **kwargs):
|
|
|
|
data = self.current_region.data
|
|
|
|
export_csv(path, data, **kwargs)
|
|
|
|
return
|
|
|
|
|
|
|
|
def create_chart(self, tipo):
|
|
|
|
chart = LOChart(None, tipo)
|
|
|
|
chart.cell = self
|
|
|
|
return chart
|
|
|
|
|
|
|
|
def search(self, options):
|
|
|
|
descriptor = self.obj.Spreadsheet.createSearchDescriptor()
|
|
|
|
descriptor.setSearchString(options.get('Search', ''))
|
|
|
|
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
|
|
|
|
descriptor.SearchWords = options.get('Words', False)
|
|
|
|
if hasattr(descriptor, 'SearchRegularExpression'):
|
|
|
|
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
|
|
|
|
if hasattr(descriptor, 'SearchType') and 'Type' in options:
|
|
|
|
descriptor.SearchType = options['Type']
|
|
|
|
|
|
|
|
if options.get('First', False):
|
|
|
|
found = self.obj.findFirst(descriptor)
|
|
|
|
else:
|
|
|
|
found = self.obj.findAll(descriptor)
|
|
|
|
|
|
|
|
return found
|
|
|
|
|
|
|
|
def replace(self, options):
|
|
|
|
descriptor = self.obj.Spreadsheet.createReplaceDescriptor()
|
|
|
|
descriptor.setSearchString(options['Search'])
|
|
|
|
descriptor.setReplaceString(options['Replace'])
|
|
|
|
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
|
|
|
|
descriptor.SearchWords = options.get('Words', False)
|
|
|
|
if hasattr(descriptor, 'SearchRegularExpression'):
|
|
|
|
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
|
|
|
|
if hasattr(descriptor, 'SearchType') and 'Type' in options:
|
|
|
|
descriptor.SearchType = options['Type']
|
|
|
|
found = self.obj.replaceAll(descriptor)
|
|
|
|
return found
|
|
|
|
|
|
|
|
@property
|
|
|
|
def validation(self):
|
|
|
|
return self.obj.Validation
|
|
|
|
@validation.setter
|
|
|
|
def validation(self, values):
|
|
|
|
is_list = False
|
|
|
|
current = self.validation
|
|
|
|
for k, v in values.items():
|
|
|
|
if k == 'Type' and v == 6:
|
|
|
|
is_list = True
|
|
|
|
if k == 'Formula1' and is_list:
|
|
|
|
if isinstance(v, (tuple, list)):
|
|
|
|
v = ';'.join(['"{}"'.format(i) for i in v])
|
|
|
|
setattr(current, k, v)
|
|
|
|
self.obj.Validation = current
|
|
|
|
|
|
|
|
def rows_insert(self, count=0):
|
|
|
|
if not count:
|
|
|
|
count = self.rows
|
|
|
|
self.obj.Rows.insertByIndex(0, count)
|
|
|
|
return
|
|
|
|
|
|
|
|
def rows_merge(self):
|
|
|
|
for r in range(self.rows):
|
|
|
|
self[r].obj.merge(True)
|
|
|
|
return
|
|
|
|
|
|
|
|
def _render_list(self, key, values):
|
|
|
|
rango = None
|
|
|
|
total_rows = len(values)
|
|
|
|
try:
|
|
|
|
rango = self.sheet[key]
|
|
|
|
if total_rows > 1:
|
|
|
|
cells = rango[0,0].offset(1).to_size(total_rows - 1, 1)
|
|
|
|
name = cells.name
|
|
|
|
cells.rows_insert()
|
|
|
|
cells = self.sheet[name]
|
|
|
|
cells.copy_format_from(rango)
|
|
|
|
except Exception as e:
|
|
|
|
print(key, e)
|
|
|
|
|
|
|
|
if rango is None:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
headers = list(rango.data[0])
|
|
|
|
positions = {}
|
|
|
|
for i, v in enumerate(headers):
|
|
|
|
if not v:
|
|
|
|
continue
|
|
|
|
k = v[1:-1]
|
|
|
|
if k in values[0]:
|
|
|
|
positions[k] = i
|
|
|
|
|
|
|
|
data = []
|
|
|
|
for row in values:
|
|
|
|
new_row = headers[:]
|
|
|
|
for k, v in positions.items():
|
|
|
|
new_row[v] = row[k]
|
|
|
|
data.append(new_row)
|
|
|
|
|
|
|
|
cell = rango[0,0]
|
|
|
|
cell.copy_from(data)
|
|
|
|
return
|
|
|
|
|
|
|
|
def find(self, search_string):
|
|
|
|
if self._sd is None:
|
|
|
|
self._sd = self.sheet.obj.createSearchDescriptor()
|
|
|
|
self._sd.SearchCaseSensitive = False
|
|
|
|
|
|
|
|
self._sd.setSearchString(search_string)
|
|
|
|
cell = self.obj.findFirst(self._sd)
|
|
|
|
return LOCellRange(self.sheet[cell.AbsoluteName].obj, self.doc)
|
|
|
|
|
|
|
|
|
|
|
|
class EventsModify(EventsListenerBase, XModifyListener):
|
|
|
|
|
|
|
|
def __init__(self, controller):
|
|
|
|
super().__init__(controller)
|
|
|
|
|
|
|
|
def modified(self, event):
|
|
|
|
event_name = '{}_modified'.format(event.Source.Name)
|
|
|
|
if hasattr(self._controller, event_name):
|
|
|
|
getattr(self._controller, event_name)(event)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class EventsTab(EventsListenerBase, XTabListener):
|
|
|
|
|
|
|
|
def __init__(self, controller, name):
|
|
|
|
super().__init__(controller, name)
|
|
|
|
|
|
|
|
def activated(self, id):
|
|
|
|
event_name = '{}_activated'.format(self.name)
|
|
|
|
if hasattr(self._controller, event_name):
|
|
|
|
getattr(self._controller, event_name)(id)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class EventsKeyWindow(EventsListenerBase, XKeyListener):
|
|
|
|
"""
|
|
|
|
event.KeyChar
|
|
|
|
event.KeyCode
|
|
|
|
event.KeyFunc
|
|
|
|
event.Modifiers
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, cls):
|
|
|
|
super().__init__(cls.events, cls.name)
|
|
|
|
self._cls = cls
|
|
|
|
|
|
|
|
def keyPressed(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def keyReleased(self, event):
|
|
|
|
event_name = '{}_key_released'.format(self._cls.name)
|
|
|
|
if hasattr(self._controller, event_name):
|
|
|
|
getattr(self._controller, event_name)(event)
|
|
|
|
else:
|
|
|
|
if event.KeyFunc == QUIT and hasattr(self._cls, 'close'):
|
|
|
|
self._cls.close()
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class EventsWindow(EventsListenerBase, XTopWindowListener, XWindowListener):
|
|
|
|
|
|
|
|
def __init__(self, cls):
|
|
|
|
self._cls = cls
|
|
|
|
super().__init__(cls.events, cls.name, cls._window)
|
|
|
|
|
|
|
|
def windowOpened(self, event):
|
|
|
|
event_name = '{}_opened'.format(self._name)
|
|
|
|
if hasattr(self._controller, event_name):
|
|
|
|
getattr(self._controller, event_name)(event)
|
|
|
|
return
|
|
|
|
|
|
|
|
def windowActivated(self, event):
|
|
|
|
control_name = '{}_activated'.format(event.Source.Model.Name)
|
|
|
|
if hasattr(self._controller, control_name):
|
|
|
|
getattr(self._controller, control_name)(event)
|
|
|
|
return
|
|
|
|
|
|
|
|
def windowDeactivated(self, event):
|
|
|
|
control_name = '{}_deactivated'.format(event.Source.Model.Name)
|
|
|
|
if hasattr(self._controller, control_name):
|
|
|
|
getattr(self._controller, control_name)(event)
|
|
|
|
return
|
|
|
|
|
|
|
|
def windowMinimized(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def windowNormalized(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def windowClosing(self, event):
|
|
|
|
if self._window:
|
|
|
|
control_name = 'window_closing'
|
|
|
|
else:
|
|
|
|
control_name = '{}_closing'.format(event.Source.Model.Name)
|
|
|
|
|
|
|
|
if hasattr(self._controller, control_name):
|
|
|
|
getattr(self._controller, control_name)(event)
|
|
|
|
# ~ else:
|
|
|
|
# ~ if not self._modal and not self._block:
|
|
|
|
# ~ event.Source.Visible = False
|
|
|
|
return
|
|
|
|
|
|
|
|
def windowClosed(self, event):
|
|
|
|
control_name = '{}_closed'.format(event.Source.Model.Name)
|
|
|
|
if hasattr(self._controller, control_name):
|
|
|
|
getattr(self._controller, control_name)(event)
|
|
|
|
return
|
|
|
|
|
|
|
|
# ~ XWindowListener
|
|
|
|
def windowResized(self, event):
|
|
|
|
sb = self._cls._subcont
|
|
|
|
sb.setPosSize(0, 0, event.Width, event.Height, SIZE)
|
|
|
|
event_name = '{}_resized'.format(self._name)
|
|
|
|
if hasattr(self._controller, event_name):
|
|
|
|
getattr(self._controller, event_name)(event)
|
|
|
|
return
|
|
|
|
|
|
|
|
def windowMoved(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def windowShown(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def windowHidden(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class EventsMenu(EventsListenerBase, XMenuListener):
|
|
|
|
|
|
|
|
def __init__(self, controller):
|
|
|
|
super().__init__(controller, '')
|
|
|
|
|
|
|
|
def itemHighlighted(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def itemSelected(self, event):
|
|
|
|
name = event.Source.getCommand(event.MenuId)
|
|
|
|
if name.startswith('menu'):
|
|
|
|
event_name = '{}_selected'.format(name)
|
|
|
|
else:
|
|
|
|
event_name = 'menu_{}_selected'.format(name)
|
|
|
|
if hasattr(self._controller, event_name):
|
|
|
|
getattr(self._controller, event_name)(event)
|
|
|
|
return
|
|
|
|
|
|
|
|
def itemActivated(self, event):
|
|
|
|
return
|
|
|
|
|
|
|
|
def itemDeactivated(self, event):
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class UnoTab(UnoBaseObject):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
self._events = None
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
return self.get_sheet(index)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def current(self):
|
|
|
|
return self.obj.getActiveTabID()
|
|
|
|
@property
|
|
|
|
def active(self):
|
|
|
|
return self.current
|
|
|
|
|
|
|
|
def get_sheet(self, id):
|
|
|
|
if isinstance(id, int):
|
|
|
|
sheet = self.obj.Controls[id-1]
|
|
|
|
else:
|
|
|
|
sheet = self.obj.getControl(id.lower())
|
|
|
|
return sheet
|
|
|
|
|
|
|
|
@property
|
|
|
|
def sheets(self):
|
|
|
|
return self._sheets
|
|
|
|
@sheets.setter
|
|
|
|
def sheets(self, values):
|
|
|
|
i = len(self.obj.Controls)
|
|
|
|
for title in values:
|
|
|
|
i += 1
|
|
|
|
sheet = self.model.createInstance('com.sun.star.awt.UnoPageModel')
|
|
|
|
sheet.Title = title
|
|
|
|
self.model.insertByName('sheet{}'.format(i), sheet)
|
|
|
|
return
|
|
|
|
|
|
|
|
def insert(self, title):
|
|
|
|
id = len(self.obj.Controls) + 1
|
|
|
|
sheet = self.model.createInstance('com.sun.star.awt.UnoPageModel')
|
|
|
|
sheet.Title = title
|
|
|
|
self.model.insertByName('sheet{}'.format(id), sheet)
|
|
|
|
return id
|
|
|
|
|
|
|
|
def remove(self, id):
|
|
|
|
sheet = self.get_sheet(id)
|
|
|
|
for control in sheet.getControls():
|
|
|
|
sheet.Model.removeByName(control.Model.Name)
|
|
|
|
sheet.removeControl(control)
|
|
|
|
# ~ self._model.removeByName('page_{}'.format(ID))
|
|
|
|
|
|
|
|
self.obj.removeTab(id)
|
|
|
|
return
|
|
|
|
|
|
|
|
def activate(self, id):
|
|
|
|
self.obj.activateTab(id)
|
|
|
|
return
|
|
|
|
|
|
|
|
@property
|
|
|
|
def events(self):
|
|
|
|
return self._events
|
|
|
|
@events.setter
|
|
|
|
def events(self, controllers):
|
|
|
|
self._events = controllers
|
|
|
|
|
|
|
|
def _special_properties(self, tipo, properties):
|
|
|
|
columns = properties.pop('Columns', ())
|
|
|
|
if tipo == 'grid':
|
|
|
|
properties['ColumnModel'] = _set_column_model(columns)
|
|
|
|
if not 'Width' in properties:
|
|
|
|
properties['Width'] = self.width
|
|
|
|
if not 'Height' in properties:
|
|
|
|
properties['Height'] = self.height
|
|
|
|
elif tipo == 'button' and 'ImageURL' in properties:
|
|
|
|
properties['ImageURL'] = self._set_image_url(properties['ImageURL'])
|
|
|
|
elif tipo == 'roadmap':
|
|
|
|
if not 'Height' in properties:
|
|
|
|
properties['Height'] = self.height
|
|
|
|
if 'Title' in properties:
|
|
|
|
properties['Text'] = properties.pop('Title')
|
|
|
|
elif tipo == 'pages':
|
|
|
|
if not 'Width' in properties:
|
|
|
|
properties['Width'] = self.width
|
|
|
|
if not 'Height' in properties:
|
|
|
|
properties['Height'] = self.height
|
|
|
|
|
|
|
|
return properties
|
|
|
|
|
|
|
|
def add_control(self, id, properties):
|
|
|
|
tipo = properties.pop('Type').lower()
|
|
|
|
root = properties.pop('Root', '')
|
|
|
|
sheets = properties.pop('Sheets', ())
|
|
|
|
properties = self._special_properties(tipo, properties)
|
|
|
|
|
|
|
|
sheet = self.get_sheet(id)
|
|
|
|
sheet_model = sheet.getModel()
|
|
|
|
model = sheet_model.createInstance(get_control_model(tipo))
|
|
|
|
set_properties(model, properties)
|
|
|
|
name = properties['Name']
|
|
|
|
sheet_model.insertByName(name, model)
|
|
|
|
|
|
|
|
control = sheet.getControl(name)
|
|
|
|
add_listeners(self.events, control, name)
|
|
|
|
control = get_custom_class(tipo, control)
|
|
|
|
|
|
|
|
if tipo == 'tree' and root:
|
|
|
|
control.root = root
|
|
|
|
elif tipo == 'pages' and sheets:
|
|
|
|
control.sheets = sheets
|
|
|
|
|
|
|
|
setattr(self, name, control)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class WriterTable(ObjectBase):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
|
|
|
|
def __getitem__(self, key):
|
|
|
|
obj = super().__getitem__(key)
|
|
|
|
return WriterTableRange(obj, key, self.name)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self.obj.Name
|
|
|
|
@name.setter
|
|
|
|
def name(self, value):
|
|
|
|
self.obj.Name = value
|
|
|
|
|
|
|
|
|
|
|
|
class WriterTableRange(ObjectBase):
|
|
|
|
|
|
|
|
def __init__(self, obj, index, table_name):
|
|
|
|
self._index = index
|
|
|
|
self._table_name = table_name
|
|
|
|
super().__init__(obj)
|
|
|
|
self._is_cell = hasattr(self.obj, 'CellName')
|
|
|
|
|
|
|
|
def __getitem__(self, key):
|
|
|
|
obj = super().__getitem__(key)
|
|
|
|
return WriterTableRange(obj, key, self._table_name)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def value(self):
|
|
|
|
return self.obj.String
|
|
|
|
@value.setter
|
|
|
|
def value(self, value):
|
|
|
|
self.obj.String = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def data(self):
|
|
|
|
return self.obj.getDataArray()
|
|
|
|
@data.setter
|
|
|
|
def data(self, values):
|
|
|
|
if isinstance(values, list):
|
|
|
|
values = tuple(values)
|
|
|
|
self.obj.setDataArray(values)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def rows(self):
|
|
|
|
return len(self.data)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def columns(self):
|
|
|
|
return len(self.data[0])
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
if self._is_cell:
|
|
|
|
name = '{}.{}'.format(self._table_name, self.obj.CellName)
|
|
|
|
elif isinstance(self._index, str):
|
|
|
|
name = '{}.{}'.format(self._table_name, self._index)
|
|
|
|
else:
|
|
|
|
c1 = self.obj[0,0].CellName
|
|
|
|
c2 = self.obj[self.rows-1,self.columns-1].CellName
|
|
|
|
name = '{}.{}:{}'.format(self._table_name, c1, c2)
|
|
|
|
return name
|
|
|
|
|
|
|
|
def get_cell(self, *index):
|
|
|
|
return self[index]
|
|
|
|
|
|
|
|
def get_column(self, index=0, start=1):
|
|
|
|
return self[start:self.rows,index:index+1]
|
|
|
|
|
|
|
|
def get_series(self):
|
|
|
|
class Serie():
|
|
|
|
pass
|
|
|
|
series = []
|
|
|
|
for i in range(self.columns):
|
|
|
|
serie = Serie()
|
|
|
|
serie.label = self.get_cell(0,i).name
|
|
|
|
serie.data = self.get_column(i).data
|
|
|
|
serie.values = self.get_column(i).name
|
|
|
|
series.append(serie)
|
|
|
|
return series
|
|
|
|
|
|
|
|
|
|
|
|
class ChartFormat(object):
|
|
|
|
|
|
|
|
def __call__(self, obj):
|
|
|
|
for k, v in self.__dict__.items():
|
|
|
|
if hasattr(obj, k):
|
|
|
|
setattr(obj, k, v)
|
|
|
|
|
|
|
|
|
|
|
|
class LOChart(object):
|
|
|
|
BASE = 'com.sun.star.chart.{}Diagram'
|
|
|
|
|
|
|
|
def __init__(self, obj, tipo=''):
|
|
|
|
self._obj = obj
|
|
|
|
self._type = tipo
|
|
|
|
self._name = ''
|
|
|
|
self._table = None
|
|
|
|
self._data = ()
|
|
|
|
self._data_series = ()
|
|
|
|
self._cell = None
|
|
|
|
self._cursor = None
|
|
|
|
self._doc = None
|
|
|
|
self._title = ChartFormat()
|
|
|
|
self._subtitle = ChartFormat()
|
|
|
|
self._legend = ChartFormat()
|
|
|
|
self._xaxistitle = ChartFormat()
|
|
|
|
self._yaxistitle = ChartFormat()
|
|
|
|
self._xaxis = ChartFormat()
|
|
|
|
self._yaxis = ChartFormat()
|
|
|
|
self._xmaingrid = ChartFormat()
|
|
|
|
self._ymaingrid = ChartFormat()
|
|
|
|
self._xhelpgrid = ChartFormat()
|
|
|
|
self._yhelpgrid = ChartFormat()
|
|
|
|
self._area = ChartFormat()
|
|
|
|
self._wall = ChartFormat()
|
|
|
|
self._dim3d = False
|
|
|
|
self._series = ()
|
|
|
|
self._labels = ()
|
|
|
|
return
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
|
|
self.insert()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
@obj.setter
|
|
|
|
def obj(self, value):
|
|
|
|
self._obj = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self._name
|
|
|
|
@name.setter
|
|
|
|
def name(self, value):
|
|
|
|
self._name = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def type(self):
|
|
|
|
return self._type
|
|
|
|
@type.setter
|
|
|
|
def type(self, value):
|
|
|
|
self._type = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def table(self):
|
|
|
|
return self._table
|
|
|
|
@table.setter
|
|
|
|
def table(self, value):
|
|
|
|
self._table = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def data(self):
|
|
|
|
return self._data
|
|
|
|
@data.setter
|
|
|
|
def data(self, value):
|
|
|
|
self._data = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def cell(self):
|
|
|
|
return self._cell
|
|
|
|
@cell.setter
|
|
|
|
def cell(self, value):
|
|
|
|
self._cell = value
|
|
|
|
self.doc = value.doc
|
|
|
|
|
|
|
|
@property
|
|
|
|
def cursor(self):
|
|
|
|
return self._cursor
|
|
|
|
@cursor.setter
|
|
|
|
def cursor(self, value):
|
|
|
|
self._cursor = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def doc(self):
|
|
|
|
return self._doc
|
|
|
|
@doc.setter
|
|
|
|
def doc(self, value):
|
|
|
|
self._doc = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def width(self):
|
|
|
|
return self._width
|
|
|
|
@width.setter
|
|
|
|
def width(self, value):
|
|
|
|
self._width = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def height(self):
|
|
|
|
return self._height
|
|
|
|
@height.setter
|
|
|
|
def height(self, value):
|
|
|
|
self._height = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def title(self):
|
|
|
|
return self._title
|
|
|
|
|
|
|
|
@property
|
|
|
|
def subtitle(self):
|
|
|
|
return self._subtitle
|
|
|
|
|
|
|
|
@property
|
|
|
|
def legend(self):
|
|
|
|
return self._legend
|
|
|
|
|
|
|
|
@property
|
|
|
|
def xaxistitle(self):
|
|
|
|
return self._xaxistitle
|
|
|
|
|
|
|
|
@property
|
|
|
|
def yaxistitle(self):
|
|
|
|
return self._yaxistitle
|
|
|
|
|
|
|
|
@property
|
|
|
|
def xaxis(self):
|
|
|
|
return self._xaxis
|
|
|
|
|
|
|
|
@property
|
|
|
|
def yaxis(self):
|
|
|
|
return self._yaxis
|
|
|
|
|
|
|
|
@property
|
|
|
|
def xmaingrid(self):
|
|
|
|
return self._xmaingrid
|
|
|
|
|
|
|
|
@property
|
|
|
|
def ymaingrid(self):
|
|
|
|
return self._ymaingrid
|
|
|
|
|
|
|
|
@property
|
|
|
|
def xhelpgrid(self):
|
|
|
|
return self._xhelpgrid
|
|
|
|
|
|
|
|
@property
|
|
|
|
def yhelpgrid(self):
|
|
|
|
return self._yhelpgrid
|
|
|
|
|
|
|
|
@property
|
|
|
|
def area(self):
|
|
|
|
return self._area
|
|
|
|
|
|
|
|
@property
|
|
|
|
def wall(self):
|
|
|
|
return self._wall
|
|
|
|
|
|
|
|
@property
|
|
|
|
def dim3d(self):
|
|
|
|
return self._dim3d
|
|
|
|
@dim3d.setter
|
|
|
|
def dim3d(self, value):
|
|
|
|
self._dim3d = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def series(self):
|
|
|
|
return self._series
|
|
|
|
@series.setter
|
|
|
|
def series(self, value):
|
|
|
|
self._series = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def data_series(self):
|
|
|
|
return self._series
|
|
|
|
@data_series.setter
|
|
|
|
def data_series(self, value):
|
|
|
|
self._data_series = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def labels(self):
|
|
|
|
return self._labels
|
|
|
|
@labels.setter
|
|
|
|
def labels(self, value):
|
|
|
|
self._labels = value
|
|
|
|
|
|
|
|
def _add_series_writer(self, chart):
|
|
|
|
dp = self.doc.create_instance('com.sun.star.chart2.data.DataProvider')
|
|
|
|
chart.attachDataProvider(dp)
|
|
|
|
chart_type = chart.getFirstDiagram().getCoordinateSystems()[0].getChartTypes()[0]
|
|
|
|
self._data_series = self.table[self.data].get_series()
|
|
|
|
series = [self._create_serie(dp, s) for s in self._data_series[1:]]
|
|
|
|
chart_type.setDataSeries(tuple(series))
|
|
|
|
chart_data = chart.getData()
|
|
|
|
chart_data.ComplexRowDescriptions = self._data_series[0].data
|
|
|
|
return
|
|
|
|
|
|
|
|
def _get_series(self):
|
|
|
|
rango = self._data_series
|
|
|
|
class Serie():
|
|
|
|
pass
|
|
|
|
series = []
|
|
|
|
for i in range(0, rango.columns, 2):
|
|
|
|
serie = Serie()
|
|
|
|
serie.label = rango[0, i+1].name
|
|
|
|
serie.xvalues = rango.get_column(i).name
|
|
|
|
serie.values = rango.get_column(i+1).name
|
|
|
|
series.append(serie)
|
|
|
|
return series
|
|
|
|
|
|
|
|
def _add_series_calc(self, chart):
|
|
|
|
dp = self.doc.create_instance('com.sun.star.chart2.data.DataProvider')
|
|
|
|
chart.attachDataProvider(dp)
|
|
|
|
chart_type = chart.getFirstDiagram().getCoordinateSystems()[0].getChartTypes()[0]
|
|
|
|
series = self._get_series()
|
|
|
|
series = [self._create_serie(dp, s) for s in series]
|
|
|
|
chart_type.setDataSeries(tuple(series))
|
|
|
|
return
|
|
|
|
|
|
|
|
def _create_serie(self, dp, data):
|
|
|
|
serie = create_instance('com.sun.star.chart2.DataSeries')
|
|
|
|
rango = data.values
|
|
|
|
is_x = hasattr(data, 'xvalues')
|
|
|
|
if is_x:
|
|
|
|
xrango = data.xvalues
|
|
|
|
rango_label = data.label
|
|
|
|
|
|
|
|
lds = create_instance('com.sun.star.chart2.data.LabeledDataSequence')
|
|
|
|
values = self._create_data(dp, rango, 'values-y')
|
|
|
|
lds.setValues(values)
|
|
|
|
if data.label:
|
|
|
|
label = self._create_data(dp, rango_label, '')
|
|
|
|
lds.setLabel(label)
|
|
|
|
|
|
|
|
xlds = ()
|
|
|
|
if is_x:
|
|
|
|
xlds = create_instance('com.sun.star.chart2.data.LabeledDataSequence')
|
|
|
|
values = self._create_data(dp, xrango, 'values-x')
|
|
|
|
xlds.setValues(values)
|
|
|
|
|
|
|
|
if is_x:
|
|
|
|
serie.setData((lds, xlds))
|
|
|
|
else:
|
|
|
|
serie.setData((lds,))
|
|
|
|
|
|
|
|
return serie
|
|
|
|
|
|
|
|
def _create_data(self, dp, rango, role):
|
|
|
|
data = dp.createDataSequenceByRangeRepresentation(rango)
|
|
|
|
if not data is None:
|
|
|
|
data.Role = role
|
|
|
|
return data
|
|
|
|
|
|
|
|
def _from_calc(self):
|
|
|
|
ps = self.cell.ps
|
|
|
|
ps.Width = self.width
|
|
|
|
ps.Height = self.height
|
|
|
|
charts = self.cell.charts
|
|
|
|
data = ()
|
|
|
|
if self.data:
|
|
|
|
data = (self.data.address,)
|
|
|
|
charts.addNewByName(self.name, ps, data, True, True)
|
|
|
|
self.obj = charts.getByName(self.name)
|
|
|
|
chart = self.obj.getEmbeddedObject()
|
|
|
|
chart.setDiagram(chart.createInstance(self.BASE.format(self.type)))
|
|
|
|
if not self.data:
|
|
|
|
self._add_series_calc(chart)
|
|
|
|
return chart
|
|
|
|
|
|
|
|
def _from_writer(self):
|
|
|
|
obj = self.doc.create_instance('com.sun.star.text.TextEmbeddedObject')
|
|
|
|
obj.setPropertyValue('CLSID', '12DCAE26-281F-416F-a234-c3086127382e')
|
|
|
|
obj.Name = self.name
|
|
|
|
obj.setSize(Size(self.width, self.height))
|
|
|
|
self.doc.insert_content(self.cursor, obj)
|
|
|
|
self.obj = obj
|
|
|
|
chart = obj.getEmbeddedObject()
|
|
|
|
tipo = self.type
|
|
|
|
if self.type == 'Column':
|
|
|
|
tipo = 'Bar'
|
|
|
|
chart.Diagram.Vertical = True
|
|
|
|
chart.setDiagram(chart.createInstance(self.BASE.format(tipo)))
|
|
|
|
chart.DataSourceLabelsInFirstColumn = True
|
|
|
|
if isinstance(self.data, str):
|
|
|
|
self._add_series_writer(chart)
|
|
|
|
else:
|
|
|
|
chart_data = chart.getData()
|
|
|
|
labels = [r[0] for r in self.data]
|
|
|
|
data = [(r[1],) for r in self.data]
|
|
|
|
chart_data.setData(data)
|
|
|
|
chart_data.RowDescriptions = labels
|
|
|
|
|
|
|
|
# ~ Bug
|
|
|
|
if tipo == 'Pie':
|
|
|
|
chart.setDiagram(chart.createInstance(self.BASE.format('Bar')))
|
|
|
|
chart.setDiagram(chart.createInstance(self.BASE.format('Pie')))
|
|
|
|
|
|
|
|
return chart
|
|
|
|
|
|
|
|
def insert(self):
|
|
|
|
if not self.cell is None:
|
|
|
|
chart = self._from_calc()
|
|
|
|
elif not self.cursor is None:
|
|
|
|
chart = self._from_writer()
|
|
|
|
|
|
|
|
diagram = chart.Diagram
|
|
|
|
|
|
|
|
if self.type == 'Bar':
|
|
|
|
diagram.Vertical = True
|
|
|
|
|
|
|
|
if hasattr(self.title, 'String'):
|
|
|
|
chart.HasMainTitle = True
|
|
|
|
self.title(chart.Title)
|
|
|
|
|
|
|
|
if hasattr(self.subtitle, 'String'):
|
|
|
|
chart.HasSubTitle = True
|
|
|
|
self.subtitle(chart.SubTitle)
|
|
|
|
|
|
|
|
if self.legend.__dict__:
|
|
|
|
chart.HasLegend = True
|
|
|
|
self.legend(chart.Legend)
|
|
|
|
|
|
|
|
if self.xaxistitle.__dict__:
|
|
|
|
diagram.HasXAxisTitle = True
|
|
|
|
self.xaxistitle(diagram.XAxisTitle)
|
|
|
|
|
|
|
|
if self.yaxistitle.__dict__:
|
|
|
|
diagram.HasYAxisTitle = True
|
|
|
|
self.yaxistitle(diagram.YAxisTitle)
|
|
|
|
|
|
|
|
if self.dim3d:
|
|
|
|
diagram.Dim3D = True
|
|
|
|
|
|
|
|
if self.series:
|
|
|
|
data_series = chart.getFirstDiagram(
|
|
|
|
).getCoordinateSystems(
|
|
|
|
)[0].getChartTypes()[0].DataSeries
|
|
|
|
for i, serie in enumerate(data_series):
|
|
|
|
for k, v in self.series[i].items():
|
|
|
|
if hasattr(serie, k):
|
|
|
|
setattr(serie, k, v)
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
|
|
class LODialog(object):
|
|
|
|
|
|
|
|
def _get_type_control(self, name):
|
|
|
|
types = {
|
|
|
|
'stardiv.Toolkit.UnoFixedTextControl': 'label',
|
|
|
|
'stardiv.Toolkit.UnoFixedHyperlinkControl': 'link',
|
|
|
|
'stardiv.Toolkit.UnoEditControl': 'text',
|
|
|
|
'stardiv.Toolkit.UnoButtonControl': 'button',
|
|
|
|
'stardiv.Toolkit.UnoListBoxControl': 'listbox',
|
|
|
|
'stardiv.Toolkit.UnoRoadmapControl': 'roadmap',
|
|
|
|
'stardiv.Toolkit.UnoMultiPageControl': 'pages',
|
|
|
|
}
|
|
|
|
return types[name]
|
|
|
|
|
|
|
|
def _init_controls(self):
|
|
|
|
for control in self.obj.getControls():
|
|
|
|
tipo = self._get_type_control(control.ImplementationName)
|
|
|
|
name = control.Model.Name
|
|
|
|
control = get_custom_class(tipo, control)
|
|
|
|
setattr(self, name, control)
|
|
|
|
return
|
|
|
|
|
|
|
|
def _set_column_model(self, columns):
|
|
|
|
#~ https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1awt_1_1grid_1_1XGridColumn.html
|
|
|
|
column_model = create_instance('com.sun.star.awt.grid.DefaultGridColumnModel', True)
|
|
|
|
for column in columns:
|
|
|
|
grid_column = create_instance('com.sun.star.awt.grid.GridColumn', True)
|
|
|
|
for k, v in column.items():
|
|
|
|
setattr(grid_column, k, v)
|
|
|
|
column_model.addColumn(grid_column)
|
|
|
|
return column_model
|
|
|
|
|
|
|
|
def add_control(self, properties):
|
|
|
|
tipo = properties.pop('Type').lower()
|
|
|
|
root = properties.pop('Root', '')
|
|
|
|
sheets = properties.pop('Sheets', ())
|
|
|
|
|
|
|
|
properties = self._special_properties(tipo, properties)
|
|
|
|
model = self.model.createInstance(self._get_control_model(tipo))
|
|
|
|
set_properties(model, properties)
|
|
|
|
name = properties['Name']
|
|
|
|
self.model.insertByName(name, model)
|
|
|
|
control = self.obj.getControl(name)
|
|
|
|
add_listeners(self.events, control, name)
|
|
|
|
control = get_custom_class(tipo, control)
|
|
|
|
|
|
|
|
if tipo == 'tree' and root:
|
|
|
|
control.root = root
|
|
|
|
elif tipo == 'pages' and sheets:
|
|
|
|
control.sheets = sheets
|
|
|
|
control.events = self.events
|
|
|
|
|
|
|
|
setattr(self, name, control)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class LOWindow(object):
|
|
|
|
EMPTY = b"""<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
|
|
|
|
<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="empty" dlg:left="0" dlg:top="0" dlg:width="0" dlg:height="0" dlg:closeable="true" dlg:moveable="true" dlg:withtitlebar="false"/>"""
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
self._events = None
|
|
|
|
self._menu = None
|
|
|
|
self._container = None
|
|
|
|
self._id_extension = ''
|
|
|
|
self._obj = self._create(kwargs)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def id_extension(self):
|
|
|
|
return self._id_extension
|
|
|
|
@id_extension.setter
|
|
|
|
def id_extension(self, value):
|
|
|
|
global ID_EXTENSION
|
|
|
|
ID_EXTENSION = value
|
|
|
|
self._id_extension = value
|
|
|
|
|
|
|
|
def _create(self, properties):
|
|
|
|
ps = (
|
|
|
|
properties.get('X', 0),
|
|
|
|
properties.get('Y', 0),
|
|
|
|
properties.get('Width', 500),
|
|
|
|
properties.get('Height', 500),
|
|
|
|
)
|
|
|
|
self._title = properties.get('Title', TITLE)
|
|
|
|
self._create_frame(ps)
|
|
|
|
self._create_container(ps)
|
|
|
|
self._create_subcontainer(ps)
|
|
|
|
# ~ self._create_splitter(ps)
|
|
|
|
return
|
|
|
|
|
|
|
|
def _create_frame(self, ps):
|
|
|
|
service = 'com.sun.star.frame.TaskCreator'
|
|
|
|
tc = create_instance(service, True)
|
|
|
|
self._frame = tc.createInstanceWithArguments((
|
|
|
|
NamedValue('FrameName', 'EasyMacroWin'),
|
|
|
|
NamedValue('PosSize', Rectangle(*ps)),
|
|
|
|
))
|
|
|
|
self._window = self._frame.getContainerWindow()
|
|
|
|
self._toolkit = self._window.getToolkit()
|
|
|
|
desktop = get_desktop()
|
|
|
|
self._frame.setCreator(desktop)
|
|
|
|
desktop.getFrames().append(self._frame)
|
|
|
|
self._frame.Title = self._title
|
|
|
|
return
|
|
|
|
|
|
|
|
def _create_container(self, ps):
|
|
|
|
# ~ toolkit = self._window.getToolkit()
|
|
|
|
service = 'com.sun.star.awt.UnoControlContainer'
|
|
|
|
self._container = create_instance(service, True)
|
|
|
|
service = 'com.sun.star.awt.UnoControlContainerModel'
|
|
|
|
model = create_instance(service, True)
|
|
|
|
model.BackgroundColor = get_color(225, 225, 225)
|
|
|
|
self._container.setModel(model)
|
|
|
|
self._container.createPeer(self._toolkit, self._window)
|
|
|
|
self._container.setPosSize(*ps, POSSIZE)
|
|
|
|
self._frame.setComponent(self._container, None)
|
|
|
|
return
|
|
|
|
|
|
|
|
def _create_subcontainer(self, ps):
|
|
|
|
service = 'com.sun.star.awt.ContainerWindowProvider'
|
|
|
|
cwp = create_instance(service, True)
|
|
|
|
with get_temp_file() as f:
|
|
|
|
f.write(self.EMPTY)
|
|
|
|
f.flush()
|
|
|
|
subcont = cwp.createContainerWindow(
|
|
|
|
_path_url(f.name), '', self._container.getPeer(), None)
|
|
|
|
|
|
|
|
# ~ service = 'com.sun.star.awt.UnoControlDialog'
|
|
|
|
# ~ subcont2 = create_instance(service, True)
|
|
|
|
# ~ service = 'com.sun.star.awt.UnoControlDialogModel'
|
|
|
|
# ~ model = create_instance(service, True)
|
|
|
|
# ~ service = 'com.sun.star.awt.UnoControlContainer'
|
|
|
|
# ~ context = create_instance(service, True)
|
|
|
|
# ~ subcont2.setModel(model)
|
|
|
|
# ~ subcont2.setContext(context)
|
|
|
|
# ~ subcont2.createPeer(self._toolkit, self._container.getPeer())
|
|
|
|
|
|
|
|
subcont.setPosSize(0, 0, 500, 500, POSSIZE)
|
|
|
|
subcont.setVisible(True)
|
|
|
|
self._container.addControl('subcont', subcont)
|
|
|
|
self._subcont = subcont
|
|
|
|
return
|
|
|
|
|
|
|
|
def _get_base_control(self, tipo):
|
|
|
|
services = {
|
|
|
|
'label': 'com.sun.star.awt.UnoControlFixedText',
|
|
|
|
'button': 'com.sun.star.awt.UnoControlButton',
|
|
|
|
'text': 'com.sun.star.awt.UnoControlEdit',
|
|
|
|
'listbox': 'com.sun.star.awt.UnoControlListBox',
|
|
|
|
'link': 'com.sun.star.awt.UnoControlFixedHyperlink',
|
|
|
|
'roadmap': 'com.sun.star.awt.UnoControlRoadmap',
|
|
|
|
'image': 'com.sun.star.awt.UnoControlImageControl',
|
|
|
|
'groupbox': 'com.sun.star.awt.UnoControlGroupBox',
|
|
|
|
'radio': 'com.sun.star.awt.UnoControlRadioButton',
|
|
|
|
'tree': 'com.sun.star.awt.tree.TreeControl',
|
|
|
|
'grid': 'com.sun.star.awt.grid.UnoControlGrid',
|
|
|
|
'tab': 'com.sun.star.awt.tab.UnoControlTabPage',
|
|
|
|
}
|
|
|
|
return services[tipo]
|
|
|
|
|
|
|
|
def _special_properties(self, tipo, properties):
|
|
|
|
columns = properties.pop('Columns', ())
|
|
|
|
if tipo == 'grid':
|
|
|
|
properties['ColumnModel'] = self._set_column_model(columns)
|
|
|
|
elif tipo == 'button' and 'ImageURL' in properties:
|
|
|
|
properties['ImageURL'] = _set_image_url(
|
|
|
|
properties['ImageURL'], self.id_extension)
|
|
|
|
elif tipo == 'roadmap':
|
|
|
|
if not 'Height' in properties:
|
|
|
|
properties['Height'] = self.height
|
|
|
|
if 'Title' in properties:
|
|
|
|
properties['Text'] = properties.pop('Title')
|
|
|
|
elif tipo == 'tab':
|
|
|
|
if not 'Width' in properties:
|
|
|
|
properties['Width'] = self.width - 20
|
|
|
|
if not 'Height' in properties:
|
|
|
|
properties['Height'] = self.height - 20
|
|
|
|
|
|
|
|
return properties
|
|
|
|
|
|
|
|
def add_control(self, properties):
|
|
|
|
tipo = properties.pop('Type').lower()
|
|
|
|
root = properties.pop('Root', '')
|
|
|
|
sheets = properties.pop('Sheets', ())
|
|
|
|
|
|
|
|
properties = self._special_properties(tipo, properties)
|
|
|
|
model = self._subcont.Model.createInstance(get_control_model(tipo))
|
|
|
|
set_properties(model, properties)
|
|
|
|
name = properties['Name']
|
|
|
|
self._subcont.Model.insertByName(name, model)
|
|
|
|
control = self._subcont.getControl(name)
|
|
|
|
add_listeners(self.events, control, name)
|
|
|
|
control = get_custom_class(tipo, control)
|
|
|
|
|
|
|
|
if tipo == 'tree' and root:
|
|
|
|
control.root = root
|
|
|
|
elif tipo == 'tab' and sheets:
|
|
|
|
control.sheets = sheets
|
|
|
|
control.events = self.events
|
|
|
|
|
|
|
|
setattr(self, name, control)
|
|
|
|
return
|
|
|
|
|
|
|
|
def _create_popupmenu(self, menus):
|
|
|
|
menu = create_instance('com.sun.star.awt.PopupMenu', True)
|
|
|
|
for i, m in enumerate(menus):
|
|
|
|
label = m['label']
|
|
|
|
cmd = m.get('event', '')
|
|
|
|
if not cmd:
|
|
|
|
cmd = label.lower().replace(' ', '_')
|
|
|
|
if label == '-':
|
|
|
|
menu.insertSeparator(i)
|
|
|
|
else:
|
|
|
|
menu.insertItem(i, label, m.get('style', 0), i)
|
|
|
|
menu.setCommand(i, cmd)
|
|
|
|
# ~ menu.setItemImage(i, path?, True)
|
|
|
|
menu.addMenuListener(EventsMenu(self.events))
|
|
|
|
return menu
|
|
|
|
|
|
|
|
def _create_menu(self, menus):
|
|
|
|
#~ https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1awt_1_1XMenu.html
|
|
|
|
#~ nItemId specifies the ID of the menu item to be inserted.
|
|
|
|
#~ aText specifies the label of the menu item.
|
|
|
|
#~ nItemStyle 0 = Standard, CHECKABLE = 1, RADIOCHECK = 2, AUTOCHECK = 4
|
|
|
|
#~ nItemPos specifies the position where the menu item will be inserted.
|
|
|
|
self._menu = create_instance('com.sun.star.awt.MenuBar', True)
|
|
|
|
for i, m in enumerate(menus):
|
|
|
|
self._menu.insertItem(i, m['label'], m.get('style', 0), i)
|
|
|
|
cmd = m['label'].lower().replace(' ', '_')
|
|
|
|
self._menu.setCommand(i, cmd)
|
|
|
|
submenu = self._create_popupmenu(m['submenu'])
|
|
|
|
self._menu.setPopupMenu(i, submenu)
|
|
|
|
|
|
|
|
self._window.setMenuBar(self._menu)
|
|
|
|
return
|
|
|
|
|
|
|
|
def add_menu(self, menus):
|
|
|
|
self._create_menu(menus)
|
|
|
|
return
|
|
|
|
|
|
|
|
def _add_listeners(self, control=None):
|
|
|
|
if self.events is None:
|
|
|
|
return
|
|
|
|
controller = EventsWindow(self)
|
|
|
|
self._window.addTopWindowListener(controller)
|
|
|
|
self._window.addWindowListener(controller)
|
|
|
|
self._container.addKeyListener(EventsKeyWindow(self))
|
|
|
|
return
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self._title.lower().replace(' ', '_')
|
|
|
|
|
|
|
|
@property
|
|
|
|
def events(self):
|
|
|
|
return self._events
|
|
|
|
@events.setter
|
|
|
|
def events(self, value):
|
|
|
|
self._events = value
|
|
|
|
self._add_listeners()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def width(self):
|
|
|
|
return self._container.Size.Width
|
|
|
|
|
|
|
|
@property
|
|
|
|
def height(self):
|
|
|
|
return self._container.Size.Height
|
|
|
|
|
|
|
|
def open(self):
|
|
|
|
self._window.setVisible(True)
|
|
|
|
return
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self._window.setMenuBar(None)
|
|
|
|
self._window.dispose()
|
|
|
|
self._frame.close(True)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
def create_window(kwargs):
|
|
|
|
return LOWindow(**kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
# ~ Export ok
|
|
|
|
def merge_zip(target, zips):
|
|
|
|
try:
|
|
|
|
with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED) as t:
|
|
|
|
for path in zips:
|
|
|
|
with zipfile.ZipFile(path, compression=zipfile.ZIP_DEFLATED) as s:
|
|
|
|
for name in s.namelist():
|
|
|
|
t.writestr(name, s.open(name).read())
|
|
|
|
except Exception as e:
|
|
|
|
error(e)
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
# ~ Export ok
|
|
|
|
def format(template, data):
|
|
|
|
"""
|
|
|
|
https://pyformat.info/
|
|
|
|
"""
|
|
|
|
if isinstance(data, (str, int, float)):
|
|
|
|
return template.format(data)
|
|
|
|
|
|
|
|
if isinstance(data, (Time, Date, DateTime)):
|
|
|
|
return template.format(_to_date(data))
|
|
|
|
|
|
|
|
if isinstance(data, tuple) and isinstance(data[0], tuple):
|
|
|
|
data = {r[0]: _to_date(r[1]) for r in data}
|
|
|
|
return template.format(**data)
|
|
|
|
|
|
|
|
data = [_to_date(v) for v in data]
|
|
|
|
result = template.format(*data)
|
|
|
|
return result
|