Add actions to controls

This commit is contained in:
El Mau 2023-12-07 19:08:49 -06:00
parent 3aaec4df56
commit d0c5f3a8ed
53 changed files with 439 additions and 28 deletions

View File

@ -1,10 +1,15 @@
v 0.5.0 [07-Dec-2023]
---------------------
- Add acctions to controls.
- Refactorize documetation.
v 0.4.0 [20-Sep-2023]
---------------------
- Add control layout manager
- Add control layout manager.
v 0.3.0 [23-Apr-2023]
---------------------
- Add method post
- Add method post.
v 0.2.0 [23-Sep-2022]
---------------------

View File

@ -14,11 +14,11 @@ This library have a cost of maintenance of 1 euro every year.
In order of preferred.
* G1: `A5DdXxCKPw3QKWVdDVs7CzkNugNUW1sHu5zDJFWxCU2h`
Mauricio Baeza
```
Euros
IBAN: BE60 9671 0556 5870
SWIFT / BIC: TRWIBEB1XXX
```
* G1: `A5DdXxCKPw3QKWVdDVs7CzkNugNUW1sHu5zDJFWxCU2h`
```

View File

@ -1 +1 @@
0.4.0
0.5.0

198
docs/en/docs/debug.md Normal file
View File

@ -0,0 +1,198 @@
## Tools for debug
<br>
### **INFO_DEBUG**
Show debugging information in a message box.
If you have any problems in your code during the development of your macros, you can [open a ticket][1] support in the system ticket of this project. Always copy the debugging information shown in your issue.
```py
import easymacro as app
def info():
app.msgbox(app.INFO_DEBUG)
return
```
![Info debug](img/install_01.png)
### **debug**
Show information at the terminal.
```py
import easymacro as app
def test_debug():
msg = 'Verify this information...'
app.debug(msg)
return
```
To view this message, you need to start LibreOffice from the command line:
```
soffice --calc
```
After executing the previous macro, you should see:
```
21/04/2023 17:04:49 - DEBUG - Verify this information...
```
<br>
### **info**
Show information messages at the terminal.
```py
import easymacro as app
def test_info():
msg = 'Starting process...'
app.info(msg)
return
```
```
11/08/2022 18:23:53 - INFO - Starting process...
```
<br>
### **error**
Show error messages at the terminal.
```py
import easymacro as app
def test_error():
msg = 'Error 505'
app.error(msg)
return
```
```
11/08/2022 18:27:34 - ERROR - Error 505
```
<br>
### **save_log**
Save log in file, automatically add date and time.
```py
import easymacro as app
def test_save_log():
app.save_log('/home/mau/log.txt', 'PyUNO')
app.save_log('/home/mau/log.txt', 'World Damn')
return
```
```
cat ~/log.txt
2022-08-11 18:30:11 - 'PyUNO'
2022-08-11 18:30:11 - 'World Damn'
```
<br>
### **msgbox**
Show any information in a message box.
```python
import easymacro as app
def message():
msg = 'Please, consume less.'
app.msgbox(msg)
msg = ('one', 2, 'three')
app.msgbox(msg)
msg = {'name': 'Teresa'}
app.msgbox(msg)
app.msgbox(app)
return
```
<br>
### **catch_exception**
Capture any error that occurs when running a macro.
!!! warning inline end "Caution"
Use this method only in development time. **Do not use it in production**.
```py
import easymacro as app
@app.catch_exception
def test_capture_error():
r = 1 / 0
return
```
```
11/08/2022 18:44:36 - ERROR - test_capture_error
Traceback (most recent call last):
File "/home/mau/.config/libreoffice/4/user/Scripts/python/pythonpath/easymacro/easytools.py", line 115, in func
return f(*args, **kwargs)
File "/home/mau/.config/libreoffice/4/user/Scripts/python/test.py", line 18, in test_capturar_error
r = 1 / 0
ZeroDivisionError: division by zero
```
<br>
### **mri**
[MRI][2] is the best extension to inspect any UNO LibreOffice object. You need to install it first so you can use it.
```py
import easymacro as app
def inspect_object():
obj = app.active
app.mri(obj)
return
```
<br>
### **inspect**
Inspect an object.
```py
import easymacro as app
def inspect_object():
doc = app.active
data = app.inspect(doc)
for p in data.properties:
app.debug(p)
for m in data.methods:
app.debug(m)
return
```
Send information of the object to worksheet.
```python
def inspect_object():
doc = app.active
app.inspect(doc, True)
return
```
[1]: https://git.cuates.net/elmau/easymacro/issues
[2]: https://github.com/hanya/MRI

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 380 B

After

Width:  |  Height:  |  Size: 380 B

29
docs/en/docs/index.md Normal file
View File

@ -0,0 +1,29 @@
# Welcome to EasyMacro's documentation
**Free Software, not gratis software**
<br>
**easymacro** is a library to develop more easily macros in LibreOffice with Python. It is an abstraction layer between the extensive and complex UNO LibreOffice API and your code.
You will probably be happier if you use it :)
You can use **easymacro** with any extension or directly on your macros.
<br>
- Symily or related projects in Python:
* [python-ooo-dev-tools](https://python-ooo-dev-tools.readthedocs.io)
* [oooscript](https://oooscript.readthedocs.io)
* [python-ooouno-ex](https://github.com/Amourspirit/python-ooouno-ex)
- Symily or related projects in other languages:
* [Java LibreOffice Programming](https://flywire.github.io/lo-p/)
<br>
Contributions:
- Moneda Libre Ğ1 (Junas):<br>
`A5DdXxCKPw3QKWVdDVs7CzkNugNUW1sHu5zDJFWxCU2h`
<br>

47
docs/en/docs/install.md Normal file
View File

@ -0,0 +1,47 @@
## Clone repository
Clone the repository in your favorite project directory.
```
git clone https://git.cuates.net/elmau/easymacro
```
Move into the directory
```
cd easymacro/source
```
copy the `easymacro` folder into the **pythonpath** folder in the Python macro folder within your user profile. Replace **USER** by your real user.
```
/home/USER/.config/libreoffice/4/user/Scripts/python/pythonpath
```
or use a symbolic link (recommended). Replace **PATH** by the absolute route where **easymacro** is located in your file system and **USER** by your username.
```
ln -s PATH/easymacro/source/easymacro /home/USER/.config/libreoffice/4/user/Scripts/python/pythonpath/
```
## Test
In your favorite macros file, for example **mymacros.py**. Use your favorite plain text editor or IDE. Remember, replace **USER** by your real user.
```
geany /home/USER/.config/libreoffice/4/user/Scripts/python/mymacros.py
```
Copy the following code:
```py
import easymacro as app
def main():
app.msgbox(app.INFO_DEBUG)
return
```
Run the **main** macro in LibreOffice, if you see a message box with information similar to the following!
![Test install](img/install_01.png)
It is all ready to start developing macros with **easymacro**.
Happy programming!

40
docs/en/mkdocs.yml Normal file
View File

@ -0,0 +1,40 @@
site_name: EasyMacro for LibreOffice
site_url: https://doc.cuates.net/easymacro/
repo_url: https://git.cuates.net/elmau/easymacro/
nav:
- Home: index.md
- Install: install.md
- Debug: debug.md
theme:
name: material
locale: en
font: false
highlightjs: true
palette:
primary: green
features:
- navigation.path
- content.code.copy
- content.code.select
markdown_extensions:
- admonition
- pymdownx.details
- pymdownx.superfences
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.snippets
- pymdownx.tabbed:
alternate_style: true
- tables
- pymdownx.keys
extra:
alternate:
- name: English
link: /
lang: en
- name: Español
link: /langs/es
lang: es

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
docs/es/docs/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

View File

@ -43,7 +43,7 @@ nav:
- examples/index.md
theme:
name: material
locale: es
locale: en
font: false
highlightjs: true
palette:
@ -66,11 +66,11 @@ markdown_extensions:
alternate_style: true
- tables
- pymdownx.keys
#~ extra:
#~ alternate:
#~ - name: Español
#~ link: /
#~ lang: es
#~ - name: English
#~ link: /en/
#~ lang: en
extra:
alternate:
- name: English
link: /
lang: en
- name: Español
link: /langs/es
lang: es

View File

@ -1,5 +1,22 @@
#!/usr/bin/env python3
# ~ easymacro - for easily develop macros in LibreOffice
# ~ Copyright (C) 2020-2023 Mauricio Baeza (elmau)
# ~ This program 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.
# ~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
from .easymain import *
from .easydialog import *
from .easytools import *
@ -8,6 +25,10 @@ from .easydocs import LODocuments
from .easydrawpage import LOGalleries
__version__ = '0.5.0'
__author__ = 'Mauricio Baeza (elMau)'
def __getattr__(name):
classes = {
'active': LODocuments().active,

View File

@ -8,7 +8,7 @@ from com.sun.star.sheet import CellFlags
from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA
from .easymain import (log, DATE_OFFSET,
BaseObject, Color,
BaseObject, Color, LOMain,
dict_to_property, run_in_thread, set_properties
)
from .easydoc import LODocument
@ -624,6 +624,20 @@ class LOCalcRange():
cols = ra.EndColumn - ra.StartColumn + 1
return rows, cols
def select(self):
""" """
self.doc.select(self.obj)
return
def to_image(self):
""" """
self.select()
self.doc.copy()
args = {'SelectedFormat': 141}
url = 'ClipboardFormatItems'
LOMain.dispatch(self.doc.frame, url, args)
return self.sheet.shapes[-1]
class LOCalcSheet(BaseObject):

View File

@ -101,6 +101,37 @@ def add_listeners(events, control):
return
# ~ getAccessibleActionKeyBinding
class UnoActions():
ACTIONS = {
'press': 0,
'activate': 0,
}
def __init__(self, obj: Any):
self._obj = obj
self._ac = obj.AccessibleContext
self._actions = hasattr(self._ac, 'AccessibleActionCount')
def __str__(self):
return ', '.join(self.get())
def get(self):
actions = ()
if self._actions:
actions = [self._ac.getAccessibleActionDescription(i) for i in
range(self._ac.AccessibleActionCount)]
return actions
def press(self):
result = self._ac.doAccessibleAction(self.ACTIONS['press'])
return result
def activate(self):
result = self._ac.doAccessibleAction(self.ACTIONS['activate'])
return result
class UnoBaseObject(object):
def __init__(self, obj: Any):
@ -317,6 +348,10 @@ class UnoBaseObject(object):
def ps(self, ps):
self.obj.setPosSize(ps.X, ps.Y, ps.Width, ps.Height, POSSIZE)
@property
def actions(self):
return UnoActions(self.obj)
def set_focus(self):
self.obj.setFocus()
return
@ -469,7 +504,7 @@ class UnoImage(UnoBaseObject):
@property
def type(self):
return 'button'
return 'image'
@property
def value(self):
@ -547,6 +582,7 @@ class DialogBox(BaseObject):
obj = self._create(properties)
super().__init__(obj)
self._init_controls()
self._events = None
self._modal = False
def _create_from_path(self, path: str):
@ -705,7 +741,7 @@ class DialogBox(BaseObject):
return Paths.to_url(path)
def _special_properties(self, tipo, properties):
if tipo == 'link' and not 'Label' in properties:
if tipo == 'link' and 'URL' in properties and not 'Label' in properties:
properties['Label'] = properties['URL']
return properties

View File

@ -46,6 +46,9 @@ class LOLayoutManager(BaseObject):
self.obj.hideElement(name)
return
# ~ def create(self, name):
# ~ return self.obj.createElement(name)
class LODocument(BaseObject):
@ -238,6 +241,8 @@ class LODocument(BaseObject):
:type args: dict
:return: None if path or stream in memory
:rtype: bytes or None
https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1document_1_1MediaDescriptor.html
"""
FILTERS = {
'xlsx': 'Calc MS Excel 2007 XML',
@ -249,8 +254,11 @@ class LODocument(BaseObject):
stream = None
path_target = 'private:stream'
if filter_name == 'svg':
filter_name = f'{self.type}_svg_Export'
else:
filter_name = FILTERS.get(filter_name, filter_name)
filter_name = FILTERS.get(filter_name, filter_name)
filter_data = dict_to_property(args, True)
filters = {
'FilterName': filter_name,
@ -266,7 +274,7 @@ class LODocument(BaseObject):
try:
self.obj.storeToURL(path_target, opt)
except Exception as e:
error(e)
log.error(e)
if not stream is None:
stream = stream.buffer
@ -284,6 +292,11 @@ class LODocument(BaseObject):
LOMain.dispatch(self.frame, 'Copy')
return
def cut(self):
"""Copy current selection"""
LOMain.dispatch(self.frame, 'Cut')
return
def paste(self):
"""Paste current content in clipboard"""
sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
@ -314,6 +327,9 @@ class LODocument(BaseObject):
self.obj.getUndoManager().clear()
return
def replace_ext(self, new_ext):
return Paths.with_suffix(self.path, new_ext)
class LODrawImpress(LODocument):

View File

@ -537,7 +537,7 @@ class LOMain():
return cls._set_app_command(command, True)
@classmethod
def enabled(cls, command) -> bool:
def enabled(cls, command: str) -> bool:
"""Enabled UNO command
:param command: UNO command to enabled
@ -599,13 +599,14 @@ class LOMain():
class ClipBoard(object):
SERVICE = 'com.sun.star.datatransfer.clipboard.SystemClipboard'
CLIPBOARD_FORMAT_TEXT = 'text/plain;charset=utf-16'
TEXT = 'text/plain;charset=utf-16'
IMAGE = 'application/x-openoffice-bitmap;windows_formatname="Bitmap"'
class TextTransferable(unohelper.Base, XTransferable):
def __init__(self, text):
df = DataFlavor()
df.MimeType = ClipBoard.CLIPBOARD_FORMAT_TEXT
df.MimeType = ClipBoard.TEXT
df.HumanPresentableName = 'encoded text utf-16'
self.flavors = (df,)
self._data = text
@ -631,7 +632,7 @@ class ClipBoard(object):
transferable = sc.getContents()
data = transferable.getTransferDataFlavors()
for df in data:
if df.MimeType == cls.CLIPBOARD_FORMAT_TEXT:
if df.MimeType == cls.TEXT:
break
if df:
text = transferable.getTransferData(df)
@ -1045,10 +1046,13 @@ class Paths(object):
:return: Path with new extension
:rtype: str
"""
p = Paths(path)
name = f'{p.name}.{new_ext}'
path = cls.join(p.path, name)
return path
if not new_ext.startswith('.'):
new_ext = f'.{new_ext}'
return Path(path).with_suffix(new_ext)
@classmethod
def with_suffix(cls, path: str, new_ext: str):
return cls.replace_ext(path, new_ext)
@classmethod
def open(cls, path: str):

View File

@ -245,6 +245,7 @@ class LOShape(BaseObject):
def save(self, path: str='', name: str=''):
"""Save image"""
if not path:
path = Paths(self.doc.URL).path
if not name: