From f03a0fd6bb27cbcb8562702fc4476c6a01b269a4 Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Mon, 28 Oct 2019 22:14:24 -0600 Subject: [PATCH] Add support for spanish --- easymacro.py | 741 ++++++++++++++++++++++++++++++--- files/ZAZPip_v0.2.0.oxt | Bin 77500 -> 79926 bytes source/ZAZPip.py | 1 - source/pythonpath/easymacro.py | 547 ++++++++++++++++++++++-- 4 files changed, 1206 insertions(+), 83 deletions(-) diff --git a/easymacro.py b/easymacro.py index e3d7cc8..a990a24 100644 --- a/easymacro.py +++ b/easymacro.py @@ -41,12 +41,13 @@ import time import traceback import zipfile -from collections import OrderedDict -from collections.abc import MutableMapping +# ~ from collections import OrderedDict +# ~ from collections.abc import MutableMapping from functools import wraps from operator import itemgetter from pathlib import Path, PurePath from pprint import pprint +from enum import Enum, IntEnum from urllib.request import Request, urlopen from urllib.error import URLError, HTTPError from string import Template @@ -78,6 +79,7 @@ from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK from com.sun.star.text.TextContentAnchorType import AS_CHARACTER +from com.sun.star.script import ScriptEventDescriptor from com.sun.star.lang import XEventListener from com.sun.star.awt import XActionListener from com.sun.star.awt import XMouseListener @@ -89,6 +91,18 @@ from com.sun.star.awt import XMenuListener from com.sun.star.awt import XKeyListener from com.sun.star.awt import XItemListener from com.sun.star.awt import XFocusListener +from com.sun.star.awt import XTabListener +from com.sun.star.awt.grid import XGridDataListener +from com.sun.star.awt.grid import XGridSelectionListener + + +class FontSlant(IntEnum): + NONE = 0 + OBLIQUE = 1 + ITALIC = 2 + DONTKNOW = 3 + REVERSE_OBLIQUE = 4 + REVERSE_ITALIC = 5 try: @@ -301,7 +315,6 @@ def info(data): return -@catch_exception def debug(*info): if IS_WIN: doc = get_document(FILE_NAME_DEBUG) @@ -336,18 +349,17 @@ def run_in_thread(fn): return run -def now(): - return datetime.datetime.now() +def now(only_time=False): + now = datetime.datetime.now() + if only_time: + return now.time() + return now def today(): return datetime.date.today() -def time(): - return datetime.datetime.now().time() - - def get_date(year, month, day, hour=-1, minute=-1, second=-1): if hour > -1 or minute > -1 or second > -1: h = hour @@ -600,9 +612,6 @@ class LODocument(object): def _init_values(self): self._type_doc = get_type_doc(self.obj) - # ~ if self._type_doc == 'base': - # ~ self._cc = self.obj.DatabaseDocument.getCurrentController() - # ~ else: self._cc = self.obj.getCurrentController() return @@ -723,10 +732,117 @@ class LODocument(object): return path_pdf +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): @@ -823,6 +939,67 @@ class LOCellStyles(object): return +class LOImage(object): + TYPES = { + 'image/png': 'png', + 'image/jpeg': 'jpg', + } + + def __init__(self, obj): + self._obj = obj + + @property + def obj(self): + return self._obj + + @property + def address(self): + return self.obj.Anchor.AbsoluteName + + @property + def name(self): + return self.obj.Name + + @property + def mimetype(self): + return self.obj.Bitmap.MimeType + + @property + def url(self): + return _path_system(self.obj.URL) + @url.setter + def url(self, value): + self.obj.URL = _path_url(value) + + @property + def path(self): + return _path_system(self.obj.GraphicURL) + @path.setter + def path(self, value): + self.obj.GraphicURL = _path_url(value) + + @property + def visible(self): + return self.obj.Visible + @visible.setter + def visible(self, value): + self_obj.Visible = value + + def save(self, path): + if is_dir(path): + p = path + n = self.name + else: + p, fn, n, e = get_info_path(path) + ext = self.TYPES[self.mimetype] + path = join(p, '{}.{}'.format(n, ext)) + size = len(self.obj.Bitmap.DIB) + data = self.obj.GraphicStream.readBytes((), size) + data = data[-1].value + save_file(path, 'wb', data) + return path + + class LOCalc(LODocument): def __init__(self, obj): @@ -1071,7 +1248,7 @@ class LOCalcSheet(object): def _init_values(self): self._events = None self._dp = self.obj.getDrawPage() - return + self._images = {i.Name: LOImage(i) for i in self._dp} @property def obj(self): @@ -1081,6 +1258,10 @@ class LOCalcSheet(object): def doc(self): return self._doc + @property + def images(self): + return self._images + @property def name(self): return self._obj.Name @@ -1257,6 +1438,42 @@ class LOWriter(LODocument): 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): @@ -1612,6 +1829,10 @@ class LOCellRange(object): rango.data = self.data return + def copy(self, source): + self.sheet.obj.copyRange(self.address, source.range_address) + return + def offset(self, row=1, col=0): ra = self.obj.getRangeAddress() col = ra.EndColumn + col @@ -1669,6 +1890,10 @@ class LOCellRange(object): a = self.obj.getRangeAddressesAsString() return a + @property + def range_address(self): + return self.obj.getRangeAddress() + @property def current_region(self): cursor = self.sheet.get_cursor(self.obj[0,0]) @@ -1801,6 +2026,36 @@ class LOCellRange(object): 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 + class EventsListenerBase(unohelper.Base, XEventListener): @@ -1809,6 +2064,10 @@ class EventsListenerBase(unohelper.Base, XEventListener): self._name = name self._window = window + @property + def name(self): + return self._name + def disposing(self, event): self._controller = None if not self._window is None: @@ -1968,6 +2227,45 @@ class EventsKey(EventsListenerBase, XKeyListener): 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 EventsGrid(EventsListenerBase, XGridDataListener, XGridSelectionListener): + + def __init__(self, controller, name): + super().__init__(controller, name) + + def dataChanged(self, event): + event_name = '{}_data_changed'.format(self.name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + def rowHeadingChanged(self, event): + pass + + def rowsInserted(self, event): + pass + + def rowsRemoved(self, evemt): + pass + + def selectionChanged(self, event): + event_name = '{}_selection_changed'.format(self.name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + class EventsKeyWindow(EventsListenerBase, XKeyListener): """ event.KeyChar @@ -2044,8 +2342,8 @@ class EventsWindow(EventsListenerBase, XTopWindowListener, XWindowListener): # ~ XWindowListener def windowResized(self, event): - # ~ sb = self._container.getControl('subcontainer') - # ~ sb.setPosSize(0, 0, event.Width, event.Height, SIZE) + 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) @@ -2069,7 +2367,6 @@ class EventsMenu(EventsListenerBase, XMenuListener): def itemHighlighted(self, event): pass - @catch_exception def itemSelected(self, event): name = event.Source.getCommand(event.MenuId) if name.startswith('menu'): @@ -2108,6 +2405,7 @@ class UnoBaseObject(object): @property def parent(self): + ps = self.obj.getContext().PosSize return self.obj.getContext() def _get_possize(self, name): @@ -2149,7 +2447,10 @@ class UnoBaseObject(object): return self._model.Width @width.setter def width(self, value): - self._model.Width = value + if hasattr(self.obj, 'PosSize'): + self._set_possize('Width', value) + else: + self._model.Width = value @property def height(self): @@ -2159,7 +2460,10 @@ class UnoBaseObject(object): return ps.Height @height.setter def height(self, value): - self._model.Height = value + if hasattr(self.obj, 'PosSize'): + self._set_possize('Height', value) + else: + self._model.Height = value @property def tag(self): @@ -2310,7 +2614,7 @@ class UnoListBox(UnoBaseObject): @property def value(self): - return self.obj.SelectedItem + return self.obj.getSelectedItem() @property def count(self): @@ -2324,6 +2628,10 @@ class UnoListBox(UnoBaseObject): self.model.StringItemList = list(sorted(values)) return + def unselect(self): + self.obj.selectItem(self.value, False) + return + def select(self, pos=0): if isinstance(pos, str): self.obj.selectItem(pos, True) @@ -2332,7 +2640,7 @@ class UnoListBox(UnoBaseObject): return def clear(self): - self.obj.removeItems(0, self.count) + self.model.removeAllItems() return def _set_image_url(self, image): @@ -2388,16 +2696,19 @@ class UnoGrid(UnoBaseObject): # ~ def format_columns(self, value): # ~ self._format_columns = value + @property + def value(self): + return self[self.column, self.row] + @property def data(self): return self._data @data.setter def data(self, values): # ~ self._data = values - self._gdm.removeAllRows() + self.clear() headings = tuple(range(1, len(values) + 1)) self._gdm.addRows(headings, values) - # ~ rows = range(grid_dm.RowCount) # ~ colors = [COLORS['GRAY'] if r % 2 else COLORS['WHITE'] for r in rows] # ~ grid.Model.RowBackgroundColors = tuple(colors) @@ -2437,6 +2748,10 @@ class UnoGrid(UnoBaseObject): row.append(d) return tuple(row) + def clear(self): + self._gdm.removeAllRows() + return + def add_row(self, data): # ~ self._data.append(data) data = self._validate_column(data) @@ -2446,10 +2761,10 @@ class UnoGrid(UnoBaseObject): def remove_row(self, row): self._gdm.removeRow(row) # ~ del self._data[row] - self._update_row_heading() + self.update_row_heading() return - def _update_row_heading(self): + def update_row_heading(self): for i in range(self.rows): self._gdm.updateRowHeading(i, i + 1) return @@ -2457,7 +2772,7 @@ class UnoGrid(UnoBaseObject): def sort(self, column, asc=True): self._gdm.sortByColumn(column, asc) # ~ self._data.sort(key=itemgetter(column), reverse=not asc) - self._update_row_heading() + self.update_row_heading() return def set_column_image(self, column, path): @@ -2503,6 +2818,173 @@ class UnoRoadmap(UnoBaseObject): return +class UnoTree(UnoBaseObject): + + def __init__(self, obj, ): + super().__init__(obj) + self._tdm = None + self._data = [] + + @property + def selection(self): + return self.obj.Selection + + @property + def root(self): + if self._tdm is None: + return '' + return self._tdm.Root.DisplayValue + + @root.setter + def root(self, value): + self._add_data_model(value) + + def _add_data_model(self, name): + tdm = create_instance('com.sun.star.awt.tree.MutableTreeDataModel') + root = tdm.createNode(name, True) + root.DataValue = 0 + tdm.setRoot(root) + self.model.DataModel = tdm + self._tdm = self.model.DataModel + self._add_data() + return + + @property + def data(self): + return self._data + @data.setter + def data(self, values): + self._data = list(values) + self._add_data() + + def _add_data(self): + if not self.data: + return + + parents = {} + for node in self.data: + parent = parents.get(node[1], self._tdm.Root) + child = self._tdm.createNode(node[2], False) + child.DataValue = node[0] + parent.appendChild(child) + parents[node[0]] = child + self.obj.expandNode(self._tdm.Root) + 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 + + def get_custom_class(tipo, obj): classes = { 'label': UnoLabel, @@ -2512,15 +2994,35 @@ def get_custom_class(tipo, obj): 'grid': UnoGrid, 'link': UnoLabelLink, 'roadmap': UnoRoadmap, - # ~ 'tab': UnoTab, + 'tree': UnoTree, + 'tab': UnoTab, # ~ 'image': UnoImage, # ~ 'radio': UnoRadio, # ~ 'groupbox': UnoGroupBox, - # ~ 'tree': UnoTree, + 'formbutton': FormButton, } return classes[tipo](obj) +def get_control_model(control): + services = { + 'label': 'com.sun.star.awt.UnoControlFixedTextModel', + 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel', + 'text': 'com.sun.star.awt.UnoControlEditModel', + 'listbox': 'com.sun.star.awt.UnoControlListBoxModel', + 'button': 'com.sun.star.awt.UnoControlButtonModel', + 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel', + 'grid': 'com.sun.star.awt.grid.UnoControlGridModel', + 'tree': 'com.sun.star.awt.tree.TreeControlModel', + 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel', + 'image': 'com.sun.star.awt.UnoControlImageControlModel', + 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel', + 'tab': 'com.sun.star.awt.UnoMultiPageModel', + } + return services[control] + + +@catch_exception def add_listeners(events, control, name=''): listeners = { 'addActionListener': EventsButton, @@ -2528,6 +3030,7 @@ def add_listeners(events, control, name=''): 'addItemListener': EventsItem, 'addFocusListener': EventsFocus, 'addKeyListener': EventsKey, + 'addTabListener': EventsTab, } if hasattr(control, 'obj'): control = contro.obj @@ -2549,6 +3052,11 @@ def add_listeners(events, control, name=''): continue getattr(control, key)(listeners[key](events, name)) + + if is_grid: + controllers = EventsGrid(events, name) + control.addSelectionListener(controllers) + control.Model.GridDataModel.addGridDataListener(controllers) return @@ -2989,6 +3497,29 @@ class LOChart(object): 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 + + +def _set_image_url(image, id_extension=''): + if exists_path(image): + return _path_url(image) + + if not id_extension: + return '' + + path = get_path_extension(id_extension) + path = join(path, DIR['images'], image) + return _path_url(path) + + class LODialog(object): def __init__(self, **properties): @@ -3037,11 +3568,12 @@ class LODialog(object): def _get_type_control(self, name): types = { 'stardiv.Toolkit.UnoFixedTextControl': 'label', - 'stardiv.Toolkit.UnoButtonControl': 'button', - 'stardiv.Toolkit.UnoEditControl': 'text', - 'stardiv.Toolkit.UnoRoadmapControl': 'roadmap', '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] @@ -3128,17 +3660,18 @@ class LODialog(object): def _get_control_model(self, control): services = { - 'button': 'com.sun.star.awt.UnoControlButtonModel', - 'grid': 'com.sun.star.awt.grid.UnoControlGridModel', - 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel', - 'image': 'com.sun.star.awt.UnoControlImageControlModel', 'label': 'com.sun.star.awt.UnoControlFixedTextModel', 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel', - 'listbox': 'com.sun.star.awt.UnoControlListBoxModel', - 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel', - 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel', 'text': 'com.sun.star.awt.UnoControlEditModel', + 'listbox': 'com.sun.star.awt.UnoControlListBoxModel', + 'button': 'com.sun.star.awt.UnoControlButtonModel', + 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel', + 'grid': 'com.sun.star.awt.grid.UnoControlGridModel', 'tree': 'com.sun.star.awt.tree.TreeControlModel', + 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel', + 'image': 'com.sun.star.awt.UnoControlImageControlModel', + 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel', + 'pages': 'com.sun.star.awt.UnoMultiPageModel', } return services[control] @@ -3174,10 +3707,19 @@ class LODialog(object): 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 + if not 'Height' in properties: + properties['Height'] = self.height + 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.model.createInstance(self._get_control_model(tipo)) set_properties(model, properties) @@ -3186,6 +3728,13 @@ class LODialog(object): 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 @@ -3217,13 +3766,26 @@ class LODialog(object): 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), @@ -3234,6 +3796,7 @@ class LOWindow(object): self._title = properties.get('Title', TITLE) self._create_frame(ps) self._create_container(ps) + self._create_subcontainer(ps) # ~ self._create_splitter(ps) return @@ -3265,6 +3828,31 @@ class LOWindow(object): 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', @@ -3278,25 +3866,51 @@ class LOWindow(object): '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 + + @catch_exception def add_control(self, properties): tipo = properties.pop('Type').lower() - base = self._get_base_control(tipo) - obj = create_instance(base, True) - model = create_instance('{}Model'.format(base), True) + 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) - obj.setModel(model) - x = properties.get('X', 5) - y = properties.get('Y', 5) - w = properties.get('Width', 200) - h = properties.get('Height', 25) - obj.setPosSize(x, y, w, h, POSSIZE) name = properties['Name'] - self._container.addControl(name, obj) - add_listeners(self.events, obj, name) - control = get_custom_class(tipo, obj) + 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 @@ -3404,7 +4018,7 @@ def get_document(title=''): return doc for d in desktop.getComponents(): - if d.Title == title: + if hasattr(d, 'Title') and d.Title == title: doc = d break @@ -3597,6 +4211,10 @@ def get_path_extension(id): return path +def get_home(): + return Path.home() + + # ~ Export ok def inputbox(message, default='', title=TITLE, echochar=''): @@ -3733,7 +4351,7 @@ def open_file(path): if IS_WIN: os.startfile(path) else: - subprocess.Popen(['xdg-open', path]) + pid = subprocess.Popen(['xdg-open', path]).pid return @@ -3791,6 +4409,7 @@ def url_open(url, options={}, json=False): req = Request(url) try: response = urlopen(req) + # ~ response.info() except HTTPError as e: error(e) except URLError as e: @@ -4421,6 +5040,24 @@ def format(template, data): return result +def _get_url_script(macro): + macro['language'] = macro.get('language', 'Python') + macro['location'] = macro.get('location', 'user') + data = macro.copy() + if data['language'] == 'Python': + data['module'] = '.py$' + elif data['language'] == 'Basic': + data['module'] = '.{}.'.format(macro['module']) + if macro['location'] == 'user': + data['location'] = 'application' + else: + data['module'] = '.' + + url = 'vnd.sun.star.script:{library}{module}{name}?language={language}&location={location}' + path = url.format(**data) + return path + + def _call_macro(macro): #~ https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification name = 'com.sun.star.script.provider.MasterScriptProviderFactory' @@ -4441,6 +5078,7 @@ def _call_macro(macro): args = macro.get('args', ()) url = 'vnd.sun.star.script:{library}{module}{name}?language={language}&location={location}' path = url.format(**data) + script = factory.createScriptProvider('').getScript(path) return script.invoke(args, None, None)[0] @@ -4675,7 +5313,6 @@ def export_csv(path, data, **kwargs): return -@catch_exception def install_locales(path, domain='base', dir_locales=DIR['locales']): p, *_ = get_info_path(path) path_locales = join(p, dir_locales) diff --git a/files/ZAZPip_v0.2.0.oxt b/files/ZAZPip_v0.2.0.oxt index a6ab8ca9248d44136c0e37ecb197d626b46d3f23..e087f5dabf249d2f9e263b5ebd054a11654e57fe 100644 GIT binary patch delta 33400 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 delta 30888 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 -1 or minute > -1 or second > -1: h = hour @@ -600,9 +608,6 @@ class LODocument(object): def _init_values(self): self._type_doc = get_type_doc(self.obj) - # ~ if self._type_doc == 'base': - # ~ self._cc = self.obj.DatabaseDocument.getCurrentController() - # ~ else: self._cc = self.obj.getCurrentController() return @@ -723,10 +728,117 @@ class LODocument(object): return path_pdf +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): @@ -823,6 +935,67 @@ class LOCellStyles(object): return +class LOImage(object): + TYPES = { + 'image/png': 'png', + 'image/jpeg': 'jpg', + } + + def __init__(self, obj): + self._obj = obj + + @property + def obj(self): + return self._obj + + @property + def address(self): + return self.obj.Anchor.AbsoluteName + + @property + def name(self): + return self.obj.Name + + @property + def mimetype(self): + return self.obj.Bitmap.MimeType + + @property + def url(self): + return _path_system(self.obj.URL) + @url.setter + def url(self, value): + self.obj.URL = _path_url(value) + + @property + def path(self): + return _path_system(self.obj.GraphicURL) + @path.setter + def path(self, value): + self.obj.GraphicURL = _path_url(value) + + @property + def visible(self): + return self.obj.Visible + @visible.setter + def visible(self, value): + self_obj.Visible = value + + def save(self, path): + if is_dir(path): + p = path + n = self.name + else: + p, fn, n, e = get_info_path(path) + ext = self.TYPES[self.mimetype] + path = join(p, '{}.{}'.format(n, ext)) + size = len(self.obj.Bitmap.DIB) + data = self.obj.GraphicStream.readBytes((), size) + data = data[-1].value + save_file(path, 'wb', data) + return path + + class LOCalc(LODocument): def __init__(self, obj): @@ -1071,7 +1244,7 @@ class LOCalcSheet(object): def _init_values(self): self._events = None self._dp = self.obj.getDrawPage() - return + self._images = {i.Name: LOImage(i) for i in self._dp} @property def obj(self): @@ -1081,6 +1254,10 @@ class LOCalcSheet(object): def doc(self): return self._doc + @property + def images(self): + return self._images + @property def name(self): return self._obj.Name @@ -1257,6 +1434,42 @@ class LOWriter(LODocument): 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): @@ -1612,6 +1825,10 @@ class LOCellRange(object): rango.data = self.data return + def copy(self, source): + self.sheet.obj.copyRange(self.address, source.range_address) + return + def offset(self, row=1, col=0): ra = self.obj.getRangeAddress() col = ra.EndColumn + col @@ -1669,6 +1886,10 @@ class LOCellRange(object): a = self.obj.getRangeAddressesAsString() return a + @property + def range_address(self): + return self.obj.getRangeAddress() + @property def current_region(self): cursor = self.sheet.get_cursor(self.obj[0,0]) @@ -1801,6 +2022,36 @@ class LOCellRange(object): 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 + class EventsListenerBase(unohelper.Base, XEventListener): @@ -1968,6 +2219,18 @@ class EventsKey(EventsListenerBase, XKeyListener): 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 @@ -2069,7 +2332,6 @@ class EventsMenu(EventsListenerBase, XMenuListener): def itemHighlighted(self, event): pass - @catch_exception def itemSelected(self, event): name = event.Source.getCommand(event.MenuId) if name.startswith('menu'): @@ -2310,7 +2572,7 @@ class UnoListBox(UnoBaseObject): @property def value(self): - return self.obj.SelectedItem + return self.obj.getSelectedItem() @property def count(self): @@ -2324,6 +2586,10 @@ class UnoListBox(UnoBaseObject): self.model.StringItemList = list(sorted(values)) return + def unselect(self): + self.obj.selectItem(self.value, False) + return + def select(self, pos=0): if isinstance(pos, str): self.obj.selectItem(pos, True) @@ -2332,7 +2598,7 @@ class UnoListBox(UnoBaseObject): return def clear(self): - self.obj.removeItems(0, self.count) + self.model.removeAllItems() return def _set_image_url(self, image): @@ -2503,6 +2769,166 @@ class UnoRoadmap(UnoBaseObject): return +class UnoTree(UnoBaseObject): + + def __init__(self, obj, ): + super().__init__(obj) + self._tdm = None + self._data = [] + + @property + def selection(self): + return self.obj.Selection + + @property + def root(self): + if self._tdm is None: + return '' + return self._tdm.Root.DisplayValue + + @root.setter + def root(self, value): + self._add_data_model(value) + + def _add_data_model(self, name): + tdm = create_instance('com.sun.star.awt.tree.MutableTreeDataModel') + root = tdm.createNode(name, True) + root.DataValue = 0 + tdm.setRoot(root) + self.model.DataModel = tdm + self._tdm = self.model.DataModel + self._add_data() + return + + @property + def data(self): + return self._data + @data.setter + def data(self, values): + self._data = list(values) + self._add_data() + + def _add_data(self): + if not self.data: + return + + parents = {} + for node in self.data: + parent = parents.get(node[1], self._tdm.Root) + child = self._tdm.createNode(node[2], False) + child.DataValue = node[0] + parent.appendChild(child) + parents[node[0]] = child + self.obj.expandNode(self._tdm.Root) + return + + +class UnoPages(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() + + 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'] = self._set_column_model(columns) + 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 + + def get_custom_class(tipo, obj): classes = { 'label': UnoLabel, @@ -2512,15 +2938,34 @@ def get_custom_class(tipo, obj): 'grid': UnoGrid, 'link': UnoLabelLink, 'roadmap': UnoRoadmap, - # ~ 'tab': UnoTab, + 'tree': UnoTree, + 'pages': UnoPages, # ~ 'image': UnoImage, # ~ 'radio': UnoRadio, # ~ 'groupbox': UnoGroupBox, - # ~ 'tree': UnoTree, + 'formbutton': FormButton, } return classes[tipo](obj) +def get_control_model(control): + services = { + 'label': 'com.sun.star.awt.UnoControlFixedTextModel', + 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel', + 'text': 'com.sun.star.awt.UnoControlEditModel', + 'listbox': 'com.sun.star.awt.UnoControlListBoxModel', + 'button': 'com.sun.star.awt.UnoControlButtonModel', + 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel', + 'grid': 'com.sun.star.awt.grid.UnoControlGridModel', + 'tree': 'com.sun.star.awt.tree.TreeControlModel', + 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel', + 'image': 'com.sun.star.awt.UnoControlImageControlModel', + 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel', + 'pages': 'com.sun.star.awt.UnoMultiPageModel', + } + return services[control] + + def add_listeners(events, control, name=''): listeners = { 'addActionListener': EventsButton, @@ -2528,6 +2973,7 @@ def add_listeners(events, control, name=''): 'addItemListener': EventsItem, 'addFocusListener': EventsFocus, 'addKeyListener': EventsKey, + 'addTabListener': EventsTab, } if hasattr(control, 'obj'): control = contro.obj @@ -3037,11 +3483,12 @@ class LODialog(object): def _get_type_control(self, name): types = { 'stardiv.Toolkit.UnoFixedTextControl': 'label', - 'stardiv.Toolkit.UnoButtonControl': 'button', - 'stardiv.Toolkit.UnoEditControl': 'text', - 'stardiv.Toolkit.UnoRoadmapControl': 'roadmap', '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] @@ -3128,17 +3575,18 @@ class LODialog(object): def _get_control_model(self, control): services = { - 'button': 'com.sun.star.awt.UnoControlButtonModel', - 'grid': 'com.sun.star.awt.grid.UnoControlGridModel', - 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel', - 'image': 'com.sun.star.awt.UnoControlImageControlModel', 'label': 'com.sun.star.awt.UnoControlFixedTextModel', 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel', - 'listbox': 'com.sun.star.awt.UnoControlListBoxModel', - 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel', - 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel', 'text': 'com.sun.star.awt.UnoControlEditModel', + 'listbox': 'com.sun.star.awt.UnoControlListBoxModel', + 'button': 'com.sun.star.awt.UnoControlButtonModel', + 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel', + 'grid': 'com.sun.star.awt.grid.UnoControlGridModel', 'tree': 'com.sun.star.awt.tree.TreeControlModel', + 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel', + 'image': 'com.sun.star.awt.UnoControlImageControlModel', + 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel', + 'pages': 'com.sun.star.awt.UnoMultiPageModel', } return services[control] @@ -3174,10 +3622,19 @@ class LODialog(object): 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, 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) @@ -3186,6 +3643,13 @@ class LODialog(object): 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 @@ -3404,7 +3868,7 @@ def get_document(title=''): return doc for d in desktop.getComponents(): - if d.Title == title: + if hasattr(d, 'Title') and d.Title == title: doc = d break @@ -3597,6 +4061,10 @@ def get_path_extension(id): return path +def get_home(): + return Path.home() + + # ~ Export ok def inputbox(message, default='', title=TITLE, echochar=''): @@ -3791,6 +4259,7 @@ def url_open(url, options={}, json=False): req = Request(url) try: response = urlopen(req) + # ~ response.info() except HTTPError as e: error(e) except URLError as e: @@ -4421,6 +4890,24 @@ def format(template, data): return result +def _get_url_script(macro): + macro['language'] = macro.get('language', 'Python') + macro['location'] = macro.get('location', 'user') + data = macro.copy() + if data['language'] == 'Python': + data['module'] = '.py$' + elif data['language'] == 'Basic': + data['module'] = '.{}.'.format(macro['module']) + if macro['location'] == 'user': + data['location'] = 'application' + else: + data['module'] = '.' + + url = 'vnd.sun.star.script:{library}{module}{name}?language={language}&location={location}' + path = url.format(**data) + return path + + def _call_macro(macro): #~ https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification name = 'com.sun.star.script.provider.MasterScriptProviderFactory' @@ -4441,6 +4928,7 @@ def _call_macro(macro): args = macro.get('args', ()) url = 'vnd.sun.star.script:{library}{module}{name}?language={language}&location={location}' path = url.format(**data) + script = factory.createScriptProvider('').getScript(path) return script.invoke(args, None, None)[0] @@ -4675,7 +5163,6 @@ def export_csv(path, data, **kwargs): return -@catch_exception def install_locales(path, domain='base', dir_locales=DIR['locales']): p, *_ = get_info_path(path) path_locales = join(p, dir_locales)