zaz/source/libo.py

2237 lines
56 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 datetime
import getpass
import logging
import os
import platform
import socket
import subprocess
import sys
import time
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
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
from com.sun.star.util import Time, Date, DateTime
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
# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt_1_1FontUnderline.html
from com.sun.star.awt import FontUnderline
from com.sun.star.style.VerticalAlignment import TOP, MIDDLE, BOTTOM
try:
from peewee import Database, DateTimeField, DateField, TimeField, \
__exception_wrapper__
except ImportError as e:
print('Install peewee')
peewee = None
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__)
LEFT = 0
CENTER = 1
RIGHT = 2
CALC = 'calc'
WRITER = 'writer'
DRAW = 'draw'
IMPRESS = 'impress'
BASE = 'base'
MATH = 'math'
BASIC = 'basic'
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',
'main': 'com.sun.star.frame.StartModule',
}
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
OS = platform.system()
IS_WIN = OS == 'Windows'
IS_MAC = OS == 'Darwin'
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)
SECONDS_DAY = 60 * 60 * 24
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')
INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{INFO_DEBUG}"
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()
def debug(*args):
data = [str(a) for a in args]
log.debug('\t'.join(data))
return
def error(info):
log.error(info)
return
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
def now(only_time=False):
now = datetime.datetime.now()
if only_time:
now = now.time()
return now
def today():
return datetime.date.today()
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')
def errorbox(message, title=TITLE):
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)
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
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
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):
d = None
if isinstance(value, Time):
d = datetime.time(value.Hours, value.Minutes, value.Seconds)
elif isinstance(value, Date):
if value != Date():
d = datetime.date(value.Year, value.Month, value.Day)
elif isinstance(value, DateTime):
if value.Year > 0:
d = datetime.datetime(
value.Year, value.Month, value.Day,
value.Hours, value.Minutes, value.Seconds)
return d
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
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
return sel
def create_instance(self, name):
obj = self.obj.createInstance(name)
return obj
def set_focus(self):
w = self.frame.ComponentWindow
w.setFocus()
return
def copy(self):
call_dispatch(self.frame, '.uno:Copy')
return
# ~ def paste(self):
# ~ call_dispatch(self.frame, '.uno:Paste')
# ~ 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)
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
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)
@property
def forms(self):
return LOSheetForms(self.obj.DrawPage.Forms)
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):
if data[0] == '=':
self.obj.setFormula(data)
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)
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
class BaseDateField(DateField):
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):
# ~ debug('LAST_ID', cursor)
return 0
def rows_affected(self, cursor):
return self._db.rows_affected
@property
def path(self):
return self._db.path
class BaseRow:
pass
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()
def __getitem__(self, index):
return self._data[index]
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
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
def _get_data(self):
data = []
while self._query.next():
row = self._get_row()
data.append(row)
return data
@property
def tuples(self):
data = [tuple(r.__dict__.values()) for r in self._data]
return tuple(data)
@property
def dicts(self):
data = [r.__dict__ for r in self._data]
return tuple(data)
class LOBase(object):
DB_TYPES = {
str: 'setString',
int: 'setInt',
float: 'setFloat',
bool: 'setBoolean',
Date: 'setDate',
Time: 'setTime',
DateTime: 'setTimestamp',
}
# ~ setArray
# ~ setBinaryStream
# ~ setBlob
# ~ setByte
# ~ setBytes
# ~ setCharacterStream
# ~ setClob
# ~ setNull
# ~ setObject
# ~ setObjectNull
# ~ setObjectWithInfo
# ~ setPropertyValue
# ~ setRef
def __init__(self, obj, args={}):
self._obj = obj
self._type = BASE
self._path = args.get('path', '')
self._dbc = create_instance('com.sun.star.sdb.DatabaseContext')
self._rows_affected = 0
if self._path:
self._name = Path(self._path).name
path_url = _path_url(self._path)
db = self._dbc.createInstance()
db.URL = 'sdbc:embedded:firebird'
db.DatabaseDocument.storeAsURL(path_url, ())
self.register()
self._obj = db
else:
self._name = self._obj
if Path(self._name).exists():
self._path = self._name
self._name = Path(self._path).name
if self.is_registered:
db = self._dbc.getByName(self.name)
self._path = _path_system(self._dbc.getDatabaseLocation(self.name))
self._obj = db
else:
path_url = _path_url(self._path)
self._dbc.registerDatabaseLocation(self.name, path_url)
db = self._dbc.getByName(self.name)
self._con = db.getConnection('', '')
def __contains__(self, item):
return item in self.tables
@property
def obj(self):
return self._obj
@property
def name(self):
return self._name
@property
def path(self):
return self._path
@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
@property
def rows_affected(self):
return self._rows_affected
def register(self):
if not self.is_registered:
path_url = _path_url(self._path)
self._dbc.registerDatabaseLocation(self.name, path_url)
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
def _validate_sql(self, sql, params):
limit = ' LIMIT '
for p in params:
sql = sql.replace('?', f"'{p}'", 1)
if limit in sql:
sql = sql.split(limit)[0]
sql = sql.replace('SELECT', f'SELECT FIRST {params[-1]}')
return sql
def cursor(self, sql, params):
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
cursor = self._con.prepareStatement(sql)
for i, v in enumerate(params, 1):
t = type(v)
if not t in self.DB_TYPES:
error('Type not support')
debug((i, t, v, self.DB_TYPES[t]))
getattr(cursor, self.DB_TYPES[t])(i, v)
return cursor
def execute(self, sql, params):
debug(sql, params)
cursor = self.cursor(sql, params)
if sql.startswith('SELECT'):
result = cursor.executeQuery()
elif params:
result = cursor.executeUpdate()
self._rows_affected = result
self.save()
else:
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)
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):
_desktop = None
def __init__(self):
self._desktop = get_desktop()
LODocs._desktop = self._desktop
def __getitem__(self, index):
for i, doc in enumerate(self._desktop.Components):
if isinstance(index, int) and i == index:
return _get_class_doc(doc)
elif isinstance(index, str) and doc.Title == index:
return _get_class_doc(doc)
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):
for i, _ in enumerate(self._desktop.Components):
pass
return i + 1
@property
def active(self):
return _get_class_doc(self._desktop.getCurrentComponent())
@classmethod
def new(cls, type_doc=CALC, args={}):
if type_doc == BASE:
return LOBase(None, args)
path = f'private:factory/s{type_doc}'
opt = dict_to_property(args)
doc = cls._desktop.loadComponentFromURL(path, '_default', 0, opt)
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)
doc = cls._desktop.loadComponentFromURL(path, '_default', 0, opt)
if doc is None:
return
return _get_class_doc(doc)
def connect(self, path):
return LOBase(path)
def _add_listeners(events, control, name=''):
listeners = {
'addActionListener': EventsButton,
'addMouseListener': EventsMouse,
# ~ 'addItemListener': EventsItem,
# ~ 'addFocusListener': EventsFocus,
# ~ '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
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
UNO_CLASSES = {
'label': UnoLabel,
'link': UnoLabelLink,
'button': UnoButton,
'radio': UnoRadio,
'check': UnoCheck,
}
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',
# ~ 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel',
# ~ 'text': 'com.sun.star.awt.UnoControlEditModel',
# ~ 'listbox': 'com.sun.star.awt.UnoControlListBoxModel',
# ~ 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel',
# ~ 'grid': 'com.sun.star.awt.grid.UnoControlGridModel',
# ~ 'tree': 'com.sun.star.awt.tree.TreeControlModel',
# ~ 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel',
# ~ 'image': 'com.sun.star.awt.UnoControlImageControlModel',
# ~ '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 = {}
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()
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 __init__(self):
pass
def __getitem__(self, index):
return docs.active[index]
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
class LOCells(object):
def __init__(self):
pass
def __getitem__(self, index):
return docs.active.active[index]
class Paths(object):
@classmethod
def exists(cls, path):
return Path(path).exists()
def __getattr__(name):
if name == 'active':
return docs.active
if name == 'active_sheet':
return docs.active.active
if name == 'selection':
return docs.active.selection
if name in ('rectangle', 'pos_size'):
return Rectangle()
if name == 'paths':
return Paths()
if name == 'docs':
return LODocs()
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
def create_dialog(args):
return LODialog(args)
def get_fonts():
toolkit = create_instance('com.sun.star.awt.Toolkit')
device = toolkit.createScreenCompatibleDevice(0, 0)
return device.FontDescriptors
# ~ docs = LODocs()
sheets = LOSheets()
cells = LOCells()
# ~ 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')
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