397 lines
11 KiB
Python
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)
|