Xml description refactory

This commit is contained in:
Mauricio Baeza 2019-11-26 23:32:39 -06:00
parent 43f8bf5a88
commit 71d1c281d6
6 changed files with 224 additions and 72 deletions

2
.gitignore vendored
View File

@ -12,4 +12,6 @@ source/source/
.env/
virtual/
source/VERSION

View File

@ -15,9 +15,9 @@ For Python 3.6+
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

View File

@ -1 +1 @@
0.10.0
0.11.0

View File

@ -633,5 +633,8 @@ DATA = {
}
with open('VERSION', 'w') as f:
f.write(VERSION)
# ~ LICENSE_ACCEPT_BY = 'user' # or admin
# ~ LICENSE_SUPPRESS_ON_UPDATE = True

View File

@ -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 Enum, IntEnum
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
from string import Template
@ -96,15 +93,6 @@ 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
except ImportError:
@ -124,7 +112,6 @@ KEY = {
SEPARATION = 5
MSG_LANG = {
'es': {
'OK': 'Aceptar',
@ -135,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',
@ -202,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'
@ -284,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):
@ -459,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://'):
@ -506,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
@ -1008,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):
@ -1376,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()
@ -1653,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)
@ -1710,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
@ -1759,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()
@ -1777,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
@ -1786,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
@ -1812,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):
@ -1833,6 +1842,33 @@ class LOCellRange(object):
self.sheet.obj.copyRange(self.address, source.range_address)
return
def transpose(self, formula=False):
data = self.data
if formula:
data = self.formula
data = tuple(zip(*data))
self.clear(1023)
self[0,0].copy_from(data, formula=formula)
return
def transpose2(self):
# ~ 'Flags': 'A',
# ~ 'FormulaCommand': 0,
# ~ 'SkipEmptyCells': False,
# ~ 'AsLink': False,
# ~ 'MoveMode': 4,
args = {
'Transpose': True,
}
args = dict_to_property(args)
self.select()
copy()
self.clear(1023)
self[0,0].select()
call_dispatch('.uno:InsertContents', args)
set_clipboard('')
return
def offset(self, row=1, col=0):
ra = self.obj.getRangeAddress()
col = ra.EndColumn + col
@ -1935,6 +1971,10 @@ class LOCellRange(object):
def auto_format(self, value):
self.obj.autoFormat(value)
def auto_width(self):
self.obj.Columns.OptimalWidth = True
return
def insert_image(self, path, **kwargs):
s = self.obj.Size
w = kwargs.get('width', s.Width)
@ -2056,6 +2096,22 @@ class LOCellRange(object):
found = self.obj.replaceAll(descriptor)
return found
@property
def validation(self):
return self.obj.Validation
@validation.setter
def validation(self, values):
is_list = False
current = self.validation
for k, v in values.items():
if k == 'Type' and v == 6:
is_list = True
if k == 'Formula1' and is_list:
if isinstance(v, (tuple, list)):
v = ';'.join(['"{}"'.format(i) for i in v])
setattr(current, k, v)
self.obj.Validation = current
class EventsListenerBase(unohelper.Base, XEventListener):
@ -2178,7 +2234,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):
@ -2447,23 +2506,39 @@ class UnoBaseObject(object):
return self._model.Width
@width.setter
def width(self, value):
if hasattr(self.obj, 'PosSize'):
self._set_possize('Width', value)
else:
self._model.Width = value
self.model.Width = value
@property
def ps_width(self):
return self._get_possize('Width')
@ps_width.setter
def ps_width(self, value):
self._set_possize('Width', value)
@property
def height(self):
if hasattr(self._model, 'Height'):
return self._model.Height
ps = self.obj.getPosSize()
return ps.Height
return self.model.Height
@height.setter
def height(self, value):
if hasattr(self.obj, 'PosSize'):
self._set_possize('Height', value)
else:
self._model.Height = value
self.model.Height = value
@property
def ps_height(self):
return self._get_possize('Height')
@ps_height.setter
def ps_height(self, value):
self._set_possize('Height', value)
@property
def size(self):
ps = self.obj.getPosSize()
return (ps.Width, ps.Height)
@size.setter
def size(self, value):
ps = self.obj.getPosSize()
ps.Width = value[0]
ps.Height = value[1]
self.obj.setPosSize(ps.X, ps.Y, ps.Width, ps.Height, SIZE)
@property
def tag(self):
@ -2526,8 +2601,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):
@ -2771,7 +2850,6 @@ 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()
return
@ -3022,7 +3100,6 @@ def get_control_model(control):
return services[control]
@catch_exception
def add_listeners(events, control, name=''):
listeners = {
'addActionListener': EventsButton,
@ -3891,7 +3968,6 @@ class LOWindow(object):
return properties
@catch_exception
def add_control(self, properties):
tipo = properties.pop('Type').lower()
root = properties.pop('Root', '')
@ -4207,8 +4283,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
@ -4405,23 +4485,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):
@ -4475,7 +4561,7 @@ def _zippwd(source, target, pwd):
# ~ Export ok
def zip(source, target='', mode='w', pwd=''):
def zip_files(source, target='', mode='w', pwd=''):
if pwd:
return _zippwd(source, target, pwd)
@ -5398,8 +5484,6 @@ class LIBOServer(object):
return instance
# ~ controls = {
# ~ 'CheckBox': 'com.sun.star.awt.UnoControlCheckBoxModel',
# ~ 'ComboBox': 'com.sun.star.awt.UnoControlComboBoxModel',

View File

@ -53,18 +53,23 @@ class LiboXML(object):
'help': 'application/vnd.sun.star.help',
'component': 'application/vnd.sun.star.uno-components',
}
NAME_SPACES = {
NS_MANIFEST = {
'manifest_version': '1.2',
'manifest': 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0',
'xmlns:loext': 'urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0',
}
NS_DESCRIPTION = {
'xmlns': 'http://openoffice.org/extensions/description/2006',
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
'xmlns:d': 'http://openoffice.org/extensions/description/2006',
}
def __init__(self):
self._manifest = None
self._paths = []
def _save_path(self, attr):
self._paths.append(attr['{{{}}}full-path'.format(self.NAME_SPACES['manifest'])])
self._paths.append(attr['{{{}}}full-path'.format(self.NS_MANIFEST['manifest'])])
return
def _clean(self, name, nodes):
@ -86,17 +91,17 @@ class LiboXML(object):
def new_manifest(self, data):
attr = {
'manifest:version': self.NAME_SPACES['manifest_version'],
'xmlns:manifest': self.NAME_SPACES['manifest'],
'xmlns:loext': self.NAME_SPACES['xmlns:loext'],
'manifest:version': self.NS_MANIFEST['manifest_version'],
'xmlns:manifest': self.NS_MANIFEST['manifest'],
'xmlns:loext': self.NS_MANIFEST['xmlns:loext'],
}
self._manifest = ET.Element('manifest:manifest', attr)
return self.add_data_manifest(data)
def parse_manifest(self, data):
ET.register_namespace('manifest', self.NAME_SPACES['manifest'])
ET.register_namespace('manifest', self.NS_MANIFEST['manifest'])
self._manifest = ET.fromstring(data)
data = {'xmlns:loext': self.NAME_SPACES['xmlns:loext']}
data = {'xmlns:loext': self.NS_MANIFEST['xmlns:loext']}
self._manifest.attrib.update(**data)
self._clean('manifest', self._manifest)
return
@ -116,6 +121,60 @@ class LiboXML(object):
ET.SubElement(self._manifest, node_name, attr)
return self._get_xml(self._manifest)
def new_description(self, data):
doc = ET.Element('description', self.NS_DESCRIPTION)
key = 'identifier'
ET.SubElement(doc, key, data[key])
key = 'version'
ET.SubElement(doc, key, data[key])
key = 'display-name'
node = ET.SubElement(doc, key)
for k, v in data[key].items():
sn = ET.SubElement(node, 'name', {'lang': k})
sn.text = v
node = ET.SubElement(doc, 'extension-description')
for k in data[key].keys():
attr = {
'lang': k,
'xlink:href': f'description/desc_{k}.txt',
}
ET.SubElement(node, 'src', attr)
key = 'icon'
node = ET.SubElement(doc, key)
attr = {'xlink:href': f"images/{data[key]}"}
ET.SubElement(node, 'default', attr)
key = 'publisher'
node = ET.SubElement(doc, key)
for k, v in data[key].items():
attr = {
'xlink:href': v['link'],
'lang': k,
}
sn = ET.SubElement(node, 'name', attr)
sn.text = v['text']
key = 'display-name'
node = ET.SubElement(doc, 'registration')
attr = {
'accept-by': 'user',
'suppress-on-update': 'true',
}
node = ET.SubElement(node, 'simple-license', attr)
for k in data[key].keys():
attr = {
'xlink:href': f"{DIRS['registration']}/license_{k}.txt",
'lang': k
}
ET.SubElement(node, 'license-text', attr)
return self._get_xml(doc)
def _get_xml(self, doc):
xml = parseString(ET.tostring(doc, encoding='utf-8'))
return xml.toprettyxml(indent=' ', encoding='utf-8').decode('utf-8')
@ -325,6 +384,13 @@ def _update_files():
data = xml.new_manifest(DATA['manifest'])
_save(path, data)
path = _join(path_source, FILES['description'])
data = xml.new_description(DATA['description'])
_save(path, data)
path = _join(path_source, DIRS['office'])
_mkdir(path)
path = _join(path_source, DIRS['office'], FILES['shortcut'])
@ -333,9 +399,6 @@ def _update_files():
path = _join(path_source, FILES['addons'])
_save(path, DATA['addons'])
path = _join(path_source, FILES['description'])
_save(path, DATA['description'])
if TYPE_EXTENSION == 3:
path = _join(path_source, FILES['addin'])
_save(path, DATA['addin'])