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 0000000..210cfba
Binary files /dev/null and b/files/ZAZBarCode_v0.5.0.oxt differ
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 18ce3d0..0aa8379 100644
Binary files a/source/locales/en/LC_MESSAGES/base.mo and b/source/locales/en/LC_MESSAGES/base.mo differ
diff --git a/source/locales/en/LC_MESSAGES/base.po b/source/locales/en/LC_MESSAGES/base.po
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 7bcdff2..43d2a9a 100644
Binary files a/source/locales/es/LC_MESSAGES/base.mo and b/source/locales/es/LC_MESSAGES/base.mo differ
diff --git a/source/locales/es/LC_MESSAGES/base.po b/source/locales/es/LC_MESSAGES/base.po
index d98fafa..371941e 100644
--- a/source/locales/es/LC_MESSAGES/base.po
+++ b/source/locales/es/LC_MESSAGES/base.po
@@ -5,31 +5,35 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
-"POT-Creation-Date: 2019-09-14 14:23-0500\n"
-"PO-Revision-Date: 2019-09-14 14:44-0500\n"
+"POT-Creation-Date: 2019-11-10 15:06-0600\n"
+"PO-Revision-Date: 2019-11-10 15:07-0600\n"
+"Last-Translator: \n"
"Language-Team: \n"
+"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
-"X-Generator: Poedit 2.2.1\n"
-"Last-Translator: \n"
+"X-Generator: Poedit 2.2.4\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"Language: es\n"
-#: source/ZAZBarCode.py:38
+#: source/ZAZBarCode.py:29
msgid "Select barcode type"
msgstr "Seleccione el tipo de código de barras"
-#: source/ZAZBarCode.py:43
+#: source/ZAZBarCode.py:34
msgid "Data field is mandatory"
msgstr "Los datos son obligatorios"
-#: source/ZAZBarCode.py:95 source/ZAZBarCode.py:117
+#: source/ZAZBarCode.py:91
+msgid "Not generated"
+msgstr "No generado"
+
+#: source/ZAZBarCode.py:109 source/ZAZBarCode.py:135
msgid "Select data"
msgstr "Seleccione los datos"
-#: 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 "~Tipo de código de barras"
-#: source/ZAZBarCode.py:179
+#: source/ZAZBarCode.py:201
msgid "~Capture data for barcode"
msgstr "~Datos del código de barras"
-#: source/ZAZBarCode.py:212
+#: source/ZAZBarCode.py:234
msgid "~Insert Barcode"
msgstr "~Insertar Código"
diff --git a/source/pythonpath/easymacro.py b/source/pythonpath/easymacro.py
index e63299f..df89fbb 100644
--- a/source/pythonpath/easymacro.py
+++ b/source/pythonpath/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
@@ -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()