easymacro/source/easymacro/easytools.py

397 lines
11 KiB
Python

#!/usr/bin/env python3
import datetime
from functools import wraps
from typing import Any
from pprint import pprint
from com.sun.star.awt import MessageBoxButtons
from com.sun.star.awt.MessageBoxResults import YES
from com.sun.star.beans import PropertyValue
from com.sun.star.beans.PropertyConcept import ALL
from .easymain import IS_WIN, TITLE, log, create_instance
from .easyuno import MessageBoxType
from .easydocs import LODocuments
__all__ = [
'LOInspect',
'catch_exception',
'debug',
'error',
'info',
'mri',
'msgbox',
'save_log',
]
def debug(*messages) -> None:
"""Show messages debug
:param messages: List of messages to debug
:type messages: list[Any]
"""
data = [str(m) for m in messages]
log.debug('\t'.join(data))
return
def error(message: Any) -> None:
"""Show message error
:param message: The message error
:type message: Any
"""
log.error(message)
return
def info(*messages) -> None:
"""Show messages info
:param messages: List of messages to debug
:type messages: list[Any]
"""
data = [str(m) for m in messages]
log.info('\t'.join(data))
return
def save_log(path: str, data: Any) -> bool:
"""Save data in file, data append to end and automatic add current time.
:param path: Path to save log
:type path: str
:param data: Data to save in file log
:type data: Any
"""
result = True
try:
with open(path, 'a') as f:
f.write(f'{str(Dates.now())} - ')
pprint(data, stream=f)
except Exception as e:
error(e)
result = False
return result
def mri(obj: Any) -> None:
"""Inspect object with MRI Extension
:param obj: Any pyUno object
:type obj: Any
`See MRI <https://github.com/hanya/MRI/releases>`_
"""
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):
"""Catch exception for any function
:param f: Any Python function
:type f: Function instance
"""
@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
def set_app_config(node_name: str, key: str, new_value: Any) -> Any:
"""Update value for key in node name.
:param node_name: Name of node
:type name: str
:param key: Name of key
:type key: str
:return: True if update sucesfully
:rtype: bool
`See Api ConfigurationUpdateAccess <https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1configuration_1_1ConfigurationUpdateAccess.html>`_
"""
result = True
current_value = ''
name = 'com.sun.star.configuration.ConfigurationProvider'
service = 'com.sun.star.configuration.ConfigurationUpdateAccess'
cp = create_instance(name, True)
node = PropertyValue(Name='nodepath', Value=node_name)
update = cp.createInstanceWithArguments(service, (node,))
try:
current_value = update.getPropertyValue(key)
update.setPropertyValue(key, new_value)
update.commitChanges()
except Exception as e:
error(e)
if update.hasByName(key) and current_value:
update.setPropertyValue(key, current_value)
update.commitChanges()
result = False
return result
def msgbox(message: Any, title: str=TITLE, buttons=MessageBoxButtons.BUTTONS_OK, \
type_message_box=MessageBoxType.INFOBOX) -> int:
"""Create message box
:param message: Any type message, all is converted to string.
:type message: Any
:param title: The title for message box
:type title: str
:param buttons: A combination of `com::sun::star::awt::MessageBoxButtons <https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt_1_1MessageBoxButtons.html>`_
:type buttons: long
:param type_message_box: The `message box type <https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt.html#ad249d76933bdf54c35f4eaf51a5b7965>`_
:type type_message_box: enum
:return: `MessageBoxResult <https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt_1_1MessageBoxResults.html>`_
:rtype: int
`See Api XMessageBoxFactory <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_message_box, buttons, title, str(message))
return box.execute()
def question(message: str, title: str=TITLE) -> bool:
"""Create message box question, show buttons YES and NO
:param message: Message question
:type message: str
:param title: The title for message box
:type title: str
:return: True if user click YES and False if click NO
:rtype: bool
"""
buttons = MessageBoxButtons.BUTTONS_YES_NO
result = msgbox(message, title, buttons, MessageBoxType.QUERYBOX)
return result == YES
def warning(message: Any, title: str=TITLE) -> int:
"""Create message box with icon warning
:param message: Any type message, all is converted to string.
:type message: Any
:param title: The title for message box
:type title: str
:return: MessageBoxResult
:rtype: int
"""
return msgbox(message, title, type_message_box=MessageBoxType.WARNINGBOX)
def errorbox(message: Any, title: str=TITLE) -> int:
"""Create message box with icon error
:param message: Any type message, all is converted to string.
:type message: Any
:param title: The title for message box
:type title: str
:return: MessageBoxResult
:rtype: int
"""
return msgbox(message, title, type_message_box=MessageBoxType.ERRORBOX)
class LOInspect():
"""Class inspect
Inspired by `MRI <https://github.com/hanya/MRI/releases>`_
"""
TYPE_CLASSES = {
'INTERFACE': '-Interface-',
'SEQUENCE': '-Sequence-',
'STRUCT': '-Struct-',
}
def __init__(self, obj: Any, to_doc: bool=False):
"""Introspection objects pyUno
:param obj: Object to inspect
:type obj: Any pyUno
:param to_doc: If show info in new doc Calc
:type to_doc: bool
"""
self._obj = obj
if hasattr(obj, 'obj'):
self._obj = obj.obj
self._properties = ()
self._methods = ()
self._interfaces = ()
self._services = ()
self._listeners = ()
introspection = create_instance('com.sun.star.beans.Introspection')
result = introspection.inspect(self._obj)
if result:
self._properties = self._get_properties(result)
self._methods = self._get_methods(result)
self._interfaces = self._get_interfaces(result)
self._services = self._get_services(self._obj)
self._listeners = self._get_listeners(result)
self._to_doc(to_doc)
def _to_doc(self, to_doc: bool):
if not to_doc:
return
doc = LODocuments().new()
sheet = doc[0]
sheet.name = 'Properties'
sheet['A1'].data = self.properties
sheet = doc.insert('Methods')
sheet['A1'].data = self.methods
sheet = doc.insert('Interfaces')
sheet['A1'].data = self.interfaces
sheet = doc.insert('Services')
sheet['A1'].data = self.services
sheet = doc.insert('Listeners')
sheet['A1'].data = self.listeners
return
def _get_value(self, p: Any):
type_class = p.Type.typeClass.value
if type_class in self.TYPE_CLASSES:
return self.TYPE_CLASSES[type_class]
value = ''
try:
value = getattr(self._obj, p.Name)
if type_class == 'ENUM' and value:
value = value.value
elif type_class == 'TYPE':
value = value.typeName
elif value is None:
value = '-void-'
except:
value = '-error-'
return str(value)
def _get_attributes(self, a: Any):
PA = {1 : 'Maybe Void', 16 : 'Read Only'}
attr = ', '.join([PA.get(k, '') for k in PA.keys() if a & k])
return attr
def _get_property(self, p: Any):
name = p.Name
tipo = p.Type.typeName
value = self._get_value(p)
attr = self._get_attributes(p.Attributes)
return name, tipo, value, attr
def _get_properties(self, result: Any):
properties = result.getProperties(ALL)
data = [('Name', 'Type', 'Value', 'Attributes')]
data += [self._get_property(p) for p in properties]
return data
def _get_arguments(self, m: Any):
arguments = '( {} )'.format(', '.join(
[' '.join((
f'[{p.aMode.value.lower()}]',
p.aName,
p.aType.Name)) for p in m.ParameterInfos]
))
return arguments
def _get_method(self, m: Any):
name = m.Name
arguments = self._get_arguments(m)
return_type = m.ReturnType.Name
class_name = m.DeclaringClass.Name
return name, arguments, return_type, class_name
def _get_methods(self, result: Any):
methods = result.getMethods(ALL)
data = [('Name', 'Arguments', 'Return Type', 'Class')]
data += [self._get_method(m) for m in methods]
return data
def _get_interfaces(self, result: Any):
methods = result.getMethods(ALL)
interfaces = {m.DeclaringClass.Name for m in methods}
return tuple(zip(interfaces))
def _get_services(self, obj: Any):
try:
data = [str(s) for s in obj.getSupportedServiceNames()]
data = tuple(zip(data))
except:
data = ()
return data
def _get_listeners(self, result: Any):
data = [l.typeName for l in result.getSupportedListeners()]
return tuple(zip(data))
@property
def properties(self):
return self._properties
@property
def methods(self):
return self._methods
@property
def interfaces(self):
return self._interfaces
@property
def services(self):
return self._services
@property
def listeners(self):
return self._listeners
class Dates(object):
"""Class for datetimes
"""
_start = None
@classmethod
def now(cls):
"""Current local date and time
:return: Return the current local date and time, remove microsecond
:rtype: datetime
"""
return datetime.datetime.now().replace(microsecond=0)