Add styles
This commit is contained in:
parent
d0c5f3a8ed
commit
5a02f50cc6
|
@ -5,3 +5,4 @@ build/
|
||||||
*.lock
|
*.lock
|
||||||
bk/
|
bk/
|
||||||
site/
|
site/
|
||||||
|
update.sh
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
v 0.6.0 [17-Dec-2023]
|
||||||
|
---------------------
|
||||||
|
- Add control styles.
|
||||||
|
|
||||||
v 0.5.0 [07-Dec-2023]
|
v 0.5.0 [07-Dec-2023]
|
||||||
---------------------
|
---------------------
|
||||||
- Add acctions to controls.
|
- Add acctions to controls.
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,177 @@
|
||||||
|
|
||||||
|
!!! tip "Atención"
|
||||||
|
|
||||||
|
La fecha inicial en Calc y en Python son diferentes.
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **today**
|
||||||
|
|
||||||
|
Obtener la fecha actual.
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
app.msgbox(d.today)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **now**
|
||||||
|
|
||||||
|
Obtener la fecha y hora actuales.
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
app.msgbox(d.now)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **time**
|
||||||
|
|
||||||
|
Obtener la hora actual.
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
app.msgbox(d.now.time())
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **epoch**
|
||||||
|
|
||||||
|
Obtener el [tiempo Unix][1]
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
app.msgbox(d.epoch)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **date**
|
||||||
|
|
||||||
|
Devolver una fecha
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
|
||||||
|
date = d.date(1974, 1, 15)
|
||||||
|
app.msgbox(date)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **time**
|
||||||
|
|
||||||
|
Devolver una hora
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
|
||||||
|
time = d.time(10, 20, 15)
|
||||||
|
app.msgbox(time)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **datetime**
|
||||||
|
|
||||||
|
Devolver fecha y hora
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
|
||||||
|
dt = d.datetime(1974, 1, 15, 10, 11, 12)
|
||||||
|
app.msgbox(dt)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **str_to_date**
|
||||||
|
|
||||||
|
Convertir una cadena en fecha. Mira este [excelente recurso][2]
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
|
||||||
|
cadena = '1974-01-15'
|
||||||
|
plantilla = '%Y-%m-%d'
|
||||||
|
fecha = d.str_to_date(cadena, plantilla)
|
||||||
|
app.msgbox(fecha)
|
||||||
|
app.msgbox(type(fecha))
|
||||||
|
```
|
||||||
|
|
||||||
|
Para obtener un valor válido para establecer en una celda de Calc.
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
|
||||||
|
cadena = '1974-01-15'
|
||||||
|
plantilla = '%Y-%m-%d'
|
||||||
|
fecha = d.str_to_date(cadena, plantilla, True)
|
||||||
|
app.msgbox(fecha)
|
||||||
|
app.msgbox(type(fecha))
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **calc_to_date**
|
||||||
|
|
||||||
|
Convierte el valor de una celda en una fecha Python, por ejemplo, la fecha inicial configurada en Calc.
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
|
||||||
|
valor_en_celda = 0
|
||||||
|
fecha = d.calc_to_date(valor_en_celda)
|
||||||
|
app.msgbox(fecha)
|
||||||
|
app.msgbox(type(fecha))
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **sleep**
|
||||||
|
|
||||||
|
Pausar la ejecución por X segundos.
|
||||||
|
|
||||||
|
!!! tip inline end "Atención"
|
||||||
|
|
||||||
|
La pausa es bloqueante.
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
|
||||||
|
app.sleep(3)
|
||||||
|
app.msgbox('Fin')
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **start** y **end**
|
||||||
|
|
||||||
|
Medir tiempo en segundos.
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
|
||||||
|
d.start()
|
||||||
|
app.sleep(5)
|
||||||
|
seconds = d.end()
|
||||||
|
app.msgbox(seconds)
|
||||||
|
```
|
||||||
|
|
||||||
|
Regresar timedelta en vez de segundos.
|
||||||
|
|
||||||
|
```py
|
||||||
|
d = app.dates
|
||||||
|
|
||||||
|
d.start()
|
||||||
|
app.sleep(5)
|
||||||
|
td = d.end(False)
|
||||||
|
app.msgbox(td)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
[1]: https://es.wikipedia.org/wiki/Tiempo_Unix
|
||||||
|
[2]: https://strftime.org
|
|
@ -0,0 +1,123 @@
|
||||||
|
---
|
||||||
|
title: Information
|
||||||
|
---
|
||||||
|
|
||||||
|
Remember, import first the library.
|
||||||
|
|
||||||
|
```py
|
||||||
|
import easymacro as app
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## About PC
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **OS**
|
||||||
|
|
||||||
|
Get Operate System.
|
||||||
|
```py
|
||||||
|
app.msgbox(app.OS)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **DESKTOP**
|
||||||
|
|
||||||
|
Get desktop type, only GNU/Linux.
|
||||||
|
```py
|
||||||
|
app.msgbox(app.DESKTOP)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **PC**
|
||||||
|
|
||||||
|
Get PC name.
|
||||||
|
```py
|
||||||
|
app.msgbox(app.PC)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **USER**
|
||||||
|
|
||||||
|
Get user name.
|
||||||
|
```py
|
||||||
|
app.msgbox(app.USER)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **IS_WIN**
|
||||||
|
|
||||||
|
If OS is Windows.
|
||||||
|
```py
|
||||||
|
app.msgbox(app.IS_WIN)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **IS_MAC**
|
||||||
|
|
||||||
|
IF OS is MAC
|
||||||
|
```py
|
||||||
|
app.msgbox(app.IS_MAC)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## About LibreOffice
|
||||||
|
|
||||||
|
### **NAME**
|
||||||
|
|
||||||
|
Application name.
|
||||||
|
```py
|
||||||
|
app.msgbox(app.NAME)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **VERSION**
|
||||||
|
|
||||||
|
Version.
|
||||||
|
```py
|
||||||
|
app.msgbox(app.VERSION)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **LANG**
|
||||||
|
|
||||||
|
Language
|
||||||
|
```py
|
||||||
|
app.msgbox(app.LANG)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **LANGUAGE**
|
||||||
|
|
||||||
|
Language with variant.
|
||||||
|
```py
|
||||||
|
app.msgbox(app.LANGUAGE)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **IS_APPIMAGE**
|
||||||
|
|
||||||
|
If LibreOffice use by AppImage.
|
||||||
|
```py
|
||||||
|
app.msgbox(app.IS_APPIMAGE)
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **IS_FLATPAK**
|
||||||
|
|
||||||
|
If LibreOffice is use by FlatPak.
|
||||||
|
```py
|
||||||
|
app.msgbox(app.IS_FLATPAK)
|
||||||
|
```
|
|
@ -0,0 +1,75 @@
|
||||||
|
## Message Box
|
||||||
|
|
||||||
|
### **msgbox**
|
||||||
|
|
||||||
|
Show standard message.
|
||||||
|
```py
|
||||||
|
message = 'Fucking World'
|
||||||
|
title = 'My Macro'
|
||||||
|
app.msgbox(message, title)
|
||||||
|
```
|
||||||
|
|
||||||
|
![msgbox](../img/tools_msg_01.png)
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **warning**
|
||||||
|
|
||||||
|
Show message with warning icon.
|
||||||
|
```py
|
||||||
|
message = 'Caution, this action is dangerous'
|
||||||
|
title = 'My Macro'
|
||||||
|
app.warning(message, title)
|
||||||
|
```
|
||||||
|
|
||||||
|
![warning](../img/tools_msg_02.png)
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **errorbox**
|
||||||
|
|
||||||
|
Show message with error icon.
|
||||||
|
```py
|
||||||
|
message = 'ERROR: contact support'
|
||||||
|
title = 'My Macro'
|
||||||
|
app.errorbox(message, title)
|
||||||
|
```
|
||||||
|
|
||||||
|
![error](../img/tools_msg_03.png)
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **question**
|
||||||
|
|
||||||
|
Ask a question by showing the interrogation icon and displaying the command buttons `Yes` and `No`. The answer is always True if user select `yes` and False otherwise.
|
||||||
|
```py
|
||||||
|
message = 'Python is easy?'
|
||||||
|
title = 'My Macro'
|
||||||
|
result = app.question(message, title)
|
||||||
|
app.msgbox(result)
|
||||||
|
```
|
||||||
|
|
||||||
|
![question](../img/tools_msg_04.png)
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
### **inputbox**
|
||||||
|
|
||||||
|
Shows a message to user, allowing to capture an answer.
|
||||||
|
```py
|
||||||
|
message = 'Capture your name'
|
||||||
|
name = app.inputbox(message)
|
||||||
|
app.msgbox(name)
|
||||||
|
```
|
||||||
|
|
||||||
|
![inputbox](../img/tools_msg_05.png)
|
||||||
|
|
||||||
|
To hide on screen what the user typing, util for request passwords.
|
||||||
|
```py
|
||||||
|
message = 'Type your password'
|
||||||
|
echochar = '*'
|
||||||
|
password = app.inputbox(message, echochar=echochar)
|
||||||
|
app.msgbox(password)
|
||||||
|
```
|
||||||
|
|
||||||
|
![inputbox](../img/tools_msg_06.png)
|
|
@ -5,6 +5,10 @@ nav:
|
||||||
- Home: index.md
|
- Home: index.md
|
||||||
- Install: install.md
|
- Install: install.md
|
||||||
- Debug: debug.md
|
- Debug: debug.md
|
||||||
|
- Tools:
|
||||||
|
- tools/index.md
|
||||||
|
- Messages: tools/messages.md
|
||||||
|
- Dates and time: tools/datetime.md
|
||||||
theme:
|
theme:
|
||||||
name: material
|
name: material
|
||||||
locale: en
|
locale: en
|
||||||
|
@ -33,8 +37,8 @@ markdown_extensions:
|
||||||
extra:
|
extra:
|
||||||
alternate:
|
alternate:
|
||||||
- name: English
|
- name: English
|
||||||
link: /
|
link: /easymacro
|
||||||
lang: en
|
lang: en
|
||||||
- name: Español
|
- name: Español
|
||||||
link: /langs/es
|
link: /easymacro/langs/es
|
||||||
lang: es
|
lang: es
|
||||||
|
|
|
@ -69,8 +69,8 @@ markdown_extensions:
|
||||||
extra:
|
extra:
|
||||||
alternate:
|
alternate:
|
||||||
- name: English
|
- name: English
|
||||||
link: /
|
link: /easymacro
|
||||||
lang: en
|
lang: en
|
||||||
- name: Español
|
- name: Español
|
||||||
link: /langs/es
|
link: /easymacro/langs/es
|
||||||
lang: es
|
lang: es
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# ~ Is de sum of:
|
||||||
|
# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1sheet_1_1CellFlags.html
|
||||||
|
|
||||||
|
from com.sun.star.sheet import CellFlags
|
||||||
|
|
||||||
|
ONLY_DATA = 31
|
||||||
|
|
||||||
|
ALL = 1023
|
|
@ -16,75 +16,13 @@ from .easyevents import EventsRangeSelectionListener, LOEvents
|
||||||
from .easyshape import LOShapes, LOShape
|
from .easyshape import LOShapes, LOShape
|
||||||
from .easydrawpage import LODrawPage
|
from .easydrawpage import LODrawPage
|
||||||
from .easyforms import LOForms
|
from .easyforms import LOForms
|
||||||
|
from .easystyles import LOStyleFamilies
|
||||||
|
|
||||||
|
|
||||||
SECONDS_DAY = 60 * 60 * 24
|
SECONDS_DAY = 60 * 60 * 24
|
||||||
ONLY_VALUES = CellFlags.VALUE + CellFlags.DATETIME + CellFlags.STRING
|
ONLY_VALUES = CellFlags.VALUE + CellFlags.DATETIME + CellFlags.STRING
|
||||||
|
|
||||||
|
|
||||||
class LOCellStyle():
|
|
||||||
|
|
||||||
def __init__(self, obj):
|
|
||||||
self._obj = obj
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'CellStyle: {self.name}'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def obj(self):
|
|
||||||
return self._obj
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
return self.obj.Name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def properties(self):
|
|
||||||
properties = self.obj.PropertySetInfo.Properties
|
|
||||||
data = {p.Name: getattr(self.obj, p.Name) for p in properties}
|
|
||||||
return data
|
|
||||||
@properties.setter
|
|
||||||
def properties(self, values):
|
|
||||||
set_properties(self.obj, values)
|
|
||||||
|
|
||||||
|
|
||||||
class LOCellStyles():
|
|
||||||
|
|
||||||
def __init__(self, obj, doc):
|
|
||||||
self._obj = obj
|
|
||||||
self._doc = doc
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self.obj)
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
|
||||||
return LOCellStyle(self.obj[index])
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
self.obj[key] = value
|
|
||||||
|
|
||||||
def __delitem__(self, key):
|
|
||||||
if not isinstance(key, str):
|
|
||||||
key = key.Name
|
|
||||||
del self.obj[key]
|
|
||||||
|
|
||||||
def __contains__(self, item):
|
|
||||||
return item in self.obj
|
|
||||||
|
|
||||||
@property
|
|
||||||
def obj(self):
|
|
||||||
return self._obj
|
|
||||||
|
|
||||||
@property
|
|
||||||
def names(self):
|
|
||||||
return self.obj.ElementNames
|
|
||||||
|
|
||||||
def new(self, name: str):
|
|
||||||
obj = self._doc.create_instance('com.sun.star.style.CellStyle')
|
|
||||||
self.obj[name] = obj
|
|
||||||
return LOCellStyle(obj)
|
|
||||||
|
|
||||||
|
|
||||||
# ~ IsFiltered,
|
# ~ IsFiltered,
|
||||||
# ~ IsManualPageBreak,
|
# ~ IsManualPageBreak,
|
||||||
# ~ IsStartOfNewPage
|
# ~ IsStartOfNewPage
|
||||||
|
@ -939,6 +877,11 @@ class LOCalc(LODocument):
|
||||||
"""Get class events"""
|
"""Get class events"""
|
||||||
return LOEvents(self.obj.Events)
|
return LOEvents(self.obj.Events)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def styles(self):
|
||||||
|
ci = self.obj.createInstance
|
||||||
|
return LOStyleFamilies(self.obj.StyleFamilies, ci)
|
||||||
|
|
||||||
def ranges(self):
|
def ranges(self):
|
||||||
"""Create ranges container"""
|
"""Create ranges container"""
|
||||||
obj = self._create_instance('com.sun.star.sheet.SheetCellRanges')
|
obj = self._create_instance('com.sun.star.sheet.SheetCellRanges')
|
||||||
|
@ -1111,5 +1054,4 @@ class LOCalc(LODocument):
|
||||||
return self.cell_styles
|
return self.cell_styles
|
||||||
@property
|
@property
|
||||||
def cell_styles(self):
|
def cell_styles(self):
|
||||||
obj = self.obj.StyleFamilies['CellStyles']
|
return self.styles['CellStyles']
|
||||||
return LOCellStyles(obj, self)
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ from com.sun.star.beans import PropertyValue, NamedValue, StringPair
|
||||||
from com.sun.star.datatransfer import XTransferable, DataFlavor
|
from com.sun.star.datatransfer import XTransferable, DataFlavor
|
||||||
from com.sun.star.ui.dialogs import TemplateDescription
|
from com.sun.star.ui.dialogs import TemplateDescription
|
||||||
|
|
||||||
|
from .constants import ALL
|
||||||
from .messages import MESSAGES
|
from .messages import MESSAGES
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,6 +32,8 @@ __all__ = [
|
||||||
'ALL',
|
'ALL',
|
||||||
'DESKTOP',
|
'DESKTOP',
|
||||||
'INFO_DEBUG',
|
'INFO_DEBUG',
|
||||||
|
'IS_APPIMAGE',
|
||||||
|
'IS_FLATPAK',
|
||||||
'IS_MAC',
|
'IS_MAC',
|
||||||
'IS_WIN',
|
'IS_WIN',
|
||||||
'LANG',
|
'LANG',
|
||||||
|
@ -63,13 +66,12 @@ PC = platform.node()
|
||||||
USER = getpass.getuser()
|
USER = getpass.getuser()
|
||||||
IS_WIN = OS == 'Windows'
|
IS_WIN = OS == 'Windows'
|
||||||
IS_MAC = OS == 'Darwin'
|
IS_MAC = OS == 'Darwin'
|
||||||
|
IS_FLATPAK = bool(os.getenv("FLATPAK_ID", ""))
|
||||||
|
IS_APPIMAGE = bool(os.getenv("APPIMAGE", ""))
|
||||||
ALL = 1023
|
|
||||||
|
|
||||||
|
|
||||||
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
|
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
|
||||||
LOG_DATE = '%d/%m/%Y %H:%M:%S'
|
LOG_DATE = '%Y/%m/%d %H:%M:%S'
|
||||||
if IS_WIN:
|
if IS_WIN:
|
||||||
logging.addLevelName(logging.ERROR, 'ERROR')
|
logging.addLevelName(logging.ERROR, 'ERROR')
|
||||||
logging.addLevelName(logging.DEBUG, 'DEBUG')
|
logging.addLevelName(logging.DEBUG, 'DEBUG')
|
||||||
|
@ -149,7 +151,6 @@ day = get_app_config(node, 'DD')
|
||||||
DATE_OFFSET = datetime.date(year, month, day).toordinal()
|
DATE_OFFSET = datetime.date(year, month, day).toordinal()
|
||||||
|
|
||||||
_info_debug = f"Python: {sys.version}\n\n{platform.platform()}\n\n" + '\n'.join(sys.path)
|
_info_debug = f"Python: {sys.version}\n\n{platform.platform()}\n\n" + '\n'.join(sys.path)
|
||||||
# ~ doc
|
|
||||||
INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{_info_debug}"
|
INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{_info_debug}"
|
||||||
|
|
||||||
|
|
||||||
|
@ -221,6 +222,12 @@ def set_properties(model, properties):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def get_properties(obj):
|
||||||
|
properties = obj.PropertySetInfo.Properties
|
||||||
|
values = {p.Name: getattr(obj, p.Name) for p in properties}
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
# ~ https://github.com/django/django/blob/main/django/utils/functional.py#L61
|
# ~ https://github.com/django/django/blob/main/django/utils/functional.py#L61
|
||||||
class classproperty:
|
class classproperty:
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
|
||||||
|
from .easymain import log, BaseObject, set_properties, get_properties
|
||||||
|
|
||||||
|
|
||||||
|
STYLE_FAMILIES = 'StyleFamilies'
|
||||||
|
|
||||||
|
|
||||||
|
class LOBaseStyles(BaseObject):
|
||||||
|
|
||||||
|
def __init__(self, obj, create_instance=None):
|
||||||
|
super().__init__(obj)
|
||||||
|
self._create_intance = create_instance
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return self.obj.Count
|
||||||
|
|
||||||
|
def __contains__(self, item):
|
||||||
|
return self.obj.hasByName(item)
|
||||||
|
|
||||||
|
def __getitem__(self, index):
|
||||||
|
if index in self:
|
||||||
|
style = self.obj.getByName(index)
|
||||||
|
else:
|
||||||
|
raise IndexError
|
||||||
|
|
||||||
|
if self.NAME == STYLE_FAMILIES:
|
||||||
|
s = LOStyles(style, index, self._create_intance)
|
||||||
|
else:
|
||||||
|
s = LOStyle(style)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
self._index = 0
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self._index < self.obj.Count:
|
||||||
|
style = self[self.names[self._index]]
|
||||||
|
else:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
self._index += 1
|
||||||
|
return style
|
||||||
|
|
||||||
|
@property
|
||||||
|
def names(self):
|
||||||
|
return self.obj.ElementNames
|
||||||
|
|
||||||
|
|
||||||
|
class LOStyle():
|
||||||
|
NAME = 'Style'
|
||||||
|
|
||||||
|
def __init__(self, obj):
|
||||||
|
self._obj = obj
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'Style: {self.name}'
|
||||||
|
|
||||||
|
def __contains__(self, item):
|
||||||
|
return hasattr(self.obj, item)
|
||||||
|
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
if name != '_obj':
|
||||||
|
self.obj.setPropertyValue(name, value)
|
||||||
|
else:
|
||||||
|
super().__setattr__(name, value)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return self.obj.getPropertyValue(name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def obj(self):
|
||||||
|
return self._obj
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.obj.Name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_in_use(self):
|
||||||
|
return self.obj.isInUse()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_user_defined(self):
|
||||||
|
return self.obj.isUserDefined()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def properties(self):
|
||||||
|
return get_properties(self.obj)
|
||||||
|
@properties.setter
|
||||||
|
def properties(self, values):
|
||||||
|
set_properties(self.obj, values)
|
||||||
|
|
||||||
|
|
||||||
|
class LOStyles(LOBaseStyles):
|
||||||
|
NAME = 'Styles'
|
||||||
|
|
||||||
|
def __init__(self, obj, type_style, create_instance):
|
||||||
|
super().__init__(obj)
|
||||||
|
self._type_style = type_style
|
||||||
|
self._create_instance = create_instance
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'Styles: {self._type_style}'
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
if key in self:
|
||||||
|
style = self.obj.getByName(key)
|
||||||
|
else:
|
||||||
|
name = f'com.sun.star.style.{self._type_style[:-1]}'
|
||||||
|
style = self._create_instance(name)
|
||||||
|
self.obj.insertByName(key, style)
|
||||||
|
set_properties(style, value)
|
||||||
|
|
||||||
|
def __delitem__(self, key):
|
||||||
|
self.obj.removeByName(key)
|
||||||
|
|
||||||
|
|
||||||
|
class LOStyleFamilies(LOBaseStyles):
|
||||||
|
NAME = STYLE_FAMILIES
|
||||||
|
|
||||||
|
def __init__(self, obj, create_instance):
|
||||||
|
super().__init__(obj, create_instance)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'Style Families: {self.names}'
|
||||||
|
|
||||||
|
def _validate_name(self, name):
|
||||||
|
if not name.endswith('Styles'):
|
||||||
|
name = f'{name}Styles'
|
||||||
|
return name
|
||||||
|
|
||||||
|
def __contains__(self, item):
|
||||||
|
return self.obj.hasByName(self._validate_name(item))
|
||||||
|
|
||||||
|
def __getitem__(self, index):
|
||||||
|
if isinstance(index, int):
|
||||||
|
index = self.names[index]
|
||||||
|
else:
|
||||||
|
index = self._validate_name(index)
|
||||||
|
return super().__getitem__(index)
|
|
@ -1,11 +1,123 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from .easymain import log, BaseObject
|
||||||
from .easydoc import LODocument
|
from .easydoc import LODocument
|
||||||
|
|
||||||
|
|
||||||
|
class LOWriterTextPortion(BaseObject):
|
||||||
|
|
||||||
|
def __init__(self, obj):
|
||||||
|
super().__init__(obj)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Writer: TextPortion'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string(self):
|
||||||
|
return self.obj.String
|
||||||
|
|
||||||
|
|
||||||
|
class LOWriterParagraph(BaseObject):
|
||||||
|
TEXT_PORTION = 'SwXTextPortion'
|
||||||
|
|
||||||
|
def __init__(self, obj):
|
||||||
|
super().__init__(obj)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Writer: Paragraph'
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
self._iter = iter(self.obj)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
obj = next(self._iter)
|
||||||
|
type_obj = obj.ImplementationName
|
||||||
|
if type_obj == self.TEXT_PORTION:
|
||||||
|
obj = LOWriterTextPortion(obj)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string(self):
|
||||||
|
return self.obj.String
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cursor(self):
|
||||||
|
return self.obj.Text.createTextCursorByRange(self.obj)
|
||||||
|
|
||||||
|
|
||||||
|
class LOWriterTextRange(BaseObject):
|
||||||
|
PARAGRAPH = 'SwXParagraph'
|
||||||
|
|
||||||
|
def __init__(self, obj):
|
||||||
|
super().__init__(obj)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Writer: TextRange'
|
||||||
|
|
||||||
|
def __getitem__(self, index):
|
||||||
|
for i, v in enumerate(self):
|
||||||
|
if index == i:
|
||||||
|
return v
|
||||||
|
if index > i:
|
||||||
|
raise IndexError
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
self._enum = self.obj.createEnumeration()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if self._enum.hasMoreElements():
|
||||||
|
obj = self._enum.nextElement()
|
||||||
|
type_obj = obj.ImplementationName
|
||||||
|
if type_obj == self.PARAGRAPH:
|
||||||
|
obj = LOWriterParagraph(obj)
|
||||||
|
else:
|
||||||
|
raise StopIteration
|
||||||
|
return obj
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string(self):
|
||||||
|
return self.obj.String
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cursor(self):
|
||||||
|
return self.obj.Text.createTextCursorByRange(self.obj)
|
||||||
|
|
||||||
|
|
||||||
|
class LOWriterTextRanges(BaseObject):
|
||||||
|
|
||||||
|
def __init__(self, obj):
|
||||||
|
super().__init__(obj)
|
||||||
|
# ~ self._doc = doc
|
||||||
|
# ~ self._paragraphs = [LOWriterTextRange(p, doc) for p in obj]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Writer: TextRanges'
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return self.obj.Count
|
||||||
|
|
||||||
|
def __getitem__(self, index):
|
||||||
|
return LOWriterTextRange(self.obj[index])
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
self._index = 0
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
try:
|
||||||
|
obj = LOWriterTextRange(self.obj[self._index])
|
||||||
|
except IndexError:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
self._index += 1
|
||||||
|
return obj
|
||||||
|
|
||||||
|
|
||||||
class LOWriter(LODocument):
|
class LOWriter(LODocument):
|
||||||
_type = 'writer'
|
|
||||||
TEXT_RANGES = 'SwXTextRanges'
|
TEXT_RANGES = 'SwXTextRanges'
|
||||||
|
_type = 'writer'
|
||||||
|
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
super().__init__(obj)
|
super().__init__(obj)
|
||||||
|
@ -17,3 +129,25 @@ class LOWriter(LODocument):
|
||||||
@zoom.setter
|
@zoom.setter
|
||||||
def zoom(self, value):
|
def zoom(self, value):
|
||||||
self._view_settings.ZoomValue = value
|
self._view_settings.ZoomValue = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def selection(self):
|
||||||
|
"""Get current seleccion"""
|
||||||
|
sel = None
|
||||||
|
selection = self.obj.CurrentSelection
|
||||||
|
type_obj = selection.ImplementationName
|
||||||
|
|
||||||
|
if type_obj == self.TEXT_RANGES:
|
||||||
|
sel = LOWriterTextRanges(selection)
|
||||||
|
if len(sel) == 1:
|
||||||
|
sel = sel[0]
|
||||||
|
else:
|
||||||
|
log.debug(type_obj)
|
||||||
|
log.debug(selection)
|
||||||
|
sel = selection
|
||||||
|
|
||||||
|
return sel
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string(self):
|
||||||
|
return self._obj.Text.String
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# ~ https://github.com/pyca/cryptography/blob/main/src/cryptography/fernet.py#L27
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import binascii
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import typing
|
||||||
|
|
||||||
|
|
||||||
|
_MAX_CLOCK_SKEW = 60
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidSignature(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidToken(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Fernet:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
key: bytes | str,
|
||||||
|
backend: typing.Any = None,
|
||||||
|
) -> None:
|
||||||
|
try:
|
||||||
|
key = base64.urlsafe_b64decode(key)
|
||||||
|
except binascii.Error as exc:
|
||||||
|
raise ValueError(
|
||||||
|
"Fernet key must be 32 url-safe base64-encoded bytes."
|
||||||
|
) from exc
|
||||||
|
if len(key) != 32:
|
||||||
|
raise ValueError(
|
||||||
|
"Fernet key must be 32 url-safe base64-encoded bytes."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
self._signing_key = key[:16]
|
||||||
|
self._encryption_key = key[16:]
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_key(cls) -> bytes:
|
||||||
|
return base64.urlsafe_b64encode(os.urandom(32))
|
||||||
|
|
||||||
|
|
||||||
|
def encrypt(self, data: bytes) -> bytes:
|
||||||
|
return self.encrypt_at_time(data, int(time.time()))
|
||||||
|
|
||||||
|
|
||||||
|
def encrypt_at_time(self, data: bytes, current_time: int) -> bytes:
|
||||||
|
iv = os.urandom(16)
|
||||||
|
return self._encrypt_from_parts(data, current_time, iv)
|
||||||
|
|
||||||
|
|
||||||
|
def _encrypt_from_parts(
|
||||||
|
self, data: bytes, current_time: int, iv: bytes
|
||||||
|
) -> bytes:
|
||||||
|
utils._check_bytes("data", data)
|
||||||
|
|
||||||
|
|
||||||
|
padder = padding.PKCS7(algorithms.AES.block_size).padder()
|
||||||
|
padded_data = padder.update(data) + padder.finalize()
|
||||||
|
encryptor = Cipher(
|
||||||
|
algorithms.AES(self._encryption_key),
|
||||||
|
modes.CBC(iv),
|
||||||
|
).encryptor()
|
||||||
|
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
|
||||||
|
|
||||||
|
|
||||||
|
basic_parts = (
|
||||||
|
b"\x80"
|
||||||
|
+ current_time.to_bytes(length=8, byteorder="big")
|
||||||
|
+ iv
|
||||||
|
+ ciphertext
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
h = HMAC(self._signing_key, hashes.SHA256())
|
||||||
|
h.update(basic_parts)
|
||||||
|
hmac = h.finalize()
|
||||||
|
return base64.urlsafe_b64encode(basic_parts + hmac)
|
||||||
|
|
||||||
|
|
||||||
|
def decrypt(self, token: bytes | str, ttl: int | None = None) -> bytes:
|
||||||
|
timestamp, data = Fernet._get_unverified_token_data(token)
|
||||||
|
if ttl is None:
|
||||||
|
time_info = None
|
||||||
|
else:
|
||||||
|
time_info = (ttl, int(time.time()))
|
||||||
|
return self._decrypt_data(data, timestamp, time_info)
|
||||||
|
|
||||||
|
|
||||||
|
def decrypt_at_time(
|
||||||
|
self, token: bytes | str, ttl: int, current_time: int
|
||||||
|
) -> bytes:
|
||||||
|
if ttl is None:
|
||||||
|
raise ValueError(
|
||||||
|
"decrypt_at_time() can only be used with a non-None ttl"
|
||||||
|
)
|
||||||
|
timestamp, data = Fernet._get_unverified_token_data(token)
|
||||||
|
return self._decrypt_data(data, timestamp, (ttl, current_time))
|
||||||
|
|
||||||
|
|
||||||
|
def extract_timestamp(self, token: bytes | str) -> int:
|
||||||
|
timestamp, data = Fernet._get_unverified_token_data(token)
|
||||||
|
# Verify the token was not tampered with.
|
||||||
|
self._verify_signature(data)
|
||||||
|
return timestamp
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_unverified_token_data(token: bytes | str) -> tuple[int, bytes]:
|
||||||
|
if not isinstance(token, (str, bytes)):
|
||||||
|
raise TypeError("token must be bytes or str")
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = base64.urlsafe_b64decode(token)
|
||||||
|
except (TypeError, binascii.Error):
|
||||||
|
raise InvalidToken
|
||||||
|
|
||||||
|
|
||||||
|
if not data or data[0] != 0x80:
|
||||||
|
raise InvalidToken
|
||||||
|
|
||||||
|
|
||||||
|
if len(data) < 9:
|
||||||
|
raise InvalidToken
|
||||||
|
|
||||||
|
|
||||||
|
timestamp = int.from_bytes(data[1:9], byteorder="big")
|
||||||
|
return timestamp, data
|
||||||
|
|
||||||
|
|
||||||
|
def _verify_signature(self, data: bytes) -> None:
|
||||||
|
h = HMAC(self._signing_key, hashes.SHA256())
|
||||||
|
h.update(data[:-32])
|
||||||
|
try:
|
||||||
|
h.verify(data[-32:])
|
||||||
|
except InvalidSignature:
|
||||||
|
raise InvalidToken
|
||||||
|
|
||||||
|
|
||||||
|
def _decrypt_data(
|
||||||
|
self,
|
||||||
|
data: bytes,
|
||||||
|
timestamp: int,
|
||||||
|
time_info: tuple[int, int] | None,
|
||||||
|
) -> bytes:
|
||||||
|
if time_info is not None:
|
||||||
|
ttl, current_time = time_info
|
||||||
|
if timestamp + ttl < current_time:
|
||||||
|
raise InvalidToken
|
||||||
|
|
||||||
|
|
||||||
|
if current_time + _MAX_CLOCK_SKEW < timestamp:
|
||||||
|
raise InvalidToken
|
||||||
|
|
||||||
|
|
||||||
|
self._verify_signature(data)
|
||||||
|
|
||||||
|
|
||||||
|
iv = data[9:25]
|
||||||
|
ciphertext = data[25:-32]
|
||||||
|
decryptor = Cipher(
|
||||||
|
algorithms.AES(self._encryption_key), modes.CBC(iv)
|
||||||
|
).decryptor()
|
||||||
|
plaintext_padded = decryptor.update(ciphertext)
|
||||||
|
try:
|
||||||
|
plaintext_padded += decryptor.finalize()
|
||||||
|
except ValueError:
|
||||||
|
raise InvalidToken
|
||||||
|
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
|
||||||
|
|
||||||
|
|
||||||
|
unpadded = unpadder.update(plaintext_padded)
|
||||||
|
try:
|
||||||
|
unpadded += unpadder.finalize()
|
||||||
|
except ValueError:
|
||||||
|
raise InvalidToken
|
||||||
|
return unpadded
|
|
@ -9,6 +9,6 @@ USER = 'elmau'
|
||||||
IS_WIN = False
|
IS_WIN = False
|
||||||
IS_MAC = False
|
IS_MAC = False
|
||||||
|
|
||||||
LIBO_VERSION = '7.4'
|
LIBO_VERSION = '7.6'
|
||||||
LANGUAGE = 'en-US'
|
LANGUAGE = 'en-US'
|
||||||
LANG = 'en'
|
LANG = 'en'
|
||||||
|
|
Loading…
Reference in New Issue