From bac1512063abb2c32293a351d5dca319baee214a Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Sun, 10 Nov 2019 15:25:24 -0600 Subject: [PATCH] Update zaz and easymacro --- .gitignore | 2 + CHANGELOG | 11 +- VERSION | 2 +- conf.py | 28 +- easymacro.py | 3264 ++++++++++++++++++++++-- files/ZAZBarCode_v0.5.0.oxt | Bin 0 -> 297020 bytes files/zazbarcode.update.xml | 4 +- source/META-INF/manifest.xml | 10 +- source/ZAZBarCode.py | 27 +- source/description.xml | 2 +- source/locales/base.pot | 20 +- source/locales/en/LC_MESSAGES/base.mo | Bin 356 -> 356 bytes source/locales/en/LC_MESSAGES/base.po | 28 +- source/locales/eo/LC_MESSAGES/base.po | 24 +- source/locales/es/LC_MESSAGES/base.mo | Bin 815 -> 865 bytes source/locales/es/LC_MESSAGES/base.po | 28 +- source/pythonpath/easymacro.py | 3267 +++++++++++++++++++++++-- zaz.py | 245 +- 18 files changed, 6405 insertions(+), 557 deletions(-) create mode 100644 files/ZAZBarCode_v0.5.0.oxt diff --git a/.gitignore b/.gitignore index 03b69a9..b621cc9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,6 @@ docs/ virtual/ + - Update library easymacro.py +*.po~ diff --git a/CHANGELOG b/CHANGELOG index 50db289..2a0b076 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,16 +1,25 @@ +v 0.5.0 [10-nov-2019] +--------------------- + - Update library easymacro.py + - Update library zaz.py + + v 0.4.0 [27-sep-2019] +--------------------- - Update library easymacro.py - Add icon in command button v 0.3.0 [18-sep-2019] +--------------------- - Add support for generate barcode by code v 0.2.1 [16-sep-2019] - +--------------------- - Fix #1 + v 0.2.0 [14-sep-2019] --------------------- - Add support for spanish 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 b0be8a7..6bd2354 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 = 'ZAZBarCode' @@ -318,6 +318,9 @@ PATHS = { 'regmerge': '/usr/lib/libreoffice/program/regmerge', 'soffice': ('soffice', PROGRAM, FILE_TEST), 'install': ('unopkg', 'add', '-v', '-f', '-s'), + 'profile': '/home/mau/.config/libreoffice/4/user', + 'gettext': PATH_PYGETTEXT, + 'msgmerge': PATH_MSGMERGE, } @@ -540,20 +543,6 @@ FILE_ADDONS = f""" """ -NODE_ADDONS = '\n ' -if TYPE_EXTENSION > 1: - NODE_ADDONS = f'\n ' -if TYPE_EXTENSION == 3: - NODE_ADDONS += '\n ' - -FILE_MANIFEST = f""" - - - {NODE_ADDONS} - -""" - - FILE_UPDATE = '' if URL_XML_UPDATE: FILE_UPDATE = f""" @@ -738,9 +727,16 @@ FILE_SHORTCUTS = f""" """ +DATA_MANIFEST = [FILES['py'], f"Office/{FILES['shortcut']}", 'Addons.xcu'] +if TYPE_EXTENSION > 1: + DATA_MANIFEST.append(FILES['rdb']) +if TYPE_EXTENSION == 3: + DATA_MANIFEST.append('CalcAddIn.xcu') + + DATA = { 'py': FILE_PY, - 'manifest': FILE_MANIFEST, + 'manifest': DATA_MANIFEST, 'description': FILE_DESCRIPTION, 'addons': FILE_ADDONS, 'update': FILE_UPDATE, diff --git a/easymacro.py b/easymacro.py index 3bf53b9..df89fbb 100644 --- a/easymacro.py +++ b/easymacro.py @@ -18,9 +18,11 @@ # ~ along with ZAZ. If not, see . import base64 +import csv import ctypes import datetime import errno +import gettext import getpass import hashlib import json @@ -30,6 +32,7 @@ import platform import re import shlex import shutil +import socket import subprocess import sys import tempfile @@ -38,12 +41,11 @@ 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 urllib.request import Request, urlopen +from urllib.error import URLError, HTTPError from string import Template from subprocess import PIPE @@ -59,27 +61,56 @@ import mailbox import uno import unohelper from com.sun.star.util import Time, Date, DateTime -from com.sun.star.beans import PropertyValue +from com.sun.star.beans import PropertyValue, NamedValue from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS from com.sun.star.awt.MessageBoxResults import YES from com.sun.star.awt.PosSize import POSSIZE, SIZE from com.sun.star.awt import Size, Point +from com.sun.star.awt import Rectangle +from com.sun.star.awt import KeyEvent +from com.sun.star.awt.KeyFunction import QUIT from com.sun.star.datatransfer import XTransferable, DataFlavor 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 +from com.sun.star.awt import XMouseMotionListener +from com.sun.star.util import XModifyListener +from com.sun.star.awt import XTopWindowListener +from com.sun.star.awt import XWindowListener +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 + try: from fernet import Fernet, InvalidToken - CRYPTO = True except ImportError: - CRYPTO = False + pass +ID_EXTENSION = '' + +DIR = { + 'images': 'images', + 'locales': 'locales', +} + +KEY = { + 'enter': 1280, +} + +SEPARATION = 5 + MSG_LANG = { 'es': { 'OK': 'Aceptar', @@ -90,38 +121,48 @@ 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', + 'main': 'com.sun.star.frame.StartModule', } NODE_MENUBAR = 'private:resource/menubar/menubar' +MENUS_MAIN = { + 'file': '.uno:PickList', + 'tools': '.uno:ToolsMenu', + 'help': '.uno:HelpMenu', +} MENUS_CALC = { 'file': '.uno:PickList', 'edit': '.uno:EditMenu', @@ -148,18 +189,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' @@ -174,13 +213,13 @@ log = logging.getLogger(__name__) _start = 0 _stop_thread = {} TIMEOUT = 10 +SECONDS_DAY = 60 * 60 * 24 CTX = uno.getComponentContext() SM = CTX.getServiceManager() -# ~ Export ok def create_instance(name, with_context=False): if with_context: instance = SM.createInstanceWithContext(name, CTX) @@ -189,28 +228,35 @@ def create_instance(name, with_context=False): return instance -def _get_app_config(key, node_name): +def get_app_config(node_name, key=''): name = 'com.sun.star.configuration.ConfigurationProvider' service = 'com.sun.star.configuration.ConfigurationAccess' cp = create_instance(name, True) node = PropertyValue(Name='nodepath', Value=node_name) try: ca = cp.createInstanceWithArguments(service, (node,)) - if ca and (ca.hasByName(key)): - data = ca.getPropertyValue(key) - return data + if ca and not key: + return ca + if ca and ca.hasByName(key): + return ca.getPropertyValue(key) except Exception as e: - log.error(e) + error(e) return '' -LANGUAGE = _get_app_config('ooLocale', 'org.openoffice.Setup/L10N/') +# ~ FILTER_PDF = '/org.openoffice.Office.Common/Filter/PDF/Export/' +LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale') LANG = LANGUAGE.split('-')[0] -NAME = TITLE = _get_app_config('ooName', 'org.openoffice.Setup/Product') -VERSION = _get_app_config('ooSetupVersion', 'org.openoffice.Setup/Product') +NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName') +VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion') + +nd = '/org.openoffice.Office.Calc/Calculate/Other/Date' +d = get_app_config(nd, 'DD') +m = get_app_config(nd, 'MM') +y = get_app_config(nd, 'YY') +DATE_OFFSET = datetime.date(y, m, d).toordinal() -# ~ Export ok def mri(obj): m = create_instance('mytools.Mri') if m is None: @@ -239,7 +285,6 @@ class LogWin(object): def __init__(self, doc): self.doc = doc - self.doc.Title = FILE_NAME_DEBUG def write(self, info): text = self.doc.Text @@ -249,34 +294,30 @@ class LogWin(object): return -# ~ Export ok def info(data): log.info(data) return -# ~ Export ok -def debug(info): +def debug(*info): if IS_WIN: doc = get_document(FILE_NAME_DEBUG) if doc is None: - # ~ doc = new_doc('writer') return doc = LogWin(doc.obj) - doc.write(info) + doc.write(str(info)) return - log.debug(str(info)) + data = [str(d) for d in info] + log.debug('\t'.join(data)) return -# ~ Export ok def error(info): log.error(info) return -# ~ Export ok def save_log(path, data): with open(path, 'a') as out: out.write('{} -{}- '.format(str(now())[:19], LOG_NAME)) @@ -292,11 +333,34 @@ 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 get_date(year, month, day, hour=-1, minute=-1, second=-1): + if hour > -1 or minute > -1 or second > -1: + h = hour + m = minute + s = second + if h == -1: + h = 0 + if m == -1: + m = 0 + if s == -1: + s = 0 + d = datetime.datetime(year, month, day, h, m, s) + else: + d = datetime.date(year, month, day) + return d -# ~ Export ok def get_config(key='', default=None, prefix='config'): path_json = FILE_NAME_CONFIG.format(prefix) values = None @@ -314,7 +378,6 @@ def get_config(key='', default=None, prefix='config'): return values -# ~ Export ok def set_config(key, value, prefix='config'): path_json = FILE_NAME_CONFIG.format(prefix) path = join(get_config_path('UserConfig'), path_json) @@ -322,10 +385,9 @@ def set_config(key, value, prefix='config'): values[key] = value with open(path, 'w', encoding='utf-8') as fh: json.dump(values, fh, ensure_ascii=False, sort_keys=True, indent=4) - return + return True -# ~ Export ok def sleep(seconds): time.sleep(seconds) return @@ -342,7 +404,6 @@ def _(msg): return MSG_LANG[L][msg] -# ~ Export ok def msgbox(message, title=TITLE, buttons=MSG_BUTTONS.BUTTONS_OK, type_msg='infobox'): """ Create message box type_msg: infobox, warningbox, errorbox, querybox, messbox @@ -354,18 +415,15 @@ def msgbox(message, title=TITLE, buttons=MSG_BUTTONS.BUTTONS_OK, type_msg='infob return mb.execute() -# ~ Export ok def question(message, title=TITLE): res = msgbox(message, title, MSG_BUTTONS.BUTTONS_YES_NO, 'querybox') return res == YES -# ~ Export ok def warning(message, title=TITLE): return msgbox(message, title, type_msg='warningbox') -# ~ Export ok def errorbox(message, title=TITLE): return msgbox(message, title, type_msg='errorbox') @@ -374,12 +432,10 @@ def get_desktop(): return create_instance('com.sun.star.frame.Desktop', True) -# ~ Export ok def get_dispatch(): return create_instance('com.sun.star.frame.DispatchHelper') -# ~ Export ok def call_dispatch(url, args=()): frame = get_document().frame dispatch = get_dispatch() @@ -387,7 +443,6 @@ def call_dispatch(url, args=()): return -# ~ Export ok def get_temp_file(): delete = True if IS_WIN: @@ -407,7 +462,6 @@ def _path_system(path): return path -# ~ Export ok def exists_app(name): try: dn = subprocess.DEVNULL @@ -418,12 +472,10 @@ def exists_app(name): return True -# ~ Export ok def exists_path(path): return Path(path).exists() -# ~ Export ok def get_type_doc(obj): for k, v in TYPE_DOC.items(): if obj.supportsService(v): @@ -443,12 +495,99 @@ def property_to_dict(values): return d +def set_properties(model, properties): + if 'X' in properties: + properties['PositionX'] = properties.pop('X') + if 'Y' in properties: + properties['PositionY'] = properties.pop('Y') + keys = tuple(properties.keys()) + values = tuple(properties.values()) + model.setPropertyValues(keys, values) + return + + def array_to_dict(values): d = {r[0]: r[1] for r in values} return d # ~ Custom classes +class ObjectBase(object): + + def __init__(self, obj): + self._obj = obj + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + def __getitem__(self, index): + return self.obj[index] + + def __getattr__(self, name): + a = None + if name == 'obj': + a = super().__getattr__(name) + else: + if hasattr(self.obj, name): + a = getattr(self.obj, name) + return a + + @property + def obj(self): + return self._obj + @obj.setter + def obj(self, value): + self._obj = value + + +class LOObjectBase(object): + + def __init__(self, obj): + self.__dict__['_obj'] = obj + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + return True + + def __setattr__(self, name, value): + print('BASE__setattr__', name) + if name == '_obj': + super().__setattr__(name, value) + else: + self.obj.setPropertyValue(name, value) + + # ~ def _try_for_method(self, name): + # ~ a = None + # ~ m = 'get{}'.format(name) + # ~ if hasattr(self.obj, m): + # ~ a = getattr(self.obj, m)() + # ~ else: + # ~ a = getattr(self.obj, name) + # ~ return a + + def __getattr__(self, name): + print('BASE__getattr__', name) + if name == 'obj': + a = super().__getattr__(name) + else: + a = self.obj.getPropertyValue(name) + # ~ Bug + if a is None: + msg = 'Error get: {} - {}'.format(self.obj.ImplementationName, name) + error(msg) + raise Exception(msg) + return a + + @property + def obj(self): + return self._obj + + class LODocument(object): def __init__(self, obj): @@ -457,23 +596,27 @@ 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() + self._cc = self.obj.getCurrentController() return @property def obj(self): return self._obj - @property - def type(self): - return self._type_doc - @property def title(self): return self.obj.getTitle() + @title.setter + def title(self, value): + self.obj.setTitle(value) + + @property + def uid(self): + return self.obj.RuntimeUID + + @property + def type(self): + return self._type_doc @property def frame(self): @@ -502,7 +645,7 @@ class LODocument(object): @property def visible(self): w = self._cc.getFrame().getContainerWindow() - return w.Visible + return w.isVisible() @visible.setter def visible(self, value): w = self._cc.getFrame().getContainerWindow() @@ -515,6 +658,11 @@ class LODocument(object): def zoom(self, value): self._cc.ZoomValue = value + @property + def table_auto_formats(self): + taf = create_instance('com.sun.star.sheet.TableAutoFormats') + return taf.ElementNames + def create_instance(self, name): obj = self.obj.createInstance(name) return obj @@ -568,19 +716,320 @@ class LODocument(object): return path_pdf -class LOCalc(LODocument): +class FormControlBase(object): + EVENTS = { + 'action': 'actionPerformed', + 'click': 'mousePressed', + } + TYPES = { + 'actionPerformed': 'XActionListener', + 'mousePressed': 'XMouseListener', + } def __init__(self, obj): - super().__init__(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): + return self._obj.getName() + @name.setter + def name(self, value): + self._obj.setName(value) + + +class LOForms(ObjectBase): + + def __init__(self, obj, doc): + self._doc = doc + super().__init__(obj) + + def __getitem__(self, index): + form = super().__getitem__(index) + return LOForm(form) + + @property + def doc(self): + return self._doc + + @property + def count(self): + return self.obj.getCount() + + @property + def names(self): + return self.obj.getElementNames() + + def exists(self, name): + return name in self.names + + def insert(self, name): + form = self.doc.create_instance('com.sun.star.form.component.Form') + self.obj.insertByName(name, form) + return self[name] + + def remove(self, index): + if isinstance(index, int): + self.obj.removeByIndex(index) + else: + self.obj.removeByName(index) + return + + +class LOCellStyle(LOObjectBase): + + def __init__(self, obj): + super().__init__(obj) + + @property + def name(self): + return self.obj.Name + + def apply(self, properties): + set_properties(self.obj, properties) + return + + +class LOCellStyles(object): + + def __init__(self, obj): + self._obj = obj + + def __len__(self): + return len(self.obj) + + def __getitem__(self, index): + return LOCellStyle(self.obj[index]) + + def __setitem__(self, key, value): + self.obj[key] = value + + def __delitem__(self, key): + if not isinstance(key, str): + key = key.Name + del self.obj[key] + + def __contains__(self, item): + return item in self.obj + + @property + def obj(self): + return self._obj + + @property + def names(self): + return self.obj.ElementNames + + def apply(self, style, properties): + set_properties(style, properties) + 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): + super().__init__(obj) + self._sheets = obj.getSheets() + + def __getitem__(self, index): + if isinstance(index, str): + 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): + self._sheets[key] = value + + def __contains__(self, item): + return item in self.obj.Sheets + + @property + def headers(self): + return self._cc.ColumnRowHeaders + @headers.setter + def headers(self, value): + self._cc.ColumnRowHeaders = value + + @property + def tabs(self): + return self._cc.SheetTabs + @tabs.setter + def tabs(self, value): + self._cc.SheetTabs = value + @property def active(self): return LOCalcSheet(self._cc.getActiveSheet(), self) + def activate(self, sheet): + obj = sheet + if isinstance(sheet, LOCalcSheet): + obj = sheet.obj + elif isinstance(sheet, str): + obj = self[sheet].obj + self._cc.setActiveSheet(obj) + return + @property def selection(self): sel = self.obj.getCurrentSelection() @@ -588,6 +1037,97 @@ class LOCalc(LODocument): sel = LOCellRange(sel, self) return sel + @property + def sheets(self): + return LOCalcSheets(self._sheets, self) + + @property + def names(self): + return self.sheets.names + + @property + def cell_style(self): + obj = self.obj.getStyleFamilies()['CellStyles'] + return LOCellStyles(obj) + + def create(self): + return self.obj.createInstance('com.sun.star.sheet.Spreadsheet') + + def insert(self, name, pos=-1): + # ~ sheet = obj.createInstance('com.sun.star.sheet.Spreadsheet') + # ~ obj.Sheets['New'] = sheet + index = pos + if pos < 0: + index = self._sheets.Count + pos + 1 + if isinstance(name, str): + self._sheets.insertNewByName(name, index) + else: + for n in name: + self._sheets.insertNewByName(n, index) + name = n + return LOCalcSheet(self._sheets[name], self) + + def move(self, name, pos=-1): + return self.sheets.move(name, pos) + + def remove(self, name): + return self.sheets.remove(name) + + def copy(self, source='', target='', pos=-1): + index = pos + if pos < 0: + index = self._sheets.Count + pos + 1 + + names = source + if not names: + names = self.names + elif isinstance(source, str): + names = (source,) + + new_names = target + if not target: + new_names = [n + '_2' for n in names] + elif isinstance(target, str): + new_names = (target,) + + for i, ns in enumerate(names): + self.sheets.copy(ns, new_names[i], index + i) + + return LOCalcSheet(self._sheets[index], self) + + def copy_from(self, doc, source='', target='', pos=-1): + index = pos + if pos < 0: + index = self._sheets.Count + pos + 1 + + names = source + if not names: + names = doc.names + elif isinstance(source, str): + names = (source,) + + new_names = target + if not target: + new_names = names + elif isinstance(target, str): + new_names = (target,) + + for i, n in enumerate(names): + self._sheets.importSheet(doc.obj, n, index + i) + self.sheets[index + i].name = new_names[i] + + # ~ doc.getCurrentController().setActiveSheet(sheet) + # ~ For controls in sheet + # ~ doc.getCurrentController().setFormDesignMode(False) + + return LOCalcSheet(self._sheets[index], self) + + def sort(self, reverse=False): + names = sorted(self.names, reverse=reverse) + for i, n in enumerate(names): + self.sheets.move(n, i) + return + def get_cell(self, index=None): """ index is str 'A1' @@ -608,6 +1148,72 @@ class LOCalc(LODocument): self._cc.select(r) return + def create_cell_style(self, name=''): + obj = self.create_instance('com.sun.star.style.CellStyle') + if name: + self.cell_style[name] = obj + return LOCellStyle(obj) + + def clear_undo(self): + self.obj.getUndoManager().clear() + return + + def filter_by_color(self, cell=None): + if cell is None: + cell = self.selection.first + cr = cell.current_region + col = cell.column - cr.column + rangos = cell.get_column(col).visible + for r in rangos: + for row in range(r.rows): + c = r[row, 0] + if c.back_color != cell.back_color: + c.rows_visible = False + return + + +class LOCalcSheets(object): + + def __init__(self, obj, doc): + self._obj = obj + self._doc = doc + + def __getitem__(self, index): + return LOCalcSheet(self.obj[index], self.doc) + + @property + def obj(self): + return self._obj + + @property + def doc(self): + return self._doc + + @property + def count(self): + return self.obj.Count + + @property + def names(self): + return self.obj.ElementNames + + def copy(self, name, new_name, pos): + self.obj.copyByName(name, new_name, pos) + return + + def move(self, name, pos): + index = pos + if pos < 0: + index = self.count + pos + 1 + sheet = self.obj[name] + self.obj.moveByName(sheet.Name, index) + return + + def remove(self, name): + sheet = self.obj[name] + self.obj.removeByName(sheet.Name) + return + class LOCalcSheet(object): @@ -619,8 +1225,16 @@ class LOCalcSheet(object): def __getitem__(self, index): return LOCellRange(self.obj[index], self.doc) + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + def _init_values(self): - return + self._events = None + self._dp = self.obj.getDrawPage() + self._images = {i.Name: LOImage(i) for i in self._dp} @property def obj(self): @@ -630,6 +1244,95 @@ class LOCalcSheet(object): def doc(self): return self._doc + @property + def images(self): + return self._images + + @property + def name(self): + return self._obj.Name + @name.setter + def name(self, value): + self._obj.Name = value + + @property + def code_name(self): + return self._obj.CodeName + @code_name.setter + def code_name(self, value): + self._obj.CodeName = value + + @property + def color(self): + return self._obj.TabColor + @color.setter + def color(self, value): + self._obj.TabColor = get_color(value) + + @property + def active(self): + return self.doc.selection.first + + def activate(self): + self.doc.activate(self.obj) + return + + @property + def visible(self): + return self.obj.IsVisible + @visible.setter + def visible(self, value): + self.obj.IsVisible = value + + @property + def is_protected(self): + return self._obj.isProtected() + + @property + def password(self): + return '' + @visible.setter + def password(self, value): + self.obj.protect(value) + + def unprotect(self, value): + try: + self.obj.unprotect(value) + return True + except: + pass + return False + + def get_cursor(self, cell): + return self.obj.createCursorByRange(cell) + + def exists_chart(self, name): + return name in self.obj.Charts.ElementNames + + @property + def forms(self): + return LOForms(self._dp.getForms(), self.doc) + + @property + def events(self): + return self._events + @events.setter + def events(self, controllers): + self._events = controllers + self._connect_listeners() + + def _connect_listeners(self): + if self.events is None: + return + + listeners = { + 'addModifyListener': EventsModify, + } + for key, value in listeners.items(): + getattr(self.obj, key)(listeners[key](self.events)) + print('add_listener') + return + class LOWriter(LODocument): @@ -652,18 +1355,50 @@ class LOWriter(LODocument): def cursor(self): return self.text.createTextCursor() + @property + def paragraphs(self): + return [LOTextRange(p) for p in self.text] + @property def selection(self): - sel = self._cc.getSelection() - return LOTextRange(sel[0]) + sel = self.obj.getCurrentSelection() + 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() + if data.startswith('\n'): + c = data.split('\n') + for i in range(len(c)-1): + self.text.insertControlCharacter(cursor, PARAGRAPH_BREAK, False) + else: + self.text.insertString(cursor, data, False) + return + + def insert_table(self, data, cursor=None): + cursor = cursor or self.selection.cursor.getEnd() + table = self.obj.createInstance('com.sun.star.text.TextTable') + rows = len(data) + cols = len(data[0]) + table.initialize(rows, cols) + self.insert_content(cursor, table) + table.DataArray = data + return WriterTable(table) + + def create_chart(self, tipo, cursor=None): + cursor = cursor or self.selection.cursor.getEnd() + chart = LOChart(None, tipo) + chart.cursor = cursor + chart.doc = self + return chart def insert_content(self, cursor, data, replace=False): self.text.insertTextContent(cursor, data, replace) return - # ~ tt = doc.createInstance('com.sun.star.text.TextTable') - # ~ tt.initialize(5, 2) - # ~ f = doc.createInstance('com.sun.star.text.TextFrame') # ~ f.setSize(Size(10000, 500)) @@ -679,16 +1414,76 @@ class LOWriter(LODocument): self.insert_content(cursor, image) return + def go_start(self): + cursor = self._cc.getViewCursor() + cursor.gotoStart(False) + return cursor + + def go_end(self): + cursor = self._cc.getViewCursor() + cursor.gotoEnd(False) + return cursor + + def select(self, text): + 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): def __init__(self, obj): self._obj = obj + self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph' + self._is_table = self.obj.ImplementationName == 'SwXTextTable' @property def obj(self): return self._obj + @property + def is_paragraph(self): + return self._is_paragraph + + @property + def is_table(self): + return self._is_table + @property def string(self): return self.obj.String @@ -702,10 +1497,139 @@ class LOTextRange(object): return self.text.createTextCursorByRange(self.obj) -class LOBase(LODocument): +class LOBase(object): + TYPES = { + str: 'setString', + int: 'setInt', + float: 'setFloat', + bool: 'setBoolean', + Date: 'setDate', + Time: 'setTime', + DateTime: 'setTimestamp', + } + # ~ setArray + # ~ setBinaryStream + # ~ setBlob + # ~ setByte + # ~ setBytes + # ~ setCharacterStream + # ~ setClob + # ~ setNull + # ~ setObject + # ~ setObjectNull + # ~ setObjectWithInfo + # ~ setPropertyValue + # ~ setRef + def __init__(self, name, path='', **kwargs): + self._name = name + self._path = path + self._dbc = create_instance('com.sun.star.sdb.DatabaseContext') + if path: + path_url = _path_url(path) + db = self._dbc.createInstance() + db.URL = 'sdbc:embedded:firebird' + db.DatabaseDocument.storeAsURL(path_url, ()) + if not self.exists: + self._dbc.registerDatabaseLocation(name, path_url) + else: + if name.startswith('odbc:'): + self._con = self._odbc(name, kwargs) + else: + db = self._dbc.getByName(name) + self.path = _path_system(self._dbc.getDatabaseLocation(name)) + self._con = db.getConnection('', '') - def __init__(self, obj): - super().__init__(obj) + if self._con is None: + msg = 'Not connected to: {}'.format(name) + else: + msg = 'Connected to: {}'.format(name) + debug(msg) + + def _odbc(self, name, kwargs): + dm = create_instance('com.sun.star.sdbc.DriverManager') + args = dict_to_property(kwargs) + try: + con = dm.getConnectionWithInfo('sdbc:{}'.format(name), args) + return con + except Exception as e: + error(str(e)) + return None + + @property + def obj(self): + return self._obj + + @property + def name(self): + return self._name + + @property + def connection(self): + return self._con + + @property + def path(self): + return self._path + @path.setter + def path(self, value): + self._path = value + + @property + def exists(self): + return self._dbc.hasRegisteredDatabase(self.name) + + @classmethod + def register(self, path, name): + if not self._dbc.hasRegisteredDatabase(name): + self._dbc.registerDatabaseLocation(name, _path_url(path)) + return + + def revoke(self, name): + self._dbc.revokeDatabaseLocation(name) + return True + + def save(self): + # ~ self._db.connection.commit() + # ~ self._db.connection.getTables().refresh() + # ~ oDisp.executeDispatch(oFrame,".uno:DBRefreshTables", "", 0, Array()) + self._obj.DatabaseDocument.store() + self.refresh() + return + + def close(self): + self._con.close() + return + + def refresh(self): + self._con.getTables().refresh() + return + + def get_tables(self): + tables = self._con.getTables() + tables = [tables.getByIndex(i) for i in range(tables.Count)] + return tables + + def cursor(self, sql, params): + cursor = self._con.prepareStatement(sql) + for i, v in enumerate(params, 1): + if not type(v) in self.TYPES: + error('Type not support') + debug((i, type(v), v, self.TYPES[type(v)])) + getattr(cursor, self.TYPES[type(v)])(i, v) + return cursor + + def execute(self, sql, params): + debug(sql) + if params: + cursor = self.cursor(sql, params) + cursor.execute() + else: + cursor = self._con.createStatement() + cursor.execute(sql) + # ~ resulset = cursor.executeQuery(sql) + # ~ rows = cursor.executeUpdate(sql) + self.save() + return cursor class LODrawImpress(LODocument): @@ -770,12 +1694,15 @@ class LOCellRange(object): def __enter__(self): return self - def __exit__(self, *args): + def __exit__(self, exc_type, exc_value, traceback): pass 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 @@ -825,31 +1752,124 @@ 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() + t = (data - datetime.datetime.fromordinal(d)).seconds / SECONDS_DAY + self.obj.setValue(d - DATE_OFFSET + t) + elif isinstance(data, datetime.date): + d = data.toordinal() + self.obj.setValue(d - DATE_OFFSET) + elif isinstance(data, datetime.time): + d = (data.hour * 3600 + data.minute * 60 + data.second) / SECONDS_DAY + self.obj.setValue(d) @property def data(self): return self.obj.getDataArray() @data.setter def data(self, values): - if isinstance(values, list): - values = tuple(values) self.obj.setDataArray(values) - def offset(self, col=1, row=0): + @property + def formula(self): + return self.obj.getFormulaArray() + @formula.setter + def formula(self, values): + self.obj.setFormulaArray(values) + + @property + def column(self): a = self.address - col = a.Column + col - row = a.Row + row - return LOCellRange(self.sheet[row,col], self.doc) + if hasattr(a, 'Column'): + c = a.Column + else: + c = a.StartColumn + return c + + @property + def columns(self): + return self._obj.Columns.Count + + @property + def rows(self): + return self._obj.Rows.Count + + def to_size(self, rows, cols): + cursor = self.sheet.get_cursor(self.obj[0,0]) + cursor.collapseToSize(cols, rows) + return LOCellRange(self.sheet[cursor.AbsoluteName].obj, self.doc) + + def copy_from(self, rango, formula=False): + data = rango + if isinstance(rango, LOCellRange): + if formula: + data = rango.formula + else: + data = rango.data + rows = len(data) + cols = len(data[0]) + 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): + rango = cell.to_size(self.rows, self.columns) + if formula: + rango.formula = self.data + else: + 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 + row = ra.EndRow + row + return LOCellRange(self.sheet[row, col].obj, self.doc) + + @property + def next_cell(self): + a = self.current_region.address + if hasattr(a, 'StartColumn'): + col = a.StartColumn + else: + col = a.Column + if hasattr(a, 'EndRow'): + row = a.EndRow + 1 + else: + row = a.Row + 1 + + return LOCellRange(self.sheet[row, col].obj, self.doc) @property def sheet(self): - return self.obj.Spreadsheet + return LOCalcSheet(self.obj.Spreadsheet, self.doc) + + @property + def charts(self): + return self.obj.Spreadsheet.Charts + + @property + def ps(self): + ps = Rectangle() + s = self.obj.Size + p = self.obj.Position + ps.X = p.X + ps.Y = p.Y + ps.Width = s.Width + ps.Height = s.Height + return ps @property def draw_page(self): - return self.sheet.getDrawPage() + return self.sheet.obj.getDrawPage() @property def name(self): @@ -865,11 +1885,50 @@ 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.createCursorByRange(self.obj[0,0]) + cursor = self.sheet.get_cursor(self.obj[0,0]) cursor.collapseToCurrentRegion() - return LOCellRange(self.sheet[cursor.AbsoluteName], self.doc) + return LOCellRange(self.sheet[cursor.AbsoluteName].obj, self.doc) + + @property + def visible(self): + cursor = self.sheet.get_cursor(self.obj) + rangos = [LOCellRange(self.sheet[r.AbsoluteName].obj, self.doc) + for r in cursor.queryVisibleCells()] + return tuple(rangos) + + @property + def empty(self): + cursor = self.sheet.get_cursor(self.obj) + rangos = [LOCellRange(self.sheet[r.AbsoluteName].obj, self.doc) + for r in cursor.queryEmptyCells()] + return tuple(rangos) + + @property + def back_color(self): + return self._obj.CellBackColor + @back_color.setter + def back_color(self, value): + self._obj.CellBackColor = get_color(value) + + @property + def cell_style(self): + return self.obj.CellStyle + @cell_style.setter + def cell_style(self, value): + self.obj.CellStyle = value + + @property + def auto_format(self): + return self.obj.CellStyle + @auto_format.setter + def auto_format(self, value): + self.obj.autoFormat(value) def insert_image(self, path, **kwargs): s = self.obj.Size @@ -882,17 +1941,128 @@ class LOCellRange(object): img.setSize(Size(w, h)) return + def insert_shape(self, tipo, **kwargs): + s = self.obj.Size + w = kwargs.get('width', s.Width) + h = kwargs.get('Height', s.Height) + img = self.doc.create_instance('com.sun.star.drawing.{}Shape'.format(tipo)) + set_properties(img, kwargs) + self.draw_page.add(img) + img.Anchor = self.obj + img.setSize(Size(w, h)) + return + def select(self): self.doc._cc.select(self.obj) return + def in_range(self, rango): + if isinstance(rango, LOCellRange): + address = rango.address + else: + address = rango.getRangeAddress() + cursor = self.sheet.get_cursor(self.obj) + result = cursor.queryIntersection(address) + return bool(result.Count) + + def fill(self, source=1): + self.obj.fillAuto(0, source) + return + + def clear(self, what=31): + # ~ http://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1sheet_1_1CellFlags.html + self.obj.clearContents(what) + return + + @property + def rows_visible(self): + return self._obj.getRows().IsVisible + @rows_visible.setter + def rows_visible(self, value): + self._obj.getRows().IsVisible = value + + @property + def columns_visible(self): + return self._obj.getColumns().IsVisible + @columns_visible.setter + def columns_visible(self, value): + self._obj.getColumns().IsVisible = value + + def get_column(self, index=0, first=False): + ca = self.address + ra = self.current_region.address + if hasattr(ca, 'Column'): + col = ca.Column + else: + col = ca.StartColumn + index + start = 1 + if first: + start = 0 + if hasattr(ra, 'Row'): + row_start = ra.Row + start + row_end = ra.Row + 1 + else: + row_start = ra.StartRow + start + row_end = ra.EndRow + 1 + return LOCellRange(self.sheet[row_start:row_end, col:col+1].obj, self.doc) + + def import_csv(self, path, **kwargs): + data = import_csv(path, **kwargs) + self.copy_from(data) + return + + def export_csv(self, path, **kwargs): + data = self.current_region.data + export_csv(path, data, **kwargs) + return + + def create_chart(self, tipo): + chart = LOChart(None, tipo) + 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): - def __init__(self, controller, window=None): + def __init__(self, controller, name, window=None): self._controller = controller + 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: @@ -901,27 +2071,25 @@ class EventsListenerBase(unohelper.Base, XEventListener): class EventsButton(EventsListenerBase, XActionListener): - def __init__(self, controller): - super().__init__(controller) + def __init__(self, controller, name): + super().__init__(controller, name) def actionPerformed(self, event): - name = event.Source.Model.Name - event_name = '{}_action'.format(name) + event_name = '{}_action'.format(self._name) if hasattr(self._controller, event_name): getattr(self._controller, event_name)(event) return -class EventsMouse(EventsListenerBase, XMouseListener): +class EventsMouse(EventsListenerBase, XMouseListener, XMouseMotionListener): - def __init__(self, controller): - super().__init__(controller) + def __init__(self, controller, name): + super().__init__(controller, name) def mousePressed(self, event): - name = event.Source.Model.Name - event_name = '{}_click'.format(name) + event_name = '{}_click'.format(self._name) if event.ClickCount == 2: - event_name = '{}_double_click'.format(name) + event_name = '{}_double_click'.format(self._name) if hasattr(self._controller, event_name): getattr(self._controller, event_name)(event) return @@ -935,6 +2103,26 @@ class EventsMouse(EventsListenerBase, XMouseListener): def mouseExited(self, event): pass + # ~ XMouseMotionListener + def mouseMoved(self, event): + pass + + def mouseDragged(self, event): + pass + + +class EventsMouseLink(EventsMouse): + + def mouseEntered(self, event): + obj = event.Source.Model + obj.TextColor = get_color('blue') + return + + def mouseExited(self, event): + obj = event.Source.Model + obj.TextColor = 0 + return + class EventsMouseGrid(EventsMouse): selected = False @@ -954,13 +2142,243 @@ class EventsMouseGrid(EventsMouse): return def mouseReleased(self, event): - obj = event.Source - col = obj.getColumnAtPoint(event.X, event.Y) - row = obj.getRowAtPoint(event.X, event.Y) - if row == -1 and col > -1: - gdm = obj.Model.GridDataModel - for i in range(gdm.RowCount): - gdm.updateRowHeading(i, i + 1) + # ~ obj = event.Source + # ~ col = obj.getColumnAtPoint(event.X, event.Y) + # ~ row = obj.getRowAtPoint(event.X, event.Y) + # ~ if row == -1 and col > -1: + # ~ gdm = obj.Model.GridDataModel + # ~ for i in range(gdm.RowCount): + # ~ gdm.updateRowHeading(i, i + 1) + return + + +class EventsModify(EventsListenerBase, XModifyListener): + + def __init__(self, controller): + super().__init__(controller) + + def modified(self, event): + event_name = '{}_modified'.format(event.Source.Name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + +class EventsItem(EventsListenerBase, XItemListener): + + def __init__(self, controller, name): + super().__init__(controller, name) + + def disposing(self, event): + pass + + def itemStateChanged(self, event): + event_name = '{}_item_changed'.format(self.name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + +class EventsItemRoadmap(EventsItem): + + def itemStateChanged(self, event): + dialog = event.Source.Context.Model + dialog.Step = event.ItemId + 1 + return + + +class EventsFocus(EventsListenerBase, XFocusListener): + + def __init__(self, controller, name): + super().__init__(controller, name) + + def focusGained(self, event): + service = event.Source.Model.ImplementationName + if service == 'stardiv.Toolkit.UnoControlListBoxModel': + return + obj = event.Source.Model + obj.BackgroundColor = COLOR_ON_FOCUS + + def focusLost(self, event): + obj = event.Source.Model + obj.BackgroundColor = -1 + + +class EventsKey(EventsListenerBase, XKeyListener): + """ + event.KeyChar + event.KeyCode + event.KeyFunc + event.Modifiers + """ + + def __init__(self, controller, name): + super().__init__(controller, name) + + def keyPressed(self, event): + pass + + def keyReleased(self, event): + event_name = '{}_key_released'.format(self._name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + 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 + event.KeyCode + event.KeyFunc + event.Modifiers + """ + + def __init__(self, cls): + super().__init__(cls.events, cls.name) + self._cls = cls + + def keyPressed(self, event): + pass + + def keyReleased(self, event): + event_name = '{}_key_released'.format(self._cls.name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + else: + if event.KeyFunc == QUIT and hasattr(self._cls, 'close'): + self._cls.close() + return + + +class EventsWindow(EventsListenerBase, XTopWindowListener, XWindowListener): + + def __init__(self, cls): + self._cls = cls + super().__init__(cls.events, cls.name, cls._window) + + def windowOpened(self, event): + event_name = '{}_opened'.format(self._name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + def windowActivated(self, event): + control_name = '{}_activated'.format(event.Source.Model.Name) + if hasattr(self._controller, control_name): + getattr(self._controller, control_name)(event) + return + + def windowDeactivated(self, event): + control_name = '{}_deactivated'.format(event.Source.Model.Name) + if hasattr(self._controller, control_name): + getattr(self._controller, control_name)(event) + return + + def windowMinimized(self, event): + pass + + def windowNormalized(self, event): + pass + + def windowClosing(self, event): + if self._window: + control_name = 'window_closing' + else: + control_name = '{}_closing'.format(event.Source.Model.Name) + + if hasattr(self._controller, control_name): + getattr(self._controller, control_name)(event) + # ~ else: + # ~ if not self._modal and not self._block: + # ~ event.Source.Visible = False + return + + def windowClosed(self, event): + control_name = '{}_closed'.format(event.Source.Model.Name) + if hasattr(self._controller, control_name): + getattr(self._controller, control_name)(event) + return + + # ~ XWindowListener + def windowResized(self, event): + 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) + return + + def windowMoved(self, event): + pass + + def windowShown(self, event): + pass + + def windowHidden(self, event): + pass + + +class EventsMenu(EventsListenerBase, XMenuListener): + + def __init__(self, controller): + super().__init__(controller, '') + + def itemHighlighted(self, event): + pass + + def itemSelected(self, event): + name = event.Source.getCommand(event.MenuId) + if name.startswith('menu'): + event_name = '{}_selected'.format(name) + else: + event_name = 'menu_{}_selected'.format(name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + def itemActivated(self, event): + return + + def itemDeactivated(self, event): return @@ -985,35 +2403,65 @@ class UnoBaseObject(object): @property def parent(self): + ps = self.obj.getContext().PosSize return self.obj.getContext() + def _get_possize(self, name): + ps = self.obj.getPosSize() + return getattr(ps, name) + + def _set_possize(self, name, value): + ps = self.obj.getPosSize() + setattr(ps, name, value) + self.obj.setPosSize(ps.X, ps.Y, ps.Width, ps.Height, POSSIZE) + return + @property def x(self): - return self.model.PositionX + if hasattr(self.model, 'PositionX'): + return self.model.PositionX + return self._get_possize('X') @x.setter def x(self, value): - self.model.PositionX = value + if hasattr(self.model, 'PositionX'): + self.model.PositionX = value + else: + self._set_possize('X', value) @property def y(self): - return self.model.PositionY + if hasattr(self.model, 'PositionY'): + return self.model.PositionY + return self._get_possize('Y') @y.setter def y(self, value): - self.model.PositionY = value + if hasattr(self.model, 'PositionY'): + self.model.PositionY = value + else: + self._set_possize('Y', value) @property def width(self): 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): - 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.obj, 'PosSize'): + self._set_possize('Height', value) + else: + self._model.Height = value @property def tag(self): @@ -1022,6 +2470,20 @@ class UnoBaseObject(object): def tag(self, value): self.model.Tag = value + @property + def visible(self): + return self.obj.Visible + @visible.setter + def visible(self, value): + self.obj.setVisible(value) + + @property + def enabled(self): + return self.model.Enabled + @enabled.setter + def enabled(self, value): + self.model.Enabled = value + @property def step(self): return self.model.Step @@ -1029,6 +2491,13 @@ class UnoBaseObject(object): def step(self, value): self.model.Step = value + @property + def back_color(self): + return self.model.BackgroundColor + @back_color.setter + def back_color(self, value): + self.model.BackgroundColor = value + @property def rules(self): return self._rules @@ -1053,16 +2522,21 @@ class UnoBaseObject(object): return def move(self, origin, x=0, y=5): - w = 0 - h = 0 if x: - w = origin.width + self.x = origin.x + origin.width + x + else: + self.x = origin.x if y: - h = origin.height - x = origin.x + x + w - y = origin.y + y + h - self.x = x - self.y = y + self.y = origin.y + origin.height + y + else: + self.y = origin.y + return + + def possize(self, origin): + self.x = origin.x + self.y = origin.y + self.width = origin.width + self.height = origin.height return @@ -1083,6 +2557,16 @@ class UnoLabel(UnoBaseObject): self.model.Label = value +class UnoLabelLink(UnoLabel): + + def __init__(self, obj): + super().__init__(obj) + + @property + def type(self): + return 'link' + + class UnoButton(UnoBaseObject): def __init__(self, obj): @@ -1125,7 +2609,6 @@ class UnoListBox(UnoBaseObject): def __init__(self, obj): super().__init__(obj) - self._data = [] @property def type(self): @@ -1133,15 +2616,55 @@ class UnoListBox(UnoBaseObject): @property def value(self): - return self.obj.SelectedItem + return self.obj.getSelectedItem() + + @property + def count(self): + return len(self.data) @property def data(self): - return self._data + return self.model.StringItemList @data.setter def data(self, values): - self._data = list(sorted(values)) - self.model.StringItemList = self.data + 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) + else: + self.obj.selectItemPos(pos, True) + return + + def clear(self): + self.model.removeAllItems() + return + + def _set_image_url(self, image): + 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) + + def insert(self, value, path='', pos=-1, show=True): + if pos < 0: + pos = self.count + if path: + self.model.insertItem(pos, value, self._set_image_url(path)) + else: + self.model.insertItemText(pos, value) + if show: + self.select(pos) return @@ -1175,16 +2698,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) @@ -1224,6 +2750,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) @@ -1233,18 +2763,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): @@ -1257,9 +2786,744 @@ class UnoGrid(UnoBaseObject): return +class UnoRoadmap(UnoBaseObject): + + def __init__(self, obj): + super().__init__(obj) + self._options = () + + @property + def options(self): + return self._options + @options.setter + def options(self, values): + self._options = values + for i, v in enumerate(values): + opt = self.model.createInstance() + opt.ID = i + opt.Label = v + self.model.insertByIndex(i, opt) + return + + @property + def enabled(self): + return True + @enabled.setter + def enabled(self, value): + for m in self.model: + m.Enabled = value + return + + def set_enabled(self, index, value): + self.model.getByIndex(index).Enabled = value + 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, + 'button': UnoButton, + 'text': UnoText, + 'listbox': UnoListBox, + 'grid': UnoGrid, + 'link': UnoLabelLink, + 'roadmap': UnoRoadmap, + 'tree': UnoTree, + 'tab': UnoTab, + # ~ 'image': UnoImage, + # ~ 'radio': UnoRadio, + # ~ 'groupbox': UnoGroupBox, + '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] + + +def add_listeners(events, control, name=''): + listeners = { + 'addActionListener': EventsButton, + 'addMouseListener': EventsMouse, + 'addItemListener': EventsItem, + 'addFocusListener': EventsFocus, + 'addKeyListener': EventsKey, + 'addTabListener': EventsTab, + } + if hasattr(control, 'obj'): + control = contro.obj + # ~ debug(control.ImplementationName) + is_grid = control.ImplementationName == 'stardiv.Toolkit.GridControl' + is_link = control.ImplementationName == 'stardiv.Toolkit.UnoFixedHyperlinkControl' + is_roadmap = control.ImplementationName == 'stardiv.Toolkit.UnoRoadmapControl' + + for key, value in listeners.items(): + if hasattr(control, key): + if is_grid and key == 'addMouseListener': + control.addMouseListener(EventsMouseGrid(events, name)) + continue + if is_link and key == 'addMouseListener': + control.addMouseListener(EventsMouseLink(events, name)) + continue + if is_roadmap and key == 'addItemListener': + control.addItemListener(EventsItemRoadmap(events, 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 + + +class WriterTable(ObjectBase): + + def __init__(self, obj): + super().__init__(obj) + + def __getitem__(self, key): + obj = super().__getitem__(key) + return WriterTableRange(obj, key, self.name) + + @property + def name(self): + return self.obj.Name + @name.setter + def name(self, value): + self.obj.Name = value + + +class WriterTableRange(ObjectBase): + + def __init__(self, obj, index, table_name): + self._index = index + self._table_name = table_name + super().__init__(obj) + self._is_cell = hasattr(self.obj, 'CellName') + + def __getitem__(self, key): + obj = super().__getitem__(key) + return WriterTableRange(obj, key, self._table_name) + + @property + def value(self): + return self.obj.String + @value.setter + def value(self, value): + self.obj.String = value + + @property + def data(self): + return self.obj.getDataArray() + @data.setter + def data(self, values): + if isinstance(values, list): + values = tuple(values) + self.obj.setDataArray(values) + + @property + def rows(self): + return len(self.data) + + @property + def columns(self): + return len(self.data[0]) + + @property + def name(self): + if self._is_cell: + name = '{}.{}'.format(self._table_name, self.obj.CellName) + elif isinstance(self._index, str): + name = '{}.{}'.format(self._table_name, self._index) + else: + c1 = self.obj[0,0].CellName + c2 = self.obj[self.rows-1,self.columns-1].CellName + name = '{}.{}:{}'.format(self._table_name, c1, c2) + return name + + def get_cell(self, *index): + return self[index] + + def get_column(self, index=0, start=1): + return self[start:self.rows,index:index+1] + + def get_series(self): + class Serie(): + pass + series = [] + for i in range(self.columns): + serie = Serie() + serie.label = self.get_cell(0,i).name + serie.data = self.get_column(i).data + serie.values = self.get_column(i).name + series.append(serie) + return series + + +class ChartFormat(object): + + def __call__(self, obj): + for k, v in self.__dict__.items(): + if hasattr(obj, k): + setattr(obj, k, v) + + +class LOChart(object): + BASE = 'com.sun.star.chart.{}Diagram' + + def __init__(self, obj, tipo=''): + self._obj = obj + self._type = tipo + self._name = '' + self._table = None + self._data = () + self._data_series = () + self._cell = None + self._cursor = None + self._doc = None + self._title = ChartFormat() + self._subtitle = ChartFormat() + self._legend = ChartFormat() + self._xaxistitle = ChartFormat() + self._yaxistitle = ChartFormat() + self._xaxis = ChartFormat() + self._yaxis = ChartFormat() + self._xmaingrid = ChartFormat() + self._ymaingrid = ChartFormat() + self._xhelpgrid = ChartFormat() + self._yhelpgrid = ChartFormat() + self._area = ChartFormat() + self._wall = ChartFormat() + self._dim3d = False + self._series = () + self._labels = () + return + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.insert() + + @property + def obj(self): + return self._obj + @obj.setter + def obj(self, value): + self._obj = value + + @property + def name(self): + return self._name + @name.setter + def name(self, value): + self._name = value + + @property + def type(self): + return self._type + @type.setter + def type(self, value): + self._type = value + + @property + def table(self): + return self._table + @table.setter + def table(self, value): + self._table = value + + @property + def data(self): + return self._data + @data.setter + def data(self, value): + self._data = value + + @property + def cell(self): + return self._cell + @cell.setter + def cell(self, value): + self._cell = value + self.doc = value.doc + + @property + def cursor(self): + return self._cursor + @cursor.setter + def cursor(self, value): + self._cursor = value + + @property + def doc(self): + return self._doc + @doc.setter + def doc(self, value): + self._doc = value + + @property + def width(self): + return self._width + @width.setter + def width(self, value): + self._width = value + + @property + def height(self): + return self._height + @height.setter + def height(self, value): + self._height = value + + @property + def title(self): + return self._title + + @property + def subtitle(self): + return self._subtitle + + @property + def legend(self): + return self._legend + + @property + def xaxistitle(self): + return self._xaxistitle + + @property + def yaxistitle(self): + return self._yaxistitle + + @property + def xaxis(self): + return self._xaxis + + @property + def yaxis(self): + return self._yaxis + + @property + def xmaingrid(self): + return self._xmaingrid + + @property + def ymaingrid(self): + return self._ymaingrid + + @property + def xhelpgrid(self): + return self._xhelpgrid + + @property + def yhelpgrid(self): + return self._yhelpgrid + + @property + def area(self): + return self._area + + @property + def wall(self): + return self._wall + + @property + def dim3d(self): + return self._dim3d + @dim3d.setter + def dim3d(self, value): + self._dim3d = value + + @property + def series(self): + return self._series + @series.setter + def series(self, value): + self._series = value + + @property + def data_series(self): + return self._series + @data_series.setter + def data_series(self, value): + self._data_series = value + + @property + def labels(self): + return self._labels + @labels.setter + def labels(self, value): + self._labels = value + + def _add_series_writer(self, chart): + dp = self.doc.create_instance('com.sun.star.chart2.data.DataProvider') + chart.attachDataProvider(dp) + chart_type = chart.getFirstDiagram().getCoordinateSystems()[0].getChartTypes()[0] + self._data_series = self.table[self.data].get_series() + series = [self._create_serie(dp, s) for s in self._data_series[1:]] + chart_type.setDataSeries(tuple(series)) + chart_data = chart.getData() + chart_data.ComplexRowDescriptions = self._data_series[0].data + return + + def _get_series(self): + rango = self._data_series + class Serie(): + pass + series = [] + for i in range(0, rango.columns, 2): + serie = Serie() + serie.label = rango[0, i+1].name + serie.xvalues = rango.get_column(i).name + serie.values = rango.get_column(i+1).name + series.append(serie) + return series + + def _add_series_calc(self, chart): + dp = self.doc.create_instance('com.sun.star.chart2.data.DataProvider') + chart.attachDataProvider(dp) + chart_type = chart.getFirstDiagram().getCoordinateSystems()[0].getChartTypes()[0] + series = self._get_series() + series = [self._create_serie(dp, s) for s in series] + chart_type.setDataSeries(tuple(series)) + return + + def _create_serie(self, dp, data): + serie = create_instance('com.sun.star.chart2.DataSeries') + rango = data.values + is_x = hasattr(data, 'xvalues') + if is_x: + xrango = data.xvalues + rango_label = data.label + + lds = create_instance('com.sun.star.chart2.data.LabeledDataSequence') + values = self._create_data(dp, rango, 'values-y') + lds.setValues(values) + if data.label: + label = self._create_data(dp, rango_label, '') + lds.setLabel(label) + + xlds = () + if is_x: + xlds = create_instance('com.sun.star.chart2.data.LabeledDataSequence') + values = self._create_data(dp, xrango, 'values-x') + xlds.setValues(values) + + if is_x: + serie.setData((lds, xlds)) + else: + serie.setData((lds,)) + + return serie + + def _create_data(self, dp, rango, role): + data = dp.createDataSequenceByRangeRepresentation(rango) + if not data is None: + data.Role = role + return data + + def _from_calc(self): + ps = self.cell.ps + ps.Width = self.width + ps.Height = self.height + charts = self.cell.charts + data = () + if self.data: + data = (self.data.address,) + charts.addNewByName(self.name, ps, data, True, True) + self.obj = charts.getByName(self.name) + chart = self.obj.getEmbeddedObject() + chart.setDiagram(chart.createInstance(self.BASE.format(self.type))) + if not self.data: + self._add_series_calc(chart) + return chart + + def _from_writer(self): + obj = self.doc.create_instance('com.sun.star.text.TextEmbeddedObject') + obj.setPropertyValue('CLSID', '12DCAE26-281F-416F-a234-c3086127382e') + obj.Name = self.name + obj.setSize(Size(self.width, self.height)) + self.doc.insert_content(self.cursor, obj) + self.obj = obj + chart = obj.getEmbeddedObject() + tipo = self.type + if self.type == 'Column': + tipo = 'Bar' + chart.Diagram.Vertical = True + chart.setDiagram(chart.createInstance(self.BASE.format(tipo))) + chart.DataSourceLabelsInFirstColumn = True + if isinstance(self.data, str): + self._add_series_writer(chart) + else: + chart_data = chart.getData() + labels = [r[0] for r in self.data] + data = [(r[1],) for r in self.data] + 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'))) + + return chart + + def insert(self): + if not self.cell is None: + chart = self._from_calc() + elif not self.cursor is None: + chart = self._from_writer() + + diagram = chart.Diagram + + if self.type == 'Bar': + diagram.Vertical = True + + if hasattr(self.title, 'String'): + chart.HasMainTitle = True + self.title(chart.Title) + + if hasattr(self.subtitle, 'String'): + chart.HasSubTitle = True + self.subtitle(chart.SubTitle) + + if self.legend.__dict__: + chart.HasLegend = True + self.legend(chart.Legend) + + if self.xaxistitle.__dict__: + diagram.HasXAxisTitle = True + self.xaxistitle(diagram.XAxisTitle) + + if self.yaxistitle.__dict__: + diagram.HasYAxisTitle = True + self.yaxistitle(diagram.YAxisTitle) + + if self.dim3d: + diagram.Dim3D = True + + if self.series: + data_series = chart.getFirstDiagram( + ).getCoordinateSystems( + )[0].getChartTypes()[0].DataSeries + for i, serie in enumerate(data_series): + for k, v in self.series[i].items(): + if hasattr(serie, k): + setattr(serie, k, v) + 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): + def __init__(self, **properties): self._obj = self._create(properties) self._init_values() @@ -1267,22 +3531,29 @@ class LODialog(object): self._model = self._obj.Model self._init_controls() self._events = None - # ~ self._response = None + self._color_on_focus = -1 + self._id_extension = '' + self._images = 'images' return def _create(self, properties): path = properties.pop('Path', '') if path: - dp = create_instance('com.sun.star.awt.DialogProvider2', True) + dp = create_instance('com.sun.star.awt.DialogProvider', True) return dp.createDialog(_path_url(path)) - if 'Library' in properties: - location = properties['Location'] + if 'Location' in properties: + location = properties.get('Location', 'application') + library = properties.get('Library', 'Standard') if location == 'user': location = 'application' - dp = create_instance('com.sun.star.awt.DialogProvider2', True) + dp = create_instance('com.sun.star.awt.DialogProvider', True) path = 'vnd.sun.star.script:{}.{}?location={}'.format( - properties['Library'], properties['Name'], location) + library, properties['Name'], location) + if location == 'document': + uid = get_document().uid + path = 'vnd.sun.star.tdoc:/{}/Dialogs/{}/{}.xml'.format( + uid, library, properties['Name']) return dp.createDialog(path) dlg = create_instance('com.sun.star.awt.UnoControlDialog', True) @@ -1295,8 +3566,24 @@ class LODialog(object): return dlg - def _init_controls(self): + def _get_type_control(self, name): + types = { + 'stardiv.Toolkit.UnoFixedTextControl': 'label', + '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] + def _init_controls(self): + for control in self.obj.getControls(): + tipo = self._get_type_control(control.ImplementationName) + name = control.Model.Name + control = get_custom_class(tipo, control) + setattr(self, name, control) return @property @@ -1307,6 +3594,52 @@ class LODialog(object): def model(self): return self._model + @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 + + @property + def images(self): + return self._images + @images.setter + def images(self, value): + self._images = value + + @property + def height(self): + return self.model.Height + @height.setter + def height(self, value): + self.model.Height = value + + @property + def width(self): + return self.model.Width + @width.setter + def width(self, value): + self.model.Width = value + + @property + def color_on_focus(self): + return self._color_on_focus + @color_on_focus.setter + def color_on_focus(self, value): + global COLOR_ON_FOCUS + COLOR_ON_FOCUS = get_color(value) + self._color_on_focus = COLOR_ON_FOCUS + + @property + def step(self): + return self.model.Step + @step.setter + def step(self, value): + self.model.Step = value + @property def events(self): return self._events @@ -1316,23 +3649,8 @@ class LODialog(object): self._connect_listeners() def _connect_listeners(self): - - return - - def _add_listeners(self, control): - if self.events is None: - return - - listeners = { - 'addActionListener': EventsButton, - 'addMouseListener': EventsMouse, - } - for key, value in listeners.items(): - if hasattr(control.obj, key): - if control.type == 'grid' and key == 'addMouseListener': - control.obj.addMouseListener(EventsMouseGrid(self.events)) - continue - getattr(control.obj, key)(listeners[key](self.events)) + for control in self.obj.getControls(): + add_listeners(self._events, control, control.Model.Name) return def open(self): @@ -1344,71 +3662,334 @@ class LODialog(object): def _get_control_model(self, control): services = { 'label': 'com.sun.star.awt.UnoControlFixedTextModel', - 'button': 'com.sun.star.awt.UnoControlButtonModel', + 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel', 'text': 'com.sun.star.awt.UnoControlEditModel', 'listbox': 'com.sun.star.awt.UnoControlListBoxModel', - 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel', + 'button': 'com.sun.star.awt.UnoControlButtonModel', 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel', - 'image': 'com.sun.star.awt.UnoControlImageControlModel', - 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel', - 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel', - 'tree': 'com.sun.star.awt.tree.TreeControlModel', '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 _get_custom_class(self, tipo, obj): - classes = { - 'label': UnoLabel, - 'button': UnoButton, - 'text': UnoText, - 'listbox': UnoListBox, - 'grid': UnoGrid, - # ~ 'link': UnoLink, - # ~ 'tab': UnoTab, - # ~ 'roadmap': UnoRoadmap, - # ~ 'image': UnoImage, - # ~ 'radio': UnoRadio, - # ~ 'groupbox': UnoGroupBox, - # ~ 'tree': UnoTree, - } - return classes[tipo](obj) - def _set_column_model(self, 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) - # ~ column_model.setDefaultColumns(len(columns)) 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) - # ~ mri(grid_column) return column_model - def _set_image_url(self, path): - if exists_path(path): - return _path_url(path) - return '' + def _set_image_url(self, image): + if exists_path(image): + return _path_url(image) - def add_control(self, properties): - tipo = properties.pop('Type').lower() + if not self.id_extension: + return '' + path = get_path_extension(self.id_extension) + path = join(path, self.images, image) + return _path_url(path) + + def _special_properties(self, tipo, properties): columns = properties.pop('Columns', ()) if tipo == 'grid': properties['ColumnModel'] = self._set_column_model(columns) - if tipo == 'button' and 'ImageURL' in properties: + 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 == '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) name = properties['Name'] self.model.insertByName(name, model) - control = self._get_custom_class(tipo, self.obj.getControl(name)) - self._add_listeners(control) + 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 + def center(self, control, x=0, y=0): + w = self.width + h = self.height + + if isinstance(control, tuple): + wt = SEPARATION * -1 + for c in control: + wt += c.width + SEPARATION + x = w / 2 - wt / 2 + for c in control: + c.x = x + x = c.x + c.width + SEPARATION + return + + if x < 0: + x = w + x - control.width + elif x == 0: + x = w / 2 - control.width / 2 + if y < 0: + y = h + y - control.height + elif y == 0: + y = h / 2 - control.height / 2 + control.x = x + control.y = y + return + + +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), + properties.get('Y', 0), + properties.get('Width', 500), + properties.get('Height', 500), + ) + self._title = properties.get('Title', TITLE) + self._create_frame(ps) + self._create_container(ps) + self._create_subcontainer(ps) + # ~ self._create_splitter(ps) + return + + def _create_frame(self, ps): + service = 'com.sun.star.frame.TaskCreator' + tc = create_instance(service, True) + self._frame = tc.createInstanceWithArguments(( + NamedValue('FrameName', 'EasyMacroWin'), + NamedValue('PosSize', Rectangle(*ps)), + )) + self._window = self._frame.getContainerWindow() + self._toolkit = self._window.getToolkit() + desktop = get_desktop() + self._frame.setCreator(desktop) + desktop.getFrames().append(self._frame) + self._frame.Title = self._title + return + + def _create_container(self, ps): + # ~ toolkit = self._window.getToolkit() + service = 'com.sun.star.awt.UnoControlContainer' + self._container = create_instance(service, True) + service = 'com.sun.star.awt.UnoControlContainerModel' + model = create_instance(service, True) + model.BackgroundColor = get_color(225, 225, 225) + self._container.setModel(model) + self._container.createPeer(self._toolkit, self._window) + self._container.setPosSize(*ps, POSSIZE) + 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', + 'button': 'com.sun.star.awt.UnoControlButton', + 'text': 'com.sun.star.awt.UnoControlEdit', + 'listbox': 'com.sun.star.awt.UnoControlListBox', + 'link': 'com.sun.star.awt.UnoControlFixedHyperlink', + 'roadmap': 'com.sun.star.awt.UnoControlRoadmap', + 'image': 'com.sun.star.awt.UnoControlImageControl', + 'groupbox': 'com.sun.star.awt.UnoControlGroupBox', + '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() + 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) + name = properties['Name'] + 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 + + def _create_popupmenu(self, menus): + menu = create_instance('com.sun.star.awt.PopupMenu', True) + for i, m in enumerate(menus): + label = m['label'] + cmd = m.get('event', '') + if not cmd: + cmd = label.lower().replace(' ', '_') + if label == '-': + menu.insertSeparator(i) + else: + menu.insertItem(i, label, m.get('style', 0), i) + menu.setCommand(i, cmd) + # ~ menu.setItemImage(i, path?, True) + menu.addMenuListener(EventsMenu(self.events)) + return menu + + def _create_menu(self, menus): + #~ https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1awt_1_1XMenu.html + #~ nItemId specifies the ID of the menu item to be inserted. + #~ aText specifies the label of the menu item. + #~ nItemStyle 0 = Standard, CHECKABLE = 1, RADIOCHECK = 2, AUTOCHECK = 4 + #~ nItemPos specifies the position where the menu item will be inserted. + self._menu = create_instance('com.sun.star.awt.MenuBar', True) + for i, m in enumerate(menus): + self._menu.insertItem(i, m['label'], m.get('style', 0), i) + cmd = m['label'].lower().replace(' ', '_') + self._menu.setCommand(i, cmd) + submenu = self._create_popupmenu(m['submenu']) + self._menu.setPopupMenu(i, submenu) + + self._window.setMenuBar(self._menu) + return + + def add_menu(self, menus): + self._create_menu(menus) + return + + def _add_listeners(self, control=None): + if self.events is None: + return + controller = EventsWindow(self) + self._window.addTopWindowListener(controller) + self._window.addWindowListener(controller) + self._container.addKeyListener(EventsKeyWindow(self)) + return + + @property + def name(self): + return self._title.lower().replace(' ', '_') + + @property + def events(self): + return self._events + @events.setter + def events(self, value): + self._events = value + self._add_listeners() + + @property + def width(self): + return self._container.Size.Width + + @property + def height(self): + return self._container.Size.Height + + def open(self): + self._window.setVisible(True) + return + + def close(self): + self._window.setMenuBar(None) + self._window.dispose() + self._frame.close(True) + return + # ~ Python >= 3.7 # ~ def __getattr__(name): @@ -1437,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 @@ -1447,7 +4028,6 @@ def get_document(title=''): return _get_class_doc(doc) -# ~ Export ok def get_documents(custom=True): docs = [] desktop = get_desktop() @@ -1479,18 +4059,11 @@ def active_cell(): def create_dialog(properties): - return LODialog(properties) + return LODialog(**properties) -def set_properties(model, properties): - if 'X' in properties: - properties['PositionX'] = properties.pop('X') - if 'Y' in properties: - properties['PositionY'] = properties.pop('Y') - keys = tuple(properties.keys()) - values = tuple(properties.values()) - model.setPropertyValues(keys, values) - return +def create_window(kwargs): + return LOWindow(**kwargs) # ~ Export ok @@ -1503,6 +4076,11 @@ def get_config_path(name='Work'): return _path_system(getattr(path, name)) +def get_path_python(): + path = get_config_path('Module') + return join(path, PYTHON) + + # ~ Export ok def get_file(init_dir='', multiple=False, filters=()): """ @@ -1617,12 +4195,26 @@ def from_json(path): return data +# ~ Export ok +def json_dumps(data): + return json.dumps(data, indent=4, sort_keys=True) + + +# ~ Export ok +def json_loads(data): + return json.loads(data) + + def get_path_extension(id): pip = CTX.getValueByName('/singletons/com.sun.star.deployment.PackageInformationProvider') path = _path_system(pip.getPackageLocation(id)) return path +def get_home(): + return Path.home() + + # ~ Export ok def inputbox(message, default='', title=TITLE, echochar=''): @@ -1640,7 +4232,7 @@ def inputbox(message, default='', title=TITLE, echochar=''): 'Width': 200, 'Height': 80, } - dlg = LODialog(args) + dlg = LODialog(**args) dlg.events = ControllersInput(dlg) args = { @@ -1706,12 +4298,29 @@ def new_doc(type_doc=CALC, **kwargs): # ~ Export ok -def new_db(path): +def new_db(path, name=''): + p, fn, n, e = get_info_path(path) + if not name: + name = n + return LOBase(name, path) + + +# ~ Todo +def exists_db(name): dbc = create_instance('com.sun.star.sdb.DatabaseContext') - db = dbc.createInstance() - db.URL = 'sdbc:embedded:firebird' # hsqldb - db.DatabaseDocument.storeAsURL(_path_url(path), ()) - return _get_class_doc(db) + return dbc.hasRegisteredDatabase(name) + + +# ~ Todo +def register_db(name, path): + dbc = create_instance('com.sun.star.sdb.DatabaseContext') + dbc.registerDatabaseLocation(name, _path_url(path)) + return + + +# ~ Todo +def get_db(name): + return LOBase(name) # ~ Export ok @@ -1730,7 +4339,7 @@ def open_doc(path, **kwargs): """ path = _path_url(path) opt = dict_to_property(kwargs) - doc = get_desktop().loadComponentFromURL(path, '_blank', 0, opt) + doc = get_desktop().loadComponentFromURL(path, '_default', 0, opt) if doc is None: return @@ -1742,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 @@ -1784,14 +4393,39 @@ def zip_content(path): return names -# ~ Export ok +def popen(command, stdin=None): + try: + proc = subprocess.Popen(shlex.split(command), shell=IS_WIN, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + for line in proc.stdout: + yield line.decode().rstrip() + except Exception as e: + error(e) + yield (e.errno, e.strerror) + + +def url_open(url, options={}, json=False): + data = '' + req = Request(url) + try: + response = urlopen(req) + # ~ response.info() + except HTTPError as e: + error(e) + except URLError as e: + error(e.reason) + else: + if json: + data = json_loads(response.read()) + else: + data = response.read() + + return data + + def run(command, wait=False): - # ~ debug(command) - # ~ debug(shlex.split(command)) try: if wait: - # ~ p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) - # ~ p.wait() result = subprocess.check_output(command, shell=True) else: p = subprocess.Popen(shlex.split(command), stdin=None, @@ -1922,7 +4556,6 @@ def kill(path): return -# ~ Export ok def get_size_screen(): if IS_WIN: user32 = ctypes.windll.user32 @@ -1933,7 +4566,6 @@ def get_size_screen(): return res.strip() -# ~ Export ok def get_clipboard(): df = None text = '' @@ -1987,7 +4619,7 @@ def set_clipboard(value): return -# ~ Todo +# ~ Export ok def copy(): call_dispatch('.uno:Copy') return @@ -2012,12 +4644,16 @@ def file_copy(source, target='', name=''): return path_new -# ~ Export ok -def get_path_content(path, filters='*'): +def get_path_content(path, filters=''): paths = [] + if filters in ('*', '*.*'): + filters = '' for folder, _, files in os.walk(path): - pattern = re.compile(r'\.(?:{})$'.format(filters), re.IGNORECASE) - paths += [join(folder, f) for f in files if pattern.search(f)] + 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 @@ -2175,7 +4811,12 @@ def end(): # ~ Export ok # ~ https://en.wikipedia.org/wiki/Web_colors -def get_color(value): +def get_color(*value): + if len(value) == 1 and isinstance(value[0], int): + return value[0] + if len(value) == 1 and isinstance(value[0], tuple): + value = value[0] + COLORS = { 'aliceblue': 15792383, 'antiquewhite': 16444375, @@ -2326,14 +4967,19 @@ def get_color(value): 'yellowgreen': 10145074, } - if isinstance(value, tuple): - return (value[0] << 16) + (value[1] << 8) + value[2] + if len(value) == 3: + color = (value[0] << 16) + (value[1] << 8) + value[2] + else: + value = value[0] + if value[0] == '#': + r, g, b = bytes.fromhex(value[1:]) + color = (r << 16) + (g << 8) + b + else: + color = COLORS.get(value.lower(), -1) + return color - if isinstance(value, str) and value[0] == '#': - r, g, b = bytes.fromhex(value[1:]) - return (r << 16) + (g << 8) + b - return COLORS.get(value.lower(), -1) +COLOR_ON_FOCUS = get_color('LightYellow') # ~ Export ok @@ -2355,6 +5001,24 @@ def _to_date(value): return new_value +def date_to_struct(value): + # ~ print(type(value)) + if isinstance(value, datetime.datetime): + d = DateTime() + d.Seconds = value.second + d.Minutes = value.minute + d.Hours = value.hour + d.Day = value.day + d.Month = value.month + d.Year = value.year + elif isinstance(value, datetime.date): + d = Date() + d.Day = value.day + d.Month = value.month + d.Year = value.year + return d + + # ~ Export ok def format(template, data): """ @@ -2376,15 +5040,35 @@ 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' factory = create_instance(name, False) + macro['language'] = macro.get('language', 'Python') + macro['location'] = macro.get('location', 'user') data = macro.copy() - if macro['language'] == 'Python': + if data['language'] == 'Python': data['module'] = '.py$' - elif macro['language'] == 'Basic': + elif data['language'] == 'Basic': data['module'] = '.{}.'.format(macro['module']) if macro['location'] == 'user': data['location'] = 'application' @@ -2394,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] @@ -2477,7 +5162,7 @@ class SmtpServer(object): def __enter__(self): return self - def __exit__(self, *args): + def __exit__(self, exc_type, exc_value, traceback): self.close() @property @@ -2612,14 +5297,121 @@ def server_smtp_test(config): return server.error -# ~ name = 'com.sun.star.configuration.ConfigurationProvider' -# ~ cp = create_instance(name, True) -# ~ node = PropertyValue(Name='nodepath', Value=NODE_SETTING) -# ~ try: - # ~ cua = cp.createInstanceWithArguments( - # ~ 'com.sun.star.configuration.ConfigurationUpdateAccess', (node,)) - # ~ cua.setPropertyValue(key, json.dumps(value)) - # ~ cua.commitChanges() -# ~ except Exception as e: - # ~ log.error(e, exc_info=True) - # ~ return False +def import_csv(path, **kwargs): + """ + See https://docs.python.org/3.5/library/csv.html#csv.reader + """ + with open(path) as f: + 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) + writer.writerows(data) + 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' + ARG = 'socket,host={},port={};urp;StarOffice.ComponentContext'.format(HOST, PORT) + CMD = ['soffice', + '-env:SingleAppInstance=false', + '-env:UserInstallation=file:///tmp/LIBO_Process8100', + '--headless', '--norestore', '--invisible', + '--accept={}'.format(ARG)] + + def __init__(self): + self._server = None + self._ctx = None + self._sm = None + self._start_server() + self._init_values() + + def _init_values(self): + global CTX + global SM + + if not self.is_running: + return + + ctx = uno.getComponentContext() + service = 'com.sun.star.bridge.UnoUrlResolver' + resolver = ctx.ServiceManager.createInstanceWithContext(service, ctx) + self._ctx = resolver.resolve('uno:{}'.format(self.ARG)) + self._sm = self._ctx.getServiceManager() + CTX = self._ctx + SM = self._sm + return + + @property + def is_running(self): + try: + s = socket.create_connection((self.HOST, self.PORT), 5.0) + s.close() + debug('LibreOffice is running...') + return True + except ConnectionRefusedError: + return False + + def _start_server(self): + if self.is_running: + return + + for i in range(3): + self._server = subprocess.Popen(self.CMD, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + time.sleep(3) + if self.is_running: + break + return + + def stop(self): + if self._server is None: + print('Search pgrep soffice') + else: + self._server.terminate() + debug('LibreOffice is stop...') + return + + def create_instance(self, name, with_context=True): + if with_context: + instance = self._sm.createInstanceWithContext(name, self._ctx) + else: + instance = self._sm.createInstance(name) + return instance + + +# ~ controls = { + # ~ 'CheckBox': 'com.sun.star.awt.UnoControlCheckBoxModel', + # ~ 'ComboBox': 'com.sun.star.awt.UnoControlComboBoxModel', + # ~ 'CurrencyField': 'com.sun.star.awt.UnoControlCurrencyFieldModel', + # ~ 'DateField': 'com.sun.star.awt.UnoControlDateFieldModel', + # ~ 'FileControl': 'com.sun.star.awt.UnoControlFileControlModel', + # ~ 'FormattedField': 'com.sun.star.awt.UnoControlFormattedFieldModel', + # ~ 'GroupBox': 'com.sun.star.awt.UnoControlGroupBoxModel', + # ~ 'ImageControl': 'com.sun.star.awt.UnoControlImageControlModel', + # ~ 'NumericField': 'com.sun.star.awt.UnoControlNumericFieldModel', + # ~ 'PatternField': 'com.sun.star.awt.UnoControlPatternFieldModel', + # ~ 'ProgressBar': 'com.sun.star.awt.UnoControlProgressBarModel', + # ~ 'ScrollBar': 'com.sun.star.awt.UnoControlScrollBarModel', + # ~ 'SimpleAnimation': 'com.sun.star.awt.UnoControlSimpleAnimationModel', + # ~ 'SpinButton': 'com.sun.star.awt.UnoControlSpinButtonModel', + # ~ 'Throbber': 'com.sun.star.awt.UnoControlThrobberModel', + # ~ 'TimeField': 'com.sun.star.awt.UnoControlTimeFieldModel', +# ~ } diff --git a/files/ZAZBarCode_v0.5.0.oxt b/files/ZAZBarCode_v0.5.0.oxt new file mode 100644 index 0000000000000000000000000000000000000000..210cfba8166943fe3a6d789f87e6194fd5676471 GIT binary patch literal 297020 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�yeAB8T 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 F{{XAVLZScw literal 0 HcmV?d00001 diff --git a/files/zazbarcode.update.xml b/files/zazbarcode.update.xml index 990e044..dc83af5 100644 --- a/files/zazbarcode.update.xml +++ b/files/zazbarcode.update.xml @@ -5,10 +5,10 @@ xmlns:xlink="http://www.w3.org/1999/xlink"> - + - + diff --git a/source/META-INF/manifest.xml b/source/META-INF/manifest.xml index a401fe8..c5251c4 100644 --- a/source/META-INF/manifest.xml +++ b/source/META-INF/manifest.xml @@ -1,6 +1,6 @@ - - - - - + + + + + diff --git a/source/ZAZBarCode.py b/source/ZAZBarCode.py index 5bbd349..9659bc0 100644 --- a/source/ZAZBarCode.py +++ b/source/ZAZBarCode.py @@ -15,15 +15,7 @@ TITLE = 'ZAZ BarCode' QR = 'qrcode' -p, *_ = app.get_info_path(__file__) -path_locales = app.join(p, 'locales') -try: - lang = gettext.translation('base', path_locales, languages=[app.LANG]) - lang.install() - _ = lang.gettext -except Exception as e: - from gettext import gettext as _ - app.error(e) +_ = app.install_locales(__file__) class Controllers(object): @@ -31,6 +23,10 @@ class Controllers(object): def __init__(self, dlg): self.d = dlg + def listbox_item_changed(self, event): + self.d.text.set_focus() + return + def button_action(self, event): if not self.d.listbox.value: self.d.listbox.set_focus() @@ -54,6 +50,7 @@ class ZAZBarCode(unohelper.Base, XJob, XJobExecutor): self.ctx = ctx self._data = '' self._type = '' + self._ask = False self.path_ext = app.get_path_extension(ID_EXTENSION) self.IMAGES = app.join(self.path_ext, self.IMAGES) @@ -89,8 +86,13 @@ class ZAZBarCode(unohelper.Base, XJob, XJobExecutor): try: generate(self._type, self._data, output=tmp_file) except Exception as e: + app.error(e) return str(e) - return '' + + if app.is_created(tmp_file.name): + return '' + + return _('Not generated') def _get_values(self): self._type = '' @@ -98,6 +100,7 @@ class ZAZBarCode(unohelper.Base, XJob, XJobExecutor): if dlg.open(): self._data = dlg.text.value.strip() self._type = dlg.listbox.value + self._ask = True return True return False @@ -118,9 +121,11 @@ class ZAZBarCode(unohelper.Base, XJob, XJobExecutor): self._show_error(result) return - cell = cell.offset() + if not self._ask: + cell = cell.offset(0, 1) if app.IS_WIN: tf.close() + cell.insert_image(tf.name) tf.close() return diff --git a/source/description.xml b/source/description.xml index a917c1f..d56f0d4 100644 --- a/source/description.xml +++ b/source/description.xml @@ -1,7 +1,7 @@ - + ZAZ Bar Code ZAZ Códigos de Barras diff --git a/source/locales/base.pot b/source/locales/base.pot index cd4a2f3..a26b24c 100644 --- a/source/locales/base.pot +++ b/source/locales/base.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2019-09-14 14:23-0500\n" +"POT-Creation-Date: 2019-11-10 15:06-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -15,34 +15,38 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" -#: source/ZAZBarCode.py:38 +#: source/ZAZBarCode.py:29 msgid "Select barcode type" msgstr "" -#: source/ZAZBarCode.py:43 +#: source/ZAZBarCode.py:34 msgid "Data field is mandatory" msgstr "" -#: source/ZAZBarCode.py:95 source/ZAZBarCode.py:117 +#: source/ZAZBarCode.py:91 +msgid "Not generated" +msgstr "" + +#: source/ZAZBarCode.py:109 source/ZAZBarCode.py:135 msgid "Select data" msgstr "" -#: source/ZAZBarCode.py:149 +#: source/ZAZBarCode.py:171 msgid "" "Error in: {}\n" "\n" "{}" msgstr "" -#: source/ZAZBarCode.py:167 +#: source/ZAZBarCode.py:189 msgid "~Select barcode type" msgstr "" -#: source/ZAZBarCode.py:179 +#: source/ZAZBarCode.py:201 msgid "~Capture data for barcode" msgstr "" -#: source/ZAZBarCode.py:212 +#: source/ZAZBarCode.py:234 msgid "~Insert Barcode" msgstr "" diff --git a/source/locales/en/LC_MESSAGES/base.mo b/source/locales/en/LC_MESSAGES/base.mo index 18ce3d0dabbebfb7ad6bf6daceb7da169a5d39f0..0aa8379399938df69c74521f528eba5e43c0f7f3 100644 GIT binary patch delta 81 zcmaFD^n__bs=cA1uAzZ~p{bRjsjh*UfdQ9KVsVLXNKs;5aZX}Mevy>|P$VzCG%-C@ aHzYMN7m07BkeWBKbrPe=WGzM=Mg{=-=@_^G delta 81 zcmaFD^n__bs)B)~uAzy7p^24=sjh*kfdQ9KVqSV_VtT4>NNQrPmBPd&lY|X{g2g4e dAw`LK#W{&3`9)R=lg$}*_+Uz{6jJlJ7y$Lx80`Q6 diff --git a/source/locales/en/LC_MESSAGES/base.po b/source/locales/en/LC_MESSAGES/base.po index 76939ed..0f6f70a 100644 --- a/source/locales/en/LC_MESSAGES/base.po +++ b/source/locales/en/LC_MESSAGES/base.po @@ -5,45 +5,49 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-09-14 14:23-0500\n" -"PO-Revision-Date: 2019-09-14 14:45-0500\n" +"POT-Creation-Date: 2019-11-10 15:06-0600\n" +"PO-Revision-Date: 2019-11-10 15:15-0600\n" +"Last-Translator: \n" "Language-Team: \n" +"Language: en\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.1\n" -"Last-Translator: \n" +"X-Generator: Poedit 2.2.4\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: en\n" -#: source/ZAZBarCode.py:38 +#: source/ZAZBarCode.py:29 msgid "Select barcode type" msgstr "" -#: source/ZAZBarCode.py:43 +#: source/ZAZBarCode.py:34 msgid "Data field is mandatory" msgstr "" -#: source/ZAZBarCode.py:95 source/ZAZBarCode.py:117 +#: source/ZAZBarCode.py:91 +msgid "Not generated" +msgstr "" + +#: source/ZAZBarCode.py:109 source/ZAZBarCode.py:135 msgid "Select data" msgstr "" -#: source/ZAZBarCode.py:149 +#: source/ZAZBarCode.py:171 msgid "" "Error in: {}\n" "\n" "{}" msgstr "" -#: source/ZAZBarCode.py:167 +#: source/ZAZBarCode.py:189 msgid "~Select barcode type" msgstr "" -#: source/ZAZBarCode.py:179 +#: source/ZAZBarCode.py:201 msgid "~Capture data for barcode" msgstr "" -#: source/ZAZBarCode.py:212 +#: source/ZAZBarCode.py:234 msgid "~Insert Barcode" msgstr "" diff --git a/source/locales/eo/LC_MESSAGES/base.po b/source/locales/eo/LC_MESSAGES/base.po index a26f435..f60753d 100644 --- a/source/locales/eo/LC_MESSAGES/base.po +++ b/source/locales/eo/LC_MESSAGES/base.po @@ -5,31 +5,35 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2019-09-14 14:23-0500\n" +"POT-Creation-Date: 2019-11-10 15:06-0600\n" "PO-Revision-Date: 2019-09-20 19:21+0200\n" +"Last-Translator: \n" "Language-Team: \n" +"Language: eo\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.0.6\n" -"Last-Translator: \n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: eo\n" -#: source/ZAZBarCode.py:38 +#: source/ZAZBarCode.py:29 msgid "Select barcode type" msgstr "Elektu strikodan tipon" -#: source/ZAZBarCode.py:43 +#: source/ZAZBarCode.py:34 msgid "Data field is mandatory" msgstr "Datumkampo estas deviga" -#: source/ZAZBarCode.py:95 source/ZAZBarCode.py:117 +#: source/ZAZBarCode.py:91 +msgid "Not generated" +msgstr "" + +#: source/ZAZBarCode.py:109 source/ZAZBarCode.py:135 msgid "Select data" msgstr "Elektu datumojn" -#: source/ZAZBarCode.py:149 +#: source/ZAZBarCode.py:171 msgid "" "Error in: {}\n" "\n" @@ -39,14 +43,14 @@ msgstr "" "\n" "{}" -#: source/ZAZBarCode.py:167 +#: source/ZAZBarCode.py:189 msgid "~Select barcode type" msgstr "~Elektu strikodan tipon" -#: source/ZAZBarCode.py:179 +#: source/ZAZBarCode.py:201 msgid "~Capture data for barcode" msgstr "~Kaptu datumojn por strikodo" -#: source/ZAZBarCode.py:212 +#: source/ZAZBarCode.py:234 msgid "~Insert Barcode" msgstr "~Enmetu Strikodon" diff --git a/source/locales/es/LC_MESSAGES/base.mo b/source/locales/es/LC_MESSAGES/base.mo index 7bcdff2a8f5c40747481eea224dc2521497d0c02..43d2a9a741b7060df8c37e3ce30b6e8b086a94e4 100644 GIT binary patch delta 341 zcmZ3__K>aqo)F7a1|Z-BVi_P#0b*VtUIWA+@BoO#f%qX13jpy?AO^{EF)}a+18E5$ z%?+e=fV3o#wgA%nKspFWivZ~)Agu+&8ZLQsfoErd@F_2;>mLvCo!5#c4E?*T+O7*?UxTVJtcqga;6RdRO~eU delta 292 zcmaFJww|s2o)F7a1|Z-7Vi_Qg0b*_-o&&@nZ~}o@U3{(mRtU!_-h&d+S)txNC*sWk-scUGWU}$1xVxntcYGA. import base64 +import csv import ctypes import datetime import errno +import gettext import getpass import hashlib import json @@ -30,6 +32,7 @@ import platform import re import shlex import shutil +import socket import subprocess import sys import tempfile @@ -38,12 +41,11 @@ 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 urllib.request import Request, urlopen +from urllib.error import URLError, HTTPError from string import Template from subprocess import PIPE @@ -59,27 +61,56 @@ import mailbox import uno import unohelper from com.sun.star.util import Time, Date, DateTime -from com.sun.star.beans import PropertyValue +from com.sun.star.beans import PropertyValue, NamedValue from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS from com.sun.star.awt.MessageBoxResults import YES from com.sun.star.awt.PosSize import POSSIZE, SIZE from com.sun.star.awt import Size, Point +from com.sun.star.awt import Rectangle +from com.sun.star.awt import KeyEvent +from com.sun.star.awt.KeyFunction import QUIT from com.sun.star.datatransfer import XTransferable, DataFlavor 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 +from com.sun.star.awt import XMouseMotionListener +from com.sun.star.util import XModifyListener +from com.sun.star.awt import XTopWindowListener +from com.sun.star.awt import XWindowListener +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 + try: from fernet import Fernet, InvalidToken - CRYPTO = True except ImportError: - CRYPTO = False + pass +ID_EXTENSION = '' + +DIR = { + 'images': 'images', + 'locales': 'locales', +} + +KEY = { + 'enter': 1280, +} + +SEPARATION = 5 + MSG_LANG = { 'es': { 'OK': 'Aceptar', @@ -90,38 +121,48 @@ 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', + 'main': 'com.sun.star.frame.StartModule', } NODE_MENUBAR = 'private:resource/menubar/menubar' +MENUS_MAIN = { + 'file': '.uno:PickList', + 'tools': '.uno:ToolsMenu', + 'help': '.uno:HelpMenu', +} MENUS_CALC = { 'file': '.uno:PickList', 'edit': '.uno:EditMenu', @@ -148,18 +189,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' @@ -174,13 +213,13 @@ log = logging.getLogger(__name__) _start = 0 _stop_thread = {} TIMEOUT = 10 +SECONDS_DAY = 60 * 60 * 24 CTX = uno.getComponentContext() SM = CTX.getServiceManager() -# ~ Export ok def create_instance(name, with_context=False): if with_context: instance = SM.createInstanceWithContext(name, CTX) @@ -189,28 +228,35 @@ def create_instance(name, with_context=False): return instance -def _get_app_config(key, node_name): +def get_app_config(node_name, key=''): name = 'com.sun.star.configuration.ConfigurationProvider' service = 'com.sun.star.configuration.ConfigurationAccess' cp = create_instance(name, True) node = PropertyValue(Name='nodepath', Value=node_name) try: ca = cp.createInstanceWithArguments(service, (node,)) - if ca and (ca.hasByName(key)): - data = ca.getPropertyValue(key) - return data + if ca and not key: + return ca + if ca and ca.hasByName(key): + return ca.getPropertyValue(key) except Exception as e: - log.error(e) + error(e) return '' -LANGUAGE = _get_app_config('ooLocale', 'org.openoffice.Setup/L10N/') +# ~ FILTER_PDF = '/org.openoffice.Office.Common/Filter/PDF/Export/' +LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale') LANG = LANGUAGE.split('-')[0] -NAME = TITLE = _get_app_config('ooName', 'org.openoffice.Setup/Product') -VERSION = _get_app_config('ooSetupVersion', 'org.openoffice.Setup/Product') +NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName') +VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion') + +nd = '/org.openoffice.Office.Calc/Calculate/Other/Date' +d = get_app_config(nd, 'DD') +m = get_app_config(nd, 'MM') +y = get_app_config(nd, 'YY') +DATE_OFFSET = datetime.date(y, m, d).toordinal() -# ~ Export ok def mri(obj): m = create_instance('mytools.Mri') if m is None: @@ -239,7 +285,6 @@ class LogWin(object): def __init__(self, doc): self.doc = doc - self.doc.Title = FILE_NAME_DEBUG def write(self, info): text = self.doc.Text @@ -249,34 +294,30 @@ class LogWin(object): return -# ~ Export ok def info(data): log.info(data) return -# ~ Export ok -def debug(info): +def debug(*info): if IS_WIN: doc = get_document(FILE_NAME_DEBUG) if doc is None: - # ~ doc = new_doc('writer') return doc = LogWin(doc.obj) - doc.write(info) + doc.write(str(info)) return - log.debug(str(info)) + data = [str(d) for d in info] + log.debug('\t'.join(data)) return -# ~ Export ok def error(info): log.error(info) return -# ~ Export ok def save_log(path, data): with open(path, 'a') as out: out.write('{} -{}- '.format(str(now())[:19], LOG_NAME)) @@ -292,11 +333,34 @@ 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 get_date(year, month, day, hour=-1, minute=-1, second=-1): + if hour > -1 or minute > -1 or second > -1: + h = hour + m = minute + s = second + if h == -1: + h = 0 + if m == -1: + m = 0 + if s == -1: + s = 0 + d = datetime.datetime(year, month, day, h, m, s) + else: + d = datetime.date(year, month, day) + return d -# ~ Export ok def get_config(key='', default=None, prefix='config'): path_json = FILE_NAME_CONFIG.format(prefix) values = None @@ -314,7 +378,6 @@ def get_config(key='', default=None, prefix='config'): return values -# ~ Export ok def set_config(key, value, prefix='config'): path_json = FILE_NAME_CONFIG.format(prefix) path = join(get_config_path('UserConfig'), path_json) @@ -322,10 +385,9 @@ def set_config(key, value, prefix='config'): values[key] = value with open(path, 'w', encoding='utf-8') as fh: json.dump(values, fh, ensure_ascii=False, sort_keys=True, indent=4) - return + return True -# ~ Export ok def sleep(seconds): time.sleep(seconds) return @@ -342,7 +404,6 @@ def _(msg): return MSG_LANG[L][msg] -# ~ Export ok def msgbox(message, title=TITLE, buttons=MSG_BUTTONS.BUTTONS_OK, type_msg='infobox'): """ Create message box type_msg: infobox, warningbox, errorbox, querybox, messbox @@ -354,18 +415,15 @@ def msgbox(message, title=TITLE, buttons=MSG_BUTTONS.BUTTONS_OK, type_msg='infob return mb.execute() -# ~ Export ok def question(message, title=TITLE): res = msgbox(message, title, MSG_BUTTONS.BUTTONS_YES_NO, 'querybox') return res == YES -# ~ Export ok def warning(message, title=TITLE): return msgbox(message, title, type_msg='warningbox') -# ~ Export ok def errorbox(message, title=TITLE): return msgbox(message, title, type_msg='errorbox') @@ -374,12 +432,10 @@ def get_desktop(): return create_instance('com.sun.star.frame.Desktop', True) -# ~ Export ok def get_dispatch(): return create_instance('com.sun.star.frame.DispatchHelper') -# ~ Export ok def call_dispatch(url, args=()): frame = get_document().frame dispatch = get_dispatch() @@ -387,7 +443,6 @@ def call_dispatch(url, args=()): return -# ~ Export ok def get_temp_file(): delete = True if IS_WIN: @@ -407,7 +462,6 @@ def _path_system(path): return path -# ~ Export ok def exists_app(name): try: dn = subprocess.DEVNULL @@ -418,12 +472,10 @@ def exists_app(name): return True -# ~ Export ok def exists_path(path): return Path(path).exists() -# ~ Export ok def get_type_doc(obj): for k, v in TYPE_DOC.items(): if obj.supportsService(v): @@ -443,12 +495,99 @@ def property_to_dict(values): return d +def set_properties(model, properties): + if 'X' in properties: + properties['PositionX'] = properties.pop('X') + if 'Y' in properties: + properties['PositionY'] = properties.pop('Y') + keys = tuple(properties.keys()) + values = tuple(properties.values()) + model.setPropertyValues(keys, values) + return + + def array_to_dict(values): d = {r[0]: r[1] for r in values} return d # ~ Custom classes +class ObjectBase(object): + + def __init__(self, obj): + self._obj = obj + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + def __getitem__(self, index): + return self.obj[index] + + def __getattr__(self, name): + a = None + if name == 'obj': + a = super().__getattr__(name) + else: + if hasattr(self.obj, name): + a = getattr(self.obj, name) + return a + + @property + def obj(self): + return self._obj + @obj.setter + def obj(self, value): + self._obj = value + + +class LOObjectBase(object): + + def __init__(self, obj): + self.__dict__['_obj'] = obj + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + return True + + def __setattr__(self, name, value): + print('BASE__setattr__', name) + if name == '_obj': + super().__setattr__(name, value) + else: + self.obj.setPropertyValue(name, value) + + # ~ def _try_for_method(self, name): + # ~ a = None + # ~ m = 'get{}'.format(name) + # ~ if hasattr(self.obj, m): + # ~ a = getattr(self.obj, m)() + # ~ else: + # ~ a = getattr(self.obj, name) + # ~ return a + + def __getattr__(self, name): + print('BASE__getattr__', name) + if name == 'obj': + a = super().__getattr__(name) + else: + a = self.obj.getPropertyValue(name) + # ~ Bug + if a is None: + msg = 'Error get: {} - {}'.format(self.obj.ImplementationName, name) + error(msg) + raise Exception(msg) + return a + + @property + def obj(self): + return self._obj + + class LODocument(object): def __init__(self, obj): @@ -457,23 +596,27 @@ 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() + self._cc = self.obj.getCurrentController() return @property def obj(self): return self._obj - @property - def type(self): - return self._type_doc - @property def title(self): return self.obj.getTitle() + @title.setter + def title(self, value): + self.obj.setTitle(value) + + @property + def uid(self): + return self.obj.RuntimeUID + + @property + def type(self): + return self._type_doc @property def frame(self): @@ -502,7 +645,7 @@ class LODocument(object): @property def visible(self): w = self._cc.getFrame().getContainerWindow() - return w.Visible + return w.isVisible() @visible.setter def visible(self, value): w = self._cc.getFrame().getContainerWindow() @@ -515,6 +658,11 @@ class LODocument(object): def zoom(self, value): self._cc.ZoomValue = value + @property + def table_auto_formats(self): + taf = create_instance('com.sun.star.sheet.TableAutoFormats') + return taf.ElementNames + def create_instance(self, name): obj = self.obj.createInstance(name) return obj @@ -543,7 +691,6 @@ class LODocument(object): self._cc.insertTransferable(transferable) return self.obj.getCurrentSelection() - @catch_exception def to_pdf(self, path, **kwargs): path_pdf = path if path: @@ -569,19 +716,320 @@ class LODocument(object): return path_pdf -class LOCalc(LODocument): +class FormControlBase(object): + EVENTS = { + 'action': 'actionPerformed', + 'click': 'mousePressed', + } + TYPES = { + 'actionPerformed': 'XActionListener', + 'mousePressed': 'XMouseListener', + } def __init__(self, obj): - super().__init__(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): + return self._obj.getName() + @name.setter + def name(self, value): + self._obj.setName(value) + + +class LOForms(ObjectBase): + + def __init__(self, obj, doc): + self._doc = doc + super().__init__(obj) + + def __getitem__(self, index): + form = super().__getitem__(index) + return LOForm(form) + + @property + def doc(self): + return self._doc + + @property + def count(self): + return self.obj.getCount() + + @property + def names(self): + return self.obj.getElementNames() + + def exists(self, name): + return name in self.names + + def insert(self, name): + form = self.doc.create_instance('com.sun.star.form.component.Form') + self.obj.insertByName(name, form) + return self[name] + + def remove(self, index): + if isinstance(index, int): + self.obj.removeByIndex(index) + else: + self.obj.removeByName(index) + return + + +class LOCellStyle(LOObjectBase): + + def __init__(self, obj): + super().__init__(obj) + + @property + def name(self): + return self.obj.Name + + def apply(self, properties): + set_properties(self.obj, properties) + return + + +class LOCellStyles(object): + + def __init__(self, obj): + self._obj = obj + + def __len__(self): + return len(self.obj) + + def __getitem__(self, index): + return LOCellStyle(self.obj[index]) + + def __setitem__(self, key, value): + self.obj[key] = value + + def __delitem__(self, key): + if not isinstance(key, str): + key = key.Name + del self.obj[key] + + def __contains__(self, item): + return item in self.obj + + @property + def obj(self): + return self._obj + + @property + def names(self): + return self.obj.ElementNames + + def apply(self, style, properties): + set_properties(style, properties) + 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): + super().__init__(obj) + self._sheets = obj.getSheets() + + def __getitem__(self, index): + if isinstance(index, str): + 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): + self._sheets[key] = value + + def __contains__(self, item): + return item in self.obj.Sheets + + @property + def headers(self): + return self._cc.ColumnRowHeaders + @headers.setter + def headers(self, value): + self._cc.ColumnRowHeaders = value + + @property + def tabs(self): + return self._cc.SheetTabs + @tabs.setter + def tabs(self, value): + self._cc.SheetTabs = value + @property def active(self): return LOCalcSheet(self._cc.getActiveSheet(), self) + def activate(self, sheet): + obj = sheet + if isinstance(sheet, LOCalcSheet): + obj = sheet.obj + elif isinstance(sheet, str): + obj = self[sheet].obj + self._cc.setActiveSheet(obj) + return + @property def selection(self): sel = self.obj.getCurrentSelection() @@ -589,6 +1037,97 @@ class LOCalc(LODocument): sel = LOCellRange(sel, self) return sel + @property + def sheets(self): + return LOCalcSheets(self._sheets, self) + + @property + def names(self): + return self.sheets.names + + @property + def cell_style(self): + obj = self.obj.getStyleFamilies()['CellStyles'] + return LOCellStyles(obj) + + def create(self): + return self.obj.createInstance('com.sun.star.sheet.Spreadsheet') + + def insert(self, name, pos=-1): + # ~ sheet = obj.createInstance('com.sun.star.sheet.Spreadsheet') + # ~ obj.Sheets['New'] = sheet + index = pos + if pos < 0: + index = self._sheets.Count + pos + 1 + if isinstance(name, str): + self._sheets.insertNewByName(name, index) + else: + for n in name: + self._sheets.insertNewByName(n, index) + name = n + return LOCalcSheet(self._sheets[name], self) + + def move(self, name, pos=-1): + return self.sheets.move(name, pos) + + def remove(self, name): + return self.sheets.remove(name) + + def copy(self, source='', target='', pos=-1): + index = pos + if pos < 0: + index = self._sheets.Count + pos + 1 + + names = source + if not names: + names = self.names + elif isinstance(source, str): + names = (source,) + + new_names = target + if not target: + new_names = [n + '_2' for n in names] + elif isinstance(target, str): + new_names = (target,) + + for i, ns in enumerate(names): + self.sheets.copy(ns, new_names[i], index + i) + + return LOCalcSheet(self._sheets[index], self) + + def copy_from(self, doc, source='', target='', pos=-1): + index = pos + if pos < 0: + index = self._sheets.Count + pos + 1 + + names = source + if not names: + names = doc.names + elif isinstance(source, str): + names = (source,) + + new_names = target + if not target: + new_names = names + elif isinstance(target, str): + new_names = (target,) + + for i, n in enumerate(names): + self._sheets.importSheet(doc.obj, n, index + i) + self.sheets[index + i].name = new_names[i] + + # ~ doc.getCurrentController().setActiveSheet(sheet) + # ~ For controls in sheet + # ~ doc.getCurrentController().setFormDesignMode(False) + + return LOCalcSheet(self._sheets[index], self) + + def sort(self, reverse=False): + names = sorted(self.names, reverse=reverse) + for i, n in enumerate(names): + self.sheets.move(n, i) + return + def get_cell(self, index=None): """ index is str 'A1' @@ -609,6 +1148,72 @@ class LOCalc(LODocument): self._cc.select(r) return + def create_cell_style(self, name=''): + obj = self.create_instance('com.sun.star.style.CellStyle') + if name: + self.cell_style[name] = obj + return LOCellStyle(obj) + + def clear_undo(self): + self.obj.getUndoManager().clear() + return + + def filter_by_color(self, cell=None): + if cell is None: + cell = self.selection.first + cr = cell.current_region + col = cell.column - cr.column + rangos = cell.get_column(col).visible + for r in rangos: + for row in range(r.rows): + c = r[row, 0] + if c.back_color != cell.back_color: + c.rows_visible = False + return + + +class LOCalcSheets(object): + + def __init__(self, obj, doc): + self._obj = obj + self._doc = doc + + def __getitem__(self, index): + return LOCalcSheet(self.obj[index], self.doc) + + @property + def obj(self): + return self._obj + + @property + def doc(self): + return self._doc + + @property + def count(self): + return self.obj.Count + + @property + def names(self): + return self.obj.ElementNames + + def copy(self, name, new_name, pos): + self.obj.copyByName(name, new_name, pos) + return + + def move(self, name, pos): + index = pos + if pos < 0: + index = self.count + pos + 1 + sheet = self.obj[name] + self.obj.moveByName(sheet.Name, index) + return + + def remove(self, name): + sheet = self.obj[name] + self.obj.removeByName(sheet.Name) + return + class LOCalcSheet(object): @@ -620,8 +1225,16 @@ class LOCalcSheet(object): def __getitem__(self, index): return LOCellRange(self.obj[index], self.doc) + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + def _init_values(self): - return + self._events = None + self._dp = self.obj.getDrawPage() + self._images = {i.Name: LOImage(i) for i in self._dp} @property def obj(self): @@ -631,6 +1244,95 @@ class LOCalcSheet(object): def doc(self): return self._doc + @property + def images(self): + return self._images + + @property + def name(self): + return self._obj.Name + @name.setter + def name(self, value): + self._obj.Name = value + + @property + def code_name(self): + return self._obj.CodeName + @code_name.setter + def code_name(self, value): + self._obj.CodeName = value + + @property + def color(self): + return self._obj.TabColor + @color.setter + def color(self, value): + self._obj.TabColor = get_color(value) + + @property + def active(self): + return self.doc.selection.first + + def activate(self): + self.doc.activate(self.obj) + return + + @property + def visible(self): + return self.obj.IsVisible + @visible.setter + def visible(self, value): + self.obj.IsVisible = value + + @property + def is_protected(self): + return self._obj.isProtected() + + @property + def password(self): + return '' + @visible.setter + def password(self, value): + self.obj.protect(value) + + def unprotect(self, value): + try: + self.obj.unprotect(value) + return True + except: + pass + return False + + def get_cursor(self, cell): + return self.obj.createCursorByRange(cell) + + def exists_chart(self, name): + return name in self.obj.Charts.ElementNames + + @property + def forms(self): + return LOForms(self._dp.getForms(), self.doc) + + @property + def events(self): + return self._events + @events.setter + def events(self, controllers): + self._events = controllers + self._connect_listeners() + + def _connect_listeners(self): + if self.events is None: + return + + listeners = { + 'addModifyListener': EventsModify, + } + for key, value in listeners.items(): + getattr(self.obj, key)(listeners[key](self.events)) + print('add_listener') + return + class LOWriter(LODocument): @@ -653,18 +1355,50 @@ class LOWriter(LODocument): def cursor(self): return self.text.createTextCursor() + @property + def paragraphs(self): + return [LOTextRange(p) for p in self.text] + @property def selection(self): - sel = self._cc.getSelection() - return LOTextRange(sel[0]) + sel = self.obj.getCurrentSelection() + 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() + if data.startswith('\n'): + c = data.split('\n') + for i in range(len(c)-1): + self.text.insertControlCharacter(cursor, PARAGRAPH_BREAK, False) + else: + self.text.insertString(cursor, data, False) + return + + def insert_table(self, data, cursor=None): + cursor = cursor or self.selection.cursor.getEnd() + table = self.obj.createInstance('com.sun.star.text.TextTable') + rows = len(data) + cols = len(data[0]) + table.initialize(rows, cols) + self.insert_content(cursor, table) + table.DataArray = data + return WriterTable(table) + + def create_chart(self, tipo, cursor=None): + cursor = cursor or self.selection.cursor.getEnd() + chart = LOChart(None, tipo) + chart.cursor = cursor + chart.doc = self + return chart def insert_content(self, cursor, data, replace=False): self.text.insertTextContent(cursor, data, replace) return - # ~ tt = doc.createInstance('com.sun.star.text.TextTable') - # ~ tt.initialize(5, 2) - # ~ f = doc.createInstance('com.sun.star.text.TextFrame') # ~ f.setSize(Size(10000, 500)) @@ -680,16 +1414,76 @@ class LOWriter(LODocument): self.insert_content(cursor, image) return + def go_start(self): + cursor = self._cc.getViewCursor() + cursor.gotoStart(False) + return cursor + + def go_end(self): + cursor = self._cc.getViewCursor() + cursor.gotoEnd(False) + return cursor + + def select(self, text): + 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): def __init__(self, obj): self._obj = obj + self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph' + self._is_table = self.obj.ImplementationName == 'SwXTextTable' @property def obj(self): return self._obj + @property + def is_paragraph(self): + return self._is_paragraph + + @property + def is_table(self): + return self._is_table + @property def string(self): return self.obj.String @@ -703,10 +1497,139 @@ class LOTextRange(object): return self.text.createTextCursorByRange(self.obj) -class LOBase(LODocument): +class LOBase(object): + TYPES = { + str: 'setString', + int: 'setInt', + float: 'setFloat', + bool: 'setBoolean', + Date: 'setDate', + Time: 'setTime', + DateTime: 'setTimestamp', + } + # ~ setArray + # ~ setBinaryStream + # ~ setBlob + # ~ setByte + # ~ setBytes + # ~ setCharacterStream + # ~ setClob + # ~ setNull + # ~ setObject + # ~ setObjectNull + # ~ setObjectWithInfo + # ~ setPropertyValue + # ~ setRef + def __init__(self, name, path='', **kwargs): + self._name = name + self._path = path + self._dbc = create_instance('com.sun.star.sdb.DatabaseContext') + if path: + path_url = _path_url(path) + db = self._dbc.createInstance() + db.URL = 'sdbc:embedded:firebird' + db.DatabaseDocument.storeAsURL(path_url, ()) + if not self.exists: + self._dbc.registerDatabaseLocation(name, path_url) + else: + if name.startswith('odbc:'): + self._con = self._odbc(name, kwargs) + else: + db = self._dbc.getByName(name) + self.path = _path_system(self._dbc.getDatabaseLocation(name)) + self._con = db.getConnection('', '') - def __init__(self, obj): - super().__init__(obj) + if self._con is None: + msg = 'Not connected to: {}'.format(name) + else: + msg = 'Connected to: {}'.format(name) + debug(msg) + + def _odbc(self, name, kwargs): + dm = create_instance('com.sun.star.sdbc.DriverManager') + args = dict_to_property(kwargs) + try: + con = dm.getConnectionWithInfo('sdbc:{}'.format(name), args) + return con + except Exception as e: + error(str(e)) + return None + + @property + def obj(self): + return self._obj + + @property + def name(self): + return self._name + + @property + def connection(self): + return self._con + + @property + def path(self): + return self._path + @path.setter + def path(self, value): + self._path = value + + @property + def exists(self): + return self._dbc.hasRegisteredDatabase(self.name) + + @classmethod + def register(self, path, name): + if not self._dbc.hasRegisteredDatabase(name): + self._dbc.registerDatabaseLocation(name, _path_url(path)) + return + + def revoke(self, name): + self._dbc.revokeDatabaseLocation(name) + return True + + def save(self): + # ~ self._db.connection.commit() + # ~ self._db.connection.getTables().refresh() + # ~ oDisp.executeDispatch(oFrame,".uno:DBRefreshTables", "", 0, Array()) + self._obj.DatabaseDocument.store() + self.refresh() + return + + def close(self): + self._con.close() + return + + def refresh(self): + self._con.getTables().refresh() + return + + def get_tables(self): + tables = self._con.getTables() + tables = [tables.getByIndex(i) for i in range(tables.Count)] + return tables + + def cursor(self, sql, params): + cursor = self._con.prepareStatement(sql) + for i, v in enumerate(params, 1): + if not type(v) in self.TYPES: + error('Type not support') + debug((i, type(v), v, self.TYPES[type(v)])) + getattr(cursor, self.TYPES[type(v)])(i, v) + return cursor + + def execute(self, sql, params): + debug(sql) + if params: + cursor = self.cursor(sql, params) + cursor.execute() + else: + cursor = self._con.createStatement() + cursor.execute(sql) + # ~ resulset = cursor.executeQuery(sql) + # ~ rows = cursor.executeUpdate(sql) + self.save() + return cursor class LODrawImpress(LODocument): @@ -718,7 +1641,6 @@ class LODrawImpress(LODocument): def draw_page(self): return self._cc.getCurrentPage() - @catch_exception def insert_image(self, path, **kwargs): w = kwargs.get('width', 3000) h = kwargs.get('Height', 1000) @@ -772,12 +1694,15 @@ class LOCellRange(object): def __enter__(self): return self - def __exit__(self, *args): + def __exit__(self, exc_type, exc_value, traceback): pass 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 @@ -827,31 +1752,124 @@ 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() + t = (data - datetime.datetime.fromordinal(d)).seconds / SECONDS_DAY + self.obj.setValue(d - DATE_OFFSET + t) + elif isinstance(data, datetime.date): + d = data.toordinal() + self.obj.setValue(d - DATE_OFFSET) + elif isinstance(data, datetime.time): + d = (data.hour * 3600 + data.minute * 60 + data.second) / SECONDS_DAY + self.obj.setValue(d) @property def data(self): return self.obj.getDataArray() @data.setter def data(self, values): - if isinstance(values, list): - values = tuple(values) self.obj.setDataArray(values) - def offset(self, col=1, row=0): + @property + def formula(self): + return self.obj.getFormulaArray() + @formula.setter + def formula(self, values): + self.obj.setFormulaArray(values) + + @property + def column(self): a = self.address - col = a.Column + col - row = a.Row + row - return LOCellRange(self.sheet[row,col], self.doc) + if hasattr(a, 'Column'): + c = a.Column + else: + c = a.StartColumn + return c + + @property + def columns(self): + return self._obj.Columns.Count + + @property + def rows(self): + return self._obj.Rows.Count + + def to_size(self, rows, cols): + cursor = self.sheet.get_cursor(self.obj[0,0]) + cursor.collapseToSize(cols, rows) + return LOCellRange(self.sheet[cursor.AbsoluteName].obj, self.doc) + + def copy_from(self, rango, formula=False): + data = rango + if isinstance(rango, LOCellRange): + if formula: + data = rango.formula + else: + data = rango.data + rows = len(data) + cols = len(data[0]) + 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): + rango = cell.to_size(self.rows, self.columns) + if formula: + rango.formula = self.data + else: + 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 + row = ra.EndRow + row + return LOCellRange(self.sheet[row, col].obj, self.doc) + + @property + def next_cell(self): + a = self.current_region.address + if hasattr(a, 'StartColumn'): + col = a.StartColumn + else: + col = a.Column + if hasattr(a, 'EndRow'): + row = a.EndRow + 1 + else: + row = a.Row + 1 + + return LOCellRange(self.sheet[row, col].obj, self.doc) @property def sheet(self): - return self.obj.Spreadsheet + return LOCalcSheet(self.obj.Spreadsheet, self.doc) + + @property + def charts(self): + return self.obj.Spreadsheet.Charts + + @property + def ps(self): + ps = Rectangle() + s = self.obj.Size + p = self.obj.Position + ps.X = p.X + ps.Y = p.Y + ps.Width = s.Width + ps.Height = s.Height + return ps @property def draw_page(self): - return self.sheet.getDrawPage() + return self.sheet.obj.getDrawPage() @property def name(self): @@ -867,11 +1885,50 @@ 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.createCursorByRange(self.obj[0,0]) + cursor = self.sheet.get_cursor(self.obj[0,0]) cursor.collapseToCurrentRegion() - return LOCellRange(self.sheet[cursor.AbsoluteName], self.doc) + return LOCellRange(self.sheet[cursor.AbsoluteName].obj, self.doc) + + @property + def visible(self): + cursor = self.sheet.get_cursor(self.obj) + rangos = [LOCellRange(self.sheet[r.AbsoluteName].obj, self.doc) + for r in cursor.queryVisibleCells()] + return tuple(rangos) + + @property + def empty(self): + cursor = self.sheet.get_cursor(self.obj) + rangos = [LOCellRange(self.sheet[r.AbsoluteName].obj, self.doc) + for r in cursor.queryEmptyCells()] + return tuple(rangos) + + @property + def back_color(self): + return self._obj.CellBackColor + @back_color.setter + def back_color(self, value): + self._obj.CellBackColor = get_color(value) + + @property + def cell_style(self): + return self.obj.CellStyle + @cell_style.setter + def cell_style(self, value): + self.obj.CellStyle = value + + @property + def auto_format(self): + return self.obj.CellStyle + @auto_format.setter + def auto_format(self, value): + self.obj.autoFormat(value) def insert_image(self, path, **kwargs): s = self.obj.Size @@ -884,17 +1941,128 @@ class LOCellRange(object): img.setSize(Size(w, h)) return + def insert_shape(self, tipo, **kwargs): + s = self.obj.Size + w = kwargs.get('width', s.Width) + h = kwargs.get('Height', s.Height) + img = self.doc.create_instance('com.sun.star.drawing.{}Shape'.format(tipo)) + set_properties(img, kwargs) + self.draw_page.add(img) + img.Anchor = self.obj + img.setSize(Size(w, h)) + return + def select(self): self.doc._cc.select(self.obj) return + def in_range(self, rango): + if isinstance(rango, LOCellRange): + address = rango.address + else: + address = rango.getRangeAddress() + cursor = self.sheet.get_cursor(self.obj) + result = cursor.queryIntersection(address) + return bool(result.Count) + + def fill(self, source=1): + self.obj.fillAuto(0, source) + return + + def clear(self, what=31): + # ~ http://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1sheet_1_1CellFlags.html + self.obj.clearContents(what) + return + + @property + def rows_visible(self): + return self._obj.getRows().IsVisible + @rows_visible.setter + def rows_visible(self, value): + self._obj.getRows().IsVisible = value + + @property + def columns_visible(self): + return self._obj.getColumns().IsVisible + @columns_visible.setter + def columns_visible(self, value): + self._obj.getColumns().IsVisible = value + + def get_column(self, index=0, first=False): + ca = self.address + ra = self.current_region.address + if hasattr(ca, 'Column'): + col = ca.Column + else: + col = ca.StartColumn + index + start = 1 + if first: + start = 0 + if hasattr(ra, 'Row'): + row_start = ra.Row + start + row_end = ra.Row + 1 + else: + row_start = ra.StartRow + start + row_end = ra.EndRow + 1 + return LOCellRange(self.sheet[row_start:row_end, col:col+1].obj, self.doc) + + def import_csv(self, path, **kwargs): + data = import_csv(path, **kwargs) + self.copy_from(data) + return + + def export_csv(self, path, **kwargs): + data = self.current_region.data + export_csv(path, data, **kwargs) + return + + def create_chart(self, tipo): + chart = LOChart(None, tipo) + 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): - def __init__(self, controller, window=None): + def __init__(self, controller, name, window=None): self._controller = controller + 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: @@ -903,27 +2071,25 @@ class EventsListenerBase(unohelper.Base, XEventListener): class EventsButton(EventsListenerBase, XActionListener): - def __init__(self, controller): - super().__init__(controller) + def __init__(self, controller, name): + super().__init__(controller, name) def actionPerformed(self, event): - name = event.Source.Model.Name - event_name = '{}_action'.format(name) + event_name = '{}_action'.format(self._name) if hasattr(self._controller, event_name): getattr(self._controller, event_name)(event) return -class EventsMouse(EventsListenerBase, XMouseListener): +class EventsMouse(EventsListenerBase, XMouseListener, XMouseMotionListener): - def __init__(self, controller): - super().__init__(controller) + def __init__(self, controller, name): + super().__init__(controller, name) def mousePressed(self, event): - name = event.Source.Model.Name - event_name = '{}_click'.format(name) + event_name = '{}_click'.format(self._name) if event.ClickCount == 2: - event_name = '{}_double_click'.format(name) + event_name = '{}_double_click'.format(self._name) if hasattr(self._controller, event_name): getattr(self._controller, event_name)(event) return @@ -937,6 +2103,26 @@ class EventsMouse(EventsListenerBase, XMouseListener): def mouseExited(self, event): pass + # ~ XMouseMotionListener + def mouseMoved(self, event): + pass + + def mouseDragged(self, event): + pass + + +class EventsMouseLink(EventsMouse): + + def mouseEntered(self, event): + obj = event.Source.Model + obj.TextColor = get_color('blue') + return + + def mouseExited(self, event): + obj = event.Source.Model + obj.TextColor = 0 + return + class EventsMouseGrid(EventsMouse): selected = False @@ -956,13 +2142,243 @@ class EventsMouseGrid(EventsMouse): return def mouseReleased(self, event): - obj = event.Source - col = obj.getColumnAtPoint(event.X, event.Y) - row = obj.getRowAtPoint(event.X, event.Y) - if row == -1 and col > -1: - gdm = obj.Model.GridDataModel - for i in range(gdm.RowCount): - gdm.updateRowHeading(i, i + 1) + # ~ obj = event.Source + # ~ col = obj.getColumnAtPoint(event.X, event.Y) + # ~ row = obj.getRowAtPoint(event.X, event.Y) + # ~ if row == -1 and col > -1: + # ~ gdm = obj.Model.GridDataModel + # ~ for i in range(gdm.RowCount): + # ~ gdm.updateRowHeading(i, i + 1) + return + + +class EventsModify(EventsListenerBase, XModifyListener): + + def __init__(self, controller): + super().__init__(controller) + + def modified(self, event): + event_name = '{}_modified'.format(event.Source.Name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + +class EventsItem(EventsListenerBase, XItemListener): + + def __init__(self, controller, name): + super().__init__(controller, name) + + def disposing(self, event): + pass + + def itemStateChanged(self, event): + event_name = '{}_item_changed'.format(self.name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + +class EventsItemRoadmap(EventsItem): + + def itemStateChanged(self, event): + dialog = event.Source.Context.Model + dialog.Step = event.ItemId + 1 + return + + +class EventsFocus(EventsListenerBase, XFocusListener): + + def __init__(self, controller, name): + super().__init__(controller, name) + + def focusGained(self, event): + service = event.Source.Model.ImplementationName + if service == 'stardiv.Toolkit.UnoControlListBoxModel': + return + obj = event.Source.Model + obj.BackgroundColor = COLOR_ON_FOCUS + + def focusLost(self, event): + obj = event.Source.Model + obj.BackgroundColor = -1 + + +class EventsKey(EventsListenerBase, XKeyListener): + """ + event.KeyChar + event.KeyCode + event.KeyFunc + event.Modifiers + """ + + def __init__(self, controller, name): + super().__init__(controller, name) + + def keyPressed(self, event): + pass + + def keyReleased(self, event): + event_name = '{}_key_released'.format(self._name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + 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 + event.KeyCode + event.KeyFunc + event.Modifiers + """ + + def __init__(self, cls): + super().__init__(cls.events, cls.name) + self._cls = cls + + def keyPressed(self, event): + pass + + def keyReleased(self, event): + event_name = '{}_key_released'.format(self._cls.name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + else: + if event.KeyFunc == QUIT and hasattr(self._cls, 'close'): + self._cls.close() + return + + +class EventsWindow(EventsListenerBase, XTopWindowListener, XWindowListener): + + def __init__(self, cls): + self._cls = cls + super().__init__(cls.events, cls.name, cls._window) + + def windowOpened(self, event): + event_name = '{}_opened'.format(self._name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + def windowActivated(self, event): + control_name = '{}_activated'.format(event.Source.Model.Name) + if hasattr(self._controller, control_name): + getattr(self._controller, control_name)(event) + return + + def windowDeactivated(self, event): + control_name = '{}_deactivated'.format(event.Source.Model.Name) + if hasattr(self._controller, control_name): + getattr(self._controller, control_name)(event) + return + + def windowMinimized(self, event): + pass + + def windowNormalized(self, event): + pass + + def windowClosing(self, event): + if self._window: + control_name = 'window_closing' + else: + control_name = '{}_closing'.format(event.Source.Model.Name) + + if hasattr(self._controller, control_name): + getattr(self._controller, control_name)(event) + # ~ else: + # ~ if not self._modal and not self._block: + # ~ event.Source.Visible = False + return + + def windowClosed(self, event): + control_name = '{}_closed'.format(event.Source.Model.Name) + if hasattr(self._controller, control_name): + getattr(self._controller, control_name)(event) + return + + # ~ XWindowListener + def windowResized(self, event): + 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) + return + + def windowMoved(self, event): + pass + + def windowShown(self, event): + pass + + def windowHidden(self, event): + pass + + +class EventsMenu(EventsListenerBase, XMenuListener): + + def __init__(self, controller): + super().__init__(controller, '') + + def itemHighlighted(self, event): + pass + + def itemSelected(self, event): + name = event.Source.getCommand(event.MenuId) + if name.startswith('menu'): + event_name = '{}_selected'.format(name) + else: + event_name = 'menu_{}_selected'.format(name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + def itemActivated(self, event): + return + + def itemDeactivated(self, event): return @@ -987,35 +2403,65 @@ class UnoBaseObject(object): @property def parent(self): + ps = self.obj.getContext().PosSize return self.obj.getContext() + def _get_possize(self, name): + ps = self.obj.getPosSize() + return getattr(ps, name) + + def _set_possize(self, name, value): + ps = self.obj.getPosSize() + setattr(ps, name, value) + self.obj.setPosSize(ps.X, ps.Y, ps.Width, ps.Height, POSSIZE) + return + @property def x(self): - return self.model.PositionX + if hasattr(self.model, 'PositionX'): + return self.model.PositionX + return self._get_possize('X') @x.setter def x(self, value): - self.model.PositionX = value + if hasattr(self.model, 'PositionX'): + self.model.PositionX = value + else: + self._set_possize('X', value) @property def y(self): - return self.model.PositionY + if hasattr(self.model, 'PositionY'): + return self.model.PositionY + return self._get_possize('Y') @y.setter def y(self, value): - self.model.PositionY = value + if hasattr(self.model, 'PositionY'): + self.model.PositionY = value + else: + self._set_possize('Y', value) @property def width(self): 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): - 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.obj, 'PosSize'): + self._set_possize('Height', value) + else: + self._model.Height = value @property def tag(self): @@ -1024,6 +2470,20 @@ class UnoBaseObject(object): def tag(self, value): self.model.Tag = value + @property + def visible(self): + return self.obj.Visible + @visible.setter + def visible(self, value): + self.obj.setVisible(value) + + @property + def enabled(self): + return self.model.Enabled + @enabled.setter + def enabled(self, value): + self.model.Enabled = value + @property def step(self): return self.model.Step @@ -1031,6 +2491,13 @@ class UnoBaseObject(object): def step(self, value): self.model.Step = value + @property + def back_color(self): + return self.model.BackgroundColor + @back_color.setter + def back_color(self, value): + self.model.BackgroundColor = value + @property def rules(self): return self._rules @@ -1055,16 +2522,21 @@ class UnoBaseObject(object): return def move(self, origin, x=0, y=5): - w = 0 - h = 0 if x: - w = origin.width + self.x = origin.x + origin.width + x + else: + self.x = origin.x if y: - h = origin.height - x = origin.x + x + w - y = origin.y + y + h - self.x = x - self.y = y + self.y = origin.y + origin.height + y + else: + self.y = origin.y + return + + def possize(self, origin): + self.x = origin.x + self.y = origin.y + self.width = origin.width + self.height = origin.height return @@ -1085,6 +2557,16 @@ class UnoLabel(UnoBaseObject): self.model.Label = value +class UnoLabelLink(UnoLabel): + + def __init__(self, obj): + super().__init__(obj) + + @property + def type(self): + return 'link' + + class UnoButton(UnoBaseObject): def __init__(self, obj): @@ -1127,7 +2609,6 @@ class UnoListBox(UnoBaseObject): def __init__(self, obj): super().__init__(obj) - self._data = [] @property def type(self): @@ -1135,15 +2616,55 @@ class UnoListBox(UnoBaseObject): @property def value(self): - return self.obj.SelectedItem + return self.obj.getSelectedItem() + + @property + def count(self): + return len(self.data) @property def data(self): - return self._data + return self.model.StringItemList @data.setter def data(self, values): - self._data = list(sorted(values)) - self.model.StringItemList = self.data + 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) + else: + self.obj.selectItemPos(pos, True) + return + + def clear(self): + self.model.removeAllItems() + return + + def _set_image_url(self, image): + 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) + + def insert(self, value, path='', pos=-1, show=True): + if pos < 0: + pos = self.count + if path: + self.model.insertItem(pos, value, self._set_image_url(path)) + else: + self.model.insertItemText(pos, value) + if show: + self.select(pos) return @@ -1177,16 +2698,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) @@ -1226,6 +2750,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) @@ -1235,18 +2763,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): @@ -1259,9 +2786,744 @@ class UnoGrid(UnoBaseObject): return +class UnoRoadmap(UnoBaseObject): + + def __init__(self, obj): + super().__init__(obj) + self._options = () + + @property + def options(self): + return self._options + @options.setter + def options(self, values): + self._options = values + for i, v in enumerate(values): + opt = self.model.createInstance() + opt.ID = i + opt.Label = v + self.model.insertByIndex(i, opt) + return + + @property + def enabled(self): + return True + @enabled.setter + def enabled(self, value): + for m in self.model: + m.Enabled = value + return + + def set_enabled(self, index, value): + self.model.getByIndex(index).Enabled = value + 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, + 'button': UnoButton, + 'text': UnoText, + 'listbox': UnoListBox, + 'grid': UnoGrid, + 'link': UnoLabelLink, + 'roadmap': UnoRoadmap, + 'tree': UnoTree, + 'tab': UnoTab, + # ~ 'image': UnoImage, + # ~ 'radio': UnoRadio, + # ~ 'groupbox': UnoGroupBox, + '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] + + +def add_listeners(events, control, name=''): + listeners = { + 'addActionListener': EventsButton, + 'addMouseListener': EventsMouse, + 'addItemListener': EventsItem, + 'addFocusListener': EventsFocus, + 'addKeyListener': EventsKey, + 'addTabListener': EventsTab, + } + if hasattr(control, 'obj'): + control = contro.obj + # ~ debug(control.ImplementationName) + is_grid = control.ImplementationName == 'stardiv.Toolkit.GridControl' + is_link = control.ImplementationName == 'stardiv.Toolkit.UnoFixedHyperlinkControl' + is_roadmap = control.ImplementationName == 'stardiv.Toolkit.UnoRoadmapControl' + + for key, value in listeners.items(): + if hasattr(control, key): + if is_grid and key == 'addMouseListener': + control.addMouseListener(EventsMouseGrid(events, name)) + continue + if is_link and key == 'addMouseListener': + control.addMouseListener(EventsMouseLink(events, name)) + continue + if is_roadmap and key == 'addItemListener': + control.addItemListener(EventsItemRoadmap(events, 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 + + +class WriterTable(ObjectBase): + + def __init__(self, obj): + super().__init__(obj) + + def __getitem__(self, key): + obj = super().__getitem__(key) + return WriterTableRange(obj, key, self.name) + + @property + def name(self): + return self.obj.Name + @name.setter + def name(self, value): + self.obj.Name = value + + +class WriterTableRange(ObjectBase): + + def __init__(self, obj, index, table_name): + self._index = index + self._table_name = table_name + super().__init__(obj) + self._is_cell = hasattr(self.obj, 'CellName') + + def __getitem__(self, key): + obj = super().__getitem__(key) + return WriterTableRange(obj, key, self._table_name) + + @property + def value(self): + return self.obj.String + @value.setter + def value(self, value): + self.obj.String = value + + @property + def data(self): + return self.obj.getDataArray() + @data.setter + def data(self, values): + if isinstance(values, list): + values = tuple(values) + self.obj.setDataArray(values) + + @property + def rows(self): + return len(self.data) + + @property + def columns(self): + return len(self.data[0]) + + @property + def name(self): + if self._is_cell: + name = '{}.{}'.format(self._table_name, self.obj.CellName) + elif isinstance(self._index, str): + name = '{}.{}'.format(self._table_name, self._index) + else: + c1 = self.obj[0,0].CellName + c2 = self.obj[self.rows-1,self.columns-1].CellName + name = '{}.{}:{}'.format(self._table_name, c1, c2) + return name + + def get_cell(self, *index): + return self[index] + + def get_column(self, index=0, start=1): + return self[start:self.rows,index:index+1] + + def get_series(self): + class Serie(): + pass + series = [] + for i in range(self.columns): + serie = Serie() + serie.label = self.get_cell(0,i).name + serie.data = self.get_column(i).data + serie.values = self.get_column(i).name + series.append(serie) + return series + + +class ChartFormat(object): + + def __call__(self, obj): + for k, v in self.__dict__.items(): + if hasattr(obj, k): + setattr(obj, k, v) + + +class LOChart(object): + BASE = 'com.sun.star.chart.{}Diagram' + + def __init__(self, obj, tipo=''): + self._obj = obj + self._type = tipo + self._name = '' + self._table = None + self._data = () + self._data_series = () + self._cell = None + self._cursor = None + self._doc = None + self._title = ChartFormat() + self._subtitle = ChartFormat() + self._legend = ChartFormat() + self._xaxistitle = ChartFormat() + self._yaxistitle = ChartFormat() + self._xaxis = ChartFormat() + self._yaxis = ChartFormat() + self._xmaingrid = ChartFormat() + self._ymaingrid = ChartFormat() + self._xhelpgrid = ChartFormat() + self._yhelpgrid = ChartFormat() + self._area = ChartFormat() + self._wall = ChartFormat() + self._dim3d = False + self._series = () + self._labels = () + return + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.insert() + + @property + def obj(self): + return self._obj + @obj.setter + def obj(self, value): + self._obj = value + + @property + def name(self): + return self._name + @name.setter + def name(self, value): + self._name = value + + @property + def type(self): + return self._type + @type.setter + def type(self, value): + self._type = value + + @property + def table(self): + return self._table + @table.setter + def table(self, value): + self._table = value + + @property + def data(self): + return self._data + @data.setter + def data(self, value): + self._data = value + + @property + def cell(self): + return self._cell + @cell.setter + def cell(self, value): + self._cell = value + self.doc = value.doc + + @property + def cursor(self): + return self._cursor + @cursor.setter + def cursor(self, value): + self._cursor = value + + @property + def doc(self): + return self._doc + @doc.setter + def doc(self, value): + self._doc = value + + @property + def width(self): + return self._width + @width.setter + def width(self, value): + self._width = value + + @property + def height(self): + return self._height + @height.setter + def height(self, value): + self._height = value + + @property + def title(self): + return self._title + + @property + def subtitle(self): + return self._subtitle + + @property + def legend(self): + return self._legend + + @property + def xaxistitle(self): + return self._xaxistitle + + @property + def yaxistitle(self): + return self._yaxistitle + + @property + def xaxis(self): + return self._xaxis + + @property + def yaxis(self): + return self._yaxis + + @property + def xmaingrid(self): + return self._xmaingrid + + @property + def ymaingrid(self): + return self._ymaingrid + + @property + def xhelpgrid(self): + return self._xhelpgrid + + @property + def yhelpgrid(self): + return self._yhelpgrid + + @property + def area(self): + return self._area + + @property + def wall(self): + return self._wall + + @property + def dim3d(self): + return self._dim3d + @dim3d.setter + def dim3d(self, value): + self._dim3d = value + + @property + def series(self): + return self._series + @series.setter + def series(self, value): + self._series = value + + @property + def data_series(self): + return self._series + @data_series.setter + def data_series(self, value): + self._data_series = value + + @property + def labels(self): + return self._labels + @labels.setter + def labels(self, value): + self._labels = value + + def _add_series_writer(self, chart): + dp = self.doc.create_instance('com.sun.star.chart2.data.DataProvider') + chart.attachDataProvider(dp) + chart_type = chart.getFirstDiagram().getCoordinateSystems()[0].getChartTypes()[0] + self._data_series = self.table[self.data].get_series() + series = [self._create_serie(dp, s) for s in self._data_series[1:]] + chart_type.setDataSeries(tuple(series)) + chart_data = chart.getData() + chart_data.ComplexRowDescriptions = self._data_series[0].data + return + + def _get_series(self): + rango = self._data_series + class Serie(): + pass + series = [] + for i in range(0, rango.columns, 2): + serie = Serie() + serie.label = rango[0, i+1].name + serie.xvalues = rango.get_column(i).name + serie.values = rango.get_column(i+1).name + series.append(serie) + return series + + def _add_series_calc(self, chart): + dp = self.doc.create_instance('com.sun.star.chart2.data.DataProvider') + chart.attachDataProvider(dp) + chart_type = chart.getFirstDiagram().getCoordinateSystems()[0].getChartTypes()[0] + series = self._get_series() + series = [self._create_serie(dp, s) for s in series] + chart_type.setDataSeries(tuple(series)) + return + + def _create_serie(self, dp, data): + serie = create_instance('com.sun.star.chart2.DataSeries') + rango = data.values + is_x = hasattr(data, 'xvalues') + if is_x: + xrango = data.xvalues + rango_label = data.label + + lds = create_instance('com.sun.star.chart2.data.LabeledDataSequence') + values = self._create_data(dp, rango, 'values-y') + lds.setValues(values) + if data.label: + label = self._create_data(dp, rango_label, '') + lds.setLabel(label) + + xlds = () + if is_x: + xlds = create_instance('com.sun.star.chart2.data.LabeledDataSequence') + values = self._create_data(dp, xrango, 'values-x') + xlds.setValues(values) + + if is_x: + serie.setData((lds, xlds)) + else: + serie.setData((lds,)) + + return serie + + def _create_data(self, dp, rango, role): + data = dp.createDataSequenceByRangeRepresentation(rango) + if not data is None: + data.Role = role + return data + + def _from_calc(self): + ps = self.cell.ps + ps.Width = self.width + ps.Height = self.height + charts = self.cell.charts + data = () + if self.data: + data = (self.data.address,) + charts.addNewByName(self.name, ps, data, True, True) + self.obj = charts.getByName(self.name) + chart = self.obj.getEmbeddedObject() + chart.setDiagram(chart.createInstance(self.BASE.format(self.type))) + if not self.data: + self._add_series_calc(chart) + return chart + + def _from_writer(self): + obj = self.doc.create_instance('com.sun.star.text.TextEmbeddedObject') + obj.setPropertyValue('CLSID', '12DCAE26-281F-416F-a234-c3086127382e') + obj.Name = self.name + obj.setSize(Size(self.width, self.height)) + self.doc.insert_content(self.cursor, obj) + self.obj = obj + chart = obj.getEmbeddedObject() + tipo = self.type + if self.type == 'Column': + tipo = 'Bar' + chart.Diagram.Vertical = True + chart.setDiagram(chart.createInstance(self.BASE.format(tipo))) + chart.DataSourceLabelsInFirstColumn = True + if isinstance(self.data, str): + self._add_series_writer(chart) + else: + chart_data = chart.getData() + labels = [r[0] for r in self.data] + data = [(r[1],) for r in self.data] + 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'))) + + return chart + + def insert(self): + if not self.cell is None: + chart = self._from_calc() + elif not self.cursor is None: + chart = self._from_writer() + + diagram = chart.Diagram + + if self.type == 'Bar': + diagram.Vertical = True + + if hasattr(self.title, 'String'): + chart.HasMainTitle = True + self.title(chart.Title) + + if hasattr(self.subtitle, 'String'): + chart.HasSubTitle = True + self.subtitle(chart.SubTitle) + + if self.legend.__dict__: + chart.HasLegend = True + self.legend(chart.Legend) + + if self.xaxistitle.__dict__: + diagram.HasXAxisTitle = True + self.xaxistitle(diagram.XAxisTitle) + + if self.yaxistitle.__dict__: + diagram.HasYAxisTitle = True + self.yaxistitle(diagram.YAxisTitle) + + if self.dim3d: + diagram.Dim3D = True + + if self.series: + data_series = chart.getFirstDiagram( + ).getCoordinateSystems( + )[0].getChartTypes()[0].DataSeries + for i, serie in enumerate(data_series): + for k, v in self.series[i].items(): + if hasattr(serie, k): + setattr(serie, k, v) + 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): + def __init__(self, **properties): self._obj = self._create(properties) self._init_values() @@ -1269,22 +3531,29 @@ class LODialog(object): self._model = self._obj.Model self._init_controls() self._events = None - # ~ self._response = None + self._color_on_focus = -1 + self._id_extension = '' + self._images = 'images' return def _create(self, properties): path = properties.pop('Path', '') if path: - dp = create_instance('com.sun.star.awt.DialogProvider2', True) + dp = create_instance('com.sun.star.awt.DialogProvider', True) return dp.createDialog(_path_url(path)) - if 'Library' in properties: - location = properties['Location'] + if 'Location' in properties: + location = properties.get('Location', 'application') + library = properties.get('Library', 'Standard') if location == 'user': location = 'application' - dp = create_instance('com.sun.star.awt.DialogProvider2', True) + dp = create_instance('com.sun.star.awt.DialogProvider', True) path = 'vnd.sun.star.script:{}.{}?location={}'.format( - properties['Library'], properties['Name'], location) + library, properties['Name'], location) + if location == 'document': + uid = get_document().uid + path = 'vnd.sun.star.tdoc:/{}/Dialogs/{}/{}.xml'.format( + uid, library, properties['Name']) return dp.createDialog(path) dlg = create_instance('com.sun.star.awt.UnoControlDialog', True) @@ -1297,8 +3566,24 @@ class LODialog(object): return dlg - def _init_controls(self): + def _get_type_control(self, name): + types = { + 'stardiv.Toolkit.UnoFixedTextControl': 'label', + '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] + def _init_controls(self): + for control in self.obj.getControls(): + tipo = self._get_type_control(control.ImplementationName) + name = control.Model.Name + control = get_custom_class(tipo, control) + setattr(self, name, control) return @property @@ -1309,6 +3594,52 @@ class LODialog(object): def model(self): return self._model + @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 + + @property + def images(self): + return self._images + @images.setter + def images(self, value): + self._images = value + + @property + def height(self): + return self.model.Height + @height.setter + def height(self, value): + self.model.Height = value + + @property + def width(self): + return self.model.Width + @width.setter + def width(self, value): + self.model.Width = value + + @property + def color_on_focus(self): + return self._color_on_focus + @color_on_focus.setter + def color_on_focus(self, value): + global COLOR_ON_FOCUS + COLOR_ON_FOCUS = get_color(value) + self._color_on_focus = COLOR_ON_FOCUS + + @property + def step(self): + return self.model.Step + @step.setter + def step(self, value): + self.model.Step = value + @property def events(self): return self._events @@ -1318,23 +3649,8 @@ class LODialog(object): self._connect_listeners() def _connect_listeners(self): - - return - - def _add_listeners(self, control): - if self.events is None: - return - - listeners = { - 'addActionListener': EventsButton, - 'addMouseListener': EventsMouse, - } - for key, value in listeners.items(): - if hasattr(control.obj, key): - if control.type == 'grid' and key == 'addMouseListener': - control.obj.addMouseListener(EventsMouseGrid(self.events)) - continue - getattr(control.obj, key)(listeners[key](self.events)) + for control in self.obj.getControls(): + add_listeners(self._events, control, control.Model.Name) return def open(self): @@ -1346,72 +3662,334 @@ class LODialog(object): def _get_control_model(self, control): services = { 'label': 'com.sun.star.awt.UnoControlFixedTextModel', - 'button': 'com.sun.star.awt.UnoControlButtonModel', + 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel', 'text': 'com.sun.star.awt.UnoControlEditModel', 'listbox': 'com.sun.star.awt.UnoControlListBoxModel', - 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel', + 'button': 'com.sun.star.awt.UnoControlButtonModel', 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel', - 'image': 'com.sun.star.awt.UnoControlImageControlModel', - 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel', - 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel', - 'tree': 'com.sun.star.awt.tree.TreeControlModel', '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 _get_custom_class(self, tipo, obj): - classes = { - 'label': UnoLabel, - 'button': UnoButton, - 'text': UnoText, - 'listbox': UnoListBox, - 'grid': UnoGrid, - # ~ 'link': UnoLink, - # ~ 'tab': UnoTab, - # ~ 'roadmap': UnoRoadmap, - # ~ 'image': UnoImage, - # ~ 'radio': UnoRadio, - # ~ 'groupbox': UnoGroupBox, - # ~ 'tree': UnoTree, - } - return classes[tipo](obj) - def _set_column_model(self, 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) - # ~ column_model.setDefaultColumns(len(columns)) 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) - # ~ mri(grid_column) return column_model - def _set_image_url(self, path): - if exists_path(path): - return _path_url(path) - return '' + def _set_image_url(self, image): + if exists_path(image): + return _path_url(image) - @catch_exception - def add_control(self, properties): - tipo = properties.pop('Type').lower() + if not self.id_extension: + return '' + path = get_path_extension(self.id_extension) + path = join(path, self.images, image) + return _path_url(path) + + def _special_properties(self, tipo, properties): columns = properties.pop('Columns', ()) if tipo == 'grid': properties['ColumnModel'] = self._set_column_model(columns) - if tipo == 'button' and 'ImageURL' in properties: + 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 == '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) name = properties['Name'] self.model.insertByName(name, model) - control = self._get_custom_class(tipo, self.obj.getControl(name)) - self._add_listeners(control) + 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 + def center(self, control, x=0, y=0): + w = self.width + h = self.height + + if isinstance(control, tuple): + wt = SEPARATION * -1 + for c in control: + wt += c.width + SEPARATION + x = w / 2 - wt / 2 + for c in control: + c.x = x + x = c.x + c.width + SEPARATION + return + + if x < 0: + x = w + x - control.width + elif x == 0: + x = w / 2 - control.width / 2 + if y < 0: + y = h + y - control.height + elif y == 0: + y = h / 2 - control.height / 2 + control.x = x + control.y = y + return + + +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), + properties.get('Y', 0), + properties.get('Width', 500), + properties.get('Height', 500), + ) + self._title = properties.get('Title', TITLE) + self._create_frame(ps) + self._create_container(ps) + self._create_subcontainer(ps) + # ~ self._create_splitter(ps) + return + + def _create_frame(self, ps): + service = 'com.sun.star.frame.TaskCreator' + tc = create_instance(service, True) + self._frame = tc.createInstanceWithArguments(( + NamedValue('FrameName', 'EasyMacroWin'), + NamedValue('PosSize', Rectangle(*ps)), + )) + self._window = self._frame.getContainerWindow() + self._toolkit = self._window.getToolkit() + desktop = get_desktop() + self._frame.setCreator(desktop) + desktop.getFrames().append(self._frame) + self._frame.Title = self._title + return + + def _create_container(self, ps): + # ~ toolkit = self._window.getToolkit() + service = 'com.sun.star.awt.UnoControlContainer' + self._container = create_instance(service, True) + service = 'com.sun.star.awt.UnoControlContainerModel' + model = create_instance(service, True) + model.BackgroundColor = get_color(225, 225, 225) + self._container.setModel(model) + self._container.createPeer(self._toolkit, self._window) + self._container.setPosSize(*ps, POSSIZE) + 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', + 'button': 'com.sun.star.awt.UnoControlButton', + 'text': 'com.sun.star.awt.UnoControlEdit', + 'listbox': 'com.sun.star.awt.UnoControlListBox', + 'link': 'com.sun.star.awt.UnoControlFixedHyperlink', + 'roadmap': 'com.sun.star.awt.UnoControlRoadmap', + 'image': 'com.sun.star.awt.UnoControlImageControl', + 'groupbox': 'com.sun.star.awt.UnoControlGroupBox', + '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() + 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) + name = properties['Name'] + 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 + + def _create_popupmenu(self, menus): + menu = create_instance('com.sun.star.awt.PopupMenu', True) + for i, m in enumerate(menus): + label = m['label'] + cmd = m.get('event', '') + if not cmd: + cmd = label.lower().replace(' ', '_') + if label == '-': + menu.insertSeparator(i) + else: + menu.insertItem(i, label, m.get('style', 0), i) + menu.setCommand(i, cmd) + # ~ menu.setItemImage(i, path?, True) + menu.addMenuListener(EventsMenu(self.events)) + return menu + + def _create_menu(self, menus): + #~ https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1awt_1_1XMenu.html + #~ nItemId specifies the ID of the menu item to be inserted. + #~ aText specifies the label of the menu item. + #~ nItemStyle 0 = Standard, CHECKABLE = 1, RADIOCHECK = 2, AUTOCHECK = 4 + #~ nItemPos specifies the position where the menu item will be inserted. + self._menu = create_instance('com.sun.star.awt.MenuBar', True) + for i, m in enumerate(menus): + self._menu.insertItem(i, m['label'], m.get('style', 0), i) + cmd = m['label'].lower().replace(' ', '_') + self._menu.setCommand(i, cmd) + submenu = self._create_popupmenu(m['submenu']) + self._menu.setPopupMenu(i, submenu) + + self._window.setMenuBar(self._menu) + return + + def add_menu(self, menus): + self._create_menu(menus) + return + + def _add_listeners(self, control=None): + if self.events is None: + return + controller = EventsWindow(self) + self._window.addTopWindowListener(controller) + self._window.addWindowListener(controller) + self._container.addKeyListener(EventsKeyWindow(self)) + return + + @property + def name(self): + return self._title.lower().replace(' ', '_') + + @property + def events(self): + return self._events + @events.setter + def events(self, value): + self._events = value + self._add_listeners() + + @property + def width(self): + return self._container.Size.Width + + @property + def height(self): + return self._container.Size.Height + + def open(self): + self._window.setVisible(True) + return + + def close(self): + self._window.setMenuBar(None) + self._window.dispose() + self._frame.close(True) + return + # ~ Python >= 3.7 # ~ def __getattr__(name): @@ -1440,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 @@ -1450,7 +4028,6 @@ def get_document(title=''): return _get_class_doc(doc) -# ~ Export ok def get_documents(custom=True): docs = [] desktop = get_desktop() @@ -1482,18 +4059,11 @@ def active_cell(): def create_dialog(properties): - return LODialog(properties) + return LODialog(**properties) -def set_properties(model, properties): - if 'X' in properties: - properties['PositionX'] = properties.pop('X') - if 'Y' in properties: - properties['PositionY'] = properties.pop('Y') - keys = tuple(properties.keys()) - values = tuple(properties.values()) - model.setPropertyValues(keys, values) - return +def create_window(kwargs): + return LOWindow(**kwargs) # ~ Export ok @@ -1506,6 +4076,11 @@ def get_config_path(name='Work'): return _path_system(getattr(path, name)) +def get_path_python(): + path = get_config_path('Module') + return join(path, PYTHON) + + # ~ Export ok def get_file(init_dir='', multiple=False, filters=()): """ @@ -1620,12 +4195,26 @@ def from_json(path): return data +# ~ Export ok +def json_dumps(data): + return json.dumps(data, indent=4, sort_keys=True) + + +# ~ Export ok +def json_loads(data): + return json.loads(data) + + def get_path_extension(id): pip = CTX.getValueByName('/singletons/com.sun.star.deployment.PackageInformationProvider') path = _path_system(pip.getPackageLocation(id)) return path +def get_home(): + return Path.home() + + # ~ Export ok def inputbox(message, default='', title=TITLE, echochar=''): @@ -1643,7 +4232,7 @@ def inputbox(message, default='', title=TITLE, echochar=''): 'Width': 200, 'Height': 80, } - dlg = LODialog(args) + dlg = LODialog(**args) dlg.events = ControllersInput(dlg) args = { @@ -1709,12 +4298,29 @@ def new_doc(type_doc=CALC, **kwargs): # ~ Export ok -def new_db(path): +def new_db(path, name=''): + p, fn, n, e = get_info_path(path) + if not name: + name = n + return LOBase(name, path) + + +# ~ Todo +def exists_db(name): dbc = create_instance('com.sun.star.sdb.DatabaseContext') - db = dbc.createInstance() - db.URL = 'sdbc:embedded:firebird' # hsqldb - db.DatabaseDocument.storeAsURL(_path_url(path), ()) - return _get_class_doc(db) + return dbc.hasRegisteredDatabase(name) + + +# ~ Todo +def register_db(name, path): + dbc = create_instance('com.sun.star.sdb.DatabaseContext') + dbc.registerDatabaseLocation(name, _path_url(path)) + return + + +# ~ Todo +def get_db(name): + return LOBase(name) # ~ Export ok @@ -1733,7 +4339,7 @@ def open_doc(path, **kwargs): """ path = _path_url(path) opt = dict_to_property(kwargs) - doc = get_desktop().loadComponentFromURL(path, '_blank', 0, opt) + doc = get_desktop().loadComponentFromURL(path, '_default', 0, opt) if doc is None: return @@ -1745,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 @@ -1787,14 +4393,39 @@ def zip_content(path): return names -# ~ Export ok +def popen(command, stdin=None): + try: + proc = subprocess.Popen(shlex.split(command), shell=IS_WIN, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + for line in proc.stdout: + yield line.decode().rstrip() + except Exception as e: + error(e) + yield (e.errno, e.strerror) + + +def url_open(url, options={}, json=False): + data = '' + req = Request(url) + try: + response = urlopen(req) + # ~ response.info() + except HTTPError as e: + error(e) + except URLError as e: + error(e.reason) + else: + if json: + data = json_loads(response.read()) + else: + data = response.read() + + return data + + def run(command, wait=False): - # ~ debug(command) - # ~ debug(shlex.split(command)) try: if wait: - # ~ p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) - # ~ p.wait() result = subprocess.check_output(command, shell=True) else: p = subprocess.Popen(shlex.split(command), stdin=None, @@ -1925,7 +4556,6 @@ def kill(path): return -# ~ Export ok def get_size_screen(): if IS_WIN: user32 = ctypes.windll.user32 @@ -1936,7 +4566,6 @@ def get_size_screen(): return res.strip() -# ~ Export ok def get_clipboard(): df = None text = '' @@ -1990,7 +4619,7 @@ def set_clipboard(value): return -# ~ Todo +# ~ Export ok def copy(): call_dispatch('.uno:Copy') return @@ -2015,12 +4644,16 @@ def file_copy(source, target='', name=''): return path_new -# ~ Export ok -def get_path_content(path, filters='*'): +def get_path_content(path, filters=''): paths = [] + if filters in ('*', '*.*'): + filters = '' for folder, _, files in os.walk(path): - pattern = re.compile(r'\.(?:{})$'.format(filters), re.IGNORECASE) - paths += [join(folder, f) for f in files if pattern.search(f)] + 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 @@ -2178,7 +4811,12 @@ def end(): # ~ Export ok # ~ https://en.wikipedia.org/wiki/Web_colors -def get_color(value): +def get_color(*value): + if len(value) == 1 and isinstance(value[0], int): + return value[0] + if len(value) == 1 and isinstance(value[0], tuple): + value = value[0] + COLORS = { 'aliceblue': 15792383, 'antiquewhite': 16444375, @@ -2329,14 +4967,19 @@ def get_color(value): 'yellowgreen': 10145074, } - if isinstance(value, tuple): - return (value[0] << 16) + (value[1] << 8) + value[2] + if len(value) == 3: + color = (value[0] << 16) + (value[1] << 8) + value[2] + else: + value = value[0] + if value[0] == '#': + r, g, b = bytes.fromhex(value[1:]) + color = (r << 16) + (g << 8) + b + else: + color = COLORS.get(value.lower(), -1) + return color - if isinstance(value, str) and value[0] == '#': - r, g, b = bytes.fromhex(value[1:]) - return (r << 16) + (g << 8) + b - return COLORS.get(value.lower(), -1) +COLOR_ON_FOCUS = get_color('LightYellow') # ~ Export ok @@ -2358,6 +5001,24 @@ def _to_date(value): return new_value +def date_to_struct(value): + # ~ print(type(value)) + if isinstance(value, datetime.datetime): + d = DateTime() + d.Seconds = value.second + d.Minutes = value.minute + d.Hours = value.hour + d.Day = value.day + d.Month = value.month + d.Year = value.year + elif isinstance(value, datetime.date): + d = Date() + d.Day = value.day + d.Month = value.month + d.Year = value.year + return d + + # ~ Export ok def format(template, data): """ @@ -2379,15 +5040,35 @@ 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' factory = create_instance(name, False) + macro['language'] = macro.get('language', 'Python') + macro['location'] = macro.get('location', 'user') data = macro.copy() - if macro['language'] == 'Python': + if data['language'] == 'Python': data['module'] = '.py$' - elif macro['language'] == 'Basic': + elif data['language'] == 'Basic': data['module'] = '.{}.'.format(macro['module']) if macro['location'] == 'user': data['location'] = 'application' @@ -2397,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] @@ -2480,7 +5162,7 @@ class SmtpServer(object): def __enter__(self): return self - def __exit__(self, *args): + def __exit__(self, exc_type, exc_value, traceback): self.close() @property @@ -2615,14 +5297,121 @@ def server_smtp_test(config): return server.error -# ~ name = 'com.sun.star.configuration.ConfigurationProvider' -# ~ cp = create_instance(name, True) -# ~ node = PropertyValue(Name='nodepath', Value=NODE_SETTING) -# ~ try: - # ~ cua = cp.createInstanceWithArguments( - # ~ 'com.sun.star.configuration.ConfigurationUpdateAccess', (node,)) - # ~ cua.setPropertyValue(key, json.dumps(value)) - # ~ cua.commitChanges() -# ~ except Exception as e: - # ~ log.error(e, exc_info=True) - # ~ return False +def import_csv(path, **kwargs): + """ + See https://docs.python.org/3.5/library/csv.html#csv.reader + """ + with open(path) as f: + 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) + writer.writerows(data) + 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' + ARG = 'socket,host={},port={};urp;StarOffice.ComponentContext'.format(HOST, PORT) + CMD = ['soffice', + '-env:SingleAppInstance=false', + '-env:UserInstallation=file:///tmp/LIBO_Process8100', + '--headless', '--norestore', '--invisible', + '--accept={}'.format(ARG)] + + def __init__(self): + self._server = None + self._ctx = None + self._sm = None + self._start_server() + self._init_values() + + def _init_values(self): + global CTX + global SM + + if not self.is_running: + return + + ctx = uno.getComponentContext() + service = 'com.sun.star.bridge.UnoUrlResolver' + resolver = ctx.ServiceManager.createInstanceWithContext(service, ctx) + self._ctx = resolver.resolve('uno:{}'.format(self.ARG)) + self._sm = self._ctx.getServiceManager() + CTX = self._ctx + SM = self._sm + return + + @property + def is_running(self): + try: + s = socket.create_connection((self.HOST, self.PORT), 5.0) + s.close() + debug('LibreOffice is running...') + return True + except ConnectionRefusedError: + return False + + def _start_server(self): + if self.is_running: + return + + for i in range(3): + self._server = subprocess.Popen(self.CMD, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + time.sleep(3) + if self.is_running: + break + return + + def stop(self): + if self._server is None: + print('Search pgrep soffice') + else: + self._server.terminate() + debug('LibreOffice is stop...') + return + + def create_instance(self, name, with_context=True): + if with_context: + instance = self._sm.createInstanceWithContext(name, self._ctx) + else: + instance = self._sm.createInstance(name) + return instance + + +# ~ controls = { + # ~ 'CheckBox': 'com.sun.star.awt.UnoControlCheckBoxModel', + # ~ 'ComboBox': 'com.sun.star.awt.UnoControlComboBoxModel', + # ~ 'CurrencyField': 'com.sun.star.awt.UnoControlCurrencyFieldModel', + # ~ 'DateField': 'com.sun.star.awt.UnoControlDateFieldModel', + # ~ 'FileControl': 'com.sun.star.awt.UnoControlFileControlModel', + # ~ 'FormattedField': 'com.sun.star.awt.UnoControlFormattedFieldModel', + # ~ 'GroupBox': 'com.sun.star.awt.UnoControlGroupBoxModel', + # ~ 'ImageControl': 'com.sun.star.awt.UnoControlImageControlModel', + # ~ 'NumericField': 'com.sun.star.awt.UnoControlNumericFieldModel', + # ~ 'PatternField': 'com.sun.star.awt.UnoControlPatternFieldModel', + # ~ 'ProgressBar': 'com.sun.star.awt.UnoControlProgressBarModel', + # ~ 'ScrollBar': 'com.sun.star.awt.UnoControlScrollBarModel', + # ~ 'SimpleAnimation': 'com.sun.star.awt.UnoControlSimpleAnimationModel', + # ~ 'SpinButton': 'com.sun.star.awt.UnoControlSpinButtonModel', + # ~ 'Throbber': 'com.sun.star.awt.UnoControlThrobberModel', + # ~ 'TimeField': 'com.sun.star.awt.UnoControlTimeFieldModel', +# ~ } diff --git a/zaz.py b/zaz.py index 5669ec1..9cad0c8 100644 --- a/zaz.py +++ b/zaz.py @@ -19,15 +19,21 @@ import argparse import os +import re import sys +import zipfile +from datetime import datetime from pathlib import Path from shutil import copyfile from subprocess import call -import zipfile +from xml.etree import ElementTree as ET +from xml.dom.minidom import parseString + from conf import ( DATA, DIRS, + DOMAIN, EXTENSION, FILES, INFO, @@ -37,6 +43,84 @@ from conf import ( log) +class LiboXML(object): + TYPES = { + 'py': 'application/vnd.sun.star.uno-component;type=Python', + 'zip': 'application/binary', + 'xcu': 'application/vnd.sun.star.configuration-data', + 'rdb': 'application/vnd.sun.star.uno-typelibrary;type=RDB', + 'xcs': 'application/vnd.sun.star.configuration-schema', + 'help': 'application/vnd.sun.star.help', + 'component': 'application/vnd.sun.star.uno-components', + } + NAME_SPACES = { + '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', + } + + def __init__(self): + self._manifest = None + self._paths = [] + + def _save_path(self, attr): + self._paths.append(attr['{{{}}}full-path'.format(self.NAME_SPACES['manifest'])]) + return + + def _clean(self, name, nodes): + has_words = re.compile('\\w') + + if not re.search(has_words, str(nodes.tail)): + nodes.tail = '' + if not re.search(has_words, str(nodes.text)): + nodes.text = '' + + for node in nodes: + if name == 'manifest': + self._save_path(node.attrib) + if not re.search(has_words, str(node.tail)): + node.tail = '' + if not re.search(has_words, str(node.text)): + node.text = '' + return + + 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'], + } + 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']) + self._manifest = ET.fromstring(data) + data = {'xmlns:loext': self.NAME_SPACES['xmlns:loext']} + self._manifest.attrib.update(**data) + self._clean('manifest', self._manifest) + return + + def add_data_manifest(self, data): + node_name = 'manifest:file-entry' + attr = { + 'manifest:full-path': '', + 'manifest:media-type': '', + } + for path in data: + if path in self._paths: + continue + ext = path.split('.')[-1] + attr['manifest:full-path'] = path + attr['manifest:media-type'] = self.TYPES.get(ext, '') + ET.SubElement(self._manifest, node_name, attr) + return self._get_xml(self._manifest) + + def _get_xml(self, doc): + xml = parseString(ET.tostring(doc, encoding='utf-8')) + return xml.toprettyxml(indent=' ', encoding='utf-8').decode('utf-8') + + def _exists(path): return os.path.exists(path) @@ -55,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...') @@ -222,8 +319,11 @@ def _update_files(): target = _join(path_source, 'pythonpath', source) copyfile(source, target) + xml = LiboXML() + path = _join(path_source, DIRS['meta'], FILES['manifest']) - _save(path, DATA['manifest']) + data = xml.new_manifest(DATA['manifest']) + _save(path, data) path = _join(path_source, DIRS['office']) _mkdir(path) @@ -265,7 +365,138 @@ def _new(): return +def _get_info_path(path): + path, filename = os.path.split(path) + name, extension = os.path.splitext(filename) + return (path, filename, name, extension) + + +def _zip_embed(source, files): + PATH = 'Scripts/python/' + EASYMACRO = 'easymacro.' + + p, f, name, e = _get_info_path(source) + now = datetime.now().strftime('_%Y%m%d_%H%M%S') + path_source = _join(p, name + now + e) + copyfile(source, path_source) + target = source + + with zipfile.PyZipFile(EASYMACRO + 'zip', mode='w') as zf: + zf.writepy(EASYMACRO + 'py') + + xml = LiboXML() + + path_easymacro = PATH + EASYMACRO + 'zip' + names = [f[1] for f in files] + [path_easymacro] + nodes = [] + with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED) as zt: + with zipfile.ZipFile(path_source, compression=zipfile.ZIP_DEFLATED) as zs: + for name in zs.namelist(): + if FILES['manifest'] in name: + path_manifest = name + xml_manifest = zs.open(name).read() + elif name in names: + continue + else: + zt.writestr(name, zs.open(name).read()) + + data = [] + for path, name in files: + data.append(name) + zt.write(path, name) + + zt.write(EASYMACRO + 'zip', path_easymacro) + data.append(path_easymacro) + + xml.parse_manifest(xml_manifest) + xml_manifest = xml.add_data_manifest(data) + zt.writestr(path_manifest, xml_manifest) + + os.unlink(EASYMACRO + 'zip') + return + + +def _embed(args): + PATH = 'Scripts/python' + PYTHONPATH = 'pythonpath' + + doc = args.document + if not doc: + msg = '-d/--document Path file to embed is mandatory' + log.error(msg) + return + if not _exists(doc): + msg = 'Path file not exists' + log.error(msg) + return + + files = [] + if args.files: + files = args.files.split(',') + source = _join(PATHS['profile'], PATH) + content = os.listdir(source) + if PYTHONPATH in content: + content.remove(PYTHONPATH) + + if files: + files = [(_join(source, f), _join(PATH, f)) for f in files if f in content] + else: + files = [(_join(source, f), _join(PATH, f)) for f in content] + + _zip_embed(doc, files) + + log.info('Embedded macros successfully...') + 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 + if args.new: _new() return @@ -279,7 +510,7 @@ def main(args): if args.install: _install_and_test() - log.info('Extension make sucesfully...') + log.info('Extension make successfully...') return @@ -290,6 +521,14 @@ def _process_command_line_arguments(): default=False, required=False) parser.add_argument('-n', '--new', dest='new', action='store_true', default=False, required=False) + parser.add_argument('-e', '--embed', dest='embed', action='store_true', + 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()