1994 lines
50 KiB
Python
1994 lines
50 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
# == Rapid Develop Macros in LibreOffice ==
|
||
|
|
||
|
# ~ This file is part of ZAZ.
|
||
|
|
||
|
# ~ ZAZ is free software: you can redistribute it and/or modify
|
||
|
# ~ it under the terms of the GNU General Public License as published by
|
||
|
# ~ the Free Software Foundation, either version 3 of the License, or
|
||
|
# ~ (at your option) any later version.
|
||
|
|
||
|
# ~ ZAZ is distributed in the hope that it will be useful,
|
||
|
# ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# ~ GNU General Public License for more details.
|
||
|
|
||
|
# ~ You should have received a copy of the GNU General Public License
|
||
|
# ~ along with ZAZ. If not, see <https://www.gnu.org/licenses/>.
|
||
|
|
||
|
|
||
|
import ctypes
|
||
|
import datetime
|
||
|
import errno
|
||
|
import getpass
|
||
|
import json
|
||
|
import logging
|
||
|
import os
|
||
|
import platform
|
||
|
import re
|
||
|
import shlex
|
||
|
import shutil
|
||
|
import subprocess
|
||
|
import sys
|
||
|
import tempfile
|
||
|
import threading
|
||
|
import time
|
||
|
import zipfile
|
||
|
|
||
|
from collections import OrderedDict
|
||
|
from collections.abc import MutableMapping
|
||
|
from datetime import datetime
|
||
|
from functools import wraps
|
||
|
from operator import itemgetter
|
||
|
from pathlib import Path, PurePath
|
||
|
from pprint import pprint
|
||
|
from subprocess import PIPE
|
||
|
|
||
|
import uno
|
||
|
import unohelper
|
||
|
from com.sun.star.beans import PropertyValue
|
||
|
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.datatransfer import XTransferable, DataFlavor
|
||
|
from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA
|
||
|
|
||
|
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
|
||
|
|
||
|
|
||
|
MSG_LANG = {
|
||
|
'es': {
|
||
|
'OK': 'Aceptar',
|
||
|
'Cancel': 'Cancelar',
|
||
|
'Select file': 'Seleccionar archivo',
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
OS = platform.system()
|
||
|
USER = getpass.getuser()
|
||
|
PC = platform.node()
|
||
|
DESKTOP = os.environ.get('DESKTOP_SESSION', '')
|
||
|
INFO_DEBUG = '{}\n\n{}\n\n{}'.format(sys.version, platform.platform(), '\n'.join(sys.path))
|
||
|
|
||
|
|
||
|
IS_WIN = OS == 'Windows'
|
||
|
LOG_NAME = 'ZAZ'
|
||
|
CLIPBOARD_FORMAT_TEXT = 'text/plain;charset=utf-16'
|
||
|
|
||
|
|
||
|
CALC = 'calc'
|
||
|
WRITER = 'writer'
|
||
|
OBJ_CELL = 'ScCellObj'
|
||
|
OBJ_RANGE = 'ScCellRangeObj'
|
||
|
OBJ_RANGES = 'ScCellRangesObj'
|
||
|
OBJ_TYPE_RANGES = (OBJ_CELL, OBJ_RANGE, OBJ_RANGES)
|
||
|
|
||
|
TYPE_DOC = {
|
||
|
'calc': 'com.sun.star.sheet.SpreadsheetDocument',
|
||
|
'writer': 'com.sun.star.text.TextDocument',
|
||
|
'impress': 'com.sun.star.presentation.PresentationDocument',
|
||
|
'draw': 'com.sun.star.drawing.DrawingDocument',
|
||
|
'base': 'com.sun.star.sdb.OfficeDatabaseDocument',
|
||
|
'math': 'com.sun.star.formula.FormulaProperties',
|
||
|
'basic': 'com.sun.star.script.BasicIDE',
|
||
|
}
|
||
|
|
||
|
NODE_MENUBAR = 'private:resource/menubar/menubar'
|
||
|
MENUS_CALC = {
|
||
|
'file': '.uno:PickList',
|
||
|
'edit': '.uno:EditMenu',
|
||
|
'view': '.uno:ViewMenu',
|
||
|
'insert': '.uno:InsertMenu',
|
||
|
'format': '.uno:FormatMenu',
|
||
|
'styles': '.uno:FormatStylesMenu',
|
||
|
'sheet': '.uno:SheetMenu',
|
||
|
'data': '.uno:DataMenu',
|
||
|
'tools': '.uno:ToolsMenu',
|
||
|
'windows': '.uno:WindowList',
|
||
|
'help': '.uno:HelpMenu',
|
||
|
}
|
||
|
|
||
|
MENUS_APP = {
|
||
|
'calc': MENUS_CALC,
|
||
|
}
|
||
|
|
||
|
|
||
|
FILE_NAME_DEBUG = 'zaz-debug.log'
|
||
|
FILE_NAME_CONFIG = 'zaz-{}.json'
|
||
|
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
|
||
|
LOG_DATE = '%d/%m/%Y %H:%M:%S'
|
||
|
logging.addLevelName(logging.ERROR, '\033[1;41mERROR\033[1;0m')
|
||
|
logging.addLevelName(logging.DEBUG, '\x1b[33mDEBUG\033[1;0m')
|
||
|
logging.addLevelName(logging.INFO, '\x1b[32mINFO\033[1;0m')
|
||
|
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE)
|
||
|
log = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
CTX = uno.getComponentContext()
|
||
|
SM = CTX.getServiceManager()
|
||
|
|
||
|
|
||
|
def create_instance(name, with_context=False):
|
||
|
if with_context:
|
||
|
instance = SM.createInstanceWithContext(name, CTX)
|
||
|
else:
|
||
|
instance = SM.createInstance(name)
|
||
|
return instance
|
||
|
|
||
|
|
||
|
def _get_app_config(key, node_name):
|
||
|
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
|
||
|
except Exception as e:
|
||
|
log.error(e)
|
||
|
return ''
|
||
|
|
||
|
|
||
|
LANGUAGE = _get_app_config('ooLocale', 'org.openoffice.Setup/L10N/')
|
||
|
LANG = LANGUAGE.split('-')[0]
|
||
|
NAME = TITLE = _get_app_config('ooName', 'org.openoffice.Setup/Product')
|
||
|
VERSION = _get_app_config('ooSetupVersion', 'org.openoffice.Setup/Product')
|
||
|
|
||
|
|
||
|
def mri(obj):
|
||
|
m = create_instance('mytools.Mri')
|
||
|
if m is None:
|
||
|
msg = 'Extension MRI not found'
|
||
|
error(msg)
|
||
|
return
|
||
|
|
||
|
m.inspect(obj)
|
||
|
return
|
||
|
|
||
|
|
||
|
def catch_exception(f):
|
||
|
@wraps(f)
|
||
|
def func(*args, **kwargs):
|
||
|
try:
|
||
|
return f(*args, **kwargs)
|
||
|
except Exception as e:
|
||
|
log.error(f.__name__, exc_info=True)
|
||
|
return func
|
||
|
|
||
|
|
||
|
class LogWin(object):
|
||
|
|
||
|
def __init__(self, doc):
|
||
|
self.doc = doc
|
||
|
|
||
|
def write(self, info):
|
||
|
text = self.doc.Text
|
||
|
cursor = text.createTextCursor()
|
||
|
cursor.gotoEnd(False)
|
||
|
text.insertString(cursor, str(info), 0)
|
||
|
return
|
||
|
|
||
|
|
||
|
def info(data):
|
||
|
log.info(data)
|
||
|
return
|
||
|
|
||
|
|
||
|
def debug(info):
|
||
|
if IS_WIN:
|
||
|
# ~ app = LOApp(self.ctx, self.sm, self.desktop, self.toolkit)
|
||
|
# ~ doc = app.getDoc(FILE_NAME_DEBUG)
|
||
|
# ~ if not doc:
|
||
|
# ~ doc = app.newDoc(WRITER)
|
||
|
# ~ out = OutputDoc(doc)
|
||
|
# ~ sys.stdout = out
|
||
|
# ~ pprint(info)
|
||
|
doc = LogWin(new_doc('writer').obj)
|
||
|
doc.write(info)
|
||
|
return
|
||
|
|
||
|
log.debug(str(info))
|
||
|
return
|
||
|
|
||
|
|
||
|
def error(info):
|
||
|
log.error(info)
|
||
|
return
|
||
|
|
||
|
|
||
|
def save_log(path, data):
|
||
|
with open(path, 'a') as out:
|
||
|
out.write('{} -{}- '.format(str(datetime.now())[:19], LOG_NAME))
|
||
|
pprint(data, stream=out)
|
||
|
return
|
||
|
|
||
|
|
||
|
def run_in_thread(fn):
|
||
|
def run(*k, **kw):
|
||
|
t = threading.Thread(target=fn, args=k, kwargs=kw)
|
||
|
t.start()
|
||
|
return t
|
||
|
return run
|
||
|
|
||
|
|
||
|
def get_config(key='', prefix='config'):
|
||
|
path_json = FILE_NAME_CONFIG.format(prefix)
|
||
|
values = {}
|
||
|
path = join(get_config_path('UserConfig'), path_json)
|
||
|
if not exists_path(path):
|
||
|
return values
|
||
|
|
||
|
with open(path, 'r', encoding='utf-8') as fh:
|
||
|
data = fh.read()
|
||
|
if data:
|
||
|
values = json.loads(data)
|
||
|
|
||
|
if key:
|
||
|
return values.get(key, None)
|
||
|
|
||
|
return values
|
||
|
|
||
|
|
||
|
def set_config(key, value, prefix='config'):
|
||
|
path_json = FILE_NAME_CONFIG.format(prefix)
|
||
|
path = join(get_config_path('UserConfig'), path_json)
|
||
|
values = get_config(prefix=prefix)
|
||
|
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 True
|
||
|
|
||
|
|
||
|
def sleep(seconds):
|
||
|
time.sleep(seconds)
|
||
|
return
|
||
|
|
||
|
|
||
|
def _(msg):
|
||
|
L = LANGUAGE.split('-')[0]
|
||
|
if L == 'en':
|
||
|
return msg
|
||
|
|
||
|
if not L in MSG_LANG:
|
||
|
return msg
|
||
|
|
||
|
return MSG_LANG[L][msg]
|
||
|
|
||
|
|
||
|
def msgbox(message, title=TITLE, buttons=MSG_BUTTONS.BUTTONS_OK, type_msg='infobox'):
|
||
|
""" Create message box
|
||
|
type_msg: infobox, warningbox, errorbox, querybox, messbox
|
||
|
http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1awt_1_1XMessageBoxFactory.html
|
||
|
"""
|
||
|
toolkit = create_instance('com.sun.star.awt.Toolkit')
|
||
|
parent = toolkit.getDesktopWindow()
|
||
|
mb = toolkit.createMessageBox(parent, type_msg, buttons, title, str(message))
|
||
|
return mb.execute()
|
||
|
|
||
|
|
||
|
def question(message, title=TITLE):
|
||
|
res = msgbox(message, title, MSG_BUTTONS.BUTTONS_YES_NO, 'querybox')
|
||
|
return res == YES
|
||
|
|
||
|
|
||
|
def warning(message, title=TITLE):
|
||
|
return msgbox(message, title, type_msg='warningbox')
|
||
|
|
||
|
|
||
|
def errorbox(message, title=TITLE):
|
||
|
return msgbox(message, title, type_msg='errorbox')
|
||
|
|
||
|
|
||
|
def get_desktop():
|
||
|
return create_instance('com.sun.star.frame.Desktop', True)
|
||
|
|
||
|
|
||
|
def get_dispatch():
|
||
|
return create_instance('com.sun.star.frame.DispatchHelper')
|
||
|
|
||
|
|
||
|
def get_temp_file():
|
||
|
delete = True
|
||
|
if IS_WIN:
|
||
|
delete = False
|
||
|
return tempfile.NamedTemporaryFile(delete=delete)
|
||
|
|
||
|
|
||
|
def _path_url(path):
|
||
|
if path.startswith('file://'):
|
||
|
return path
|
||
|
return uno.systemPathToFileUrl(path)
|
||
|
|
||
|
|
||
|
def _path_system(path):
|
||
|
if path.startswith('file://'):
|
||
|
return os.path.abspath(uno.fileUrlToSystemPath(path))
|
||
|
return path
|
||
|
|
||
|
|
||
|
def exists_app(name):
|
||
|
try:
|
||
|
dn = subprocess.DEVNULL
|
||
|
subprocess.Popen([name, ''], stdout=dn, stderr=dn).terminate()
|
||
|
except OSError as e:
|
||
|
if e.errno == errno.ENOENT:
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
# ~ Delete
|
||
|
# ~ def exists(path):
|
||
|
# ~ return Path(path).exists()
|
||
|
def exists_path(path):
|
||
|
return Path(path).exists()
|
||
|
|
||
|
|
||
|
def get_type_doc(obj):
|
||
|
# ~ services = {
|
||
|
# ~ 'calc': 'com.sun.star.sheet.SpreadsheetDocument',
|
||
|
# ~ 'writer': 'com.sun.star.text.TextDocument',
|
||
|
# ~ 'impress': 'com.sun.star.presentation.PresentationDocument',
|
||
|
# ~ 'draw': 'com.sun.star.drawing.DrawingDocument',
|
||
|
# ~ 'base': 'com.sun.star.sdb.OfficeDatabaseDocument',
|
||
|
# ~ 'math': 'com.sun.star.formula.FormulaProperties',
|
||
|
# ~ 'basic': 'com.sun.star.script.BasicIDE',
|
||
|
# ~ }
|
||
|
for k, v in TYPE_DOC.items():
|
||
|
if obj.supportsService(v):
|
||
|
return k
|
||
|
return ''
|
||
|
|
||
|
|
||
|
# ~ def _properties(values):
|
||
|
# ~ p = [PropertyValue(Name=n, Value=v) for n, v in values.items()]
|
||
|
# ~ return tuple(p)
|
||
|
|
||
|
def dict_to_property(values, uno_any=False):
|
||
|
ps = tuple([PropertyValue(Name=n, Value=v) for n, v in values.items()])
|
||
|
if uno_any:
|
||
|
ps = uno.Any('[]com.sun.star.beans.PropertyValue', ps)
|
||
|
return ps
|
||
|
|
||
|
|
||
|
def property_to_dict(values):
|
||
|
d = {i.Name: i.Value for i in values}
|
||
|
return d
|
||
|
|
||
|
|
||
|
# ~ Third classes
|
||
|
|
||
|
|
||
|
# ~ https://github.com/psf/requests/blob/v2.22.0/requests/structures.py
|
||
|
class CaseInsensitiveDict(MutableMapping):
|
||
|
"""A case-insensitive ``dict``-like object.
|
||
|
Implements all methods and operations of
|
||
|
``MutableMapping`` as well as dict's ``copy``. Also
|
||
|
provides ``lower_items``.
|
||
|
All keys are expected to be strings. The structure remembers the
|
||
|
case of the last key to be set, and ``iter(instance)``,
|
||
|
``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()``
|
||
|
will contain case-sensitive keys. However, querying and contains
|
||
|
testing is case insensitive::
|
||
|
cid = CaseInsensitiveDict()
|
||
|
cid['Accept'] = 'application/json'
|
||
|
cid['aCCEPT'] == 'application/json' # True
|
||
|
list(cid) == ['Accept'] # True
|
||
|
For example, ``headers['content-encoding']`` will return the
|
||
|
value of a ``'Content-Encoding'`` response header, regardless
|
||
|
of how the header name was originally stored.
|
||
|
If the constructor, ``.update``, or equality comparison
|
||
|
operations are given keys that have equal ``.lower()``s, the
|
||
|
behavior is undefined.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, data=None, **kwargs):
|
||
|
self._store = OrderedDict()
|
||
|
if data is None:
|
||
|
data = {}
|
||
|
self.update(data, **kwargs)
|
||
|
|
||
|
def __setitem__(self, key, value):
|
||
|
# Use the lowercased key for lookups, but store the actual
|
||
|
# key alongside the value.
|
||
|
self._store[key.lower()] = (key, value)
|
||
|
|
||
|
def __getitem__(self, key):
|
||
|
return self._store[key.lower()][1]
|
||
|
|
||
|
def __delitem__(self, key):
|
||
|
del self._store[key.lower()]
|
||
|
|
||
|
def __iter__(self):
|
||
|
return (casedkey for casedkey, mappedvalue in self._store.values())
|
||
|
|
||
|
def __len__(self):
|
||
|
return len(self._store)
|
||
|
|
||
|
def lower_items(self):
|
||
|
"""Like iteritems(), but with all lowercase keys."""
|
||
|
return (
|
||
|
(lowerkey, keyval[1])
|
||
|
for (lowerkey, keyval)
|
||
|
in self._store.items()
|
||
|
)
|
||
|
|
||
|
def __eq__(self, other):
|
||
|
if isinstance(other, Mapping):
|
||
|
other = CaseInsensitiveDict(other)
|
||
|
else:
|
||
|
return NotImplemented
|
||
|
# Compare insensitively
|
||
|
return dict(self.lower_items()) == dict(other.lower_items())
|
||
|
|
||
|
# Copy is required
|
||
|
def copy(self):
|
||
|
return CaseInsensitiveDict(self._store.values())
|
||
|
|
||
|
def __repr__(self):
|
||
|
return str(dict(self.items()))
|
||
|
|
||
|
|
||
|
# ~ Custom classes
|
||
|
|
||
|
|
||
|
class LODocument(object):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
self._obj = obj
|
||
|
self._init_values()
|
||
|
|
||
|
def _init_values(self):
|
||
|
self._type_doc = get_type_doc(self.obj)
|
||
|
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()
|
||
|
|
||
|
@property
|
||
|
def frame(self):
|
||
|
return self._cc.getFrame()
|
||
|
|
||
|
@property
|
||
|
def is_saved(self):
|
||
|
return self.obj.hasLocation()
|
||
|
|
||
|
@property
|
||
|
def is_modified(self):
|
||
|
return self.obj.isModified()
|
||
|
|
||
|
@property
|
||
|
def is_read_only(self):
|
||
|
return self.obj.isReadOnly()
|
||
|
|
||
|
@property
|
||
|
def path(self):
|
||
|
return _path_system(self.obj.getURL())
|
||
|
|
||
|
@property
|
||
|
def visible(self):
|
||
|
w = self._cc.getFrame().getContainerWindow()
|
||
|
return w.Visible
|
||
|
@visible.setter
|
||
|
def visible(self, value):
|
||
|
w = self._cc.getFrame().getContainerWindow()
|
||
|
w.setVisible(value)
|
||
|
|
||
|
@property
|
||
|
def zoom(self):
|
||
|
return self._cc.ZoomValue
|
||
|
@zoom.setter
|
||
|
def zoom(self, value):
|
||
|
self._cc.ZoomValue = value
|
||
|
|
||
|
def create_instance(self, name):
|
||
|
obj = self.obj.createInstance(name)
|
||
|
return obj
|
||
|
|
||
|
def save(self, path='', **kwargs):
|
||
|
# ~ opt = _properties(kwargs)
|
||
|
opt = dict_to_property(kwargs)
|
||
|
if path:
|
||
|
self._obj.storeAsURL(_path_url(path), opt)
|
||
|
else:
|
||
|
self._obj.store()
|
||
|
return True
|
||
|
|
||
|
def close(self):
|
||
|
self.obj.close(True)
|
||
|
return
|
||
|
|
||
|
def focus(self):
|
||
|
w = self._cc.getFrame().getComponentWindow()
|
||
|
w.setFocus()
|
||
|
return
|
||
|
|
||
|
def paste(self):
|
||
|
sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
|
||
|
transferable = sc.getContents()
|
||
|
self._cc.insertTransferable(transferable)
|
||
|
return self.obj.getCurrentSelection()
|
||
|
|
||
|
|
||
|
class LOCalc(LODocument):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
@property
|
||
|
def obj(self):
|
||
|
return self._obj
|
||
|
|
||
|
@property
|
||
|
def active(self):
|
||
|
return LOCalcSheet(self._cc.getActiveSheet(), self)
|
||
|
|
||
|
@property
|
||
|
def selection(self):
|
||
|
sel = self.obj.getCurrentSelection()
|
||
|
if sel.ImplementationName in OBJ_TYPE_RANGES:
|
||
|
sel = LOCellRange(sel, self)
|
||
|
return sel
|
||
|
|
||
|
def get_cell(self, index=None):
|
||
|
"""
|
||
|
index is str 'A1'
|
||
|
index is tuple (row, col)
|
||
|
"""
|
||
|
if index is None:
|
||
|
cell = self.selection.first
|
||
|
else:
|
||
|
cell = LOCellRange(self.active[index].obj, self)
|
||
|
return cell
|
||
|
|
||
|
def select(self, rango):
|
||
|
r = rango
|
||
|
if hasattr(rango, 'obj'):
|
||
|
r = rango.obj
|
||
|
elif isinstance(rango, str):
|
||
|
r = self.get_cell(rango).obj
|
||
|
self._cc.select(r)
|
||
|
return
|
||
|
|
||
|
|
||
|
class LOCalcSheet(object):
|
||
|
|
||
|
def __init__(self, obj, doc):
|
||
|
self._obj = obj
|
||
|
self._doc = doc
|
||
|
self._init_values()
|
||
|
|
||
|
def __getitem__(self, index):
|
||
|
return LOCellRange(self.obj[index], self.doc)
|
||
|
|
||
|
def _init_values(self):
|
||
|
return
|
||
|
|
||
|
@property
|
||
|
def obj(self):
|
||
|
return self._obj
|
||
|
|
||
|
@property
|
||
|
def doc(self):
|
||
|
return self._doc
|
||
|
|
||
|
|
||
|
class LOWriter(LODocument):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
@property
|
||
|
def obj(self):
|
||
|
return self._obj
|
||
|
|
||
|
@property
|
||
|
def string(self):
|
||
|
return self._obj.getText().String
|
||
|
|
||
|
@property
|
||
|
def text(self):
|
||
|
return self._obj.getText()
|
||
|
|
||
|
@property
|
||
|
def cursor(self):
|
||
|
return self.text.createTextCursor()
|
||
|
|
||
|
@property
|
||
|
def selection(self):
|
||
|
sel = self._cc.getSelection()
|
||
|
return LOTextRange(sel[0])
|
||
|
|
||
|
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))
|
||
|
|
||
|
def insert_image(self, path, **kwargs):
|
||
|
cursor = kwargs.get('cursor', self.selection.cursor.getEnd())
|
||
|
w = kwargs.get('width', 1000)
|
||
|
h = kwargs.get('Height', 1000)
|
||
|
image = self.create_instance('com.sun.star.text.GraphicObject')
|
||
|
image.GraphicURL = _path_url(path)
|
||
|
image.AnchorType = AS_CHARACTER
|
||
|
image.Width = w
|
||
|
image.Height = h
|
||
|
self.insert_content(cursor, image)
|
||
|
return
|
||
|
|
||
|
|
||
|
class LOTextRange(object):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
self._obj = obj
|
||
|
|
||
|
@property
|
||
|
def obj(self):
|
||
|
return self._obj
|
||
|
|
||
|
@property
|
||
|
def string(self):
|
||
|
return self.obj.String
|
||
|
|
||
|
@property
|
||
|
def text(self):
|
||
|
return self.obj.getText()
|
||
|
|
||
|
@property
|
||
|
def cursor(self):
|
||
|
return self.text.createTextCursorByRange(self.obj)
|
||
|
|
||
|
|
||
|
class LOBase(LODocument):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
|
||
|
class LODrawImpress(LODocument):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
@property
|
||
|
def draw_page(self):
|
||
|
return self._cc.getCurrentPage()
|
||
|
|
||
|
@catch_exception
|
||
|
def insert_image(self, path, **kwargs):
|
||
|
w = kwargs.get('width', 3000)
|
||
|
h = kwargs.get('Height', 1000)
|
||
|
x = kwargs.get('X', 1000)
|
||
|
y = kwargs.get('Y', 1000)
|
||
|
|
||
|
image = self.create_instance('com.sun.star.drawing.GraphicObjectShape')
|
||
|
image.GraphicURL = _path_url(path)
|
||
|
image.Size = Size(w, h)
|
||
|
image.Position = Point(x, y)
|
||
|
self.draw_page.add(image)
|
||
|
return
|
||
|
|
||
|
|
||
|
class LOImpress(LODrawImpress):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
|
||
|
class LODraw(LODrawImpress):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
|
||
|
class LOMath(LODocument):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
|
||
|
class LOBasicIde(LODocument):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
@property
|
||
|
def selection(self):
|
||
|
sel = self._cc.getSelection()
|
||
|
return sel
|
||
|
|
||
|
|
||
|
class LOCellRange(object):
|
||
|
|
||
|
def __init__(self, obj, doc):
|
||
|
self._obj = obj
|
||
|
self._doc = doc
|
||
|
self._init_values()
|
||
|
|
||
|
def __enter__(self):
|
||
|
return self
|
||
|
|
||
|
def __exit__(self, *args):
|
||
|
pass
|
||
|
|
||
|
def __getitem__(self, index):
|
||
|
return LOCellRange(self.obj[index], self.doc)
|
||
|
|
||
|
def _init_values(self):
|
||
|
self._type_obj = self.obj.ImplementationName
|
||
|
self._type_content = EMPTY
|
||
|
|
||
|
if self._type_obj == OBJ_CELL:
|
||
|
self._type_content = self.obj.getType()
|
||
|
return
|
||
|
|
||
|
@property
|
||
|
def obj(self):
|
||
|
return self._obj
|
||
|
|
||
|
@property
|
||
|
def doc(self):
|
||
|
return self._doc
|
||
|
|
||
|
@property
|
||
|
def type(self):
|
||
|
return self._type_obj
|
||
|
|
||
|
@property
|
||
|
def type_content(self):
|
||
|
return self._type_content
|
||
|
|
||
|
@property
|
||
|
def first(self):
|
||
|
if self.type == OBJ_RANGES:
|
||
|
obj = LOCellRange(self.obj[0][0,0], self.doc)
|
||
|
else:
|
||
|
obj = LOCellRange(self.obj[0,0], self.doc)
|
||
|
return obj
|
||
|
|
||
|
@property
|
||
|
def value(self):
|
||
|
v = None
|
||
|
if self._type_content == VALUE:
|
||
|
v = self.obj.getValue()
|
||
|
elif self._type_content == TEXT:
|
||
|
v = self.obj.getString()
|
||
|
elif self._type_content == FORMULA:
|
||
|
v = self.obj.getFormula()
|
||
|
return v
|
||
|
@value.setter
|
||
|
def value(self, data):
|
||
|
if isinstance(data, str):
|
||
|
if data.startswith('='):
|
||
|
self.obj.setFormula(data)
|
||
|
else:
|
||
|
self.obj.setString(data)
|
||
|
elif isinstance(data, (int, float)):
|
||
|
self.obj.setValue(data)
|
||
|
|
||
|
@property
|
||
|
def data(self):
|
||
|
return self.obj.getDataArray()
|
||
|
@data.setter
|
||
|
def data(self, values):
|
||
|
if isinstance(values, list):
|
||
|
values = tuple(values)
|
||
|
self.obj.setDataArray(values)
|
||
|
|
||
|
def offset(self, col=1, row=0):
|
||
|
a = self.address
|
||
|
col = a.Column + col
|
||
|
row = a.Row + row
|
||
|
return LOCellRange(self.sheet[row,col], self.doc)
|
||
|
|
||
|
@property
|
||
|
def sheet(self):
|
||
|
return self.obj.Spreadsheet
|
||
|
|
||
|
@property
|
||
|
def draw_page(self):
|
||
|
return self.sheet.getDrawPage()
|
||
|
|
||
|
@property
|
||
|
def name(self):
|
||
|
return self.obj.AbsoluteName
|
||
|
|
||
|
@property
|
||
|
def address(self):
|
||
|
if self._type_obj == OBJ_CELL:
|
||
|
a = self.obj.getCellAddress()
|
||
|
elif self._type_obj == OBJ_RANGE:
|
||
|
a = self.obj.getRangeAddress()
|
||
|
else:
|
||
|
a = self.obj.getRangeAddressesAsString()
|
||
|
return a
|
||
|
|
||
|
@property
|
||
|
def current_region(self):
|
||
|
cursor = self.sheet.createCursorByRange(self.obj[0,0])
|
||
|
cursor.collapseToCurrentRegion()
|
||
|
return LOCellRange(self.sheet[cursor.AbsoluteName], self.doc)
|
||
|
|
||
|
def insert_image(self, path, **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.GraphicObjectShape')
|
||
|
img.GraphicURL = _path_url(path)
|
||
|
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
|
||
|
|
||
|
|
||
|
class EventsListenerBase(unohelper.Base, XEventListener):
|
||
|
|
||
|
def __init__(self, controller, window=None):
|
||
|
self._controller = controller
|
||
|
self._window = window
|
||
|
|
||
|
def disposing(self, event):
|
||
|
self._controller = None
|
||
|
if not self._window is None:
|
||
|
self._window.setMenuBar(None)
|
||
|
|
||
|
|
||
|
class EventsButton(EventsListenerBase, XActionListener):
|
||
|
|
||
|
def __init__(self, controller):
|
||
|
super().__init__(controller)
|
||
|
|
||
|
def actionPerformed(self, event):
|
||
|
name = event.Source.Model.Name
|
||
|
event_name = '{}_action'.format(name)
|
||
|
if hasattr(self._controller, event_name):
|
||
|
getattr(self._controller, event_name)(event)
|
||
|
return
|
||
|
|
||
|
|
||
|
class EventsMouse(EventsListenerBase, XMouseListener):
|
||
|
|
||
|
def __init__(self, controller):
|
||
|
super().__init__(controller)
|
||
|
|
||
|
def mousePressed(self, event):
|
||
|
name = event.Source.Model.Name
|
||
|
event_name = '{}_click'.format(name)
|
||
|
if event.ClickCount == 2:
|
||
|
event_name = '{}_double_click'.format(name)
|
||
|
if hasattr(self._controller, event_name):
|
||
|
getattr(self._controller, event_name)(event)
|
||
|
return
|
||
|
|
||
|
def mouseReleased(self, event):
|
||
|
pass
|
||
|
|
||
|
def mouseEntered(self, event):
|
||
|
pass
|
||
|
|
||
|
def mouseExited(self, event):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class EventsMouseGrid(EventsMouse):
|
||
|
selected = False
|
||
|
|
||
|
def mousePressed(self, event):
|
||
|
super().mousePressed(event)
|
||
|
# ~ obj = event.Source
|
||
|
# ~ col = obj.getColumnAtPoint(event.X, event.Y)
|
||
|
# ~ row = obj.getRowAtPoint(event.X, event.Y)
|
||
|
# ~ print(col, row)
|
||
|
# ~ if col == -1 and row == -1:
|
||
|
# ~ if self.selected:
|
||
|
# ~ obj.deselectAllRows()
|
||
|
# ~ else:
|
||
|
# ~ obj.selectAllRows()
|
||
|
# ~ self.selected = not self.selected
|
||
|
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)
|
||
|
return
|
||
|
|
||
|
|
||
|
class UnoBaseObject(object):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
self._obj = obj
|
||
|
self._model = self.obj.Model
|
||
|
self._rules = {}
|
||
|
|
||
|
@property
|
||
|
def obj(self):
|
||
|
return self._obj
|
||
|
|
||
|
@property
|
||
|
def model(self):
|
||
|
return self._model
|
||
|
|
||
|
@property
|
||
|
def name(self):
|
||
|
return self.model.Name
|
||
|
|
||
|
@property
|
||
|
def parent(self):
|
||
|
return self.obj.getContext()
|
||
|
|
||
|
@property
|
||
|
def x(self):
|
||
|
return self.model.PositionX
|
||
|
@x.setter
|
||
|
def x(self, value):
|
||
|
self.model.PositionX = value
|
||
|
|
||
|
@property
|
||
|
def y(self):
|
||
|
return self.model.PositionY
|
||
|
@y.setter
|
||
|
def y(self, value):
|
||
|
self.model.PositionY = value
|
||
|
|
||
|
@property
|
||
|
def width(self):
|
||
|
return self._model.Width
|
||
|
@width.setter
|
||
|
def width(self, value):
|
||
|
self._model.Width = value
|
||
|
|
||
|
@property
|
||
|
def height(self):
|
||
|
return self._model.Height
|
||
|
@height.setter
|
||
|
def height(self, value):
|
||
|
self._model.Height = value
|
||
|
|
||
|
@property
|
||
|
def tag(self):
|
||
|
return self.model.Tag
|
||
|
@tag.setter
|
||
|
def tag(self, value):
|
||
|
self.model.Tag = value
|
||
|
|
||
|
@property
|
||
|
def step(self):
|
||
|
return self.model.Step
|
||
|
@step.setter
|
||
|
def step(self, value):
|
||
|
self.model.Step = value
|
||
|
|
||
|
@property
|
||
|
def rules(self):
|
||
|
return self._rules
|
||
|
@rules.setter
|
||
|
def rules(self, value):
|
||
|
self._rules = value
|
||
|
|
||
|
def set_focus(self):
|
||
|
self.obj.setFocus()
|
||
|
return
|
||
|
|
||
|
def center(self, horizontal=True, vertical=False):
|
||
|
p = self.parent.Model
|
||
|
w = p.Width
|
||
|
h = p.Height
|
||
|
if horizontal:
|
||
|
x = w / 2 - self.width / 2
|
||
|
self.x = x
|
||
|
if vertical:
|
||
|
y = h / 2 - self.height / 2
|
||
|
self.y = y
|
||
|
return
|
||
|
|
||
|
def move(self, origin, x=0, y=5):
|
||
|
w = 0
|
||
|
h = 0
|
||
|
if x:
|
||
|
w = origin.width
|
||
|
if y:
|
||
|
h = origin.height
|
||
|
x = origin.x + x + w
|
||
|
y = origin.y + y + h
|
||
|
self.x = x
|
||
|
self.y = y
|
||
|
return
|
||
|
|
||
|
|
||
|
class UnoLabel(UnoBaseObject):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
@property
|
||
|
def type(self):
|
||
|
return 'label'
|
||
|
|
||
|
@property
|
||
|
def value(self):
|
||
|
return self.model.Label
|
||
|
@value.setter
|
||
|
def value(self, value):
|
||
|
self.model.Label = value
|
||
|
|
||
|
|
||
|
class UnoButton(UnoBaseObject):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
@property
|
||
|
def type(self):
|
||
|
return 'button'
|
||
|
|
||
|
@property
|
||
|
def value(self):
|
||
|
return self.model.Label
|
||
|
@value.setter
|
||
|
def value(self, value):
|
||
|
self.model.Label = value
|
||
|
|
||
|
|
||
|
class UnoText(UnoBaseObject):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
|
||
|
@property
|
||
|
def type(self):
|
||
|
return 'text'
|
||
|
|
||
|
@property
|
||
|
def value(self):
|
||
|
return self.model.Text
|
||
|
@value.setter
|
||
|
def value(self, value):
|
||
|
self.model.Text = value
|
||
|
|
||
|
def validate(self):
|
||
|
|
||
|
return
|
||
|
|
||
|
|
||
|
class UnoListBox(UnoBaseObject):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
self._data = []
|
||
|
|
||
|
@property
|
||
|
def value(self):
|
||
|
return self.obj.SelectedItem
|
||
|
|
||
|
@property
|
||
|
def data(self):
|
||
|
return self._data
|
||
|
@data.setter
|
||
|
def data(self, values):
|
||
|
self._data = list(sorted(values))
|
||
|
self.model.StringItemList = self.data
|
||
|
return
|
||
|
|
||
|
|
||
|
class UnoGrid(UnoBaseObject):
|
||
|
|
||
|
def __init__(self, obj):
|
||
|
super().__init__(obj)
|
||
|
self._gdm = self._model.GridDataModel
|
||
|
# ~ self._data = []
|
||
|
self._columns = {}
|
||
|
# ~ self._format_columns = ()
|
||
|
|
||
|
def __getitem__(self, index):
|
||
|
value = self._gdm.getCellData(index[0], index[1])
|
||
|
return value
|
||
|
|
||
|
@property
|
||
|
def type(self):
|
||
|
return 'grid'
|
||
|
|
||
|
def _format_cols(self):
|
||
|
rows = tuple(tuple(
|
||
|
self._format_columns[i].format(r) for i, r in enumerate(row)) for row in self._data
|
||
|
)
|
||
|
return rows
|
||
|
|
||
|
# ~ @property
|
||
|
# ~ def format_columns(self):
|
||
|
# ~ return self._format_columns
|
||
|
# ~ @format_columns.setter
|
||
|
# ~ def format_columns(self, value):
|
||
|
# ~ self._format_columns = value
|
||
|
|
||
|
@property
|
||
|
def data(self):
|
||
|
return self._data
|
||
|
@data.setter
|
||
|
def data(self, values):
|
||
|
# ~ self._data = values
|
||
|
self._gdm.removeAllRows()
|
||
|
headings = tuple(range(1, len(values) + 1))
|
||
|
self._gdm.addRows(headings, values)
|
||
|
|
||
|
# ~ rows = range(grid_dm.RowCount)
|
||
|
# ~ colors = [COLORS['GRAY'] if r % 2 else COLORS['WHITE'] for r in rows]
|
||
|
# ~ grid.Model.RowBackgroundColors = tuple(colors)
|
||
|
return
|
||
|
|
||
|
@property
|
||
|
def row(self):
|
||
|
return self.obj.CurrentRow
|
||
|
|
||
|
@property
|
||
|
def rows(self):
|
||
|
return self._gdm.RowCount
|
||
|
|
||
|
@property
|
||
|
def column(self):
|
||
|
return self.obj.CurrentColumn
|
||
|
|
||
|
@property
|
||
|
def columns(self):
|
||
|
return self._gdm.ColumnCount
|
||
|
|
||
|
def set_cell_tooltip(self, col, row, value):
|
||
|
self._gdm.updateCellToolTip(col, row, value)
|
||
|
return
|
||
|
|
||
|
def get_cell_tooltip(self, col, row):
|
||
|
value = self._gdm.getCellToolTip(col, row)
|
||
|
return value
|
||
|
|
||
|
def _validate_column(self, data):
|
||
|
row = []
|
||
|
for i, d in enumerate(data):
|
||
|
if i in self._columns:
|
||
|
if 'image' in self._columns[i]:
|
||
|
row.append(self._columns[i]['image'])
|
||
|
else:
|
||
|
row.append(d)
|
||
|
return tuple(row)
|
||
|
|
||
|
def add_row(self, data):
|
||
|
# ~ self._data.append(data)
|
||
|
data = self._validate_column(data)
|
||
|
self._gdm.addRow(self.rows + 1, data)
|
||
|
return
|
||
|
|
||
|
def remove_row(self, row):
|
||
|
self._gdm.removeRow(row)
|
||
|
# ~ del self._data[row]
|
||
|
self._update_row_heading()
|
||
|
return
|
||
|
|
||
|
def _update_row_heading(self):
|
||
|
for i in range(self.rows):
|
||
|
self._gdm.updateRowHeading(i, i + 1)
|
||
|
return
|
||
|
|
||
|
def sort(self, column, asc=True):
|
||
|
self._gdm.sortByColumn(column, asc)
|
||
|
# ~ self._data.sort(key=itemgetter(column), reverse=not asc)
|
||
|
self._update_row_heading()
|
||
|
return
|
||
|
|
||
|
def set_column_image(self, column, path):
|
||
|
gp = create_instance('com.sun.star.graphic.GraphicProvider')
|
||
|
data = dict_to_property({'URL': _path_url(path)})
|
||
|
image = gp.queryGraphic(data)
|
||
|
if not column in self._columns:
|
||
|
self._columns[column] = {}
|
||
|
self._columns[column]['image'] = image
|
||
|
return
|
||
|
|
||
|
|
||
|
class LODialog(object):
|
||
|
|
||
|
def __init__(self, properties):
|
||
|
self._obj = self._create(properties)
|
||
|
self._init_values()
|
||
|
|
||
|
def _init_values(self):
|
||
|
self._model = self._obj.Model
|
||
|
self._init_controls()
|
||
|
self._events = None
|
||
|
# ~ self._response = None
|
||
|
return
|
||
|
|
||
|
def _create(self, properties):
|
||
|
path = properties.pop('Path', '')
|
||
|
if path:
|
||
|
dp = create_instance('com.sun.star.awt.DialogProvider2', True)
|
||
|
return dp.createDialog(_path_url(path))
|
||
|
|
||
|
if 'Library' in properties:
|
||
|
location = properties['Location']
|
||
|
if location == 'user':
|
||
|
location = 'application'
|
||
|
dp = create_instance('com.sun.star.awt.DialogProvider2', True)
|
||
|
path = 'vnd.sun.star.script:{}.{}?location={}'.format(
|
||
|
properties['Library'], properties['Name'], location)
|
||
|
return dp.createDialog(path)
|
||
|
|
||
|
dlg = create_instance('com.sun.star.awt.UnoControlDialog', True)
|
||
|
model = create_instance('com.sun.star.awt.UnoControlDialogModel', True)
|
||
|
toolkit = create_instance('com.sun.star.awt.Toolkit', True)
|
||
|
set_properties(model, properties)
|
||
|
dlg.setModel(model)
|
||
|
dlg.setVisible(False)
|
||
|
dlg.createPeer(toolkit, None)
|
||
|
|
||
|
return dlg
|
||
|
|
||
|
def _init_controls(self):
|
||
|
|
||
|
return
|
||
|
|
||
|
@property
|
||
|
def obj(self):
|
||
|
return self._obj
|
||
|
|
||
|
@property
|
||
|
def model(self):
|
||
|
return self._model
|
||
|
|
||
|
@property
|
||
|
def events(self):
|
||
|
return self._events
|
||
|
@events.setter
|
||
|
def events(self, controllers):
|
||
|
self._events = controllers
|
||
|
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))
|
||
|
return
|
||
|
|
||
|
def open(self):
|
||
|
return self.obj.execute()
|
||
|
|
||
|
def close(self, value=0):
|
||
|
return self.obj.endDialog(value)
|
||
|
|
||
|
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',
|
||
|
}
|
||
|
return services[control]
|
||
|
|
||
|
def _get_custom_class(self, tipo, obj):
|
||
|
classes = {
|
||
|
'label': UnoLabel,
|
||
|
'button': UnoButton,
|
||
|
'text': UnoText,
|
||
|
'listbox': UnoListBox,
|
||
|
'grid': UnoGrid,
|
||
|
# ~ 'link': UnoLink,
|
||
|
# ~ 'tab': UnoTab,
|
||
|
# ~ 'roadmap': UnoRoadmap,
|
||
|
# ~ 'image': UnoImage,
|
||
|
# ~ 'radio': UnoRadio,
|
||
|
# ~ 'groupbox': UnoGroupBox,
|
||
|
# ~ 'tree': UnoTree,
|
||
|
}
|
||
|
return classes[tipo](obj)
|
||
|
|
||
|
def _set_column_model(self, columns):
|
||
|
#~ https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1awt_1_1grid_1_1XGridColumn.html
|
||
|
column_model = create_instance('com.sun.star.awt.grid.DefaultGridColumnModel', True)
|
||
|
# ~ column_model.setDefaultColumns(len(columns))
|
||
|
for column in columns:
|
||
|
grid_column = create_instance('com.sun.star.awt.grid.GridColumn', True)
|
||
|
for k, v in column.items():
|
||
|
setattr(grid_column, k, v)
|
||
|
column_model.addColumn(grid_column)
|
||
|
# ~ mri(grid_column)
|
||
|
return column_model
|
||
|
|
||
|
def _set_image_url(self, path):
|
||
|
if exists_path(path):
|
||
|
return _path_url(path)
|
||
|
return ''
|
||
|
|
||
|
@catch_exception
|
||
|
def add_control(self, properties):
|
||
|
tipo = properties.pop('Type').lower()
|
||
|
|
||
|
columns = properties.pop('Columns', ())
|
||
|
if tipo == 'grid':
|
||
|
properties['ColumnModel'] = self._set_column_model(columns)
|
||
|
if tipo == 'button' and 'ImageURL' in properties:
|
||
|
properties['ImageURL'] = self._set_image_url(properties['ImageURL'])
|
||
|
|
||
|
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)
|
||
|
setattr(self, name, control)
|
||
|
return
|
||
|
|
||
|
|
||
|
# ~ Python >= 3.7
|
||
|
# ~ def __getattr__(name):
|
||
|
|
||
|
|
||
|
def _get_class_doc(obj):
|
||
|
classes = {
|
||
|
'calc': LOCalc,
|
||
|
'writer': LOWriter,
|
||
|
'base': LOBase,
|
||
|
'impress': LOImpress,
|
||
|
'draw': LODraw,
|
||
|
'math': LOMath,
|
||
|
'basic': LOBasicIde,
|
||
|
}
|
||
|
type_doc = get_type_doc(obj)
|
||
|
return classes[type_doc](obj)
|
||
|
|
||
|
|
||
|
def get_document():
|
||
|
doc = None
|
||
|
desktop = get_desktop()
|
||
|
try:
|
||
|
doc = _get_class_doc(desktop.getCurrentComponent())
|
||
|
except Exception as e:
|
||
|
log.error(e)
|
||
|
return doc
|
||
|
|
||
|
|
||
|
def get_selection():
|
||
|
return get_document().selection
|
||
|
|
||
|
|
||
|
def get_cell(*args):
|
||
|
if args:
|
||
|
index = args
|
||
|
if len(index) == 1:
|
||
|
index = args[0]
|
||
|
cell = get_document().get_cell(index)
|
||
|
else:
|
||
|
cell = get_selection().first
|
||
|
return cell
|
||
|
|
||
|
|
||
|
def active_cell():
|
||
|
return get_cell()
|
||
|
|
||
|
|
||
|
def create_dialog(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 get_config_path(name='Work'):
|
||
|
"""
|
||
|
Return de path name in config
|
||
|
http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1util_1_1XPathSettings.html
|
||
|
"""
|
||
|
path = create_instance('com.sun.star.util.PathSettings')
|
||
|
return _path_system(getattr(path, name))
|
||
|
|
||
|
|
||
|
def get_file(init_dir='', multiple=False, filters=()):
|
||
|
"""
|
||
|
init_folder: folder default open
|
||
|
multiple: True for multiple selected
|
||
|
filters: Example
|
||
|
(
|
||
|
('XML', '*.xml'),
|
||
|
('TXT', '*.txt'),
|
||
|
)
|
||
|
"""
|
||
|
if not init_dir:
|
||
|
init_dir = get_config_path()
|
||
|
init_dir = _path_url(init_dir)
|
||
|
file_picker = create_instance('com.sun.star.ui.dialogs.FilePicker')
|
||
|
file_picker.setTitle(_('Select file'))
|
||
|
file_picker.setDisplayDirectory(init_dir)
|
||
|
file_picker.setMultiSelectionMode(multiple)
|
||
|
|
||
|
if filters:
|
||
|
file_picker.setCurrentFilter(filters[0][0])
|
||
|
for f in filters:
|
||
|
file_picker.appendFilter(f[0], f[1])
|
||
|
|
||
|
if file_picker.execute():
|
||
|
if multiple:
|
||
|
return [_path_system(f) for f in file_picker.getSelectedFiles()]
|
||
|
return _path_system(file_picker.getSelectedFiles()[0])
|
||
|
|
||
|
return ''
|
||
|
|
||
|
|
||
|
def get_info_path(path):
|
||
|
path, filename = os.path.split(path)
|
||
|
name, extension = os.path.splitext(filename)
|
||
|
return (path, filename, name, extension)
|
||
|
|
||
|
|
||
|
def get_path_extension(id):
|
||
|
pip = CTX.getValueByName('/singletons/com.sun.star.deployment.PackageInformationProvider')
|
||
|
path = _path_system(pip.getPackageLocation(id))
|
||
|
return path
|
||
|
|
||
|
|
||
|
def inputbox(message, default='', title=TITLE):
|
||
|
|
||
|
class ControllersInput(object):
|
||
|
|
||
|
def __init__(self, dlg):
|
||
|
self.d = dlg
|
||
|
|
||
|
def cmd_ok_action(self, event):
|
||
|
self.d.close(1)
|
||
|
return
|
||
|
|
||
|
args = {
|
||
|
'Title': title,
|
||
|
'Width': 200,
|
||
|
'Height': 80,
|
||
|
}
|
||
|
dlg = LODialog(args)
|
||
|
dlg.events = ControllersInput(dlg)
|
||
|
|
||
|
args = {
|
||
|
'Type': 'Label',
|
||
|
'Name': 'lbl_msg',
|
||
|
'Label': message,
|
||
|
'Width': 140,
|
||
|
'Height': 50,
|
||
|
'X': 5,
|
||
|
'Y': 5,
|
||
|
'MultiLine': True,
|
||
|
'Border': 1,
|
||
|
}
|
||
|
dlg.add_control(args)
|
||
|
|
||
|
args = {
|
||
|
'Type': 'Text',
|
||
|
'Name': 'txt_value',
|
||
|
'Text': default,
|
||
|
'Width': 190,
|
||
|
'Height': 15,
|
||
|
}
|
||
|
dlg.add_control(args)
|
||
|
dlg.txt_value.move(dlg.lbl_msg)
|
||
|
|
||
|
args = {
|
||
|
'Type': 'button',
|
||
|
'Name': 'cmd_ok',
|
||
|
'Label': _('OK'),
|
||
|
'Width': 40,
|
||
|
'Height': 15,
|
||
|
'DefaultButton': True,
|
||
|
'PushButtonType': 1,
|
||
|
}
|
||
|
dlg.add_control(args)
|
||
|
dlg.cmd_ok.move(dlg.lbl_msg, 10, 0)
|
||
|
|
||
|
args = {
|
||
|
'Type': 'button',
|
||
|
'Name': 'cmd_cancel',
|
||
|
'Label': _('Cancel'),
|
||
|
'Width': 40,
|
||
|
'Height': 15,
|
||
|
'PushButtonType': 2,
|
||
|
}
|
||
|
dlg.add_control(args)
|
||
|
dlg.cmd_cancel.move(dlg.cmd_ok)
|
||
|
|
||
|
if dlg.open():
|
||
|
return dlg.txt_value.value
|
||
|
|
||
|
return ''
|
||
|
|
||
|
|
||
|
def new_doc(type_doc=CALC):
|
||
|
path = 'private:factory/s{}'.format(type_doc)
|
||
|
doc = get_desktop().loadComponentFromURL(path, '_default', 0, ())
|
||
|
return _get_class_doc(doc)
|
||
|
|
||
|
|
||
|
def open_doc(path, **kwargs):
|
||
|
""" Open document in path
|
||
|
Usually options:
|
||
|
Hidden: True or False
|
||
|
AsTemplate: True or False
|
||
|
ReadOnly: True or False
|
||
|
Password: super_secret
|
||
|
MacroExecutionMode: 4 = Activate macros
|
||
|
Preview: True or False
|
||
|
|
||
|
http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1frame_1_1XComponentLoader.html
|
||
|
http://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1document_1_1MediaDescriptor.html
|
||
|
"""
|
||
|
path = _path_url(path)
|
||
|
# ~ opt = _properties(kwargs)
|
||
|
opt = dict_to_property(kwargs)
|
||
|
doc = get_desktop().loadComponentFromURL(path, '_blank', 0, opt)
|
||
|
if doc is None:
|
||
|
return
|
||
|
|
||
|
return _get_class_doc(doc)
|
||
|
|
||
|
|
||
|
def open_file(path):
|
||
|
if IS_WIN:
|
||
|
os.startfile(path)
|
||
|
else:
|
||
|
subprocess.Popen(['xdg-open', path])
|
||
|
return
|
||
|
|
||
|
|
||
|
def join(*paths):
|
||
|
return os.path.join(*paths)
|
||
|
|
||
|
|
||
|
def is_dir(path):
|
||
|
return Path(path).is_dir()
|
||
|
|
||
|
|
||
|
def is_file(path):
|
||
|
return Path(path).is_file()
|
||
|
|
||
|
|
||
|
def get_file_size(path):
|
||
|
return Path(path).stat().st_size
|
||
|
|
||
|
|
||
|
def is_created(path):
|
||
|
return is_file(path) and bool(get_file_size(path))
|
||
|
|
||
|
|
||
|
def replace_ext(path, extension):
|
||
|
path, _, name, _ = get_info_path(path)
|
||
|
return '{}/{}.{}'.format(path, name, extension)
|
||
|
|
||
|
|
||
|
def zip_names(path):
|
||
|
with zipfile.ZipFile(path) as z:
|
||
|
names = z.namelist()
|
||
|
return names
|
||
|
|
||
|
|
||
|
def run(command, wait=False):
|
||
|
# ~ debug(command)
|
||
|
# ~ debug(shlex.split(command))
|
||
|
try:
|
||
|
if wait:
|
||
|
# ~ p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
|
||
|
# ~ p.wait()
|
||
|
result = subprocess.check_output(command, shell=True)
|
||
|
else:
|
||
|
p = subprocess.Popen(shlex.split(command), stdin=None,
|
||
|
stdout=None, stderr=None, close_fds=True)
|
||
|
result, er = p.communicate()
|
||
|
except subprocess.CalledProcessError as e:
|
||
|
msg = ("run [ERROR]: output = %s, error code = %s\n"
|
||
|
% (e.output, e.returncode))
|
||
|
error(msg)
|
||
|
return False
|
||
|
|
||
|
if result is None:
|
||
|
return True
|
||
|
|
||
|
return result.decode()
|
||
|
|
||
|
|
||
|
def _zippwd(source, target, pwd):
|
||
|
if IS_WIN:
|
||
|
return False
|
||
|
if not exists_app('zip'):
|
||
|
return False
|
||
|
|
||
|
cmd = 'zip'
|
||
|
opt = '-j '
|
||
|
args = "{} --password {} ".format(cmd, pwd)
|
||
|
|
||
|
if isinstance(source, (tuple, list)):
|
||
|
if not target:
|
||
|
return False
|
||
|
args += opt + target + ' ' + ' '.join(source)
|
||
|
else:
|
||
|
if is_file(source) and not target:
|
||
|
target = replace_ext(source, 'zip')
|
||
|
elif is_dir(source) and not target:
|
||
|
target = join(PurePath(source).parent,
|
||
|
'{}.zip'.format(PurePath(source).name))
|
||
|
opt = '-r '
|
||
|
args += opt + target + ' ' + source
|
||
|
|
||
|
result = run(args, True)
|
||
|
if not result:
|
||
|
return False
|
||
|
|
||
|
return is_created(target)
|
||
|
|
||
|
|
||
|
def zip(source, target='', mode='w', pwd=''):
|
||
|
if pwd:
|
||
|
return _zippwd(source, target, pwd)
|
||
|
|
||
|
if isinstance(source, (tuple, list)):
|
||
|
if not target:
|
||
|
return False
|
||
|
|
||
|
with zipfile.ZipFile(target, mode, compression=zipfile.ZIP_DEFLATED) as z:
|
||
|
for path in source:
|
||
|
_, name, _, _ = get_info_path(path)
|
||
|
z.write(path, name)
|
||
|
|
||
|
return is_created(target)
|
||
|
|
||
|
if is_file(source):
|
||
|
if not target:
|
||
|
target = replace_ext(source, 'zip')
|
||
|
z = zipfile.ZipFile(target, mode, compression=zipfile.ZIP_DEFLATED)
|
||
|
_, name, _, _ = get_info_path(source)
|
||
|
z.write(source, name)
|
||
|
z.close()
|
||
|
return is_created(target)
|
||
|
|
||
|
if not target:
|
||
|
target = join(
|
||
|
PurePath(source).parent,
|
||
|
'{}.zip'.format(PurePath(source).name))
|
||
|
z = zipfile.ZipFile(target, mode, compression=zipfile.ZIP_DEFLATED)
|
||
|
root_len = len(os.path.abspath(source))
|
||
|
for root, dirs, files in os.walk(source):
|
||
|
relative = os.path.abspath(root)[root_len:]
|
||
|
for f in files:
|
||
|
fullpath = join(root, f)
|
||
|
file_name = join(relative, f)
|
||
|
z.write(fullpath, file_name)
|
||
|
z.close()
|
||
|
|
||
|
return is_created(target)
|
||
|
|
||
|
|
||
|
def unzip(source, path='', members=None, pwd=None):
|
||
|
if not path:
|
||
|
path, _, _, _ = get_info_path(source)
|
||
|
with zipfile.ZipFile(source) as z:
|
||
|
if not pwd is None:
|
||
|
pwd = pwd.encode()
|
||
|
if isinstance(members, str):
|
||
|
members = (members,)
|
||
|
z.extractall(path, members=members, pwd=pwd)
|
||
|
return True
|
||
|
|
||
|
|
||
|
def merge_zip(target, zips):
|
||
|
try:
|
||
|
with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED) as t:
|
||
|
for path in zips:
|
||
|
with zipfile.ZipFile(path, compression=zipfile.ZIP_DEFLATED) as s:
|
||
|
for name in s.namelist():
|
||
|
t.writestr(name, s.open(name).read())
|
||
|
except Exception as e:
|
||
|
error(e)
|
||
|
return False
|
||
|
|
||
|
return True
|
||
|
|
||
|
|
||
|
def kill(path):
|
||
|
p = Path(path)
|
||
|
if p.is_file():
|
||
|
try:
|
||
|
p.unlink()
|
||
|
except:
|
||
|
pass
|
||
|
elif p.is_dir():
|
||
|
p.rmdir()
|
||
|
return
|
||
|
|
||
|
|
||
|
def get_size_screen():
|
||
|
if IS_WIN:
|
||
|
user32 = ctypes.windll.user32
|
||
|
res = '{}x{}'.format(user32.GetSystemMetrics(0), user32.GetSystemMetrics(1))
|
||
|
else:
|
||
|
args = 'xrandr | grep "*" | cut -d " " -f4'
|
||
|
res = run(args, True)
|
||
|
return res.strip()
|
||
|
|
||
|
|
||
|
def get_clipboard():
|
||
|
df = None
|
||
|
text = ''
|
||
|
sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
|
||
|
transferable = sc.getContents()
|
||
|
data = transferable.getTransferDataFlavors()
|
||
|
for df in data:
|
||
|
if df.MimeType == CLIPBOARD_FORMAT_TEXT:
|
||
|
break
|
||
|
if df:
|
||
|
text = transferable.getTransferData(df)
|
||
|
return text
|
||
|
|
||
|
|
||
|
class TextTransferable(unohelper.Base, XTransferable):
|
||
|
"""Keep clipboard data and provide them."""
|
||
|
|
||
|
def __init__(self, text):
|
||
|
df = DataFlavor()
|
||
|
df.MimeType = CLIPBOARD_FORMAT_TEXT
|
||
|
df.HumanPresentableName = "encoded text utf-16"
|
||
|
self.flavors = [df]
|
||
|
self.data = [text]
|
||
|
|
||
|
def getTransferData(self, flavor):
|
||
|
if not flavor:
|
||
|
return
|
||
|
for i, f in enumerate(self.flavors):
|
||
|
if flavor.MimeType == f.MimeType:
|
||
|
return self.data[i]
|
||
|
return
|
||
|
|
||
|
def getTransferDataFlavors(self):
|
||
|
return tuple(self.flavors)
|
||
|
|
||
|
def isDataFlavorSupported(self, flavor):
|
||
|
if not flavor:
|
||
|
return False
|
||
|
mtype = flavor.MimeType
|
||
|
for f in self.flavors:
|
||
|
if mtype == f.MimeType:
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
|
||
|
def set_clipboard(value):
|
||
|
ts = TextTransferable(value)
|
||
|
sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
|
||
|
sc.setContents(ts, None)
|
||
|
return
|
||
|
|
||
|
|
||
|
def copy(doc=None):
|
||
|
if doc is None:
|
||
|
doc = get_document()
|
||
|
if hasattr(doc, 'frame'):
|
||
|
frame = doc.frame
|
||
|
else:
|
||
|
frame = doc.getCurrentController().getFrame()
|
||
|
dispatch = get_dispatch()
|
||
|
dispatch.executeDispatch(frame, '.uno:Copy', '', 0, ())
|
||
|
return
|
||
|
|
||
|
|
||
|
def get_epoch():
|
||
|
now = datetime.datetime.now()
|
||
|
return int(time.mktime(now.timetuple()))
|
||
|
|
||
|
|
||
|
def file_copy(source, target='', name=''):
|
||
|
p, f, n, e = get_info_path(source)
|
||
|
if target:
|
||
|
p = target
|
||
|
if name:
|
||
|
n = name
|
||
|
path_new = join(p, '{}{}'.format(n, e))
|
||
|
shutil.copy(source, path_new)
|
||
|
return
|
||
|
|
||
|
|
||
|
def get_files(path, ext='*'):
|
||
|
docs = []
|
||
|
for folder, _, files in os.walk(path):
|
||
|
pattern = re.compile(r'\.{}'.format(ext), re.IGNORECASE)
|
||
|
docs += [join(folder, f) for f in files if pattern.search(f)]
|
||
|
return docs
|
||
|
|
||
|
|
||
|
def _get_menu(type_doc, name_menu):
|
||
|
instance = 'com.sun.star.ui.ModuleUIConfigurationManagerSupplier'
|
||
|
service = TYPE_DOC[type_doc]
|
||
|
manager = create_instance(instance, True)
|
||
|
ui = manager.getUIConfigurationManager(service)
|
||
|
menus = ui.getSettings(NODE_MENUBAR, True)
|
||
|
command = MENUS_APP[type_doc][name_menu]
|
||
|
for menu in menus:
|
||
|
data = property_to_dict(menu)
|
||
|
if data.get('CommandURL', '') == command:
|
||
|
idc = data.get('ItemDescriptorContainer', None)
|
||
|
return ui, menus, idc
|
||
|
return None, None, None
|
||
|
|
||
|
|
||
|
def _get_index_menu(menu, command):
|
||
|
for i, m in enumerate(menu):
|
||
|
data = property_to_dict(m)
|
||
|
cmd = data.get('CommandURL', '')
|
||
|
if cmd == command:
|
||
|
return i
|
||
|
# ~ submenu = data.get('ItemDescriptorContainer', None)
|
||
|
# ~ if not submenu is None:
|
||
|
# ~ get_index_menu(submenu, command, count + 1)
|
||
|
return 0
|
||
|
|
||
|
|
||
|
def _store_menu(ui, menus, menu, index, data=(), remove=False):
|
||
|
if remove:
|
||
|
uno.invoke(menu, 'removeByIndex', (index,))
|
||
|
else:
|
||
|
properties = dict_to_property(data, True)
|
||
|
uno.invoke(menu, 'insertByIndex', (index + 1, properties))
|
||
|
ui.replaceSettings(NODE_MENUBAR, menus)
|
||
|
ui.store()
|
||
|
return
|
||
|
|
||
|
|
||
|
def insert_menu(type_doc, name_menu, **kwargs):
|
||
|
ui, menus, menu = _get_menu(type_doc, name_menu.lower())
|
||
|
if menu is None:
|
||
|
return 0
|
||
|
|
||
|
label = kwargs.get('Label', '-')
|
||
|
separator = False
|
||
|
if label == '-':
|
||
|
separator = True
|
||
|
command = kwargs.get('CommandURL', '')
|
||
|
index = kwargs.get('Index', 0)
|
||
|
if not index:
|
||
|
index = _get_index_menu(menu, kwargs['After'])
|
||
|
if separator:
|
||
|
data = {'Type': 1}
|
||
|
_store_menu(ui, menus, menu, index, data)
|
||
|
return index + 1
|
||
|
|
||
|
index_menu = _get_index_menu(menu, command)
|
||
|
if index_menu:
|
||
|
msg = 'Exists: %s' % command
|
||
|
debug(msg)
|
||
|
return 0
|
||
|
|
||
|
sub_menu = kwargs.get('Submenu', ())
|
||
|
idc = None
|
||
|
if sub_menu:
|
||
|
idc = ui.createSettings()
|
||
|
|
||
|
data = {
|
||
|
'CommandURL': command,
|
||
|
'Label': label,
|
||
|
'Style': 0,
|
||
|
'Type': 0,
|
||
|
'ItemDescriptorContainer': idc
|
||
|
}
|
||
|
_store_menu(ui, menus, menu, index, data)
|
||
|
if sub_menu:
|
||
|
_add_sub_menus(ui, menus, idc, sub_menu)
|
||
|
return True
|
||
|
|
||
|
|
||
|
def _add_sub_menus(ui, menus, menu, sub_menu):
|
||
|
for i, sm in enumerate(sub_menu):
|
||
|
submenu = sm.pop('Submenu', ())
|
||
|
sm['Type'] = 0
|
||
|
if submenu:
|
||
|
idc = ui.createSettings()
|
||
|
sm['ItemDescriptorContainer'] = idc
|
||
|
if sm['Label'] == '-':
|
||
|
sm = {'Type': 1}
|
||
|
_store_menu(ui, menus, menu, i - 1, sm)
|
||
|
if submenu:
|
||
|
_add_sub_menus(ui, menus, idc, submenu)
|
||
|
return
|
||
|
|
||
|
|
||
|
def remove_menu(type_doc, name_menu, command):
|
||
|
ui, menus, menu = _get_menu(type_doc, name_menu.lower())
|
||
|
if menu is None:
|
||
|
return False
|
||
|
|
||
|
index = _get_index_menu(menu, command)
|
||
|
if not index:
|
||
|
debug('Not exists: %s' % command)
|
||
|
return False
|
||
|
|
||
|
_store_menu(ui, menus, menu, index, remove=True)
|
||
|
return True
|
||
|
|
||
|
|
||
|
# ~ 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
|