diff --git a/.gitignore b/.gitignore
index 03b69a9..399bdd7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
__pycache__/
*.py[cod]
+*.po~
*.log
images/
diff --git a/VERSION b/VERSION
index 49b49e4..5faa42c 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-0.1.0
+0.2.0
diff --git a/conf.py b/conf.py
index 7fe37de..f1685e9 100644
--- a/conf.py
+++ b/conf.py
@@ -26,7 +26,7 @@ import logging
TYPE_EXTENSION = 1
# ~ https://semver.org/
-VERSION = '0.1.0'
+VERSION = '0.2.0'
# ~ Your great extension name, not used spaces
NAME = 'ZAZPip'
@@ -207,6 +207,8 @@ PATHS = {
'soffice': ('soffice', PROGRAM, FILE_TEST),
'install': ('unopkg', 'add', '-v', '-f', '-s'),
'profile': '/home/mau/.config/libreoffice/4/user',
+ 'gettext': PATH_PYGETTEXT,
+ 'msgmerge': PATH_MSGMERGE,
}
diff --git a/easymacro.py b/easymacro.py
index 20923a8..a990a24 100644
--- a/easymacro.py
+++ b/easymacro.py
@@ -22,6 +22,7 @@ import csv
import ctypes
import datetime
import errno
+import gettext
import getpass
import hashlib
import json
@@ -40,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
@@ -77,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
@@ -88,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:
@@ -100,6 +115,7 @@ ID_EXTENSION = ''
DIR = {
'images': 'images',
+ 'locales': 'locales',
}
KEY = {
@@ -299,7 +315,6 @@ def info(data):
return
-@catch_exception
def debug(*info):
if IS_WIN:
doc = get_document(FILE_NAME_DEBUG)
@@ -334,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
@@ -598,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
@@ -721,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):
@@ -821,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):
@@ -1069,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):
@@ -1079,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
@@ -1255,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):
@@ -1610,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
@@ -1667,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])
@@ -1799,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):
@@ -1807,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:
@@ -1966,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
@@ -2042,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)
@@ -2067,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'):
@@ -2106,6 +2405,7 @@ class UnoBaseObject(object):
@property
def parent(self):
+ ps = self.obj.getContext().PosSize
return self.obj.getContext()
def _get_possize(self, name):
@@ -2147,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):
@@ -2157,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):
@@ -2308,7 +2614,7 @@ class UnoListBox(UnoBaseObject):
@property
def value(self):
- return self.obj.SelectedItem
+ return self.obj.getSelectedItem()
@property
def count(self):
@@ -2322,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)
@@ -2330,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):
@@ -2386,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)
@@ -2435,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)
@@ -2444,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
@@ -2455,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):
@@ -2501,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,
@@ -2510,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,
@@ -2526,6 +3030,7 @@ def add_listeners(events, control, name=''):
'addItemListener': EventsItem,
'addFocusListener': EventsFocus,
'addKeyListener': EventsKey,
+ 'addTabListener': EventsTab,
}
if hasattr(control, 'obj'):
control = contro.obj
@@ -2547,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
@@ -2987,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):
@@ -3035,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]
@@ -3126,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]
@@ -3172,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)
@@ -3184,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
@@ -3215,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),
@@ -3232,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
@@ -3263,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',
@@ -3276,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
@@ -3402,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
@@ -3595,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=''):
@@ -3731,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
@@ -3789,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:
@@ -4419,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'
@@ -4439,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]
@@ -4665,6 +5305,7 @@ def import_csv(path, **kwargs):
rows = tuple(csv.reader(f, **kwargs))
return rows
+
def export_csv(path, data, **kwargs):
with open(path, 'w') as f:
writer = csv.writer(f, **kwargs)
@@ -4672,6 +5313,19 @@ def export_csv(path, data, **kwargs):
return
+def install_locales(path, domain='base', dir_locales=DIR['locales']):
+ p, *_ = get_info_path(path)
+ path_locales = join(p, dir_locales)
+ try:
+ lang = gettext.translation(domain, path_locales, languages=[LANG])
+ lang.install()
+ _ = lang.gettext
+ except Exception as e:
+ from gettext import gettext as _
+ error(e)
+ return _
+
+
class LIBOServer(object):
HOST = 'localhost'
PORT = '8100'
diff --git a/files/ZAZPip_v0.2.0.oxt b/files/ZAZPip_v0.2.0.oxt
new file mode 100644
index 0000000..e087f5d
Binary files /dev/null and b/files/ZAZPip_v0.2.0.oxt differ
diff --git a/source/ZAZPip.py b/source/ZAZPip.py
index dc29d36..8cbfacb 100644
--- a/source/ZAZPip.py
+++ b/source/ZAZPip.py
@@ -1,10 +1,8 @@
import uno
import unohelper
-import os
from com.sun.star.task import XJobExecutor
import easymacro as app
-import site
ID_EXTENSION = 'net.elmau.zaz.pip'
SERVICE = ('com.sun.star.task.Job',)
@@ -21,11 +19,7 @@ PACKAGES = {
}
-# ~ sudoPassword = 'mypass'
-# ~ command = 'mount -t vboxsf myfolder /home/myuser/myfolder'.split()
-# ~ cmd1 = subprocess.Popen(['echo',sudoPassword], stdout=subprocess.PIPE)
-# ~ cmd2 = subprocess.Popen(['sudo','-S'] + command, stdin=cmd1.stdout, stdout=subprocess.PIPE)
-# ~ output = cmd2.stdout.read.decode()
+_ = app.install_locales(__file__)
class Controllers(object):
@@ -52,7 +46,7 @@ class Controllers(object):
return
def cmd_install_pip_action(self, event):
- msg = 'Do you want install PIP?'
+ msg = _('Do you want install PIP?')
if not app.question(msg, 'ZAZ-Pip'):
return
@@ -70,20 +64,20 @@ class Controllers(object):
self.d.lst_log.insert('Download PIP...')
data = app.url_open(URL_PIP)
if not data:
- msg = 'Do you have internet connection?'
+ msg = _('Do you have internet connection?')
app.errorbox(msg)
return
app.save_file(path_pip, 'wb', data)
if not app.is_created(path_pip):
- msg = 'File PIP not save'
+ msg = _('File PIP not save')
app.errorbox(msg)
return
- self.d.lst_log.insert('PIP save correctly...')
+ self.d.lst_log.insert(_('PIP save correctly...'))
try:
- self.d.lst_log.insert('Start installing PIP...')
+ self.d.lst_log.insert(_('Start installing PIP...'))
cmd = '"{}" "{}" --user'.format(self.path_python, path_pip)
for line in app.popen(cmd):
if isinstance(line, tuple):
@@ -97,10 +91,10 @@ class Controllers(object):
self.d.lbl_pip.value = label
self.d.cmd_install_pip.visible = False
self.d.cmd_admin_pip.visible = True
- msg = 'PIP installed sucesfully'
+ msg = _('PIP installed sucesfully')
app.msgbox(msg)
else:
- msg = 'PIP not installed, see log.'
+ msg = _('PIP not installed, see log')
app.warning(msg)
except Exception as e:
app.errorbox(e)
@@ -120,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
@@ -176,7 +169,7 @@ class Controllers(object):
if line:
self.d.lst_package.select()
else:
- self.d.lst_package.insert('Not found...', 'error.png', show=False)
+ self.d.lst_package.insert(_('Not found...'), 'error.png', show=False)
return
def cmd_search_action(self, event):
@@ -212,7 +205,7 @@ class Controllers(object):
opt = 'upgrade'
name = self.d.lst_package.value
- msg = 'Do you want {}:\n\n{} ?'.format(opt, name)
+ msg = _('Do you want {}:\n\n{} ?').format(opt, name)
if not app.question(msg, TITLE):
return
@@ -238,12 +231,12 @@ class Controllers(object):
def cmd_uninstall_action(self, event):
if not self._states['list']:
- msg = 'Select installed package'
+ msg = _('Select installed package')
app.warning(msg)
return
name = self.d.lst_package.value
- msg = 'Do you want uninstall:\n\n{} ?'.format(name)
+ msg = _('Do you want uninstall:\n\n{} ?').format(name)
if not app.question(msg):
return
@@ -254,13 +247,13 @@ class Controllers(object):
def cmd_shell_action(self, name):
if app.IS_WIN:
cmd = '"{}"'.format(self.path_python)
- os.startfile(cmd)
+ app.open_file(cmd)
else:
if app.DESKTOP == 'gnome':
cmd = 'gnome-terminal -- {}'.format(self.path_python)
else:
cmd = 'exec {}'.format(self.path_python)
- os.system(cmd)
+ app.run(cmd)
return
@@ -277,7 +270,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
def _create_dialog(self):
args= {
'Name': 'dialog',
- 'Title': 'ZAZ-Pip',
+ 'Title': 'ZAZ-PIP',
'Width': 200,
'Height': 220,
}
@@ -288,7 +281,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
args = {
'Type': 'Label',
'Name': 'lbl_title',
- 'Label': 'ZAZ Pip',
+ 'Label': 'ZAZ PIP',
'Width': 50,
'Height': 15,
'Border': 1,
@@ -330,7 +323,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
exists_pip = True
if not label:
exists_pip = False
- label = 'PIP not installed'
+ label = _('PIP not installed')
args = {
'Type': 'Label',
'Name': 'lbl_pip',
@@ -349,7 +342,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
args = {
'Type': 'Button',
'Name': 'cmd_admin_pip',
- 'Label': 'Admin PIP',
+ 'Label': _('Admin PIP'),
'Width': 60,
'Height': 18,
'Step': 10,
@@ -362,7 +355,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
args = {
'Type': 'Button',
'Name': 'cmd_install_pip',
- 'Label': 'Install PIP',
+ 'Label': _('Install PIP'),
'Width': 60,
'Height': 18,
'Step': 10,
@@ -400,7 +393,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
args = {
'Type': 'Label',
'Name': 'lbl_package',
- 'Label': 'Packages',
+ 'Label': _('Packages'),
'Width': 100,
'Height': 15,
'Border': 1,
@@ -432,7 +425,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
args = {
'Type': 'Button',
'Name': 'cmd_close',
- 'Label': '~Close',
+ 'Label': _('~Close'),
'Width': 60,
'Height': 18,
'Step': 1,
diff --git a/source/description.xml b/source/description.xml
index ca62b47..66dbf0a 100644
--- a/source/description.xml
+++ b/source/description.xml
@@ -1,7 +1,7 @@
-
+
ZAZ Pip
ZAZ Pip
diff --git a/source/locales/base.pot b/source/locales/base.pot
new file mode 100644
index 0000000..efec610
--- /dev/null
+++ b/source/locales/base.pot
@@ -0,0 +1,87 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR , YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-10-19 15:19-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
+#: source/ZAZPip.py:49
+msgid "Do you want install PIP?"
+msgstr ""
+
+#: source/ZAZPip.py:67
+msgid "Do you have internet connection?"
+msgstr ""
+
+#: source/ZAZPip.py:73
+msgid "File PIP not save"
+msgstr ""
+
+#: source/ZAZPip.py:76
+msgid "PIP save correctly..."
+msgstr ""
+
+#: source/ZAZPip.py:80
+msgid "Start installing PIP..."
+msgstr ""
+
+#: source/ZAZPip.py:94
+msgid "PIP installed sucesfully"
+msgstr ""
+
+#: source/ZAZPip.py:97
+msgid "PIP not installed, see log"
+msgstr ""
+
+#: source/ZAZPip.py:173
+msgid "Not found..."
+msgstr ""
+
+#: source/ZAZPip.py:209
+msgid ""
+"Do you want {}:\n"
+"\n"
+"{} ?"
+msgstr ""
+
+#: source/ZAZPip.py:235
+msgid "Select installed package"
+msgstr ""
+
+#: source/ZAZPip.py:240
+msgid ""
+"Do you want uninstall:\n"
+"\n"
+"{} ?"
+msgstr ""
+
+#: source/ZAZPip.py:327
+msgid "PIP not installed"
+msgstr ""
+
+#: source/ZAZPip.py:346
+msgid "Admin PIP"
+msgstr ""
+
+#: source/ZAZPip.py:359
+msgid "Install PIP"
+msgstr ""
+
+#: source/ZAZPip.py:397
+msgid "Packages"
+msgstr ""
+
+#: source/ZAZPip.py:429
+msgid "~Close"
+msgstr ""
+
diff --git a/source/locales/en/LC_MESSAGES/base.mo b/source/locales/en/LC_MESSAGES/base.mo
new file mode 100644
index 0000000..ba5e52a
Binary files /dev/null and b/source/locales/en/LC_MESSAGES/base.mo differ
diff --git a/source/locales/en/LC_MESSAGES/base.po b/source/locales/en/LC_MESSAGES/base.po
new file mode 100644
index 0000000..c752f52
--- /dev/null
+++ b/source/locales/en/LC_MESSAGES/base.po
@@ -0,0 +1,88 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR , YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2019-10-19 15:19-0500\n"
+"PO-Revision-Date: 2019-10-19 15:20-0500\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+"X-Generator: Poedit 2.2.4\n"
+"Last-Translator: \n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Language: en\n"
+
+#: source/ZAZPip.py:49
+msgid "Do you want install PIP?"
+msgstr ""
+
+#: source/ZAZPip.py:67
+msgid "Do you have internet connection?"
+msgstr ""
+
+#: source/ZAZPip.py:73
+msgid "File PIP not save"
+msgstr ""
+
+#: source/ZAZPip.py:76
+msgid "PIP save correctly..."
+msgstr ""
+
+#: source/ZAZPip.py:80
+msgid "Start installing PIP..."
+msgstr ""
+
+#: source/ZAZPip.py:94
+msgid "PIP installed sucesfully"
+msgstr ""
+
+#: source/ZAZPip.py:97
+msgid "PIP not installed, see log"
+msgstr ""
+
+#: source/ZAZPip.py:173
+msgid "Not found..."
+msgstr ""
+
+#: source/ZAZPip.py:209
+msgid ""
+"Do you want {}:\n"
+"\n"
+"{} ?"
+msgstr ""
+
+#: source/ZAZPip.py:235
+msgid "Select installed package"
+msgstr ""
+
+#: source/ZAZPip.py:240
+msgid ""
+"Do you want uninstall:\n"
+"\n"
+"{} ?"
+msgstr ""
+
+#: source/ZAZPip.py:327
+msgid "PIP not installed"
+msgstr ""
+
+#: source/ZAZPip.py:346
+msgid "Admin PIP"
+msgstr ""
+
+#: source/ZAZPip.py:359
+msgid "Install PIP"
+msgstr ""
+
+#: source/ZAZPip.py:397
+msgid "Packages"
+msgstr ""
+
+#: source/ZAZPip.py:429
+msgid "~Close"
+msgstr ""
diff --git a/source/locales/es/LC_MESSAGES/base.mo b/source/locales/es/LC_MESSAGES/base.mo
new file mode 100644
index 0000000..4d88f20
Binary files /dev/null and b/source/locales/es/LC_MESSAGES/base.mo differ
diff --git a/source/locales/es/LC_MESSAGES/base.po b/source/locales/es/LC_MESSAGES/base.po
new file mode 100644
index 0000000..3970f03
--- /dev/null
+++ b/source/locales/es/LC_MESSAGES/base.po
@@ -0,0 +1,94 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR , YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2019-10-19 15:19-0500\n"
+"PO-Revision-Date: 2019-10-19 15:24-0500\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+"X-Generator: Poedit 2.2.4\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: source/ZAZPip.py:49
+msgid "Do you want install PIP?"
+msgstr "¿Desea instalar PIP?"
+
+#: source/ZAZPip.py:67
+msgid "Do you have internet connection?"
+msgstr "¿Tiene conexión a Internet?"
+
+#: source/ZAZPip.py:73
+msgid "File PIP not save"
+msgstr "No se guardo el archivo PIP"
+
+#: source/ZAZPip.py:76
+msgid "PIP save correctly..."
+msgstr "Archivo PIP guardado correctamente..."
+
+#: source/ZAZPip.py:80
+msgid "Start installing PIP..."
+msgstr "Iniciando instalación de PIP..."
+
+#: source/ZAZPip.py:94
+msgid "PIP installed sucesfully"
+msgstr "PIP instalado correctamente"
+
+#: source/ZAZPip.py:97
+msgid "PIP not installed, see log"
+msgstr "PIP no fue instalado, vea el registro"
+
+#: source/ZAZPip.py:173
+msgid "Not found..."
+msgstr "No encontrado..."
+
+#: source/ZAZPip.py:209
+msgid ""
+"Do you want {}:\n"
+"\n"
+"{} ?"
+msgstr ""
+"¿Desea {}:\n"
+"\n"
+"{} ?"
+
+#: source/ZAZPip.py:235
+msgid "Select installed package"
+msgstr "Seleccione un paquete instalado"
+
+#: source/ZAZPip.py:240
+msgid ""
+"Do you want uninstall:\n"
+"\n"
+"{} ?"
+msgstr ""
+"¿Desea desinstalar:\n"
+"\n"
+"{} ?"
+
+#: source/ZAZPip.py:327
+msgid "PIP not installed"
+msgstr "PIP no esta instalado"
+
+#: source/ZAZPip.py:346
+msgid "Admin PIP"
+msgstr "Administrar PIP"
+
+#: source/ZAZPip.py:359
+msgid "Install PIP"
+msgstr "Instalar PIP"
+
+#: source/ZAZPip.py:397
+msgid "Packages"
+msgstr "Paquetes"
+
+#: source/ZAZPip.py:429
+msgid "~Close"
+msgstr "~Cerrar"
diff --git a/source/pythonpath/easymacro.py b/source/pythonpath/easymacro.py
index 20923a8..39a2a79 100644
--- a/source/pythonpath/easymacro.py
+++ b/source/pythonpath/easymacro.py
@@ -22,6 +22,7 @@ import csv
import ctypes
import datetime
import errno
+import gettext
import getpass
import hashlib
import json
@@ -40,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
@@ -77,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
@@ -88,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
@@ -100,6 +111,7 @@ ID_EXTENSION = ''
DIR = {
'images': 'images',
+ 'locales': 'locales',
}
KEY = {
@@ -299,7 +311,6 @@ def info(data):
return
-@catch_exception
def debug(*info):
if IS_WIN:
doc = get_document(FILE_NAME_DEBUG)
@@ -334,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
@@ -598,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
@@ -721,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):
@@ -821,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):
@@ -1069,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):
@@ -1079,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
@@ -1255,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):
@@ -1610,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
@@ -1667,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])
@@ -1799,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):
@@ -1966,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
@@ -2067,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'):
@@ -2308,7 +2572,7 @@ class UnoListBox(UnoBaseObject):
@property
def value(self):
- return self.obj.SelectedItem
+ return self.obj.getSelectedItem()
@property
def count(self):
@@ -2322,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)
@@ -2330,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):
@@ -2501,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,
@@ -2510,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,
@@ -2526,6 +2973,7 @@ def add_listeners(events, control, name=''):
'addItemListener': EventsItem,
'addFocusListener': EventsFocus,
'addKeyListener': EventsKey,
+ 'addTabListener': EventsTab,
}
if hasattr(control, 'obj'):
control = contro.obj
@@ -3035,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]
@@ -3126,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]
@@ -3172,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)
@@ -3184,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
@@ -3402,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
@@ -3595,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=''):
@@ -3789,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:
@@ -4419,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'
@@ -4439,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]
@@ -4665,6 +5155,7 @@ def import_csv(path, **kwargs):
rows = tuple(csv.reader(f, **kwargs))
return rows
+
def export_csv(path, data, **kwargs):
with open(path, 'w') as f:
writer = csv.writer(f, **kwargs)
@@ -4672,6 +5163,19 @@ def export_csv(path, data, **kwargs):
return
+def install_locales(path, domain='base', dir_locales=DIR['locales']):
+ p, *_ = get_info_path(path)
+ path_locales = join(p, dir_locales)
+ try:
+ lang = gettext.translation(domain, path_locales, languages=[LANG])
+ lang.install()
+ _ = lang.gettext
+ except Exception as e:
+ from gettext import gettext as _
+ error(e)
+ return _
+
+
class LIBOServer(object):
HOST = 'localhost'
PORT = '8100'
diff --git a/zaz.py b/zaz.py
index 2cac1bc..9cad0c8 100644
--- a/zaz.py
+++ b/zaz.py
@@ -33,6 +33,7 @@ from xml.dom.minidom import parseString
from conf import (
DATA,
DIRS,
+ DOMAIN,
EXTENSION,
FILES,
INFO,
@@ -138,6 +139,19 @@ def _save(path, data):
return
+def _get_files(path, filters=''):
+ paths = []
+ if filters in ('*', '*.*'):
+ filters = ''
+ for folder, _, files in os.walk(path):
+ if filters:
+ pattern = re.compile(r'\.(?:{})$'.format(filters), re.IGNORECASE)
+ paths += [_join(folder, f) for f in files if pattern.search(f)]
+ else:
+ paths += files
+ return paths
+
+
def _compress_oxt():
log.info('Compress OXT extension...')
@@ -435,8 +449,50 @@ def _embed(args):
return
+def _locales(args):
+ EASYMACRO = 'easymacro.py'
+
+ if args.files:
+ files = args.files.split(',')
+ else:
+ files = _get_files(DIRS['source'], 'py')
+ paths = ' '.join([f for f in files if not EASYMACRO in f])
+ path_pot = _join(DIRS['source'], DIRS['locales'], '{}.pot'.format(DOMAIN))
+ call([PATHS['gettext'], '-o', path_pot, paths])
+ log.info('POT generate successfully...')
+ return
+
+
+def _update():
+ path_locales = _join(DIRS['source'], DIRS['locales'])
+ path_pot = _join(DIRS['source'], DIRS['locales'], '{}.pot'.format(DOMAIN))
+ if not _exists(path_pot):
+ log.error('Not exists file POT...')
+ return
+
+ files = _get_files(path_locales, 'po')
+ if not files:
+ log.error('First, generate files PO...')
+ return
+
+ for f in files:
+ call([PATHS['msgmerge'], '-U', f, path_pot])
+ log.info('\tUpdate: {}'.format(f))
+
+ log.info('Locales update successfully...')
+ return
+
+
def main(args):
+ if args.update:
+ _update()
+ return
+
+ if args.locales:
+ _locales(args)
+ return
+
if args.embed:
_embed(args)
return
@@ -469,6 +525,10 @@ def _process_command_line_arguments():
default=False, required=False)
parser.add_argument('-d', '--document', dest='document', default='')
parser.add_argument('-f', '--files', dest='files', default='')
+ parser.add_argument('-l', '--locales', dest='locales', action='store_true',
+ default=False, required=False)
+ parser.add_argument('-u', '--update', dest='update', action='store_true',
+ default=False, required=False)
return parser.parse_args()