zaz/source/easymacro2.py

2939 lines
74 KiB
Python
Raw Normal View History

2020-08-16 22:04:40 -05:00
#!/usr/bin/env python3
# == Rapid Develop Macros in LibreOffice ==
# ~ This file is part of ZAZ.
2020-09-11 21:54:38 -05:00
# ~ https://gitlab.com/mauriciobaeza/zaz
2020-08-16 22:04:40 -05:00
# ~ 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 datetime
2020-08-23 12:43:04 -05:00
import getpass
2020-09-11 21:54:38 -05:00
import gettext
2020-08-16 22:04:40 -05:00
import logging
2020-08-23 12:43:04 -05:00
import os
2020-08-16 22:04:40 -05:00
import platform
2020-09-11 21:54:38 -05:00
import shlex
2020-08-25 12:32:58 -05:00
import socket
import subprocess
2020-08-23 12:43:04 -05:00
import sys
2020-08-25 22:41:45 -05:00
import threading
2020-08-25 12:32:58 -05:00
import time
2020-08-16 22:04:40 -05:00
from enum import IntEnum
from functools import wraps
from pathlib import Path
from typing import Any
import uno
import unohelper
from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS
from com.sun.star.awt.MessageBoxResults import YES
from com.sun.star.awt import Rectangle
2020-09-11 21:54:38 -05:00
from com.sun.star.awt import Key, KeyModifier, KeyEvent
from com.sun.star.container import NoSuchElementException
2020-08-16 22:04:40 -05:00
from com.sun.star.beans import PropertyValue, NamedValue
from com.sun.star.sheet import TableFilterField
from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA
2020-08-23 12:43:04 -05:00
from com.sun.star.util import Time, Date, DateTime
2020-08-16 22:04:40 -05:00
from com.sun.star.awt import XActionListener
from com.sun.star.lang import XEventListener
from com.sun.star.awt import XMouseListener
from com.sun.star.awt import XMouseMotionListener
2020-09-11 21:54:38 -05:00
from com.sun.star.awt import XFocusListener
2020-08-16 22:04:40 -05:00
# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt_1_1FontUnderline.html
from com.sun.star.awt import FontUnderline
2020-08-23 12:43:04 -05:00
from com.sun.star.style.VerticalAlignment import TOP, MIDDLE, BOTTOM
try:
from peewee import Database, DateTimeField, DateField, TimeField, \
__exception_wrapper__
except ImportError as e:
2020-09-11 21:54:38 -05:00
Database = DateField = TimeField = DateTimeField = object
2020-08-25 12:32:58 -05:00
print('Install peewee')
2020-08-16 22:04:40 -05:00
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__)
2020-08-23 12:43:04 -05:00
LEFT = 0
CENTER = 1
RIGHT = 2
2020-08-16 22:04:40 -05:00
CALC = 'calc'
WRITER = 'writer'
DRAW = 'draw'
IMPRESS = 'impress'
BASE = 'base'
MATH = 'math'
BASIC = 'basic'
2020-09-11 21:54:38 -05:00
MAIN = 'main'
2020-08-16 22:04:40 -05:00
TYPE_DOC = {
CALC: 'com.sun.star.sheet.SpreadsheetDocument',
WRITER: 'com.sun.star.text.TextDocument',
DRAW: 'com.sun.star.drawing.DrawingDocument',
IMPRESS: 'com.sun.star.presentation.PresentationDocument',
BASE: 'com.sun.star.sdb.DocumentDataSource',
MATH: 'com.sun.star.formula.FormulaProperties',
BASIC: 'com.sun.star.script.BasicIDE',
2020-09-11 21:54:38 -05:00
MAIN: 'com.sun.star.frame.StartModule',
2020-08-16 22:04:40 -05:00
}
OBJ_CELL = 'ScCellObj'
OBJ_RANGE = 'ScCellRangeObj'
OBJ_RANGES = 'ScCellRangesObj'
TYPE_RANGES = (OBJ_CELL, OBJ_RANGE, OBJ_RANGES)
# ~ from com.sun.star.sheet.FilterOperator import EMPTY, NO_EMPTY, EQUAL, NOT_EQUAL
class FilterOperator(IntEnum):
EMPTY = 0
NO_EMPTY = 1
EQUAL = 2
NOT_EQUAL = 3
2020-09-11 21:54:38 -05:00
# ~ https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1awt_1_1UnoControlEditModel.html#a54d3ff280d892218d71e667f81ce99d4
class Border(IntEnum):
NO_BORDER = 0
BORDER = 1
SIMPLE = 2
2020-08-16 22:04:40 -05:00
OS = platform.system()
IS_WIN = OS == 'Windows'
IS_MAC = OS == 'Darwin'
2020-08-23 12:43:04 -05:00
USER = getpass.getuser()
PC = platform.node()
DESKTOP = os.environ.get('DESKTOP_SESSION', '')
INFO_DEBUG = f"{sys.version}\n\n{platform.platform()}\n\n" + '\n'.join(sys.path)
2020-09-11 21:54:38 -05:00
_MACROS = {}
2020-08-16 22:04:40 -05:00
SECONDS_DAY = 60 * 60 * 24
2020-09-11 21:54:38 -05:00
DIR = {
'images': 'images',
'locales': 'locales',
}
MIMETYPE = 'png'
MODIFIERS = {
'shift': KeyModifier.SHIFT,
'ctrl': KeyModifier.MOD1,
'alt': KeyModifier.MOD2,
'ctrlmac': KeyModifier.MOD3,
}
# ~ Menus
NODE_MENUBAR = 'private:resource/menubar/menubar'
MENUS = {
'file': '.uno:PickList',
'tools': '.uno:ToolsMenu',
'help': '.uno:HelpMenu',
'windows': '.uno:WindowList',
'edit': '.uno:EditMenu',
'view': '.uno:ViewMenu',
'insert': '.uno:InsertMenu',
'format': '.uno:FormatMenu',
'styles': '.uno:FormatStylesMenu',
'sheet': '.uno:SheetMenu',
'data': '.uno:DataMenu',
'table': '.uno:TableMenu',
'form': '.uno:FormatFormMenu',
'page': '.uno:PageMenu',
'shape': '.uno:ShapeMenu',
'slide': '.uno:SlideMenu',
'show': '.uno:SlideShowMenu',
}
MESSAGES = {
'es': {
'OK': 'Aceptar',
'Cancel': 'Cancelar',
'Select file': 'Seleccionar archivo',
'Incorrect user or password': 'Nombre de usuario o contraseƱa invƔlidos',
'Allow less secure apps in GMail': 'Activa: Permitir aplicaciones menos segura en GMail',
}
}
2020-08-16 22:04:40 -05:00
CTX = uno.getComponentContext()
SM = CTX.getServiceManager()
def create_instance(name: str, with_context: bool=False, args: Any=None) -> Any:
if with_context:
instance = SM.createInstanceWithContext(name, CTX)
elif args:
instance = SM.createInstanceWithArguments(name, (args,))
else:
instance = SM.createInstance(name)
return instance
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 not key:
return ca
if ca and ca.hasByName(key):
return ca.getPropertyValue(key)
except Exception as e:
error(e)
return ''
LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale')
LANG = LANGUAGE.split('-')[0]
NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName')
VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion')
2020-08-23 12:43:04 -05:00
INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{INFO_DEBUG}"
2020-08-16 22:04:40 -05:00
2020-08-23 12:43:04 -05:00
node = '/org.openoffice.Office.Calc/Calculate/Other/Date'
y = get_app_config(node, 'YY')
m = get_app_config(node, 'MM')
d = get_app_config(node, 'DD')
DATE_OFFSET = datetime.date(y, m, d).toordinal()
2020-08-16 22:04:40 -05:00
2020-08-25 22:41:45 -05:00
def error(info):
log.error(info)
return
2020-08-16 22:04:40 -05:00
def debug(*args):
data = [str(a) for a in args]
log.debug('\t'.join(data))
return
2020-08-25 22:41:45 -05:00
def info(*args):
data = [str(a) for a in args]
log.info('\t'.join(data))
2020-08-23 12:43:04 -05:00
return
2020-08-16 22:04:40 -05:00
def catch_exception(f):
@wraps(f)
def func(*args, **kwargs):
try:
return f(*args, **kwargs)
except Exception as e:
name = f.__name__
if IS_WIN:
debug(traceback.format_exc())
log.error(name, exc_info=True)
return func
def inspect(obj: Any) -> None:
zaz = create_instance('net.elmau.zaz.inspect')
if hasattr(obj, 'obj'):
obj = obj.obj
zaz.inspect(obj)
return
2020-09-11 21:54:38 -05:00
def mri(obj):
m = create_instance('mytools.Mri')
if m is None:
msg = 'Extension MRI not found'
error(msg)
return
m.inspect(obj)
return
2020-08-16 22:04:40 -05:00
def now(only_time=False):
now = datetime.datetime.now()
if only_time:
now = now.time()
return now
def today():
return datetime.date.today()
2020-09-11 21:54:38 -05:00
def _(msg):
if LANG == 'en':
return msg
if not LANG in MESSAGES:
return msg
return MESSAGES[LANG][msg]
2020-08-16 22:04:40 -05:00
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()
box = toolkit.createMessageBox(parent, type_msg, buttons, title, str(message))
return box.execute()
def question(message, title=TITLE):
result = msgbox(message, title, MSG_BUTTONS.BUTTONS_YES_NO, 'querybox')
return result == YES
def warning(message, title=TITLE):
return msgbox(message, title, type_msg='warningbox')
2020-08-23 12:43:04 -05:00
def errorbox(message, title=TITLE):
2020-08-16 22:04:40 -05:00
return msgbox(message, title, type_msg='errorbox')
def get_type_doc(obj: Any) -> str:
for k, v in TYPE_DOC.items():
if obj.supportsService(v):
return k
return ''
def _get_class_doc(obj: Any) -> Any:
classes = {
CALC: LOCalc,
WRITER: LOWriter,
DRAW: LODraw,
IMPRESS: LOImpress,
BASE: LOBase,
MATH: LOMath,
BASIC: LOBasic,
}
type_doc = get_type_doc(obj)
return classes[type_doc](obj)
2020-09-11 21:54:38 -05:00
def _get_class_uno(obj: Any) -> Any:
classes = dict(
SwXTextGraphicObject = LOImage,
SvxShapeText = LOImage,
)
name = obj.ImplementationName
print(f'ImplementationName = {name}')
instance = obj
if name in classes:
instance = classes[name](obj)
return instance
2020-08-16 22:04:40 -05:00
def dict_to_property(values: dict, uno_any: bool=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
2020-08-25 22:41:45 -05:00
def _array_to_dict(values):
d = {v[0]: v[1] for v in values}
return d
def _property_to_dict(values):
d = {v.Name: v.Value for v in values}
return d
def data_to_dict(data):
if isinstance(data, tuple) and isinstance(data[0], tuple):
return _array_to_dict(data)
if isinstance(data, tuple) and isinstance(data[0], (PropertyValue, NamedValue)):
return _property_to_dict(data)
return {}
2020-08-16 22:04:40 -05:00
def _path_url(path: str) -> str:
if path.startswith('file://'):
return path
return uno.systemPathToFileUrl(path)
def _path_system(path: str) -> str:
if path.startswith('file://'):
return str(Path(uno.fileUrlToSystemPath(path)).resolve())
return path
def _get_dispatch() -> Any:
return create_instance('com.sun.star.frame.DispatchHelper')
def call_dispatch(frame: Any, url: str, args: dict={}) -> None:
dispatch = _get_dispatch()
opt = dict_to_property(args)
dispatch.executeDispatch(frame, url, '', 0, opt)
return
2020-08-23 12:43:04 -05:00
def get_desktop():
return create_instance('com.sun.star.frame.Desktop', True)
def _date_to_struct(value):
if isinstance(value, datetime.datetime):
d = DateTime()
d.Year = value.year
d.Month = value.month
d.Day = value.day
d.Hours = value.hour
d.Minutes = value.minute
d.Seconds = value.second
elif isinstance(value, datetime.date):
d = Date()
d.Day = value.day
d.Month = value.month
d.Year = value.year
elif isinstance(value, datetime.time):
d = Time()
d.Hours = value.hour
d.Minutes = value.minute
d.Seconds = value.second
return d
def _struct_to_date(value):
2020-08-23 23:53:37 -05:00
d = None
2020-08-23 12:43:04 -05:00
if isinstance(value, Time):
d = datetime.time(value.Hours, value.Minutes, value.Seconds)
elif isinstance(value, Date):
2020-08-23 23:53:37 -05:00
if value != Date():
d = datetime.date(value.Year, value.Month, value.Day)
2020-08-23 12:43:04 -05:00
elif isinstance(value, DateTime):
2020-08-23 23:53:37 -05:00
if value.Year > 0:
d = datetime.datetime(
value.Year, value.Month, value.Day,
value.Hours, value.Minutes, value.Seconds)
2020-08-23 12:43:04 -05:00
return d
2020-08-25 22:41:45 -05:00
def _get_url_script(args):
library = args['library']
module = '.'
name = args['name']
language = args.get('language', 'Python')
location = args.get('location', 'user')
if language == 'Python':
module = '.py$'
elif language == 'Basic':
module = f".{module}."
if location == 'user':
location = 'application'
url = 'vnd.sun.star.script'
url = f'{url}:{library}{module}{name}?language={language}&location={location}'
return url
def _call_macro(args):
#~ https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
url = _get_url_script(args)
args = args.get('args', ())
service = 'com.sun.star.script.provider.MasterScriptProviderFactory'
factory = create_instance(service)
script = factory.createScriptProvider('').getScript(url)
result = script.invoke(args, None, None)[0]
return result
def call_macro(args, in_thread=False):
result = None
if in_thread:
t = threading.Thread(target=_call_macro, args=(args,))
t.start()
else:
result = _call_macro(args)
return result
2020-09-11 21:54:38 -05:00
def run(command, capture=False):
result = subprocess.run(shlex.split(command),
capture_output=capture, text=True).stdout
return result
def sleep(seconds):
time.sleep(seconds)
return
2020-08-25 22:41:45 -05:00
class TimerThread(threading.Thread):
def __init__(self, event, seconds, macro):
threading.Thread.__init__(self)
self.stopped = event
self.seconds = seconds
self.macro = macro
def run(self):
info('Timer started... {}'.format(self.macro['name']))
while not self.stopped.wait(self.seconds):
_call_macro(self.macro)
info('Timer stopped... {}'.format(self.macro['name']))
return
def start_timer(name, seconds, macro):
global _MACROS
_MACROS[name] = threading.Event()
thread = TimerThread(_MACROS[name], seconds, macro)
thread.start()
return
def stop_timer(name):
global _MACROS
_MACROS[name].set()
del _MACROS[name]
return
2020-09-11 21:54:38 -05:00
def install_locales(path, domain='base', dir_locales=DIR['locales']):
path_locales = _P.join(_P(path).path, dir_locales)
try:
lang = gettext.translation(domain, path_locales, languages=[LANG])
lang.install()
_ = lang.gettext
except Exception as e:
from gettext import gettext as _
error(e)
return _
def _export_image(obj, args):
name = 'com.sun.star.drawing.GraphicExportFilter'
exporter = create_instance(name)
path = _P.to_system(args['URL'])
args = dict_to_property(args)
exporter.setSourceDocument(obj)
exporter.filter(args)
return _P.exists(path)
2020-08-16 22:04:40 -05:00
class LOBaseObject(object):
def __init__(self, obj):
self._obj = obj
def __setattr__(self, name, value):
exists = hasattr(self, name)
if not exists and name != '_obj':
setattr(self._obj, name, value)
else:
super().__setattr__(name, value)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
@property
def obj(self):
return self._obj
2020-09-11 21:54:38 -05:00
class LOImage(object):
TYPE = {
'png': 'image/png',
'jpg': 'image/jpeg',
}
def __init__(self, obj):
self._obj = obj
@property
def obj(self):
return self._obj
@property
def name(self):
return self.obj.Name or 'img'
@property
def mimetype(self):
return self.obj.Bitmap.MimeType
def save(self, path, mimetype=MIMETYPE):
p = _P(path)
if _P.is_dir(path):
name = self.name
else:
path = p.path
name = p.name
path = _P.join(path, f'{name}.{mimetype.lower()}')
args = dict(
URL = _P.to_url(path),
MimeType = self.TYPE[mimetype],
)
if not _export_image(self.obj, args):
path = ''
# ~ size = len(self.obj.Bitmap.DIB)
# ~ data = self.obj.GraphicStream.readBytes((), size)
# ~ data = data[-1].value
# ~ data = self.obj.Bitmap.DIB.value
# ~ data = self.obj.Graphic.DIB.value
# ~ _P.save_bin(path, data)
return path
2020-08-16 22:04:40 -05:00
class LODocument(object):
def __init__(self, obj):
self._obj = obj
self._cc = self.obj.getCurrentController()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
@property
def obj(self):
return self._obj
@property
def title(self):
return self.obj.getTitle()
@title.setter
def title(self, value):
self.obj.setTitle(value)
@property
def type(self):
return self._type
@property
def uid(self):
return self.obj.RuntimeUID
@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.URL)
@property
def status_bar(self):
return self._cc.getStatusIndicator()
@property
def visible(self):
w = self.frame.ContainerWindow
return w.isVisible()
@visible.setter
def visible(self, value):
w = self.frame.ContainerWindow
w.setVisible(value)
@property
def zoom(self):
return self._cc.ZoomValue
@zoom.setter
def zoom(self, value):
self._cc.ZoomValue = value
@property
def selection(self):
sel = self.obj.CurrentSelection
2020-09-11 21:54:38 -05:00
return _get_class_uno(sel)
2020-08-16 22:04:40 -05:00
def create_instance(self, name):
obj = self.obj.createInstance(name)
return obj
2020-08-23 12:43:04 -05:00
def set_focus(self):
2020-08-16 22:04:40 -05:00
w = self.frame.ComponentWindow
w.setFocus()
return
def copy(self):
call_dispatch(self.frame, '.uno:Copy')
return
def paste(self):
sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
transferable = sc.getContents()
self._cc.insertTransferable(transferable)
return
def to_pdf(self, path: str='', args: dict={}):
path_pdf = path
if path:
if is_dir(path):
_, _, n, _ = get_info_path(self.path)
path_pdf = join(path, '{}.{}'.format(n, EXT['pdf']))
else:
path_pdf = replace_ext(self.path, EXT['pdf'])
filter_name = '{}_pdf_Export'.format(self.type)
filter_data = dict_to_property(args, True)
args = {
'FilterName': filter_name,
'FilterData': filter_data,
}
opt = dict_to_property(args)
try:
self.obj.storeToURL(_path_url(path_pdf), opt)
except Exception as e:
error(e)
path_pdf = ''
return path_pdf
def save(self, path: str='', args: dict={}) -> bool:
result = True
opt = dict_to_property(args)
if path:
try:
self.obj.storeAsURL(_path_url(path), opt)
except Exception as e:
error(e)
result = False
else:
self.obj.store()
return result
def close(self):
self.obj.close(True)
return
class LOCalc(LODocument):
def __init__(self, obj):
super().__init__(obj)
self._type = CALC
self._sheets = obj.Sheets
def __getitem__(self, index):
return LOCalcSheet(self._sheets[index])
def __len__(self):
return self._sheets.Count
@property
def selection(self):
sel = self.obj.CurrentSelection
if sel.ImplementationName in TYPE_RANGES:
sel = LOCalcRange(sel)
return sel
@property
def active(self):
return LOCalcSheet(self._cc.ActiveSheet)
@property
def db_ranges(self):
# ~ return LOCalcDataBaseRanges(self.obj.DataBaseRanges)
return self.obj.DatabaseRanges
class LOChart(object):
def __init__(self, name, obj, draw_page):
self._name = name
self._obj = obj
self._eobj = self._obj.EmbeddedObject
self._type = 'Column'
self._cell = None
self._shape = self._get_shape(draw_page)
self._pos = self._shape.Position
def __getitem__(self, index):
return LOBaseObject(self.diagram.getDataRowProperties(index))
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
@property
def obj(self):
return self._obj
@property
def name(self):
return self._name
@property
def diagram(self):
return self._eobj.Diagram
@property
def type(self):
return self._type
@type.setter
def type(self, value):
self._type = value
if value == 'Bar':
self.diagram.Vertical = True
return
type_chart = f'com.sun.star.chart.{value}Diagram'
self._eobj.setDiagram(self._eobj.createInstance(type_chart))
@property
def cell(self):
return self._cell
@cell.setter
def cell(self, value):
self._cell = value
self._shape.Anchor = value.obj
@property
def position(self):
return self._pos
@position.setter
def position(self, value):
self._pos = value
self._shape.Position = value
def _get_shape(self, draw_page):
for shape in draw_page:
if shape.PersistName == self.name:
break
return shape
class LOSheetCharts(object):
def __init__(self, obj, sheet):
self._obj = obj
self._sheet = sheet
def __getitem__(self, index):
return LOChart(index, self.obj[index], self._sheet.draw_page)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
def __contains__(self, item):
return item in self.obj
def __len__(self):
return len(self.obj)
@property
def obj(self):
return self._obj
def new(self, name, pos_size, data):
self.obj.addNewByName(name, pos_size, data, True, True)
return LOChart(name, self.obj[name], self._sheet.draw_page)
2020-08-23 12:43:04 -05:00
class LOFormControl(LOBaseObject):
def __init__(self, obj):
self._obj = obj
self._control = self.doc.CurrentController.getControl(self.obj)
def __setattr__(self, name, value):
if name == '_control':
self.__dict__[name] = value
else:
super().__setattr__(name, value)
@property
def doc(self):
return self.obj.Parent.Parent.Parent
@property
def name(self):
return self.obj.Name
@property
def label(self):
return self.obj.Label
def set_focus(self):
self._control.setFocus()
return
class LOForm(object):
def __init__(self, obj):
self._obj = obj
def __getitem__(self, index):
return LOFormControl(self.obj[index])
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
def __contains__(self, item):
return item in self.obj
def __len__(self):
return len(self.obj)
@property
def obj(self):
return self._obj
class LOSheetForms(object):
def __init__(self, obj):
self._obj = obj
def __getitem__(self, index):
return LOForm(self.obj[index])
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
def __contains__(self, item):
return item in self.obj
def __len__(self):
return len(self.obj)
@property
def obj(self):
return self._obj
2020-08-16 22:04:40 -05:00
class LOCalcSheet(object):
def __init__(self, obj):
self._obj = obj
def __getitem__(self, index):
return LOCalcRange(self.obj[index])
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
@property
def obj(self):
return self._obj
@property
def name(self):
return self._obj.Name
@name.setter
def name(self, value):
self._obj.Name = value
@property
def draw_page(self):
return self.obj.DrawPage
@property
def doc(self):
return self.draw_page.Forms.Parent
@property
def charts(self):
return LOSheetCharts(self.obj.Charts, self)
2020-08-23 12:43:04 -05:00
@property
def forms(self):
return LOSheetForms(self.obj.DrawPage.Forms)
2020-08-16 22:04:40 -05:00
def get_cursor(self, cell):
return self.obj.createCursorByRange(cell)
class LOCalcRange(object):
def __init__(self, obj):
self._obj = obj
def __getitem__(self, index):
return LOCalcRange(self.obj[index])
def __iter__(self):
self._r = 0
self._c = 0
return self
def __next__(self):
try:
rango = self[self._r, self._c]
except Exception as e:
raise StopIteration
self._c += 1
if self._c == self.columns:
self._c = 0
self._r +=1
return rango
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
@property
def obj(self):
return self._obj
@property
def sheet(self):
return LOCalcSheet(self.obj.Spreadsheet)
@property
def doc(self):
doc = self.obj.Spreadsheet.DrawPage.Forms.Parent
return doc
@property
def name(self):
return self.obj.AbsoluteName
@property
def columns(self):
return self.obj.Columns.Count
@property
def rows(self):
return self.obj.Rows.Count
@property
def type(self):
return self.obj.Type
@property
def value(self):
v = None
if self.type == VALUE:
v = self.obj.getValue()
elif self.type == TEXT:
v = self.obj.getString()
elif self.type == FORMULA:
v = self.obj.getFormula()
return v
@value.setter
def value(self, data):
if isinstance(data, str):
2020-09-11 21:54:38 -05:00
print(isinstance(data, str), data[0])
if data[0] in '=+-':
2020-08-16 22:04:40 -05:00
self.obj.setFormula(data)
2020-09-11 21:54:38 -05:00
print('Set Formula')
2020-08-16 22:04:40 -05:00
else:
self.obj.setString(data)
elif isinstance(data, (int, float, bool)):
self.obj.setValue(data)
elif isinstance(data, datetime.datetime):
d = data.toordinal()
t = (data - datetime.datetime.fromordinal(d)).seconds / SECONDS_DAY
self.obj.setValue(d - DATE_OFFSET + t)
elif isinstance(data, datetime.date):
d = data.toordinal()
self.obj.setValue(d - DATE_OFFSET)
elif isinstance(data, datetime.time):
d = (data.hour * 3600 + data.minute * 60 + data.second) / SECONDS_DAY
self.obj.setValue(d)
@property
def data(self):
return self.obj.getDataArray()
@data.setter
def data(self, values):
self.obj.setDataArray(values)
@property
def formula(self):
return self.obj.getFormulaArray()
@formula.setter
def formula(self, values):
self.obj.setFormulaArray(values)
@property
def address(self):
return self.obj.CellAddress
@property
def range_address(self):
return self.obj.RangeAddress
@property
def cursor(self):
cursor = self.obj.Spreadsheet.createCursorByRange(self.obj)
return cursor
@property
def current_region(self):
cursor = self.cursor
cursor.collapseToCurrentRegion()
return LOCalcRange(self.sheet[cursor.AbsoluteName].obj)
@property
def next_cell(self):
a = self.current_region.range_address
col = a.StartColumn
row = a.EndRow + 1
return LOCalcRange(self.sheet[row, col].obj)
@property
def position(self):
return self.obj.Position
def select(self):
self.doc.CurrentController.select(self.obj)
return
def to_size(self, rows, cols):
cursor = self.cursor
cursor.collapseToSize(cols, rows)
return LOCalcRange(self.sheet[cursor.AbsoluteName].obj)
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 auto_width(self):
self.obj.Columns.OptimalWidth = True
return
def filter(self, args, with_headers=True):
ff = TableFilterField()
ff.Field = args['Field']
ff.Operator = args['Operator']
if isinstance(args['Value'], str):
ff.IsNumeric = False
ff.StringValue = args['Value']
else:
ff.IsNumeric = True
ff.NumericValue = args['Value']
fd = self.obj.createFilterDescriptor(True)
fd.ContainsHeader = with_headers
fd.FilterFields = ((ff,))
# ~ self.obj.AutoFilter = True
self.obj.filter(fd)
return
class LOWriter(LODocument):
def __init__(self, obj):
super().__init__(obj)
self._type = WRITER
class LODrawImpress(LODocument):
def __init__(self, obj):
super().__init__(obj)
2020-09-11 21:54:38 -05:00
@property
def selection(self):
sel = self.obj.CurrentSelection[0]
return _get_class_uno(sel)
def paste(self):
call_dispatch(self.frame, '.uno:Paste')
return self.selection
2020-08-16 22:04:40 -05:00
class LODraw(LODrawImpress):
def __init__(self, obj):
super().__init__(obj)
self._type = DRAW
class LOImpress(LODrawImpress):
def __init__(self, obj):
super().__init__(obj)
self._type = IMPRESS
2020-08-23 12:43:04 -05:00
class BaseDateField(DateField):
2020-08-16 22:04:40 -05:00
2020-08-23 12:43:04 -05:00
def db_value(self, value):
return _date_to_struct(value)
def python_value(self, value):
return _struct_to_date(value)
class BaseTimeField(TimeField):
def db_value(self, value):
return _date_to_struct(value)
def python_value(self, value):
return _struct_to_date(value)
class BaseDateTimeField(DateTimeField):
def db_value(self, value):
return _date_to_struct(value)
def python_value(self, value):
return _struct_to_date(value)
class FirebirdDatabase(Database):
field_types = {'BOOL': 'BOOLEAN', 'DATETIME': 'TIMESTAMP'}
def __init__(self, database, **kwargs):
super().__init__(database, **kwargs)
self._db = database
def _connect(self):
return self._db
def create_tables(self, models, **options):
options['safe'] = False
tables = self._db.tables
models = [m for m in models if not m.__name__.lower() in tables]
super().create_tables(models, **options)
def execute_sql(self, sql, params=None, commit=True):
with __exception_wrapper__:
cursor = self._db.execute(sql, params)
return cursor
def last_insert_id(self, cursor, query_type=None):
2020-08-23 23:53:37 -05:00
# ~ debug('LAST_ID', cursor)
2020-08-25 12:32:58 -05:00
return 0
2020-08-23 12:43:04 -05:00
2020-08-23 23:53:37 -05:00
def rows_affected(self, cursor):
return self._db.rows_affected
2020-08-23 12:43:04 -05:00
@property
def path(self):
return self._db.path
2020-08-25 12:32:58 -05:00
class BaseRow:
pass
2020-08-23 23:53:37 -05:00
class BaseQuery(object):
PY_TYPES = {
'SQL_LONG': 'getLong',
'SQL_VARYING': 'getString',
'SQL_FLOAT': 'getFloat',
'SQL_BOOLEAN': 'getBoolean',
'SQL_TYPE_DATE': 'getDate',
'SQL_TYPE_TIME': 'getTime',
'SQL_TIMESTAMP': 'getTimestamp',
}
TYPES_DATE = ('SQL_TYPE_DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP')
def __init__(self, query):
self._query = query
self._meta = query.MetaData
self._cols = self._meta.ColumnCount
self._names = query.Columns.ElementNames
self._data = self._get_data()
2020-08-25 12:32:58 -05:00
def __getitem__(self, index):
return self._data[index]
2020-08-23 23:53:37 -05:00
def __iter__(self):
self._index = 0
return self
def __next__(self):
try:
row = self._data[self._index]
except IndexError:
raise StopIteration
self._index += 1
return row
def _to_python(self, index):
type_field = self._meta.getColumnTypeName(index)
value = getattr(self._query, self.PY_TYPES[type_field])(index)
if type_field in self.TYPES_DATE:
value = _struct_to_date(value)
return value
2020-08-25 12:32:58 -05:00
def _get_row(self):
row = BaseRow()
for i in range(1, self._cols + 1):
column_name = self._meta.getColumnName(i)
value = self._to_python(i)
setattr(row, column_name, value)
return row
2020-08-23 23:53:37 -05:00
def _get_data(self):
data = []
while self._query.next():
2020-08-25 12:32:58 -05:00
row = self._get_row()
data.append(row)
2020-08-23 23:53:37 -05:00
return data
@property
def tuples(self):
2020-08-25 12:32:58 -05:00
data = [tuple(r.__dict__.values()) for r in self._data]
return tuple(data)
2020-08-23 23:53:37 -05:00
@property
def dicts(self):
2020-08-25 12:32:58 -05:00
data = [r.__dict__ for r in self._data]
2020-08-23 23:53:37 -05:00
return tuple(data)
2020-08-23 12:43:04 -05:00
class LOBase(object):
2020-08-23 23:53:37 -05:00
DB_TYPES = {
2020-08-23 12:43:04 -05:00
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, obj, args={}):
self._obj = obj
2020-08-16 22:04:40 -05:00
self._type = BASE
2020-08-23 12:43:04 -05:00
self._dbc = create_instance('com.sun.star.sdb.DatabaseContext')
2020-08-23 23:53:37 -05:00
self._rows_affected = 0
2020-09-11 21:54:38 -05:00
path = args.get('path', '')
self._path = _P(path)
self._name = self._path.name
if _P.exists(path):
if not self.is_registered:
self.register()
db = self._dbc.getByName(self.name)
else:
2020-08-23 12:43:04 -05:00
db = self._dbc.createInstance()
db.URL = 'sdbc:embedded:firebird'
2020-09-11 21:54:38 -05:00
db.DatabaseDocument.storeAsURL(self._path.url, ())
2020-08-23 12:43:04 -05:00
self.register()
2020-09-11 21:54:38 -05:00
self._obj = db
2020-08-23 12:43:04 -05:00
self._con = db.getConnection('', '')
2020-08-25 12:32:58 -05:00
def __contains__(self, item):
return item in self.tables
2020-08-23 12:43:04 -05:00
@property
def obj(self):
return self._obj
@property
def name(self):
return self._name
@property
def path(self):
2020-09-11 21:54:38 -05:00
return str(self._path)
2020-08-23 12:43:04 -05:00
@property
def is_registered(self):
return self._dbc.hasRegisteredDatabase(self.name)
@property
def tables(self):
tables = [t.Name.lower() for t in self._con.getTables()]
return tables
2020-08-23 23:53:37 -05:00
@property
def rows_affected(self):
return self._rows_affected
2020-08-23 12:43:04 -05:00
def register(self):
if not self.is_registered:
2020-09-11 21:54:38 -05:00
self._dbc.registerDatabaseLocation(self.name, self._path.url)
2020-08-23 12:43:04 -05:00
return
def revoke(self, name):
self._dbc.revokeDatabaseLocation(name)
return True
def save(self):
self.obj.DatabaseDocument.store()
self.refresh()
return
def close(self):
self._con.close()
return
def refresh(self):
self._con.getTables().refresh()
return
def initialize(self, database_proxy, tables):
db = FirebirdDatabase(self)
database_proxy.initialize(db)
db.create_tables(tables)
return
2020-08-23 23:53:37 -05:00
def _validate_sql(self, sql, params):
2020-08-25 12:32:58 -05:00
limit = ' LIMIT '
2020-08-23 23:53:37 -05:00
for p in params:
2020-08-25 12:32:58 -05:00
sql = sql.replace('?', f"'{p}'", 1)
if limit in sql:
sql = sql.split(limit)[0]
sql = sql.replace('SELECT', f'SELECT FIRST {params[-1]}')
2020-08-23 23:53:37 -05:00
return sql
2020-08-23 12:43:04 -05:00
def cursor(self, sql, params):
2020-08-23 23:53:37 -05:00
if sql.startswith('SELECT'):
sql = self._validate_sql(sql, params)
cursor = self._con.prepareStatement(sql)
return cursor
if not params:
cursor = self._con.createStatement()
return cursor
2020-08-23 12:43:04 -05:00
cursor = self._con.prepareStatement(sql)
for i, v in enumerate(params, 1):
t = type(v)
2020-08-23 23:53:37 -05:00
if not t in self.DB_TYPES:
2020-08-23 12:43:04 -05:00
error('Type not support')
2020-08-23 23:53:37 -05:00
debug((i, t, v, self.DB_TYPES[t]))
getattr(cursor, self.DB_TYPES[t])(i, v)
2020-08-23 12:43:04 -05:00
return cursor
def execute(self, sql, params):
debug(sql, params)
2020-08-23 23:53:37 -05:00
cursor = self.cursor(sql, params)
if sql.startswith('SELECT'):
result = cursor.executeQuery()
elif params:
result = cursor.executeUpdate()
self._rows_affected = result
self.save()
2020-08-23 12:43:04 -05:00
else:
2020-08-23 23:53:37 -05:00
result = cursor.execute(sql)
self.save()
return result
def select(self, sql):
debug('SELECT', sql)
if not sql.startswith('SELECT'):
return ()
cursor = self._con.prepareStatement(sql)
query = cursor.executeQuery()
return BaseQuery(query)
def get_query(self, query):
sql, args = query.sql()
sql = self._validate_sql(sql, args)
return self.select(sql)
2020-08-16 22:04:40 -05:00
class LOMath(LODocument):
def __init__(self, obj):
super().__init__(obj)
self._type = MATH
class LOBasic(LODocument):
def __init__(self, obj):
super().__init__(obj)
self._type = BASIC
class LODocs(object):
2020-08-23 12:43:04 -05:00
_desktop = None
2020-08-16 22:04:40 -05:00
def __init__(self):
2020-08-23 12:43:04 -05:00
self._desktop = get_desktop()
LODocs._desktop = self._desktop
2020-08-16 22:04:40 -05:00
def __getitem__(self, index):
2020-09-11 21:54:38 -05:00
doc = None
2020-08-23 12:43:04 -05:00
for i, doc in enumerate(self._desktop.Components):
2020-08-16 22:04:40 -05:00
if isinstance(index, int) and i == index:
2020-09-11 21:54:38 -05:00
doc = _get_class_doc(doc)
break
2020-08-16 22:04:40 -05:00
elif isinstance(index, str) and doc.Title == index:
2020-09-11 21:54:38 -05:00
doc = _get_class_doc(doc)
break
return doc
2020-08-16 22:04:40 -05:00
def __contains__(self, item):
doc = self[item]
return not doc is None
def __iter__(self):
self._i = 0
return self
def __next__(self):
doc = self[self._i]
if doc is None:
raise StopIteration
self._i += 1
return doc
def __len__(self):
2020-08-23 12:43:04 -05:00
for i, _ in enumerate(self._desktop.Components):
2020-08-16 22:04:40 -05:00
pass
return i + 1
@property
def active(self):
2020-08-23 12:43:04 -05:00
return _get_class_doc(self._desktop.getCurrentComponent())
2020-08-16 22:04:40 -05:00
@classmethod
def new(cls, type_doc=CALC, args={}):
2020-08-23 12:43:04 -05:00
if type_doc == BASE:
return LOBase(None, args)
2020-08-16 22:04:40 -05:00
path = f'private:factory/s{type_doc}'
opt = dict_to_property(args)
2020-08-23 12:43:04 -05:00
doc = cls._desktop.loadComponentFromURL(path, '_default', 0, opt)
2020-08-16 22:04:40 -05:00
return _get_class_doc(doc)
@classmethod
def open(cls, path, args={}):
""" 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 = dict_to_property(args)
2020-08-23 12:43:04 -05:00
doc = cls._desktop.loadComponentFromURL(path, '_default', 0, opt)
2020-08-16 22:04:40 -05:00
if doc is None:
return
return _get_class_doc(doc)
2020-08-23 12:43:04 -05:00
def connect(self, path):
2020-09-11 21:54:38 -05:00
return LOBase(None, {'path': path})
2020-08-23 12:43:04 -05:00
2020-08-16 22:04:40 -05:00
def _add_listeners(events, control, name=''):
listeners = {
'addActionListener': EventsButton,
'addMouseListener': EventsMouse,
2020-09-11 21:54:38 -05:00
'addFocusListener': EventsFocus,
2020-08-16 22:04:40 -05:00
# ~ 'addItemListener': EventsItem,
# ~ 'addKeyListener': EventsKey,
# ~ 'addTabListener': EventsTab,
}
if hasattr(control, 'obj'):
control = control.obj
# ~ debug(control.ImplementationName)
is_grid = control.ImplementationName == 'stardiv.Toolkit.GridControl'
is_link = control.ImplementationName == 'stardiv.Toolkit.UnoFixedHyperlinkControl'
is_roadmap = control.ImplementationName == 'stardiv.Toolkit.UnoRoadmapControl'
for key, value in listeners.items():
if hasattr(control, key):
if is_grid and key == 'addMouseListener':
control.addMouseListener(EventsMouseGrid(events, name))
continue
if is_link and key == 'addMouseListener':
control.addMouseListener(EventsMouseLink(events, name))
continue
if is_roadmap and key == 'addItemListener':
control.addItemListener(EventsItemRoadmap(events, name))
continue
getattr(control, key)(listeners[key](events, name))
# ~ if is_grid:
# ~ controllers = EventsGrid(events, name)
# ~ control.addSelectionListener(controllers)
# ~ control.Model.GridDataModel.addGridDataListener(controllers)
return
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
class EventsListenerBase(unohelper.Base, XEventListener):
def __init__(self, controller, name, window=None):
self._controller = controller
self._name = name
self._window = window
@property
def name(self):
return self._name
def disposing(self, event):
self._controller = None
if not self._window is None:
self._window.setMenuBar(None)
class EventsMouse(EventsListenerBase, XMouseListener, XMouseMotionListener):
def __init__(self, controller, name):
super().__init__(controller, name)
def mousePressed(self, event):
event_name = '{}_click'.format(self._name)
if event.ClickCount == 2:
event_name = '{}_double_click'.format(self._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
# ~ XMouseMotionListener
def mouseMoved(self, event):
pass
def mouseDragged(self, event):
pass
class EventsMouseLink(EventsMouse):
def __init__(self, controller, name):
super().__init__(controller, name)
self._text_color = 0
def mouseEntered(self, event):
model = event.Source.Model
self._text_color = model.TextColor or 0
model.TextColor = get_color('blue')
return
def mouseExited(self, event):
model = event.Source.Model
model.TextColor = self._text_color
return
class EventsButton(EventsListenerBase, XActionListener):
def __init__(self, controller, name):
super().__init__(controller, name)
def actionPerformed(self, event):
event_name = f'{self.name}_action'
if hasattr(self._controller, event_name):
getattr(self._controller, event_name)(event)
return
2020-09-11 21:54:38 -05:00
class EventsFocus(EventsListenerBase, XFocusListener):
CONTROLS = (
'stardiv.Toolkit.UnoControlEditModel',
)
def __init__(self, controller, name):
super().__init__(controller, name)
def focusGained(self, event):
service = event.Source.Model.ImplementationName
# ~ print('Focus enter', service)
if service in self.CONTROLS:
obj = event.Source.Model
obj.BackgroundColor = COLOR_ON_FOCUS
return
def focusLost(self, event):
service = event.Source.Model.ImplementationName
if service in self.CONTROLS:
obj = event.Source.Model
obj.BackgroundColor = -1
return
2020-08-16 22:04:40 -05:00
# ~ BorderColor = ?
# ~ FontStyleName = ?
# ~ HelpURL = ?
class UnoBaseObject(object):
def __init__(self, obj):
self._obj = obj
self._model = obj.Model
def __setattr__(self, name, value):
exists = hasattr(self, name)
if not exists and not name in ('_obj', '_model'):
setattr(self._model, name, value)
else:
super().__setattr__(name, value)
@property
def obj(self):
return self._obj
@property
def model(self):
return self._model
@property
def m(self):
return self._model
@property
def properties(self):
return {}
@properties.setter
def properties(self, values):
_set_properties(self.model, values)
@property
def name(self):
return self.model.Name
@property
def parent(self):
return self.obj.Context
@property
def tag(self):
return self.model.Tag
@tag.setter
def tag(self, value):
self.model.Tag = value
@property
def visible(self):
return self.obj.Visible
@visible.setter
def visible(self, value):
self.obj.setVisible(value)
@property
def enabled(self):
return self.model.Enabled
@enabled.setter
def enabled(self, value):
self.model.Enabled = value
@property
def step(self):
return self.model.Step
@step.setter
def step(self, value):
self.model.Step = value
@property
def align(self):
return self.model.Align
@align.setter
def align(self, value):
self.model.Align = value
@property
def valign(self):
return self.model.VerticalAlign
@valign.setter
def valign(self, value):
self.model.VerticalAlign = value
@property
def font_weight(self):
return self.model.FontWeight
@font_weight.setter
def font_weight(self, value):
self.model.FontWeight = value
@property
def font_height(self):
return self.model.FontHeight
@font_height.setter
def font_height(self, value):
self.model.FontHeight = value
@property
def font_name(self):
return self.model.FontName
@font_name.setter
def font_name(self, value):
self.model.FontName = value
@property
def font_underline(self):
return self.model.FontUnderline
@font_underline.setter
def font_underline(self, value):
self.model.FontUnderline = value
@property
def text_color(self):
return self.model.TextColor
@text_color.setter
def text_color(self, value):
self.model.TextColor = value
@property
def back_color(self):
return self.model.BackgroundColor
@back_color.setter
def back_color(self, value):
self.model.BackgroundColor = value
@property
def multi_line(self):
return self.model.MultiLine
@multi_line.setter
def multi_line(self, value):
self.model.MultiLine = value
@property
def help_text(self):
return self.model.HelpText
@help_text.setter
def help_text(self, value):
self.model.HelpText = value
@property
def border(self):
return self.model.Border
@border.setter
def border(self, value):
# ~ Bug for report
self.model.Border = 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
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):
if hasattr(self.model, 'PositionX'):
return self.model.PositionX
return self._get_possize('X')
@x.setter
def x(self, value):
if hasattr(self.model, 'PositionX'):
self.model.PositionX = value
else:
self._set_possize('X', value)
@property
def y(self):
if hasattr(self.model, 'PositionY'):
return self.model.PositionY
return self._get_possize('Y')
@y.setter
def y(self, value):
if hasattr(self.model, 'PositionY'):
self.model.PositionY = value
else:
self._set_possize('Y', value)
@property
def tab_index(self):
return self._model.TabIndex
@tab_index.setter
def tab_index(self, value):
self.model.TabIndex = value
@property
def tab_stop(self):
return self._model.Tabstop
@tab_stop.setter
def tab_stop(self, value):
self.model.Tabstop = value
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, center=False):
if x:
self.x = origin.x + origin.width + x
else:
self.x = origin.x
if y:
self.y = origin.y + origin.height + y
else:
self.y = origin.y
if center:
self.center()
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 UnoLabelLink(UnoLabel):
def __init__(self, obj):
super().__init__(obj)
@property
def type(self):
return 'link'
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 UnoRadio(UnoBaseObject):
def __init__(self, obj):
super().__init__(obj)
@property
def type(self):
return 'radio'
@property
def value(self):
return self.model.Label
@value.setter
def value(self, value):
self.model.Label = value
class UnoCheck(UnoBaseObject):
def __init__(self, obj):
super().__init__(obj)
@property
def type(self):
return 'check'
@property
def value(self):
return self.model.State
@value.setter
def value(self, value):
self.model.State = value
@property
def label(self):
return self.model.Label
@label.setter
def label(self, value):
self.model.Label = value
@property
def tri_state(self):
return self.model.TriState
@tri_state.setter
def tri_state(self, value):
self.model.TriState = value
2020-09-11 21:54:38 -05:00
# ~ https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1awt_1_1UnoControlEditModel.html
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
2020-08-16 22:04:40 -05:00
UNO_CLASSES = {
'label': UnoLabel,
'link': UnoLabelLink,
'button': UnoButton,
'radio': UnoRadio,
'check': UnoCheck,
2020-09-11 21:54:38 -05:00
'text': UnoText,
2020-08-16 22:04:40 -05:00
}
class LODialog(object):
MODELS = {
'label': 'com.sun.star.awt.UnoControlFixedTextModel',
'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
'button': 'com.sun.star.awt.UnoControlButtonModel',
'radio': 'com.sun.star.awt.UnoControlRadioButtonModel',
'check': 'com.sun.star.awt.UnoControlCheckBoxModel',
2020-09-11 21:54:38 -05:00
'text': 'com.sun.star.awt.UnoControlEditModel',
# ~ 'grid': 'com.sun.star.awt.grid.UnoControlGridModel',
2020-08-16 22:04:40 -05:00
# ~ 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel',
# ~ 'listbox': 'com.sun.star.awt.UnoControlListBoxModel',
# ~ 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel',
# ~ 'tree': 'com.sun.star.awt.tree.TreeControlModel',
# ~ 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel',
# ~ 'image': 'com.sun.star.awt.UnoControlImageControlModel',
# ~ 'pages': 'com.sun.star.awt.UnoMultiPageModel',
}
def __init__(self, args):
self._obj = self._create(args)
self._model = self.obj.Model
self._events = None
self._modal = True
self._controls = {}
2020-09-11 21:54:38 -05:00
self._color_on_focus = COLOR_ON_FOCUS
2020-08-16 22:04:40 -05:00
def _create(self, args):
service = 'com.sun.star.awt.DialogProvider'
path = args.pop('Path', '')
if path:
dp = create_instance(service, True)
dlg = dp.createDialog(_path_url(path))
return dlg
if 'Location' in args:
name = args['Name']
library = args.get('Library', 'Standard')
location = args.get('Location', 'application')
if location == 'user':
location = 'application'
url = f'vnd.sun.star.script:{library}.{name}?location={location}'
if location == 'document':
dp = create_instance(service, args=docs.active.obj)
else:
dp = create_instance(service, True)
# ~ uid = docs.active.uid
# ~ url = f'vnd.sun.star.tdoc:/{uid}/Dialogs/{library}/{name}.xml'
dlg = dp.createDialog(url)
return dlg
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, args)
dlg.setModel(model)
dlg.setVisible(False)
dlg.createPeer(toolkit, None)
return dlg
@property
def obj(self):
return self._obj
@property
def model(self):
return self._model
@property
def controls(self):
return self._controls
@property
def visible(self):
return self.obj.Visible
@visible.setter
def visible(self, value):
self.obj.Visible = value
@property
def events(self):
return self._events
@events.setter
def events(self, controllers):
self._events = controllers(self)
self._connect_listeners()
2020-09-11 21:54:38 -05:00
@property
def color_on_focus(self):
return self._color_on_focus
@color_on_focus.setter
def color_on_focus(self, value):
self._color_on_focus = get_color(value)
2020-08-16 22:04:40 -05:00
def _connect_listeners(self):
for control in self.obj.Controls:
_add_listeners(self.events, control, control.Model.Name)
return
def _special_properties(self, tipo, args):
columns = args.pop('Columns', ())
if tipo == 'link' and not 'Label' in args:
args['Label'] = args['URL']
elif tipo == 'grid':
args['ColumnModel'] = self._set_column_model(columns)
elif tipo == 'button':
if 'ImageURL' in args:
args['ImageURL'] = self._set_image_url(args['ImageURL'])
if not 'FocusOnClick' in args:
args['FocusOnClick'] = False
elif tipo == 'roadmap':
if not 'Height' in args:
args['Height'] = self.height
if 'Title' in args:
args['Text'] = args.pop('Title')
elif tipo == 'tab':
if not 'Width' in args:
args['Width'] = self.width
if not 'Height' in args:
args['Height'] = self.height
return args
def add_control(self, args):
tipo = args.pop('Type').lower()
root = args.pop('Root', '')
sheets = args.pop('Sheets', ())
args = self._special_properties(tipo, args)
model = self.model.createInstance(self.MODELS[tipo])
_set_properties(model, args)
name = args['Name']
self.model.insertByName(name, model)
control = self.obj.getControl(name)
_add_listeners(self.events, control, name)
control = UNO_CLASSES[tipo](control)
if tipo == 'tree' and root:
control.root = root
elif tipo == 'pages' and sheets:
control.sheets = sheets
control.events = self.events
setattr(self, name, control)
self._controls[name] = control
return control
def open(self, modal=True):
self._modal = modal
if modal:
return self.obj.execute()
else:
self.visible = True
return
def close(self, value=0):
if self._modal:
value = self.obj.endDialog(value)
else:
self.visible = False
self.obj.dispose()
return value
class LOSheets(object):
def __getitem__(self, index):
2020-08-25 22:41:45 -05:00
return LODocs().active[index]
2020-08-16 22:04:40 -05:00
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
class LOCells(object):
def __getitem__(self, index):
2020-08-25 22:41:45 -05:00
return LODocs().active.active[index]
2020-08-16 22:04:40 -05:00
2020-09-11 21:54:38 -05:00
class LOShortCut(object):
# ~ getKeyEventsByCommand
def __init__(self, app):
self._app = app
self._scm = None
self._init_values()
def _init_values(self):
name = 'com.sun.star.ui.GlobalAcceleratorConfiguration'
instance = 'com.sun.star.ui.ModuleUIConfigurationManagerSupplier'
service = TYPE_DOC[self._app]
manager = create_instance(instance, True)
uicm = manager.getUIConfigurationManager(service)
self._scm = uicm.ShortCutManager
return
def __contains__(self, item):
cmd = self._get_command(item)
return bool(cmd)
def _get_key_event(self, command):
events = self._scm.AllKeyEvents
for event in events:
cmd = self._scm.getCommandByKeyEvent(event)
if cmd == command:
break
return event
def _to_key_event(self, shortcut):
key_event = KeyEvent()
keys = shortcut.split('+')
for v in keys[:-1]:
key_event.Modifiers += MODIFIERS[v.lower()]
key_event.KeyCode = getattr(Key, keys[-1].upper())
return key_event
def _get_command(self, shortcut):
command = ''
key_event = self._to_key_event(shortcut)
try:
command = self._scm.getCommandByKeyEvent(key_event)
except NoSuchElementException:
debug(f'No exists: {shortcut}')
return command
def add(self, shortcut, command):
if isinstance(command, dict):
command = _get_url_script(command)
key_event = self._to_key_event(shortcut)
self._scm.setKeyEvent(key_event, command)
self._scm.store()
return
def reset(self):
self._scm.reset()
self._scm.store()
return
def remove(self, shortcut):
key_event = self._to_key_event(shortcut)
try:
self._scm.removeKeyEvent(key_event)
self._scm.store()
except NoSuchElementException:
debug(f'No exists: {shortcut}')
return
def remove_by_command(self, command):
if isinstance(command, dict):
command = _get_url_script(command)
try:
self._scm.removeCommandFromAllKeyEvents(command)
self._scm.store()
except NoSuchElementException:
debug(f'No exists: {command}')
return
class LOShortCuts(object):
def __getitem__(self, index):
return LOShortCut(index)
class LOMenu(object):
def __init__(self, app):
self._app = app
self._ui = None
self._pymenus = None
self._menu = None
self._menus = self._get_menus()
def __getitem__(self, index):
if isinstance(index, int):
self._menu = self._menus[index]
else:
for menu in self._menus:
cmd = menu.get('CommandURL', '')
if MENUS[index.lower()] == cmd:
self._menu = menu
break
line = self._menu.get('CommandURL', '')
line += self._get_submenus(self._menu['ItemDescriptorContainer'])
return line
def _get_menus(self):
instance = 'com.sun.star.ui.ModuleUIConfigurationManagerSupplier'
service = TYPE_DOC[self._app]
manager = create_instance(instance, True)
self._ui = manager.getUIConfigurationManager(service)
self._pymenus = self._ui.getSettings(NODE_MENUBAR, True)
data = []
for menu in self._pymenus:
data.append(data_to_dict(menu))
return data
def _get_info(self, menu):
line = menu.get('CommandURL', '')
line += self._get_submenus(menu['ItemDescriptorContainer'])
return line
def _get_submenus(self, menu, level=1):
line = ''
for i, v in enumerate(menu):
data = data_to_dict(v)
cmd = data.get('CommandURL', '----------')
line += f'\n{" " * level}ā”œā”€ ({i}) {cmd}'
submenu = data.get('ItemDescriptorContainer', None)
if not submenu is None:
line += self._get_submenus(submenu, level + 1)
return line
def __str__(self):
info = '\n'.join([self._get_info(m) for m in self._menus])
return info
def _get_index_menu(self, menu, command):
index = -1
for i, v in enumerate(menu):
data = data_to_dict(v)
cmd = data.get('CommandURL', '')
if cmd == command:
index = i
break
return index
def insert(self, name, args):
idc = None
replace = False
command = args['CommandURL']
label = args['Label']
self[name]
menu = self._menu['ItemDescriptorContainer']
submenu = args.get('Submenu', False)
if submenu:
idc = self._ui.createSettings()
index = self._get_index_menu(menu, command)
if index == -1:
if 'Index' in args:
index = args['Index']
else:
index = self._get_index_menu(menu, args['After']) + 1
else:
replace = True
data = dict (
CommandURL = command,
Label = label,
Style = 0,
Type = 0,
ItemDescriptorContainer = idc,
)
self._save(menu, data, index, replace)
self._insert_submenu(idc, submenu)
return
def _get_command(self, args):
shortcut = args.get('ShortCut', '')
cmd = args['CommandURL']
if isinstance(cmd, dict):
cmd = _get_url_script(cmd)
if shortcut:
LOShortCut(self._app).add(shortcut, cmd)
return cmd
def _insert_submenu(self, parent, menus):
for i, v in enumerate(menus):
submenu = v.pop('Submenu', False)
if submenu:
idc = self._ui.createSettings()
v['ItemDescriptorContainer'] = idc
v['Type'] = 0
if v['Label'] == '-':
v['Type'] = 1
else:
v['CommandURL'] = self._get_command(v)
self._save(parent, v, i)
if submenu:
self._insert_submenu(idc, submenu)
return
def remove(self, name, command):
self[name]
menu = self._menu['ItemDescriptorContainer']
index = self._get_index_menu(menu, command)
if index > -1:
uno.invoke(menu, 'removeByIndex', (index,))
self._ui.replaceSettings(NODE_MENUBAR, self._pymenus)
self._ui.store()
return
def _save(self, menu, properties, index, replace=False):
properties = dict_to_property(properties, True)
if replace:
uno.invoke(menu, 'replaceByIndex', (index, properties))
else:
uno.invoke(menu, 'insertByIndex', (index, properties))
self._ui.replaceSettings(NODE_MENUBAR, self._pymenus)
self._ui.store()
return
class LOMenus(object):
def __getitem__(self, index):
return LOMenu(index)
class classproperty:
def __init__(self, method=None):
self.fget = method
def __get__(self, instance, cls=None):
return self.fget(cls)
def getter(self, method):
self.fget = method
return self
2020-08-23 12:43:04 -05:00
class Paths(object):
2020-09-11 21:54:38 -05:00
def __init__(self, path=''):
self._path = Path(path)
@property
def path(self):
return str(self._path.parent)
@property
def file_name(self):
return self._path.name
@property
def name(self):
return self._path.stem
@property
def ext(self):
return self._path.suffix
@property
def url(self):
return self._path.as_uri()
@classproperty
def home(self):
return str(Path.home())
2020-08-23 12:43:04 -05:00
@classmethod
def exists(cls, path):
return Path(path).exists()
2020-09-11 21:54:38 -05:00
@classmethod
def is_dir(cls, path):
return Path(path).is_dir()
@classmethod
def join(cls, *paths):
return str(Path(paths[0]).joinpath(paths[1]))
@classmethod
def save(cls, path, data, encoding='utf-8'):
result = bool(Path(path).write_text(data, encoding=encoding))
return result
@classmethod
def save_bin(cls, path, data):
result = bool(Path(path).write_bytes(data))
return result
@classmethod
def to_url(cls, path):
if not path.startswith('file://'):
path = Path(path).as_uri()
return path
@classmethod
def to_system(cls, path):
if path.startswith('file://'):
path = str(Path(uno.fileUrlToSystemPath(path)).resolve())
return path
_P = Paths
2020-08-23 12:43:04 -05:00
2020-08-16 22:04:40 -05:00
def __getattr__(name):
if name == 'active':
2020-09-11 21:54:38 -05:00
return LODocs().active
2020-08-16 22:04:40 -05:00
if name == 'active_sheet':
2020-09-11 21:54:38 -05:00
return LODocs().active.active
2020-08-16 22:04:40 -05:00
if name == 'selection':
2020-09-11 21:54:38 -05:00
return LODocs().active.selection
2020-08-16 22:04:40 -05:00
if name in ('rectangle', 'pos_size'):
return Rectangle()
2020-08-23 12:43:04 -05:00
if name == 'paths':
2020-09-11 21:54:38 -05:00
return Paths
2020-08-25 12:32:58 -05:00
if name == 'docs':
return LODocs()
2020-08-25 22:41:45 -05:00
if name == 'sheets':
return LOSheets()
if name == 'cells':
return LOCells()
2020-09-11 21:54:38 -05:00
if name == 'menus':
return LOMenus()
if name == 'shortcuts':
return LOShortCuts()
2020-08-16 22:04:40 -05:00
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
def create_dialog(args):
return LODialog(args)
2020-09-11 21:54:38 -05:00
def inputbox(message, default='', title=TITLE, echochar=''):
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
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,
}
if echochar:
args['EchoChar'] = ord(echochar[0])
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 ''
2020-08-16 22:04:40 -05:00
def get_fonts():
toolkit = create_instance('com.sun.star.awt.Toolkit')
device = toolkit.createScreenCompatibleDevice(0, 0)
return device.FontDescriptors
# ~ https://en.wikipedia.org/wiki/Web_colors
def get_color(value):
COLORS = {
'aliceblue': 15792383,
'antiquewhite': 16444375,
'aqua': 65535,
'aquamarine': 8388564,
'azure': 15794175,
'beige': 16119260,
'bisque': 16770244,
'black': 0,
'blanchedalmond': 16772045,
'blue': 255,
'blueviolet': 9055202,
'brown': 10824234,
'burlywood': 14596231,
'cadetblue': 6266528,
'chartreuse': 8388352,
'chocolate': 13789470,
'coral': 16744272,
'cornflowerblue': 6591981,
'cornsilk': 16775388,
'crimson': 14423100,
'cyan': 65535,
'darkblue': 139,
'darkcyan': 35723,
'darkgoldenrod': 12092939,
'darkgray': 11119017,
'darkgreen': 25600,
'darkgrey': 11119017,
'darkkhaki': 12433259,
'darkmagenta': 9109643,
'darkolivegreen': 5597999,
'darkorange': 16747520,
'darkorchid': 10040012,
'darkred': 9109504,
'darksalmon': 15308410,
'darkseagreen': 9419919,
'darkslateblue': 4734347,
'darkslategray': 3100495,
'darkslategrey': 3100495,
'darkturquoise': 52945,
'darkviolet': 9699539,
'deeppink': 16716947,
'deepskyblue': 49151,
'dimgray': 6908265,
'dimgrey': 6908265,
'dodgerblue': 2003199,
'firebrick': 11674146,
'floralwhite': 16775920,
'forestgreen': 2263842,
'fuchsia': 16711935,
'gainsboro': 14474460,
'ghostwhite': 16316671,
'gold': 16766720,
'goldenrod': 14329120,
'gray': 8421504,
'grey': 8421504,
'green': 32768,
'greenyellow': 11403055,
'honeydew': 15794160,
'hotpink': 16738740,
'indianred': 13458524,
'indigo': 4915330,
'ivory': 16777200,
'khaki': 15787660,
'lavender': 15132410,
'lavenderblush': 16773365,
'lawngreen': 8190976,
'lemonchiffon': 16775885,
'lightblue': 11393254,
'lightcoral': 15761536,
'lightcyan': 14745599,
'lightgoldenrodyellow': 16448210,
'lightgray': 13882323,
'lightgreen': 9498256,
'lightgrey': 13882323,
'lightpink': 16758465,
'lightsalmon': 16752762,
'lightseagreen': 2142890,
'lightskyblue': 8900346,
'lightslategray': 7833753,
'lightslategrey': 7833753,
'lightsteelblue': 11584734,
'lightyellow': 16777184,
'lime': 65280,
'limegreen': 3329330,
'linen': 16445670,
'magenta': 16711935,
'maroon': 8388608,
'mediumaquamarine': 6737322,
'mediumblue': 205,
'mediumorchid': 12211667,
'mediumpurple': 9662683,
'mediumseagreen': 3978097,
'mediumslateblue': 8087790,
'mediumspringgreen': 64154,
'mediumturquoise': 4772300,
'mediumvioletred': 13047173,
'midnightblue': 1644912,
'mintcream': 16121850,
'mistyrose': 16770273,
'moccasin': 16770229,
'navajowhite': 16768685,
'navy': 128,
'oldlace': 16643558,
'olive': 8421376,
'olivedrab': 7048739,
'orange': 16753920,
'orangered': 16729344,
'orchid': 14315734,
'palegoldenrod': 15657130,
'palegreen': 10025880,
'paleturquoise': 11529966,
'palevioletred': 14381203,
'papayawhip': 16773077,
'peachpuff': 16767673,
'peru': 13468991,
'pink': 16761035,
'plum': 14524637,
'powderblue': 11591910,
'purple': 8388736,
'red': 16711680,
'rosybrown': 12357519,
'royalblue': 4286945,
'saddlebrown': 9127187,
'salmon': 16416882,
'sandybrown': 16032864,
'seagreen': 3050327,
'seashell': 16774638,
'sienna': 10506797,
'silver': 12632256,
'skyblue': 8900331,
'slateblue': 6970061,
'slategray': 7372944,
'slategrey': 7372944,
'snow': 16775930,
'springgreen': 65407,
'steelblue': 4620980,
'tan': 13808780,
'teal': 32896,
'thistle': 14204888,
'tomato': 16737095,
'turquoise': 4251856,
'violet': 15631086,
'wheat': 16113331,
'white': 16777215,
'whitesmoke': 16119285,
'yellow': 16776960,
'yellowgreen': 10145074,
}
if isinstance(value, tuple):
color = (value[0] << 16) + (value[1] << 8) + value[2]
else:
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
COLOR_ON_FOCUS = get_color('LightYellow')
2020-08-25 12:32:58 -05:00
class LOServer(object):
HOST = 'localhost'
PORT = '8100'
ARG = f'socket,host={HOST},port={PORT};urp;StarOffice.ComponentContext'
CMD = ['soffice',
'-env:SingleAppInstance=false',
'-env:UserInstallation=file:///tmp/LO_Process8100',
'--headless', '--norestore', '--invisible',
f'--accept={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