2019-09-07 00:02:59 -05:00
|
|
|
#!/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 getpass
|
|
|
|
import logging
|
|
|
|
import platform
|
|
|
|
import sys
|
2019-09-08 00:25:30 -05:00
|
|
|
import tempfile
|
2019-09-07 00:02:59 -05:00
|
|
|
import threading
|
|
|
|
import time
|
|
|
|
from functools import wraps
|
|
|
|
|
|
|
|
import uno
|
|
|
|
|
|
|
|
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
|
2019-09-08 00:25:30 -05:00
|
|
|
from com.sun.star.awt.PosSize import POSSIZE, SIZE
|
|
|
|
from com.sun.star.awt import Size
|
|
|
|
from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA
|
2019-09-07 00:02:59 -05:00
|
|
|
|
|
|
|
|
|
|
|
FILE_NAME_DEBUG = 'debug.log'
|
|
|
|
MSG_LANG = {
|
|
|
|
'es': {
|
|
|
|
'OK': 'Aceptar',
|
|
|
|
'Cancel': 'Cancelar',
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
|
|
|
|
DATE = '%d/%m/%Y %H:%M:%S'
|
|
|
|
LEVEL_ERROR = logging.getLevelName(logging.ERROR)
|
2019-09-08 00:25:30 -05:00
|
|
|
LEVEL_DEBUG = logging.getLevelName(logging.DEBUG)
|
2019-09-07 00:02:59 -05:00
|
|
|
LEVEL_INFO = logging.getLevelName(logging.INFO)
|
|
|
|
logging.addLevelName(logging.ERROR, f'\033[1;41m{LEVEL_ERROR}\033[1;0m')
|
2019-09-08 00:25:30 -05:00
|
|
|
logging.addLevelName(logging.DEBUG, f'\x1b[33m{LEVEL_DEBUG}\033[1;0m')
|
2019-09-07 00:02:59 -05:00
|
|
|
logging.addLevelName(logging.INFO, f'\x1b[32m{LEVEL_INFO}\033[1;0m')
|
|
|
|
logging.basicConfig(level=logging.DEBUG, format=FORMAT, datefmt=DATE)
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
OBJ_CELL = 'ScCellObj'
|
|
|
|
OBJ_RANGE = 'ScCellRangeObj'
|
|
|
|
OBJ_RANGES = 'ScCellRangesObj'
|
|
|
|
|
|
|
|
|
2019-09-07 00:02:59 -05:00
|
|
|
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_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 ''
|
|
|
|
|
|
|
|
|
|
|
|
OS = sys.platform
|
|
|
|
USER = getpass.getuser()
|
|
|
|
PC = platform.node()
|
|
|
|
|
|
|
|
LANGUAGE = _get_config('ooLocale', 'org.openoffice.Setup/L10N/')
|
|
|
|
NAME = TITLE = _get_config('ooName', 'org.openoffice.Setup/Product')
|
|
|
|
VERSION = _get_config('ooSetupVersion', 'org.openoffice.Setup/Product')
|
|
|
|
DESKTOP = create_instance('com.sun.star.frame.Desktop', True)
|
|
|
|
|
|
|
|
INFO_DEBUG = '{}\n\n{}\n\n{}'.format(
|
|
|
|
sys.version, platform.platform(), '\n'.join(sys.path))
|
|
|
|
|
|
|
|
|
|
|
|
def mri(obj):
|
|
|
|
m = create_instance('mytools.Mri')
|
|
|
|
if m is None:
|
|
|
|
msg = 'Extension MRI not found'
|
|
|
|
error(msg)
|
|
|
|
return
|
|
|
|
|
|
|
|
m.inspect(obj)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
def debug(info):
|
|
|
|
log.debug(info)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
def error(info):
|
|
|
|
log.error(info)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
2019-09-07 00:02:59 -05:00
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
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 _(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')
|
|
|
|
|
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
def errorbox(message, title=TITLE):
|
2019-09-07 00:02:59 -05:00
|
|
|
return msgbox(message, title, type_msg='errorbox')
|
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
|
|
|
|
def get_temp_file():
|
|
|
|
return tempfile.NamedTemporaryFile()
|
|
|
|
|
|
|
|
|
|
|
|
def _path_url(path):
|
|
|
|
if path.startswith('file://'):
|
|
|
|
return path
|
|
|
|
return uno.systemPathToFileUrl(path)
|
|
|
|
|
|
|
|
|
|
|
|
# ~ Custom classes
|
|
|
|
class LOCellRange(object):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
self._obj = obj
|
|
|
|
self._init_values()
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, *args):
|
|
|
|
pass
|
|
|
|
|
|
|
|
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 type_content(self):
|
|
|
|
return self._type_content
|
|
|
|
|
|
|
|
@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)
|
|
|
|
|
|
|
|
def offset(self, col=1, row=0):
|
|
|
|
a = self.address
|
|
|
|
col = a.Column + col
|
|
|
|
row = a.Row + row
|
|
|
|
return LOCellRange(self.obj.Spreadsheet[row,col])
|
|
|
|
|
|
|
|
@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
|
|
|
|
|
|
|
|
def add_image(self, path, **kwargs):
|
|
|
|
s = self.obj.Size
|
|
|
|
w = kwargs.get('width', s.Width)
|
|
|
|
h = kwargs.get('Height', s.Height)
|
|
|
|
doc = get_document()
|
|
|
|
img = doc.createInstance('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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ~ Python >= 3.7
|
|
|
|
# ~ def __getattr__(name):
|
|
|
|
|
|
|
|
|
|
|
|
def get_document():
|
|
|
|
doc = None
|
|
|
|
try:
|
|
|
|
doc = DESKTOP.getCurrentComponent()
|
|
|
|
except Exception as e:
|
|
|
|
log.error(e)
|
|
|
|
return doc
|
|
|
|
|
|
|
|
|
|
|
|
def get_selection():
|
|
|
|
obj = None
|
|
|
|
try:
|
|
|
|
obj = get_document().getCurrentSelection()
|
|
|
|
except Exception as e:
|
|
|
|
log.error(e)
|
|
|
|
return obj
|
|
|
|
|
|
|
|
|
|
|
|
def get_cell(*args):
|
|
|
|
sel = get_selection()
|
|
|
|
if sel.ImplementationName == OBJ_RANGE:
|
|
|
|
sel = sel[0,0]
|
|
|
|
elif sel.ImplementationName == OBJ_RANGES:
|
|
|
|
sel = sel[0][0,0]
|
|
|
|
return LOCellRange(sel)
|