easymacro/source/easymacro.py

287 lines
7.6 KiB
Python

#!/usr/bin/env python3
# == Rapid Develop Macros in LibreOffice ==
# ~ https://git.cuates.net/elmau/easymacro
# ~ easymacro 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.
# ~ easymacro 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 easymacro. 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
import traceback
from functools import wraps
from pprint import pprint
from typing import Any
import uno
from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS
from com.sun.star.awt.MessageBoxResults import YES
from com.sun.star.beans import PropertyValue
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__)
# Global variables
OS = platform.system()
DESKTOP = os.environ.get('DESKTOP_SESSION', '')
PC = platform.node()
USER = getpass.getuser()
IS_WIN = OS == 'Windows'
IS_MAC = OS == 'Darwin'
_info_debug = f"Python: {sys.version}\n\n{platform.platform()}\n\n" + '\n'.join(sys.path)
SALT = b'00a1bfb05353bb3fd8e7aa7fe5efdccc'
CTX = uno.getComponentContext()
SM = CTX.getServiceManager()
def debug(*args) -> None:
"""
Show messages debug
Parameters:
args (list): iterable messages for show
"""
data = [str(a) for a in args]
log.debug('\t'.join(data))
return
def error(message: Any) -> None:
"""
Show message error
Parameters:
message (Any): message show error
"""
log.error(message)
return
def info(*args) -> None:
"""
Show messages info
Parameters:
args (list): iterable messages for show
"""
data = [str(a) for a in args]
log.info('\t'.join(data))
return
def save_log(path: str, data: Any) -> None:
"""
Save data in file, data append to end
Parameters:
path (str): path to save
data (Any): any info data
"""
with open(path, 'a') as f:
f.write(f'{str(now())[:19]} - ')
pprint(data, stream=f)
return
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: str, key: str='', update: bool=False):
name = 'com.sun.star.configuration.ConfigurationProvider'
service = 'com.sun.star.configuration.ConfigurationAccess'
if update:
service = 'com.sun.star.configuration.ConfigurationUpdateAccess'
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 ''
# Get info LibO
NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName')
VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion')
LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale')
LANG = LANGUAGE.split('-')[0]
INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{_info_debug}"
node = '/org.openoffice.Office.Calc/Calculate/Other/Date'
year = get_app_config(node, 'YY')
month = get_app_config(node, 'MM')
day = get_app_config(node, 'DD')
DATE_OFFSET = datetime.date(year, month, day).toordinal()
def msgbox(message: Any, title: str=TITLE, buttons=MSG_BUTTONS.BUTTONS_OK, type_msg: str='infobox') -> Any:
""" 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: Any, title: str=TITLE) -> Any:
result = msgbox(message, title, MSG_BUTTONS.BUTTONS_YES_NO, 'querybox')
return result == YES
def warning(message: Any, title: str=TITLE) -> Any:
return msgbox(message, title, type_msg='warningbox')
def errorbox(message: Any, title: str=TITLE) -> Any:
return msgbox(message, title, type_msg='errorbox')
def mri(obj: Any) -> None:
"""
Inspect object with MRI Extension
"""
m = create_instance('mytools.Mri')
if m is None:
msg = 'Extension MRI not found'
error(msg)
return
if hasattr(obj, 'obj'):
obj = obj.obj
m.inspect(obj)
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:
msgbox(traceback.format_exc())
log.error(name, exc_info=True)
return func
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