diff --git a/CHANGELOG b/CHANGELOG
index 3b183ba..1d1843c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,9 @@
+v 0.3.0 [15-oct-2019]
+---------------------
+ - Add menus in start application.
+ - Update easymacro.py
+
+
v 0.2.0 [27-sep-2019]
---------------------
- Update easymacro.py
diff --git a/VERSION b/VERSION
index 5faa42c..69367fd 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-0.2.0
+0.3.0
diff --git a/conf.py b/conf.py
index 0543de4..839b08a 100644
--- a/conf.py
+++ b/conf.py
@@ -26,7 +26,7 @@ import logging
TYPE_EXTENSION = 1
# ~ https://semver.org/
-VERSION = '0.2.0'
+VERSION = '0.3.0'
# ~ Your great extension name, not used spaces
NAME = 'ZAZFavorites'
@@ -184,7 +184,6 @@ FILES = {
'update': f'{NAME.lower()}.update.xml',
'addin': 'CalcAddIn.xcu',
'shortcut': 'Accelerators.xcu',
- 'jobs': 'Jobs.xcu',
'easymacro': True,
}
@@ -206,6 +205,7 @@ 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',
}
@@ -428,21 +428,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"""
@@ -627,9 +612,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..bd5f1aa 100644
--- a/easymacro.py
+++ b/easymacro.py
@@ -18,6 +18,7 @@
# ~ along with ZAZ. If not, see .
import base64
+import csv
import ctypes
import datetime
import errno
@@ -30,6 +31,7 @@ import platform
import re
import shlex
import shutil
+import socket
import subprocess
import sys
import tempfile
@@ -59,25 +61,37 @@ 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.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
+
try:
from fernet import Fernet, InvalidToken
- CRYPTO = True
except ImportError:
- CRYPTO = False
+ pass
MSG_LANG = {
@@ -119,9 +133,15 @@ TYPE_DOC = {
'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',
@@ -150,6 +170,7 @@ MENUS_WRITER = {
}
MENUS_APP = {
+ 'main': MENUS_MAIN,
'calc': MENUS_CALC,
'writer': MENUS_WRITER,
}
@@ -174,13 +195,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 +210,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 +267,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,18 +276,15 @@ class LogWin(object):
return
-# ~ Export ok
def info(data):
log.info(data)
return
-# ~ Export ok
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)
@@ -270,13 +294,11 @@ def debug(info):
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))
@@ -296,7 +318,31 @@ def now():
return datetime.datetime.now()
-# ~ Export ok
+def today():
+ return datetime.date.today()
+
+
+def time():
+ return datetime.datetime.now().time()
+
+
+def get_date(year, month, day, hour=-1, minute=-1, second=-1):
+ if hour > -1 or minute > -1 or second > -1:
+ h = hour
+ 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
+
+
def get_config(key='', default=None, prefix='config'):
path_json = FILE_NAME_CONFIG.format(prefix)
values = None
@@ -314,7 +360,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 +367,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 +386,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 +397,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 +414,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 +425,6 @@ def call_dispatch(url, args=()):
return
-# ~ Export ok
def get_temp_file():
delete = True
if IS_WIN:
@@ -407,7 +444,6 @@ def _path_system(path):
return path
-# ~ Export ok
def exists_app(name):
try:
dn = subprocess.DEVNULL
@@ -418,12 +454,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 +477,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 +578,30 @@ 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()
+ # ~ if self._type_doc == 'base':
+ # ~ self._cc = self.obj.DatabaseDocument.getCurrentController()
+ # ~ else:
+ 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 +630,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 +643,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 +701,150 @@ class LODocument(object):
return path_pdf
-class LOCalc(LODocument):
+class LOForm(ObjectBase):
def __init__(self, obj):
super().__init__(obj)
+ @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 LOCalc(LODocument):
+
+ def __init__(self, obj):
+ super().__init__(obj)
+ self._sheets = obj.getSheets()
+
+ def __getitem__(self, index):
+ if isinstance(index, str):
+ index = [s.Name for s in self._sheets if s.CodeName == index][0] or index
+ 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 +852,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 +963,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,7 +1040,15 @@ 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):
+ self._events = None
+ self._dp = self.obj.getDrawPage()
return
@property
@@ -630,6 +1059,91 @@ class LOCalcSheet(object):
def doc(self):
return self._doc
+ @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 +1166,46 @@ 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()
+ sel = self.obj.getCurrentSelection()
return LOTextRange(sel[0])
+ 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 +1221,40 @@ 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
+
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 +1268,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,7 +1465,7 @@ 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):
@@ -827,6 +1522,16 @@ class LOCellRange(object):
self.obj.setString(data)
elif isinstance(data, (int, float)):
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):
@@ -837,19 +1542,96 @@ class LOCellRange(object):
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):
+ if isinstance(values, list):
+ values = tuple(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):
+ data = rango
+ if isinstance(rango, LOCellRange):
+ data = rango.data
+ rows = len(data)
+ cols = len(data[0])
+ 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 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,9 +1649,44 @@ class LOCellRange(object):
@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,15 +1699,92 @@ 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
+
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
def disposing(self, event):
@@ -901,25 +1795,23 @@ 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)
if hasattr(self._controller, event_name):
@@ -935,6 +1827,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 +1866,178 @@ 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):
+ pass
+
+
+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):
+ 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, 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._container.getControl('subcontainer')
+ # ~ 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
+
+ @catch_exception
+ 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,19 +2064,39 @@ class UnoBaseObject(object):
def parent(self):
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):
@@ -1010,7 +2107,10 @@ class UnoBaseObject(object):
@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
@@ -1029,6 +2129,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
@@ -1083,6 +2190,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):
@@ -1257,9 +2374,517 @@ 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
+
+ def set_enabled(self, index, value):
+ self.model.getByIndex(index).Enabled = value
+ return
+
+
+def get_custom_class(tipo, obj):
+ classes = {
+ 'label': UnoLabel,
+ 'button': UnoButton,
+ 'text': UnoText,
+ 'listbox': UnoListBox,
+ 'grid': UnoGrid,
+ 'link': UnoLabelLink,
+ 'roadmap': UnoRoadmap,
+ # ~ 'tab': UnoTab,
+ # ~ 'image': UnoImage,
+ # ~ 'radio': UnoRadio,
+ # ~ 'groupbox': UnoGroupBox,
+ # ~ 'tree': UnoTree,
+ }
+ return classes[tipo](obj)
+
+
+def add_listeners(events, control, name=''):
+ listeners = {
+ 'addActionListener': EventsButton,
+ 'addMouseListener': EventsMouse,
+ 'addItemListener': EventsItem,
+ 'addFocusListener': EventsFocus,
+ }
+ 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))
+ 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
+
+ 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
+
+
class LODialog(object):
- def __init__(self, properties):
+ def __init__(self, **properties):
self._obj = self._create(properties)
self._init_values()
@@ -1267,22 +2892,27 @@ class LODialog(object):
self._model = self._obj.Model
self._init_controls()
self._events = None
- # ~ self._response = None
+ self._color_on_focus = -1
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 +2925,22 @@ class LODialog(object):
return dlg
- def _init_controls(self):
+ def _get_type_control(self, name):
+ types = {
+ 'stardiv.Toolkit.UnoFixedTextControl': 'label',
+ 'stardiv.Toolkit.UnoButtonControl': 'button',
+ 'stardiv.Toolkit.UnoEditControl': 'text',
+ 'stardiv.Toolkit.UnoRoadmapControl': 'roadmap',
+ 'stardiv.Toolkit.UnoFixedHyperlinkControl': 'link',
+ }
+ 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 +2951,29 @@ class LODialog(object):
def model(self):
return self._model
+ @property
+ def height(self):
+ return self.model.Height
+ @height.setter
+ def height(self, value):
+ self.model.Height = 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 +2983,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):
@@ -1343,47 +2995,28 @@ class LODialog(object):
def _get_control_model(self, control):
services = {
- 'label': 'com.sun.star.awt.UnoControlFixedTextModel',
'button': 'com.sun.star.awt.UnoControlButtonModel',
- 'text': 'com.sun.star.awt.UnoControlEditModel',
- 'listbox': 'com.sun.star.awt.UnoControlListBoxModel',
- 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
- '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',
+ 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel',
+ 'image': 'com.sun.star.awt.UnoControlImageControlModel',
+ 'label': 'com.sun.star.awt.UnoControlFixedTextModel',
+ 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
+ 'listbox': 'com.sun.star.awt.UnoControlListBoxModel',
+ 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel',
+ 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel',
+ 'text': 'com.sun.star.awt.UnoControlEditModel',
+ 'tree': 'com.sun.star.awt.tree.TreeControlModel',
}
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):
@@ -1391,25 +3024,191 @@ class LODialog(object):
return _path_url(path)
return ''
- def add_control(self, properties):
- tipo = properties.pop('Type').lower()
-
+ 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' and not 'Height' in properties:
+ properties['Height'] = self.height
+ return properties
+ def add_control(self, properties):
+ tipo = properties.pop('Type').lower()
+ 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)
setattr(self, name, control)
return
+class LOWindow(object):
+
+ def __init__(self, **kwargs):
+ self._events = None
+ self._menu = None
+ self._container = None
+ self._obj = self._create(kwargs)
+
+ 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_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 _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',
+ }
+ return services[tipo]
+
+ def add_control(self, properties):
+ tipo = properties.pop('Type').lower()
+ base = self._get_base_control(tipo)
+ obj = create_instance(base, True)
+ model = create_instance('{}Model'.format(base), True)
+ set_properties(model, properties)
+ obj.setModel(model)
+ x = properties.get('X', 5)
+ y = properties.get('Y', 5)
+ w = properties.get('Width', 200)
+ h = properties.get('Height', 25)
+ obj.setPosSize(x, y, w, h, POSSIZE)
+ name = properties['Name']
+ self._container.addControl(name, obj)
+ add_listeners(self.events, obj, name)
+ control = get_custom_class(tipo, obj)
+ 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(EventsKey(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):
@@ -1447,7 +3246,6 @@ def get_document(title=''):
return _get_class_doc(doc)
-# ~ Export ok
def get_documents(custom=True):
docs = []
desktop = get_desktop()
@@ -1479,18 +3277,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
@@ -1617,6 +3408,16 @@ 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))
@@ -1640,7 +3441,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 +3507,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
@@ -1784,7 +3602,6 @@ def zip_content(path):
return names
-# ~ Export ok
def run(command, wait=False):
# ~ debug(command)
# ~ debug(shlex.split(command))
@@ -1922,7 +3739,6 @@ def kill(path):
return
-# ~ Export ok
def get_size_screen():
if IS_WIN:
user32 = ctypes.windll.user32
@@ -1933,7 +3749,6 @@ def get_size_screen():
return res.strip()
-# ~ Export ok
def get_clipboard():
df = None
text = ''
@@ -1987,7 +3802,7 @@ def set_clipboard(value):
return
-# ~ Todo
+# ~ Export ok
def copy():
call_dispatch('.uno:Copy')
return
@@ -2012,12 +3827,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 +3994,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 +4150,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 +4184,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):
"""
@@ -2381,10 +4228,12 @@ def _call_macro(macro):
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'
@@ -2477,7 +4326,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 +4461,112 @@ 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
+
+
+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',
+ # ~ 'FixedLine': 'com.sun.star.awt.UnoControlFixedLineModel',
+ # ~ 'FixedText': 'com.sun.star.awt.UnoControlFixedTextModel',
+ # ~ 'FormattedField': 'com.sun.star.awt.UnoControlFormattedFieldModel',
+ # ~ 'GroupBox': 'com.sun.star.awt.UnoControlGroupBoxModel',
+ # ~ 'ImageControl': 'com.sun.star.awt.UnoControlImageControlModel',
+ # ~ 'ListBox': 'com.sun.star.awt.UnoControlListBoxModel',
+ # ~ '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/ZAZFavorites_v0.3.0.oxt b/files/ZAZFavorites_v0.3.0.oxt
new file mode 100644
index 0000000..1b8f5e6
Binary files /dev/null and b/files/ZAZFavorites_v0.3.0.oxt differ
diff --git a/source/Jobs.xcu b/source/Jobs.xcu
deleted file mode 100755
index 2acfa90..0000000
--- a/source/Jobs.xcu
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
- service:net.elmau.zaz.Favorites
-
-
-
- first
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/source/META-INF/manifest.xml b/source/META-INF/manifest.xml
index ef10414..ce03a57 100644
--- a/source/META-INF/manifest.xml
+++ b/source/META-INF/manifest.xml
@@ -1,7 +1,6 @@
-
-
-
-
-
-
+
+
+
+
+
diff --git a/source/ZAZFavorites.py b/source/ZAZFavorites.py
index b70d1c2..46c993e 100644
--- a/source/ZAZFavorites.py
+++ b/source/ZAZFavorites.py
@@ -70,9 +70,8 @@ class Controllers(object):
'After': '.uno:RecentFileList',
'Submenu': submenus,
}
- doc = app.get_document()
- for doc_type in ('calc', 'writer'):
+ for doc_type in ('main', 'calc', 'writer'):
app.remove_menu(doc_type, 'File', command)
app.insert_menu(doc_type, 'File', **data)
app.set_config('paths', paths)
@@ -115,6 +114,7 @@ class ZAZFavorites(unohelper.Base, XJobExecutor):
self.path_ext = app.get_path_extension(ID_EXTENSION)
self.IMAGES = app.join(self.path_ext, self.IMAGES)
+ @app.catch_exception
def trigger(self, args):
if args == 'config':
return self._config()
diff --git a/source/description.xml b/source/description.xml
index 30abecd..d0da032 100644
--- a/source/description.xml
+++ b/source/description.xml
@@ -1,7 +1,7 @@
-
+
Favorites files
Archivos favoritos
diff --git a/source/pythonpath/easymacro.py b/source/pythonpath/easymacro.py
index 3bf53b9..bd5f1aa 100644
--- a/source/pythonpath/easymacro.py
+++ b/source/pythonpath/easymacro.py
@@ -18,6 +18,7 @@
# ~ along with ZAZ. If not, see .
import base64
+import csv
import ctypes
import datetime
import errno
@@ -30,6 +31,7 @@ import platform
import re
import shlex
import shutil
+import socket
import subprocess
import sys
import tempfile
@@ -59,25 +61,37 @@ 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.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
+
try:
from fernet import Fernet, InvalidToken
- CRYPTO = True
except ImportError:
- CRYPTO = False
+ pass
MSG_LANG = {
@@ -119,9 +133,15 @@ TYPE_DOC = {
'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',
@@ -150,6 +170,7 @@ MENUS_WRITER = {
}
MENUS_APP = {
+ 'main': MENUS_MAIN,
'calc': MENUS_CALC,
'writer': MENUS_WRITER,
}
@@ -174,13 +195,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 +210,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 +267,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,18 +276,15 @@ class LogWin(object):
return
-# ~ Export ok
def info(data):
log.info(data)
return
-# ~ Export ok
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)
@@ -270,13 +294,11 @@ def debug(info):
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))
@@ -296,7 +318,31 @@ def now():
return datetime.datetime.now()
-# ~ Export ok
+def today():
+ return datetime.date.today()
+
+
+def time():
+ return datetime.datetime.now().time()
+
+
+def get_date(year, month, day, hour=-1, minute=-1, second=-1):
+ if hour > -1 or minute > -1 or second > -1:
+ h = hour
+ 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
+
+
def get_config(key='', default=None, prefix='config'):
path_json = FILE_NAME_CONFIG.format(prefix)
values = None
@@ -314,7 +360,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 +367,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 +386,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 +397,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 +414,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 +425,6 @@ def call_dispatch(url, args=()):
return
-# ~ Export ok
def get_temp_file():
delete = True
if IS_WIN:
@@ -407,7 +444,6 @@ def _path_system(path):
return path
-# ~ Export ok
def exists_app(name):
try:
dn = subprocess.DEVNULL
@@ -418,12 +454,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 +477,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 +578,30 @@ 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()
+ # ~ if self._type_doc == 'base':
+ # ~ self._cc = self.obj.DatabaseDocument.getCurrentController()
+ # ~ else:
+ 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 +630,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 +643,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 +701,150 @@ class LODocument(object):
return path_pdf
-class LOCalc(LODocument):
+class LOForm(ObjectBase):
def __init__(self, obj):
super().__init__(obj)
+ @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 LOCalc(LODocument):
+
+ def __init__(self, obj):
+ super().__init__(obj)
+ self._sheets = obj.getSheets()
+
+ def __getitem__(self, index):
+ if isinstance(index, str):
+ index = [s.Name for s in self._sheets if s.CodeName == index][0] or index
+ 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 +852,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 +963,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,7 +1040,15 @@ 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):
+ self._events = None
+ self._dp = self.obj.getDrawPage()
return
@property
@@ -630,6 +1059,91 @@ class LOCalcSheet(object):
def doc(self):
return self._doc
+ @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 +1166,46 @@ 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()
+ sel = self.obj.getCurrentSelection()
return LOTextRange(sel[0])
+ 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 +1221,40 @@ 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
+
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 +1268,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,7 +1465,7 @@ 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):
@@ -827,6 +1522,16 @@ class LOCellRange(object):
self.obj.setString(data)
elif isinstance(data, (int, float)):
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):
@@ -837,19 +1542,96 @@ class LOCellRange(object):
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):
+ if isinstance(values, list):
+ values = tuple(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):
+ data = rango
+ if isinstance(rango, LOCellRange):
+ data = rango.data
+ rows = len(data)
+ cols = len(data[0])
+ 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 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,9 +1649,44 @@ class LOCellRange(object):
@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,15 +1699,92 @@ 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
+
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
def disposing(self, event):
@@ -901,25 +1795,23 @@ 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)
if hasattr(self._controller, event_name):
@@ -935,6 +1827,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 +1866,178 @@ 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):
+ pass
+
+
+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):
+ 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, 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._container.getControl('subcontainer')
+ # ~ 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
+
+ @catch_exception
+ 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,19 +2064,39 @@ class UnoBaseObject(object):
def parent(self):
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):
@@ -1010,7 +2107,10 @@ class UnoBaseObject(object):
@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
@@ -1029,6 +2129,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
@@ -1083,6 +2190,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):
@@ -1257,9 +2374,517 @@ 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
+
+ def set_enabled(self, index, value):
+ self.model.getByIndex(index).Enabled = value
+ return
+
+
+def get_custom_class(tipo, obj):
+ classes = {
+ 'label': UnoLabel,
+ 'button': UnoButton,
+ 'text': UnoText,
+ 'listbox': UnoListBox,
+ 'grid': UnoGrid,
+ 'link': UnoLabelLink,
+ 'roadmap': UnoRoadmap,
+ # ~ 'tab': UnoTab,
+ # ~ 'image': UnoImage,
+ # ~ 'radio': UnoRadio,
+ # ~ 'groupbox': UnoGroupBox,
+ # ~ 'tree': UnoTree,
+ }
+ return classes[tipo](obj)
+
+
+def add_listeners(events, control, name=''):
+ listeners = {
+ 'addActionListener': EventsButton,
+ 'addMouseListener': EventsMouse,
+ 'addItemListener': EventsItem,
+ 'addFocusListener': EventsFocus,
+ }
+ 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))
+ 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
+
+ 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
+
+
class LODialog(object):
- def __init__(self, properties):
+ def __init__(self, **properties):
self._obj = self._create(properties)
self._init_values()
@@ -1267,22 +2892,27 @@ class LODialog(object):
self._model = self._obj.Model
self._init_controls()
self._events = None
- # ~ self._response = None
+ self._color_on_focus = -1
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 +2925,22 @@ class LODialog(object):
return dlg
- def _init_controls(self):
+ def _get_type_control(self, name):
+ types = {
+ 'stardiv.Toolkit.UnoFixedTextControl': 'label',
+ 'stardiv.Toolkit.UnoButtonControl': 'button',
+ 'stardiv.Toolkit.UnoEditControl': 'text',
+ 'stardiv.Toolkit.UnoRoadmapControl': 'roadmap',
+ 'stardiv.Toolkit.UnoFixedHyperlinkControl': 'link',
+ }
+ 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 +2951,29 @@ class LODialog(object):
def model(self):
return self._model
+ @property
+ def height(self):
+ return self.model.Height
+ @height.setter
+ def height(self, value):
+ self.model.Height = 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 +2983,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):
@@ -1343,47 +2995,28 @@ class LODialog(object):
def _get_control_model(self, control):
services = {
- 'label': 'com.sun.star.awt.UnoControlFixedTextModel',
'button': 'com.sun.star.awt.UnoControlButtonModel',
- 'text': 'com.sun.star.awt.UnoControlEditModel',
- 'listbox': 'com.sun.star.awt.UnoControlListBoxModel',
- 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
- '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',
+ 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel',
+ 'image': 'com.sun.star.awt.UnoControlImageControlModel',
+ 'label': 'com.sun.star.awt.UnoControlFixedTextModel',
+ 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
+ 'listbox': 'com.sun.star.awt.UnoControlListBoxModel',
+ 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel',
+ 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel',
+ 'text': 'com.sun.star.awt.UnoControlEditModel',
+ 'tree': 'com.sun.star.awt.tree.TreeControlModel',
}
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):
@@ -1391,25 +3024,191 @@ class LODialog(object):
return _path_url(path)
return ''
- def add_control(self, properties):
- tipo = properties.pop('Type').lower()
-
+ 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' and not 'Height' in properties:
+ properties['Height'] = self.height
+ return properties
+ def add_control(self, properties):
+ tipo = properties.pop('Type').lower()
+ 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)
setattr(self, name, control)
return
+class LOWindow(object):
+
+ def __init__(self, **kwargs):
+ self._events = None
+ self._menu = None
+ self._container = None
+ self._obj = self._create(kwargs)
+
+ 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_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 _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',
+ }
+ return services[tipo]
+
+ def add_control(self, properties):
+ tipo = properties.pop('Type').lower()
+ base = self._get_base_control(tipo)
+ obj = create_instance(base, True)
+ model = create_instance('{}Model'.format(base), True)
+ set_properties(model, properties)
+ obj.setModel(model)
+ x = properties.get('X', 5)
+ y = properties.get('Y', 5)
+ w = properties.get('Width', 200)
+ h = properties.get('Height', 25)
+ obj.setPosSize(x, y, w, h, POSSIZE)
+ name = properties['Name']
+ self._container.addControl(name, obj)
+ add_listeners(self.events, obj, name)
+ control = get_custom_class(tipo, obj)
+ 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(EventsKey(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):
@@ -1447,7 +3246,6 @@ def get_document(title=''):
return _get_class_doc(doc)
-# ~ Export ok
def get_documents(custom=True):
docs = []
desktop = get_desktop()
@@ -1479,18 +3277,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
@@ -1617,6 +3408,16 @@ 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))
@@ -1640,7 +3441,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 +3507,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
@@ -1784,7 +3602,6 @@ def zip_content(path):
return names
-# ~ Export ok
def run(command, wait=False):
# ~ debug(command)
# ~ debug(shlex.split(command))
@@ -1922,7 +3739,6 @@ def kill(path):
return
-# ~ Export ok
def get_size_screen():
if IS_WIN:
user32 = ctypes.windll.user32
@@ -1933,7 +3749,6 @@ def get_size_screen():
return res.strip()
-# ~ Export ok
def get_clipboard():
df = None
text = ''
@@ -1987,7 +3802,7 @@ def set_clipboard(value):
return
-# ~ Todo
+# ~ Export ok
def copy():
call_dispatch('.uno:Copy')
return
@@ -2012,12 +3827,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 +3994,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 +4150,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 +4184,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):
"""
@@ -2381,10 +4228,12 @@ def _call_macro(macro):
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'
@@ -2477,7 +4326,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 +4461,112 @@ 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
+
+
+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',
+ # ~ 'FixedLine': 'com.sun.star.awt.UnoControlFixedLineModel',
+ # ~ 'FixedText': 'com.sun.star.awt.UnoControlFixedTextModel',
+ # ~ 'FormattedField': 'com.sun.star.awt.UnoControlFormattedFieldModel',
+ # ~ 'GroupBox': 'com.sun.star.awt.UnoControlGroupBoxModel',
+ # ~ 'ImageControl': 'com.sun.star.awt.UnoControlImageControlModel',
+ # ~ 'ListBox': 'com.sun.star.awt.UnoControlListBoxModel',
+ # ~ '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..2cac1bc 100644
--- a/zaz.py
+++ b/zaz.py
@@ -19,11 +19,16 @@
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,
@@ -37,6 +42,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)
@@ -222,8 +305,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 +351,96 @@ 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 main(args):
+ if args.embed:
+ _embed(args)
+ return
+
if args.new:
_new()
return
@@ -279,7 +454,7 @@ def main(args):
if args.install:
_install_and_test()
- log.info('Extension make sucesfully...')
+ log.info('Extension make successfully...')
return
@@ -290,6 +465,10 @@ 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='')
return parser.parse_args()