# ~ FILTER_PDF = '/org.openoffice.Office.Common/Filter/PDF/Export/' # ~ If location="document" Then # ~ sp = ThisComponent.getScriptProvider() 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 auto_width(self): self.obj.Columns.OptimalWidth = True return def insert_shape(self, tipo, **kwargs): s = self.obj.Size w = kwargs.get('width', s.Width) h = kwargs.get('Height', s.Height) img = self.doc.create_instance('com.sun.star.drawing.{}Shape'.format(tipo)) set_properties(img, kwargs) self.draw_page.add(img) img.Anchor = self.obj img.setSize(Size(w, h)) return 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 @property def columns_visible(self): return self._obj.getColumns().IsVisible @columns_visible.setter def columns_visible(self, value): self._obj.getColumns().IsVisible = value 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 EventsMouseGrid(EventsMouse): selected = False def mousePressed(self, event): super().mousePressed(event) # ~ obj = event.Source # ~ col = obj.getColumnAtPoint(event.X, event.Y) # ~ row = obj.getRowAtPoint(event.X, event.Y) # ~ print(col, row) # ~ if col == -1 and row == -1: # ~ if self.selected: # ~ obj.deselectAllRows() # ~ else: # ~ obj.selectAllRows() # ~ self.selected = not self.selected return def mouseReleased(self, event): # ~ obj = event.Source # ~ col = obj.getColumnAtPoint(event.X, event.Y) # ~ row = obj.getRowAtPoint(event.X, event.Y) # ~ if row == -1 and col > -1: # ~ gdm = obj.Model.GridDataModel # ~ for i in range(gdm.RowCount): # ~ gdm.updateRowHeading(i, i + 1) return 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 def _set_column_model(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 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""" """ 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