diff --git a/CHANGELOG b/CHANGELOG
index 8c96867..85092b8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,7 @@
+v 0.5.0 [22-nov-2019]
+ - Update easymacro.py
+
+
v 0.4.0 [23-oct-2019]
- Fix error in main
diff --git a/README.md b/README.md
index 16d67fa..fbfcd2a 100644
--- a/README.md
+++ b/README.md
@@ -9,11 +9,12 @@ https://gitlab.com/mauriciobaeza/zaz
### Software libre, no gratis
+
This extension have a cost of maintenance of 1 euro every year.
-BCH: `1RPLWHJW34p7pMQV1ft4x7eWhAYw69Dsb`
+BCH: `qztd3l00xle5tffdqvh2snvadkuau2ml0uqm4n875d`
-BTC: `3Fe4JuADrAK8Qs7GDAxbSXR8E54avwZJLW`
+BTC: `3FhiXcXmAesmQzrNEngjHFnvaJRhU1AGWV`
PayPal :( donate ATT elmau DOT net
diff --git a/VERSION b/VERSION
index 26b5dec..8ea2ddf 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-0.4.0
+0.5.0
diff --git a/conf.py b/conf.py
index 012a322..9f2b603 100644
--- a/conf.py
+++ b/conf.py
@@ -26,7 +26,7 @@ import logging
TYPE_EXTENSION = 1
# ~ https://semver.org/
-VERSION = '0.4.0'
+VERSION = '0.5.0'
# ~ Your great extension name, not used spaces
NAME = 'ZAZFavorites'
@@ -206,6 +206,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 547f936..8259aca 100644
--- a/easymacro.py
+++ b/easymacro.py
@@ -34,6 +34,7 @@ import shlex
import shutil
import socket
import subprocess
+import ssl
import sys
import tempfile
import threading
@@ -41,13 +42,9 @@ import time
import traceback
import zipfile
-# ~ 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
@@ -91,14 +88,10 @@ 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:
from fernet import Fernet, InvalidToken
@@ -119,7 +112,6 @@ KEY = {
SEPARATION = 5
-
MSG_LANG = {
'es': {
'OK': 'Aceptar',
@@ -130,35 +122,36 @@ MSG_LANG = {
}
}
-
OS = platform.system()
USER = getpass.getuser()
PC = platform.node()
DESKTOP = os.environ.get('DESKTOP_SESSION', '')
INFO_DEBUG = '{}\n\n{}\n\n{}'.format(sys.version, platform.platform(), '\n'.join(sys.path))
-
IS_WIN = OS == 'Windows'
LOG_NAME = 'ZAZ'
CLIPBOARD_FORMAT_TEXT = 'text/plain;charset=utf-16'
-
PYTHON = 'python'
if IS_WIN:
PYTHON = 'python.exe'
CALC = 'calc'
WRITER = 'writer'
+
OBJ_CELL = 'ScCellObj'
OBJ_RANGE = 'ScCellRangeObj'
OBJ_RANGES = 'ScCellRangesObj'
OBJ_TYPE_RANGES = (OBJ_CELL, OBJ_RANGE, OBJ_RANGES)
+TEXT_RANGE = 'SwXTextRange'
+TEXT_RANGES = 'SwXTextRanges'
+TEXT_TYPE_RANGES = (TEXT_RANGE, TEXT_RANGES)
+
TYPE_DOC = {
'calc': 'com.sun.star.sheet.SpreadsheetDocument',
'writer': 'com.sun.star.text.TextDocument',
'impress': 'com.sun.star.presentation.PresentationDocument',
'draw': 'com.sun.star.drawing.DrawingDocument',
- # ~ 'base': 'com.sun.star.sdb.OfficeDatabaseDocument',
'base': 'com.sun.star.sdb.DocumentDataSource',
'math': 'com.sun.star.formula.FormulaProperties',
'basic': 'com.sun.star.script.BasicIDE',
@@ -197,19 +190,16 @@ MENUS_WRITER = {
'windows': '.uno:WindowList',
'help': '.uno:HelpMenu',
}
-
MENUS_APP = {
'main': MENUS_MAIN,
'calc': MENUS_CALC,
'writer': MENUS_WRITER,
}
-
EXT = {
'pdf': 'pdf',
}
-
FILE_NAME_DEBUG = 'debug.odt'
FILE_NAME_CONFIG = 'zaz-{}.json'
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
@@ -279,6 +269,12 @@ def mri(obj):
return
+def inspect(obj):
+ zaz = create_instance('net.elmau.zaz.inspect')
+ zaz.inspect(obj)
+ return
+
+
def catch_exception(f):
@wraps(f)
def func(*args, **kwargs):
@@ -454,12 +450,14 @@ def call_dispatch(url, args=()):
return
-def get_temp_file():
+def get_temp_file(only_name=False):
delete = True
if IS_WIN:
delete = False
- return tempfile.NamedTemporaryFile(delete=delete)
-
+ tmp = tempfile.NamedTemporaryFile(delete=delete)
+ if only_name:
+ tmp = tmp.name
+ return tmp
def _path_url(path):
if path.startswith('file://'):
@@ -501,6 +499,11 @@ def dict_to_property(values, uno_any=False):
return ps
+def dict_to_named(values):
+ ps = tuple([NamedValue(n, v) for n, v in values.items()])
+ return ps
+
+
def property_to_dict(values):
d = {i.Name: i.Value for i in values}
return d
@@ -934,6 +937,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):
@@ -942,7 +1006,9 @@ class LOCalc(LODocument):
def __getitem__(self, index):
if isinstance(index, str):
- index = [s.Name for s in self._sheets if s.CodeName == index][0] or index
+ code_name = [s.Name for s in self._sheets if s.CodeName == index]
+ if code_name:
+ index = code_name[0]
return LOCalcSheet(self._sheets[index], self)
def __setitem__(self, key, value):
@@ -1182,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):
@@ -1192,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
@@ -1306,7 +1376,11 @@ class LOWriter(LODocument):
@property
def selection(self):
sel = self.obj.getCurrentSelection()
- return LOTextRange(sel[0])
+ if sel.ImplementationName == TEXT_RANGES:
+ return LOTextRange(sel[0])
+ elif sel.ImplementationName == TEXT_RANGE:
+ return LOTextRange(sel)
+ return sel
def write(self, data, cursor=None):
cursor = cursor or self.selection.cursor.getEnd()
@@ -1583,7 +1657,7 @@ class LODrawImpress(LODocument):
def insert_image(self, path, **kwargs):
w = kwargs.get('width', 3000)
- h = kwargs.get('Height', 1000)
+ h = kwargs.get('Height', 3000)
x = kwargs.get('X', 1000)
y = kwargs.get('Y', 1000)
@@ -1640,6 +1714,9 @@ class LOCellRange(object):
def __getitem__(self, index):
return LOCellRange(self.obj[index], self.doc)
+ def __contains__(self, item):
+ return item.in_range(self)
+
def _init_values(self):
self._type_obj = self.obj.ImplementationName
self._type_content = EMPTY
@@ -1689,7 +1766,7 @@ class LOCellRange(object):
self.obj.setFormula(data)
else:
self.obj.setString(data)
- elif isinstance(data, (int, float)):
+ elif isinstance(data, (int, float, bool)):
self.obj.setValue(data)
elif isinstance(data, datetime.datetime):
d = data.toordinal()
@@ -1707,8 +1784,6 @@ class LOCellRange(object):
return self.obj.getDataArray()
@data.setter
def data(self, values):
- if isinstance(values, list):
- values = tuple(values)
self.obj.setDataArray(values)
@property
@@ -1716,8 +1791,6 @@ class LOCellRange(object):
return self.obj.getFormulaArray()
@formula.setter
def formula(self, values):
- if isinstance(values, list):
- values = tuple(values)
self.obj.setFormulaArray(values)
@property
@@ -1742,13 +1815,19 @@ class LOCellRange(object):
cursor.collapseToSize(cols, rows)
return LOCellRange(self.sheet[cursor.AbsoluteName].obj, self.doc)
- def copy_from(self, rango):
+ def copy_from(self, rango, formula=False):
data = rango
if isinstance(rango, LOCellRange):
- data = rango.data
+ if formula:
+ data = rango.formula
+ else:
+ data = rango.data
rows = len(data)
cols = len(data[0])
- self.to_size(rows, cols).data = data
+ if formula:
+ self.to_size(rows, cols).formula = data
+ else:
+ self.to_size(rows, cols).data = data
return
def copy_to(self, cell, formula=False):
@@ -1759,6 +1838,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
@@ -1816,6 +1899,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])
@@ -1986,6 +2073,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:
@@ -2096,7 +2187,10 @@ class EventsItem(EventsListenerBase, XItemListener):
pass
def itemStateChanged(self, event):
- pass
+ event_name = '{}_item_changed'.format(self.name)
+ if hasattr(self._controller, event_name):
+ getattr(self._controller, event_name)(event)
+ return
class EventsItemRoadmap(EventsItem):
@@ -2145,6 +2239,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
@@ -2221,8 +2354,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)
@@ -2284,6 +2417,7 @@ class UnoBaseObject(object):
@property
def parent(self):
+ ps = self.obj.getContext().PosSize
return self.obj.getContext()
def _get_possize(self, name):
@@ -2325,17 +2459,23 @@ class UnoBaseObject(object):
return self._model.Width
@width.setter
def width(self, value):
- self._model.Width = value
+ if hasattr(self.model, 'Width'):
+ self.model.Width = value
+ elif hasattr(self.obj, 'PosSize'):
+ self._set_possize('Width', value)
@property
def height(self):
- if hasattr(self._model, 'Height'):
- return self._model.Height
+ if hasattr(self.model, 'Height'):
+ return self.model.Height
ps = self.obj.getPosSize()
return ps.Height
@height.setter
def height(self, value):
- self._model.Height = value
+ if hasattr(self.model, 'Height'):
+ self.model.Height = value
+ elif hasattr(self.obj, 'PosSize'):
+ self._set_possize('Height', value)
@property
def tag(self):
@@ -2398,8 +2538,12 @@ class UnoBaseObject(object):
def move(self, origin, x=0, y=5):
if x:
self.x = origin.x + origin.width + x
+ else:
+ self.x = origin.x
if y:
self.y = origin.y + origin.height + y
+ else:
+ self.y = origin.y
return
def possize(self, origin):
@@ -2568,16 +2712,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)
@@ -2617,6 +2764,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)
@@ -2626,18 +2777,17 @@ 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
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):
@@ -2685,7 +2835,6 @@ class UnoRoadmap(UnoBaseObject):
class UnoTree(UnoBaseObject):
- @catch_exception
def __init__(self, obj, ):
super().__init__(obj)
self._tdm = None
@@ -2738,6 +2887,119 @@ class UnoTree(UnoBaseObject):
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,
@@ -2748,7 +3010,7 @@ def get_custom_class(tipo, obj):
'link': UnoLabelLink,
'roadmap': UnoRoadmap,
'tree': UnoTree,
- # ~ 'tab': UnoTab,
+ 'tab': UnoTab,
# ~ 'image': UnoImage,
# ~ 'radio': UnoRadio,
# ~ 'groupbox': UnoGroupBox,
@@ -2757,6 +3019,24 @@ def get_custom_class(tipo, obj):
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]
+
+
def add_listeners(events, control, name=''):
listeners = {
'addActionListener': EventsButton,
@@ -2764,6 +3044,7 @@ def add_listeners(events, control, name=''):
'addItemListener': EventsItem,
'addFocusListener': EventsFocus,
'addKeyListener': EventsKey,
+ 'addTabListener': EventsTab,
}
if hasattr(control, 'obj'):
control = contro.obj
@@ -2785,6 +3066,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
@@ -3174,6 +3460,7 @@ class LOChart(object):
chart_data.setData(data)
chart_data.RowDescriptions = labels
+ # ~ Bug
if tipo == 'Pie':
chart.setDiagram(chart.createInstance(self.BASE.format('Bar')))
chart.setDiagram(chart.createInstance(self.BASE.format('Pie')))
@@ -3225,6 +3512,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):
@@ -3278,6 +3588,7 @@ class LODialog(object):
'stardiv.Toolkit.UnoButtonControl': 'button',
'stardiv.Toolkit.UnoListBoxControl': 'listbox',
'stardiv.Toolkit.UnoRoadmapControl': 'roadmap',
+ 'stardiv.Toolkit.UnoMultiPageControl': 'pages',
}
return types[name]
@@ -3375,6 +3686,7 @@ class LODialog(object):
'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]
@@ -3410,11 +3722,18 @@ 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))
@@ -3427,6 +3746,9 @@ class LODialog(object):
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
@@ -3459,13 +3781,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),
@@ -3476,6 +3811,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
@@ -3507,6 +3843,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',
@@ -3520,25 +3881,50 @@ 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
+
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
@@ -3834,8 +4220,12 @@ def json_loads(data):
def get_path_extension(id):
+ path = ''
pip = CTX.getValueByName('/singletons/com.sun.star.deployment.PackageInformationProvider')
- path = _path_system(pip.getPackageLocation(id))
+ try:
+ path = _path_system(pip.getPackageLocation(id))
+ except Exception as e:
+ error(e)
return path
@@ -3979,7 +4369,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
@@ -4032,23 +4422,29 @@ def popen(command, stdin=None):
yield (e.errno, e.strerror)
-def url_open(url, options={}, json=False):
+def url_open(url, options={}, verify=True, json=False):
data = ''
+ err = ''
req = Request(url)
try:
- response = urlopen(req)
- # ~ response.info()
+ if verify:
+ response = urlopen(req)
+ else:
+ context = ssl._create_unverified_context()
+ response = urlopen(req, context=context)
except HTTPError as e:
error(e)
+ err = str(e)
except URLError as e:
error(e.reason)
+ err = str(e.reason)
else:
if json:
data = json_loads(response.read())
else:
data = response.read()
- return data
+ return data, err
def run(command, wait=False):
@@ -5025,8 +5421,6 @@ class LIBOServer(object):
return instance
-
-
# ~ controls = {
# ~ 'CheckBox': 'com.sun.star.awt.UnoControlCheckBoxModel',
# ~ 'ComboBox': 'com.sun.star.awt.UnoControlComboBoxModel',
diff --git a/files/ZAZFavorites_v0.1.0.oxt b/files/ZAZFavorites_v0.1.0.oxt
deleted file mode 100644
index 09db96c..0000000
Binary files a/files/ZAZFavorites_v0.1.0.oxt and /dev/null differ
diff --git a/files/ZAZFavorites_v0.2.0.oxt b/files/ZAZFavorites_v0.2.0.oxt
deleted file mode 100644
index acaa466..0000000
Binary files a/files/ZAZFavorites_v0.2.0.oxt and /dev/null differ
diff --git a/files/ZAZFavorites_v0.3.0.oxt b/files/ZAZFavorites_v0.3.0.oxt
deleted file mode 100644
index 0136be9..0000000
Binary files a/files/ZAZFavorites_v0.3.0.oxt and /dev/null differ
diff --git a/files/ZAZFavorites_v0.4.0.oxt b/files/ZAZFavorites_v0.5.0.oxt
similarity index 51%
rename from files/ZAZFavorites_v0.4.0.oxt
rename to files/ZAZFavorites_v0.5.0.oxt
index 679b8fe..62348e0 100644
Binary files a/files/ZAZFavorites_v0.4.0.oxt and b/files/ZAZFavorites_v0.5.0.oxt differ
diff --git a/source/META-INF/manifest.xml b/source/META-INF/manifest.xml
index ce03a57..d111eff 100644
--- a/source/META-INF/manifest.xml
+++ b/source/META-INF/manifest.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/source/description.xml b/source/description.xml
index 79c0dc7..1132090 100644
--- a/source/description.xml
+++ b/source/description.xml
@@ -1,7 +1,7 @@
-
+
Favorites files
Archivos favoritos
diff --git a/source/pythonpath/easymacro.py b/source/pythonpath/easymacro.py
index 547f936..8259aca 100644
--- a/source/pythonpath/easymacro.py
+++ b/source/pythonpath/easymacro.py
@@ -34,6 +34,7 @@ import shlex
import shutil
import socket
import subprocess
+import ssl
import sys
import tempfile
import threading
@@ -41,13 +42,9 @@ import time
import traceback
import zipfile
-# ~ 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
@@ -91,14 +88,10 @@ 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:
from fernet import Fernet, InvalidToken
@@ -119,7 +112,6 @@ KEY = {
SEPARATION = 5
-
MSG_LANG = {
'es': {
'OK': 'Aceptar',
@@ -130,35 +122,36 @@ MSG_LANG = {
}
}
-
OS = platform.system()
USER = getpass.getuser()
PC = platform.node()
DESKTOP = os.environ.get('DESKTOP_SESSION', '')
INFO_DEBUG = '{}\n\n{}\n\n{}'.format(sys.version, platform.platform(), '\n'.join(sys.path))
-
IS_WIN = OS == 'Windows'
LOG_NAME = 'ZAZ'
CLIPBOARD_FORMAT_TEXT = 'text/plain;charset=utf-16'
-
PYTHON = 'python'
if IS_WIN:
PYTHON = 'python.exe'
CALC = 'calc'
WRITER = 'writer'
+
OBJ_CELL = 'ScCellObj'
OBJ_RANGE = 'ScCellRangeObj'
OBJ_RANGES = 'ScCellRangesObj'
OBJ_TYPE_RANGES = (OBJ_CELL, OBJ_RANGE, OBJ_RANGES)
+TEXT_RANGE = 'SwXTextRange'
+TEXT_RANGES = 'SwXTextRanges'
+TEXT_TYPE_RANGES = (TEXT_RANGE, TEXT_RANGES)
+
TYPE_DOC = {
'calc': 'com.sun.star.sheet.SpreadsheetDocument',
'writer': 'com.sun.star.text.TextDocument',
'impress': 'com.sun.star.presentation.PresentationDocument',
'draw': 'com.sun.star.drawing.DrawingDocument',
- # ~ 'base': 'com.sun.star.sdb.OfficeDatabaseDocument',
'base': 'com.sun.star.sdb.DocumentDataSource',
'math': 'com.sun.star.formula.FormulaProperties',
'basic': 'com.sun.star.script.BasicIDE',
@@ -197,19 +190,16 @@ MENUS_WRITER = {
'windows': '.uno:WindowList',
'help': '.uno:HelpMenu',
}
-
MENUS_APP = {
'main': MENUS_MAIN,
'calc': MENUS_CALC,
'writer': MENUS_WRITER,
}
-
EXT = {
'pdf': 'pdf',
}
-
FILE_NAME_DEBUG = 'debug.odt'
FILE_NAME_CONFIG = 'zaz-{}.json'
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
@@ -279,6 +269,12 @@ def mri(obj):
return
+def inspect(obj):
+ zaz = create_instance('net.elmau.zaz.inspect')
+ zaz.inspect(obj)
+ return
+
+
def catch_exception(f):
@wraps(f)
def func(*args, **kwargs):
@@ -454,12 +450,14 @@ def call_dispatch(url, args=()):
return
-def get_temp_file():
+def get_temp_file(only_name=False):
delete = True
if IS_WIN:
delete = False
- return tempfile.NamedTemporaryFile(delete=delete)
-
+ tmp = tempfile.NamedTemporaryFile(delete=delete)
+ if only_name:
+ tmp = tmp.name
+ return tmp
def _path_url(path):
if path.startswith('file://'):
@@ -501,6 +499,11 @@ def dict_to_property(values, uno_any=False):
return ps
+def dict_to_named(values):
+ ps = tuple([NamedValue(n, v) for n, v in values.items()])
+ return ps
+
+
def property_to_dict(values):
d = {i.Name: i.Value for i in values}
return d
@@ -934,6 +937,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):
@@ -942,7 +1006,9 @@ class LOCalc(LODocument):
def __getitem__(self, index):
if isinstance(index, str):
- index = [s.Name for s in self._sheets if s.CodeName == index][0] or index
+ code_name = [s.Name for s in self._sheets if s.CodeName == index]
+ if code_name:
+ index = code_name[0]
return LOCalcSheet(self._sheets[index], self)
def __setitem__(self, key, value):
@@ -1182,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):
@@ -1192,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
@@ -1306,7 +1376,11 @@ class LOWriter(LODocument):
@property
def selection(self):
sel = self.obj.getCurrentSelection()
- return LOTextRange(sel[0])
+ if sel.ImplementationName == TEXT_RANGES:
+ return LOTextRange(sel[0])
+ elif sel.ImplementationName == TEXT_RANGE:
+ return LOTextRange(sel)
+ return sel
def write(self, data, cursor=None):
cursor = cursor or self.selection.cursor.getEnd()
@@ -1583,7 +1657,7 @@ class LODrawImpress(LODocument):
def insert_image(self, path, **kwargs):
w = kwargs.get('width', 3000)
- h = kwargs.get('Height', 1000)
+ h = kwargs.get('Height', 3000)
x = kwargs.get('X', 1000)
y = kwargs.get('Y', 1000)
@@ -1640,6 +1714,9 @@ class LOCellRange(object):
def __getitem__(self, index):
return LOCellRange(self.obj[index], self.doc)
+ def __contains__(self, item):
+ return item.in_range(self)
+
def _init_values(self):
self._type_obj = self.obj.ImplementationName
self._type_content = EMPTY
@@ -1689,7 +1766,7 @@ class LOCellRange(object):
self.obj.setFormula(data)
else:
self.obj.setString(data)
- elif isinstance(data, (int, float)):
+ elif isinstance(data, (int, float, bool)):
self.obj.setValue(data)
elif isinstance(data, datetime.datetime):
d = data.toordinal()
@@ -1707,8 +1784,6 @@ class LOCellRange(object):
return self.obj.getDataArray()
@data.setter
def data(self, values):
- if isinstance(values, list):
- values = tuple(values)
self.obj.setDataArray(values)
@property
@@ -1716,8 +1791,6 @@ class LOCellRange(object):
return self.obj.getFormulaArray()
@formula.setter
def formula(self, values):
- if isinstance(values, list):
- values = tuple(values)
self.obj.setFormulaArray(values)
@property
@@ -1742,13 +1815,19 @@ class LOCellRange(object):
cursor.collapseToSize(cols, rows)
return LOCellRange(self.sheet[cursor.AbsoluteName].obj, self.doc)
- def copy_from(self, rango):
+ def copy_from(self, rango, formula=False):
data = rango
if isinstance(rango, LOCellRange):
- data = rango.data
+ if formula:
+ data = rango.formula
+ else:
+ data = rango.data
rows = len(data)
cols = len(data[0])
- self.to_size(rows, cols).data = data
+ if formula:
+ self.to_size(rows, cols).formula = data
+ else:
+ self.to_size(rows, cols).data = data
return
def copy_to(self, cell, formula=False):
@@ -1759,6 +1838,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
@@ -1816,6 +1899,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])
@@ -1986,6 +2073,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:
@@ -2096,7 +2187,10 @@ class EventsItem(EventsListenerBase, XItemListener):
pass
def itemStateChanged(self, event):
- pass
+ event_name = '{}_item_changed'.format(self.name)
+ if hasattr(self._controller, event_name):
+ getattr(self._controller, event_name)(event)
+ return
class EventsItemRoadmap(EventsItem):
@@ -2145,6 +2239,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
@@ -2221,8 +2354,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)
@@ -2284,6 +2417,7 @@ class UnoBaseObject(object):
@property
def parent(self):
+ ps = self.obj.getContext().PosSize
return self.obj.getContext()
def _get_possize(self, name):
@@ -2325,17 +2459,23 @@ class UnoBaseObject(object):
return self._model.Width
@width.setter
def width(self, value):
- self._model.Width = value
+ if hasattr(self.model, 'Width'):
+ self.model.Width = value
+ elif hasattr(self.obj, 'PosSize'):
+ self._set_possize('Width', value)
@property
def height(self):
- if hasattr(self._model, 'Height'):
- return self._model.Height
+ if hasattr(self.model, 'Height'):
+ return self.model.Height
ps = self.obj.getPosSize()
return ps.Height
@height.setter
def height(self, value):
- self._model.Height = value
+ if hasattr(self.model, 'Height'):
+ self.model.Height = value
+ elif hasattr(self.obj, 'PosSize'):
+ self._set_possize('Height', value)
@property
def tag(self):
@@ -2398,8 +2538,12 @@ class UnoBaseObject(object):
def move(self, origin, x=0, y=5):
if x:
self.x = origin.x + origin.width + x
+ else:
+ self.x = origin.x
if y:
self.y = origin.y + origin.height + y
+ else:
+ self.y = origin.y
return
def possize(self, origin):
@@ -2568,16 +2712,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)
@@ -2617,6 +2764,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)
@@ -2626,18 +2777,17 @@ 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
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):
@@ -2685,7 +2835,6 @@ class UnoRoadmap(UnoBaseObject):
class UnoTree(UnoBaseObject):
- @catch_exception
def __init__(self, obj, ):
super().__init__(obj)
self._tdm = None
@@ -2738,6 +2887,119 @@ class UnoTree(UnoBaseObject):
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,
@@ -2748,7 +3010,7 @@ def get_custom_class(tipo, obj):
'link': UnoLabelLink,
'roadmap': UnoRoadmap,
'tree': UnoTree,
- # ~ 'tab': UnoTab,
+ 'tab': UnoTab,
# ~ 'image': UnoImage,
# ~ 'radio': UnoRadio,
# ~ 'groupbox': UnoGroupBox,
@@ -2757,6 +3019,24 @@ def get_custom_class(tipo, obj):
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]
+
+
def add_listeners(events, control, name=''):
listeners = {
'addActionListener': EventsButton,
@@ -2764,6 +3044,7 @@ def add_listeners(events, control, name=''):
'addItemListener': EventsItem,
'addFocusListener': EventsFocus,
'addKeyListener': EventsKey,
+ 'addTabListener': EventsTab,
}
if hasattr(control, 'obj'):
control = contro.obj
@@ -2785,6 +3066,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
@@ -3174,6 +3460,7 @@ class LOChart(object):
chart_data.setData(data)
chart_data.RowDescriptions = labels
+ # ~ Bug
if tipo == 'Pie':
chart.setDiagram(chart.createInstance(self.BASE.format('Bar')))
chart.setDiagram(chart.createInstance(self.BASE.format('Pie')))
@@ -3225,6 +3512,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):
@@ -3278,6 +3588,7 @@ class LODialog(object):
'stardiv.Toolkit.UnoButtonControl': 'button',
'stardiv.Toolkit.UnoListBoxControl': 'listbox',
'stardiv.Toolkit.UnoRoadmapControl': 'roadmap',
+ 'stardiv.Toolkit.UnoMultiPageControl': 'pages',
}
return types[name]
@@ -3375,6 +3686,7 @@ class LODialog(object):
'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]
@@ -3410,11 +3722,18 @@ 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))
@@ -3427,6 +3746,9 @@ class LODialog(object):
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
@@ -3459,13 +3781,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),
@@ -3476,6 +3811,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
@@ -3507,6 +3843,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',
@@ -3520,25 +3881,50 @@ 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
+
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
@@ -3834,8 +4220,12 @@ def json_loads(data):
def get_path_extension(id):
+ path = ''
pip = CTX.getValueByName('/singletons/com.sun.star.deployment.PackageInformationProvider')
- path = _path_system(pip.getPackageLocation(id))
+ try:
+ path = _path_system(pip.getPackageLocation(id))
+ except Exception as e:
+ error(e)
return path
@@ -3979,7 +4369,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
@@ -4032,23 +4422,29 @@ def popen(command, stdin=None):
yield (e.errno, e.strerror)
-def url_open(url, options={}, json=False):
+def url_open(url, options={}, verify=True, json=False):
data = ''
+ err = ''
req = Request(url)
try:
- response = urlopen(req)
- # ~ response.info()
+ if verify:
+ response = urlopen(req)
+ else:
+ context = ssl._create_unverified_context()
+ response = urlopen(req, context=context)
except HTTPError as e:
error(e)
+ err = str(e)
except URLError as e:
error(e.reason)
+ err = str(e.reason)
else:
if json:
data = json_loads(response.read())
else:
data = response.read()
- return data
+ return data, err
def run(command, wait=False):
@@ -5025,8 +5421,6 @@ class LIBOServer(object):
return instance
-
-
# ~ controls = {
# ~ 'CheckBox': 'com.sun.star.awt.UnoControlCheckBoxModel',
# ~ 'ComboBox': 'com.sun.star.awt.UnoControlComboBoxModel',
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()