diff --git a/doc/docs/dp/drawpage.md b/doc/docs/dp/drawpage.md
index e1f6846..b78a29e 100644
--- a/doc/docs/dp/drawpage.md
+++ b/doc/docs/dp/drawpage.md
@@ -106,4 +106,18 @@ Agrega una nueva forma (un rectángulo) y la devuelve.
app.debug(forma)
```
+De forma predeterminada la posición será a 1 cm en Y y X y de 3 cm de ancho y alto. Estos valores se pueden modificar al crear la forma. Todas las unidades en milésimas de centímetro.
+
+```py
+ opciones = dict(
+ Name = 'mi_rectangulo_1',
+ Width = 5000,
+ Height = 2000,
+ X = 3000,
+ Y = 1000,
+ )
+
+ forma = formas.add('Rectangle', opciones)
+```
+
\ No newline at end of file
diff --git a/doc/docs/dp/shapes.md b/doc/docs/dp/shapes.md
index 2e731d4..c0bc240 100644
--- a/doc/docs/dp/shapes.md
+++ b/doc/docs/dp/shapes.md
@@ -1,7 +1,202 @@
## Propiedades
+Todas las unidades en milésimas de centímetro.
+
---
+### **anchor**
+
+Anclaje de la forma, por default se agrega a la página.
+
+#### Anclaje a una celda
+
+```py
+ celda = hoja['A1']
+ forma.anchor = celda
+```
+
+
+
+### **height**
+
+Alto de la forma.
+
+```py
+ forma.height = 2000
+```
+
+
+
+### **name**
+
+Devuelve o establece el nombre de la forma.
+
+```py
+ app.debug(forma.name)
+ forma.name = 'otro_rectangulo'
+ app.debug(forma.name)
+```
+
+
+
+### **obj**
+
+**Solo lectura.** Devuelve el objeto original pyUNO.
+
+```py
+ objeto = forma.obj
+```
+
+
+
+### **possize**
+
+Devuelve o establece la posición y el tamaño de la forma.
+
+```py
+ posicion_y_tamaño = dict(
+ Width = 5000,
+ Height = 2000,
+ X = 3000,
+ Y = 1000,
+ )
+ forma.possize = posicion_y_tamaño
+```
+
+
+
+### **properties**
+
+Devuelve un diccionario con todas las propiedades de la forma.
+
+```py
+ for p, v in forma.properties.items():
+ app.debug(f'{p} = {v}')
+```
+
+Al establecer solo aplica las que se pasen en un diccionario.
+
+```py
+ propiedades = dict(
+ LineColor = app.color('red'),
+ LineWidth = 100,
+ )
+ forma.properties = propiedades
+```
+
+!!! tip "Atención"
+
+ Aquí hay que usar los nombres "originales" de las propiedades de la forma en el API de LibreOffice.
+
+
+
+### **resize_with_cell**
+
+Si el tamaño de la forma cambia con la celda, solo cuando el anclaje es a una celda.
+
+```py
+ forma.resize_with_cell = True
+```
+
+
+
+### **shape_type**
+
+**Solo lectura**. Devuelve el tipo de forma.
+
+```py
+ app.debug(forma.shape_type)
+```
+
+```
+24/04/2023 13:55:32 - DEBUG - com.sun.star.drawing.RectangleShape
+```
+
+
+
+### **width**
+
+Ancho de la forma.
+
+```py
+ forma.width = 6000
+```
+
+
+
+### **x**
+
+Posición en el eje X.
+
+```py
+ forma.x = 5000
+```
+
+
+
+### **y**
+
+Posición en el eje Y.
+
+```py
+ forma.y = 1000
+```
+
## Métodos
----
\ No newline at end of file
+---
+
+### **clone**
+
+Clona la imagen en la misma hoja.
+
+```py
+ imagen.clone()
+```
+
+Clona la imagen en otra hoja.
+
+```py
+ imagen.clone(doc['Hoja5'].draw_page)
+```
+
+
+
+### **remove**
+
+Eliminar la forma.
+
+```py
+ forma.remove()
+```
+
+
+
+### **save**
+
+Guarda la imagen en disco. Si no se pasa ningún argumento, toma la ruta del documento y el nombre de la imagen.
+
+!!! tip inline end "Atención"
+
+ El documento ya debe estar guardado
+
+```py
+ imagen.save()
+```
+
+Podemos pasar una ruta diferente, seguira tomando el nombre de la imagen.
+
+```py
+ ruta = '/home/elmau/imagenes'
+ imagen.save(ruta)
+```
+
+Podemos cambiar el nombre.
+
+```py
+ ruta = '/home/elmau/imagenes'
+ name = f'{hoja.name}_nuevo_nombre'
+ imagen.save(path, name)
+```
+
+
\ No newline at end of file
diff --git a/doc/docs/examples/index.md b/doc/docs/examples/index.md
new file mode 100644
index 0000000..3ab3408
--- /dev/null
+++ b/doc/docs/examples/index.md
@@ -0,0 +1,155 @@
+---
+title: Índice
+---
+
+# Ejemplos reales de uso
+
+---
+
+## Calc
+
+---
+
+### Solicitar precios
+
+Consultar datos en json a una página web y vaciarlos en una hoja.
+
+=== "EasyMacro"
+
+ ```py
+ import easymacro as app
+
+ def obtener_precios():
+ URL = 'https://api.binance.com/api/v3/ticker/price'
+ respuesta = app.url.get(URL)
+ if respuesta.status_code == 200:
+ datos = respuesta.json()
+ app.active.active['A1'].dict = datos
+ return
+ ```
+
+=== "Sin EasyMacro"
+
+ ```py
+ import uno
+ import json
+ from urllib import request
+
+ def obtener_precios():
+ URL = 'https://api.binance.com/api/v3/ticker/price'
+ data = json.loads(request.urlopen(URL).read().decode())
+
+ doc = XSCRIPTCONTEXT.getDocument()
+ sheet = doc.CurrentController.ActiveSheet
+
+ sheet[0,0].String = 'symbol'
+ sheet[0,1].String = 'price'
+
+ for i, row in enumerate(data):
+ sheet[i + 1,0].String = row['symbol']
+ sheet[i + 1,1].Value = float(row['price'])
+
+ return
+ ```
+
+
+
+### Clonar imagenes
+
+Clonar todas las imagenes de una hoja a otra.
+
+=== "EasyMacro"
+
+ ```py
+ doc = app.active
+ for image in doc[0].dp:
+ if image.is_image:
+ image.clone(doc[1].dp)
+ ```
+
+=== "Sin EasyMacro"
+
+ ```py
+ import uno
+ import io
+ import unohelper
+ from com.sun.star.io import IOException, XOutputStream
+ from com.sun.star.beans import PropertyValue
+
+
+ CTX = uno.getComponentContext()
+ SM = CTX.getServiceManager()
+
+
+ class LOShape():
+
+ def __init__(self, shape):
+ self._shape = shape
+
+ class OutputStream(unohelper.Base, XOutputStream):
+
+ def __init__(self):
+ self._buffer = b''
+ self.closed = 0
+
+ @property
+ def buffer(self):
+ return self._buffer
+
+ def closeOutput(self):
+ self.closed = 1
+
+ def writeBytes(self, seq):
+ if seq.value:
+ self._buffer = seq.value
+
+ def flush(self):
+ pass
+
+ def clone_image(self, doc, to_sheet):
+ stream = self._shape.GraphicStream
+ buffer = self.OutputStream()
+ size, data = stream.readBytes(buffer, stream.available())
+
+ stream = SM.createInstanceWithContext('com.sun.star.io.SequenceInputStream', CTX)
+ stream.initialize((data,))
+
+ image = doc.createInstance('com.sun.star.drawing.GraphicObjectShape')
+ gp = SM.createInstance('com.sun.star.graphic.GraphicProvider')
+ properties = (PropertyValue(Name='InputStream', Value=stream),)
+ image.Graphic = gp.queryGraphic(properties)
+ to_sheet.DrawPage.add(image)
+ image.Size = self._shape.Size
+ image.Position = self._shape.Position
+ return
+
+ def clone_shape(self, doc, to_sheet):
+ for p in self._shape.CustomShapeGeometry:
+ if p.Name == 'Type':
+ type_shape = p.Value.title()
+
+ service = f'com.sun.star.drawing.{type_shape}Shape'
+ shape = doc.createInstance(service)
+ shape.Size = self._shape.Size
+ shape.Position = self._shape.Position
+ to_sheet.DrawPage.add(shape)
+ return
+
+
+ def main():
+ IMAGE = 'com.sun.star.drawing.GraphicObjectShape'
+ SHAPE = 'com.sun.star.drawing.CustomShape'
+
+ doc = XSCRIPTCONTEXT.getDocument()
+ source = doc.CurrentController.ActiveSheet
+ target = doc.Sheets[1]
+
+ for shape in source.DrawPage:
+ s = LOShape(shape)
+ if shape.ShapeType == IMAGE:
+ s.clone_image(doc, target)
+ elif shape.ShapeType == SHAPE:
+ s.clone_shape(doc, tar
+ ```
+
+
\ No newline at end of file
diff --git a/doc/mkdocs.yml b/doc/mkdocs.yml
index 0e47fee..3c66251 100644
--- a/doc/mkdocs.yml
+++ b/doc/mkdocs.yml
@@ -32,6 +32,8 @@ nav:
- Página de dibujo:
- dp/drawpage.md
- Formas: dp/shapes.md
+ - Ejemplos de uso:
+ - examples/index.md
theme:
name: material
locale: es
@@ -53,7 +55,8 @@ markdown_extensions:
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.snippets
- - pymdownx.superfences
+ - pymdownx.tabbed:
+ alternate_style: true
#~ extra:
#~ alternate:
#~ - name: Español
diff --git a/source/easymacro/easydoc.py b/source/easymacro/easydoc.py
index ca7d915..5e5c1dc 100644
--- a/source/easymacro/easydoc.py
+++ b/source/easymacro/easydoc.py
@@ -1,51 +1,11 @@
#!/usr/bin/env python3
import uno
-import unohelper
-from com.sun.star.io import IOException, XOutputStream
from .easymain import (log,
BaseObject, LOMain, Paths,
dict_to_property, create_instance
)
-
-
-class IOStream(object):
- """Classe for input/output stream"""
-
- class OutputStream(unohelper.Base, XOutputStream):
-
- def __init__(self):
- self._buffer = b''
- self.closed = 0
-
- @property
- def buffer(self):
- return self._buffer
-
- def closeOutput(self):
- self.closed = 1
-
- def writeBytes(self, seq):
- if seq.value:
- self._buffer = seq.value
-
- def flush(self):
- pass
-
- @classmethod
- def buffer(cls):
- return io.BytesIO()
-
- @classmethod
- def input(cls, buffer):
- service = 'com.sun.star.io.SequenceInputStream'
- stream = create_instance(service, True)
- stream.initialize((uno.ByteSequence(buffer.getvalue()),))
- return stream
-
- @classmethod
- def output(cls):
- return cls.OutputStream()
+from .easyuno import IOStream
class LODocument(BaseObject):
diff --git a/source/easymacro/easydrawpage.py b/source/easymacro/easydrawpage.py
index 05dca93..1fa0a9a 100644
--- a/source/easymacro/easydrawpage.py
+++ b/source/easymacro/easydrawpage.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
+from pathlib import Path
from com.sun.star.awt import Size, Point
from .easymain import (
@@ -228,7 +229,7 @@ class LODrawPage(BaseObject):
image = self._create_instance('com.sun.star.drawing.GraphicObjectShape')
if isinstance(path, str):
- image.GraphicURL = _P.to_url(path)
+ image.GraphicURL = Path(path).as_uri()
else:
gp = create_instance('com.sun.star.graphic.GraphicProvider')
stream = IOStream.input(path)
diff --git a/source/easymacro/easyshape.py b/source/easymacro/easyshape.py
index f3488b4..75039d5 100644
--- a/source/easymacro/easyshape.py
+++ b/source/easymacro/easyshape.py
@@ -1,7 +1,8 @@
#!/usr/bin/env python3
from com.sun.star.awt import Size, Point
-from .easymain import BaseObject, set_properties
+from .easymain import BaseObject, Paths, create_instance, dict_to_property, set_properties
+from .easyuno import IOStream, get_input_stream
class LOShapes(object):
@@ -43,6 +44,10 @@ class LOShapes(object):
class LOShape(BaseObject):
IMAGE = 'com.sun.star.drawing.GraphicObjectShape'
+ MIME_TYPE = {
+ 'image/png': 'png',
+ 'image/jpeg': 'jpg',
+ }
def __init__(self, obj):
self._obj = obj
@@ -52,10 +57,12 @@ class LOShape(BaseObject):
@property
def obj(self):
+ """Get original UNO object"""
return self._obj
@property
def anchor(self):
+ """Get anchor object"""
return self.obj.Anchor
@anchor.setter
def anchor(self, obj):
@@ -66,6 +73,7 @@ class LOShape(BaseObject):
@property
def resize_with_cell(self):
+ """If resize with cell"""
return self.obj.ResizeWithCell
@resize_with_cell.setter
def resize_with_cell(self, value):
@@ -74,8 +82,7 @@ class LOShape(BaseObject):
@property
def properties(self):
- # ~ properties = self.obj.PropertySetInfo.Properties
- # ~ data = {p.Name: getattr(self.obj, p.Name) for p in properties}
+ """Get all properties"""
data = self.obj.PropertySetInfo.Properties
keys = [p.Name for p in data]
values = self.obj.getPropertyValues(keys)
@@ -87,10 +94,12 @@ class LOShape(BaseObject):
@property
def shape_type(self):
+ """Get type shape"""
return self.obj.ShapeType
@property
def name(self):
+ """Get name"""
return self.obj.Name
@name.setter
def name(self, value):
@@ -114,6 +123,7 @@ class LOShape(BaseObject):
@property
def width(self):
+ """Width of shape"""
s = self.obj.Size
return s.Width
@width.setter
@@ -124,6 +134,7 @@ class LOShape(BaseObject):
@property
def height(self):
+ """Height of shape"""
s = self.obj.Size
return s.Height
@height.setter
@@ -137,6 +148,7 @@ class LOShape(BaseObject):
return self.obj.Position
@property
def x(self):
+ """Position X"""
return self.position.X
@x.setter
def x(self, value):
@@ -144,6 +156,7 @@ class LOShape(BaseObject):
@property
def y(self):
+ """Position Y"""
return self.position.Y
@y.setter
def y(self, value):
@@ -199,11 +212,69 @@ class LOShape(BaseObject):
self.obj.LayerID = value
@property
- def is_range(self):
- return False
+ def type(self):
+ mt = self.obj.GraphicURL.MimeType
+ mime_type = self.MIME_TYPE.get(mt, mt)
+ return mime_type
+
+ # ~ not work
+ @property
+ def visible(self):
+ return self.obj.Visible
+ @visible.setter
+ def visible(self, value):
+ self.obj.Visible = value
@property
- def is_cell(self):
- return False
+ def doc(self):
+ return self.obj.Parent.Forms.Parent
+
+ def remove(self):
+ """Auto remove"""
+ self.obj.Parent.remove(self.obj)
+ return
+
+ def save(self, path: str='', name: str=''):
+ """Save image"""
+ if not path:
+ path = Paths(self.doc.URL).path
+ if not name:
+ name = self.name.replace(' ', '_')
+
+ path_img = Paths.join(path, f'{name}.{self.type}')
+ data = IOStream.to_bin(self.obj.GraphicStream)
+ Paths.save_bin(path_img, data)
+
+ return path_img
+
+ def _get_graphic(self):
+ stream = self.obj.GraphicStream
+ buffer = IOStream.output()
+ _, data = stream.readBytes(buffer, stream.available())
+ stream = get_input_stream(data)
+ gp = create_instance('com.sun.star.graphic.GraphicProvider')
+ properties = dict_to_property({'InputStream': stream})
+ graphic = gp.queryGraphic(properties)
+ return graphic
+
+ def clone(self, draw_page=None):
+ """Clone image"""
+ image = self.doc.createInstance('com.sun.star.drawing.GraphicObjectShape')
+ image.Graphic = self._get_graphic()
+ plus = 0
+ if draw_page is None:
+ draw_page = self.obj.Parent
+ plus = 1000
+ else:
+ if hasattr(draw_page, 'obj'):
+ draw_page = draw_page.obj
+
+ draw_page.add(image)
+ image.Size = self.size
+ position = self.position
+ position.X += plus
+ position.Y += plus
+ image.Position = position
+ return LOShape(image)
diff --git a/source/easymacro/easyuno.py b/source/easymacro/easyuno.py
index f25d715..ff6d128 100644
--- a/source/easymacro/easyuno.py
+++ b/source/easymacro/easyuno.py
@@ -1,5 +1,9 @@
#!/usr/bin/env python3
+import unohelper
+from com.sun.star.io import IOException, XOutputStream
+from .easymain import create_instance
+
# UNO Enum
class MessageBoxType():
@@ -9,3 +13,54 @@ class MessageBoxType():
"""
from com.sun.star.awt.MessageBoxType \
import MESSAGEBOX, INFOBOX, WARNINGBOX, ERRORBOX, QUERYBOX
+
+
+class IOStream(object):
+ """Classe for input/output stream"""
+
+ class OutputStream(unohelper.Base, XOutputStream):
+
+ def __init__(self):
+ self._buffer = b''
+ self.closed = 0
+
+ @property
+ def buffer(self):
+ return self._buffer
+
+ def closeOutput(self):
+ self.closed = 1
+
+ def writeBytes(self, seq):
+ if seq.value:
+ self._buffer = seq.value
+
+ def flush(self):
+ pass
+
+ @classmethod
+ def buffer(cls):
+ return io.BytesIO()
+
+ @classmethod
+ def input(cls, buffer):
+ service = 'com.sun.star.io.SequenceInputStream'
+ stream = create_instance(service, True)
+ stream.initialize((uno.ByteSequence(buffer.getvalue()),))
+ return stream
+
+ @classmethod
+ def output(cls):
+ return cls.OutputStream()
+
+ @classmethod
+ def to_bin(cls, stream):
+ buffer = cls.OutputStream()
+ _, data = stream.readBytes(buffer, stream.available())
+ return data.value
+
+
+def get_input_stream(data):
+ stream = create_instance('com.sun.star.io.SequenceInputStream', True)
+ stream.initialize((data,))
+ return stream