easymacro/source/easymacro.py

287 lines
7.6 KiB
Python
Raw Normal View History

2022-02-21 23:43:58 -06:00
#!/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/>.
2022-02-23 22:49:43 -06:00
import datetime
2022-02-21 23:43:58 -06:00
import getpass
import logging
import os
import platform
import socket
import subprocess
import sys
import time
2022-02-23 22:49:43 -06:00
import traceback
2022-02-21 23:43:58 -06:00
2022-02-23 22:49:43 -06:00
from functools import wraps
from pprint import pprint
2022-02-21 23:43:58 -06:00
from typing import Any
import uno
2022-02-23 22:49:43 -06:00
from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS
from com.sun.star.awt.MessageBoxResults import YES
2022-02-21 23:43:58 -06:00
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'
2022-02-23 22:49:43 -06:00
2022-02-21 23:43:58 -06:00
_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()
2022-02-23 22:49:43 -06:00
def debug(*args) -> None:
"""
Show messages debug
Parameters:
args (list): iterable messages for show
"""
2022-02-21 23:43:58 -06:00
data = [str(a) for a in args]
log.debug('\t'.join(data))
return
2022-02-23 22:49:43 -06:00
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)
2022-02-21 23:43:58 -06:00
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
2022-02-23 22:49:43 -06:00
NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName')
2022-02-21 23:43:58 -06:00
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}"
2022-02-23 22:49:43 -06:00
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
2022-02-21 23:43:58 -06: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