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 a6ab8ca..e087f5d 100644 Binary files a/files/ZAZPip_v0.2.0.oxt and b/files/ZAZPip_v0.2.0.oxt differ diff --git a/source/ZAZPip.py b/source/ZAZPip.py index 7f3a8a7..8cbfacb 100644 --- a/source/ZAZPip.py +++ b/source/ZAZPip.py @@ -114,7 +114,6 @@ class Controllers(object): self.cmd_home_action(None) return - @app.catch_exception def cmd_close_action(self, event): self.d.close() return diff --git a/source/pythonpath/easymacro.py b/source/pythonpath/easymacro.py index e3d7cc8..39a2a79 100644 --- a/source/pythonpath/easymacro.py +++ b/source/pythonpath/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 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,7 +91,15 @@ 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 +class FontSlant(IntEnum): + NONE = 0 + OBLIQUE = 1 + ITALIC = 2 + DONTKNOW = 3 + REVERSE_OBLIQUE = 4 + REVERSE_ITALIC = 5 try: from fernet import Fernet, InvalidToken @@ -301,7 +311,6 @@ def info(data): return -@catch_exception def debug(*info): if IS_WIN: doc = get_document(FILE_NAME_DEBUG) @@ -336,18 +345,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 +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)