diff --git a/CHANGELOG.md b/CHANGELOG.md index 85952be..fc58da4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v 0.2.0 [23-Sep-2022] +--------------------- + - Add DrawPage. + v 0.1.0 [21-Sep-2022] --------------------- - Tools refactorize and documented. diff --git a/source/easymacro/__init__.py b/source/easymacro/__init__.py index 1896225..560698b 100644 --- a/source/easymacro/__init__.py +++ b/source/easymacro/__init__.py @@ -7,7 +7,6 @@ from .easydocs import LODocuments def __getattr__(name): - print(name) classes = { 'active': LODocuments().active, 'active_sheet': LODocuments().active.active, diff --git a/source/easymacro/easycalc.py b/source/easymacro/easycalc.py index f689ff4..205ddab 100644 --- a/source/easymacro/easycalc.py +++ b/source/easymacro/easycalc.py @@ -14,6 +14,7 @@ from .easymain import (log, DATE_OFFSET, from .easydoc import LODocument from .easyevents import EventsRangeSelectionListener, LOEvents from .easyshape import LOShapes, LOShape +from .easydrawpage import LODrawPage SECONDS_DAY = 60 * 60 * 24 @@ -83,6 +84,74 @@ class LOCellStyles(): return LOCellStyle(obj) +# ~ IsFiltered, +# ~ IsManualPageBreak, +# ~ IsStartOfNewPage +class LOSheetRows(): + + def __init__(self, sheet, obj): + self._sheet = sheet + self._obj = obj + + def __getitem__(self, index): + if isinstance(index, int): + rows = LOSheetRows(self._sheet, self.obj[index]) + else: + rango = self._sheet[index.start:index.stop,0:] + rows = LOSheetRows(self._sheet, rango.obj.Rows) + return rows + + def __len__(self): + return self.obj.Count + + def __str__(self): + return self.obj.Name + + @property + def obj(self): + return self._obj + + @property + def visible(self): + return self._obj.IsVisible + @visible.setter + def visible(self, value): + self._obj.IsVisible = value + + @property + def color(self): + return self.obj.CellBackColor + @color.setter + def color(self, value): + self.obj.CellBackColor = value + + @property + def is_transparent(self): + return self.obj.IsCellBackgroundTransparent + @is_transparent.setter + def is_transparent(self, value): + self.obj.IsCellBackgroundTransparent = value + + @property + def height(self): + return self.obj.Height + @height.setter + def height(self, value): + self.obj.Height = value + + def optimal(self): + self.obj.OptimalHeight = True + return + + def insert(self, index, count): + self.obj.insertByIndex(index, count) + return + + def remove(self, index, count): + self.obj.removeByIndex(index, count) + return + + class LOCalcRanges(object): def __init__(self, obj): @@ -231,6 +300,10 @@ class LOCalcRange(): """True if range is cell""" return self._is_cell + @property + def is_range(self): + return not self._is_cell + @property def name(self): """Return the range address like string""" @@ -456,6 +529,47 @@ class LOCalcRange(): cursor = self.obj.Spreadsheet.createCursorByRange(self.obj) return cursor + # ~ To doc + @property + def position(self): + return self.obj.Position + + # ~ To doc + @property + def size(self): + return self.obj.Size + + @property + def height(self): + return self.obj.Size.Height + + @property + def width(self): + return self.obj.Size.Width + + @property + def x(self): + return self.obj.Position.X + + @property + def y(self): + return self.obj.Position.Y + + # ~ To doc + @property + def possize(self): + data = { + 'Width': self.size.Width, + 'Height': self.size.Height, + 'X': self.position.X, + 'Y': self.position.Y, + } + return data + + @property + def rows(self): + return LOSheetRows(self.sheet, self.obj.Rows) + def clear(self, what: int=ONLY_VALUES): """Clear contents""" # ~ http://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1sheet_1_1CellFlags.html @@ -541,10 +655,28 @@ class LOCalcSheet(BaseObject): def password(self, value): self.obj.protect(value) + @property + def draw_page(self): + return LODrawPage(self.obj.DrawPage) + @property + def dp(self): + return self.draw_page + @property + def shapes(self): + return self.draw_page + @property def events(self): return LOEvents(self.obj.Events) + @property + def height(self): + return self.obj.Size.Height + + @property + def width(self): + return self.obj.Size.Width + def protect(self, value): self.obj.protect(value) return @@ -587,6 +719,7 @@ class LOCalcSheet(BaseObject): return sheet def activate(self): + """Activate sheet""" self.doc.activate(self.obj) return @@ -601,6 +734,41 @@ class LOCalcSheet(BaseObject): return cursor +class LOCalcSheetsCodeName(BaseObject): + """Access by code name sheet""" + + def __init__(self, obj): + super().__init__(obj) + self._sheets = obj.Sheets + + def __getitem__(self, index): + """Index access""" + for sheet in self._sheets: + if sheet.CodeName == index: + return LOCalcSheet(sheet) + raise IndexError + + def __iter__(self): + self._i = 0 + return self + + def __next__(self): + """Interation sheets""" + try: + sheet = LOCalcSheet(self._sheets[self._i]) + except Exception as e: + raise StopIteration + self._i += 1 + return sheet + + def __contains__(self, item): + """Contains""" + for sheet in self._sheets: + if sheet.CodeName == item: + return True + return False + + class LOCalc(LODocument): """Classe for Calc module""" TYPE_RANGES = ('ScCellObj', 'ScCellRangeObj') @@ -622,9 +790,11 @@ class LOCalc(LODocument): self._sheets[key] = value def __len__(self): + """Count sheets""" return self._sheets.Count def __contains__(self, item): + """Contains""" return item in self._sheets def __iter__(self): @@ -632,6 +802,7 @@ class LOCalc(LODocument): return self def __next__(self): + """Interation sheets""" try: sheet = LOCalcSheet(self._sheets[self._i]) except Exception as e: @@ -642,6 +813,11 @@ class LOCalc(LODocument): def __str__(self): return f'Calc: {self.title}' + @property + def sheets(self): + """Acces by code name sheet""" + return LOCalcSheetsCodeName(self.obj) + @property def headers(self): """Get true if is visible columns/rows headers""" diff --git a/source/easymacro/easydialog.py b/source/easymacro/easydialog.py index 2877dd8..f0d8032 100644 --- a/source/easymacro/easydialog.py +++ b/source/easymacro/easydialog.py @@ -7,8 +7,7 @@ from com.sun.star.view.SelectionType import SINGLE, MULTI, RANGE from .easyevents import * from .easydocs import LODocuments from .easymain import log, TITLE, Color, BaseObject, create_instance, set_properties -from .easytools import LOInspect, Paths, Services -from .easytools import _ +from .easytools import _, LOInspect, Paths, Services __all__ = [ diff --git a/source/easymacro/easydrawpage.py b/source/easymacro/easydrawpage.py new file mode 100644 index 0000000..e9f7830 --- /dev/null +++ b/source/easymacro/easydrawpage.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python3 + +from com.sun.star.awt import Size, Point + +from .easymain import BaseObject, set_properties +from .easyshape import LOShape + + +DEFAULT_WH = 3000 +DEFAULT_XY = 1000 + + +# ~ class LOShapeBK(BaseObject): + + # ~ @property + # ~ def cell(self): + # ~ return self.anchor + + # ~ @property + # ~ def anchor(self): + # ~ obj = self.obj.Anchor + # ~ if obj.ImplementationName == OBJ_CELL: + # ~ obj = LOCalcRange(obj) + # ~ elif obj.ImplementationName == OBJ_TEXT: + # ~ obj = LOWriterTextRange(obj, LODocs().active) + # ~ else: + # ~ debug('Anchor', obj.ImplementationName) + # ~ return obj + # ~ @anchor.setter + # ~ def anchor(self, value): + # ~ if hasattr(value, 'obj'): + # ~ value = value.obj + # ~ try: + # ~ self.obj.Anchor = value + # ~ except Exception as e: + # ~ self.obj.AnchorType = value + + # ~ @property + # ~ def visible(self): + # ~ return self.obj.Visible + # ~ @visible.setter + # ~ def visible(self, value): + # ~ self.obj.Visible = value + + # ~ @property + # ~ def path(self): + # ~ return self.url + # ~ @property + # ~ def url(self): + # ~ url = '' + # ~ if self.is_image: + # ~ url = _P.to_system(self.obj.GraphicURL.OriginURL) + # ~ return url + + # ~ @property + # ~ def mimetype(self): + # ~ mt = '' + # ~ if self.is_image: + # ~ mt = self.obj.GraphicURL.MimeType + # ~ return mt + + # ~ @property + # ~ def linked(self): + # ~ l = False + # ~ if self.is_image: + # ~ l = self.obj.GraphicURL.Linked + # ~ return l + + # ~ def delete(self): + # ~ self.remove() + # ~ return + # ~ def remove(self): + # ~ self.obj.Parent.remove(self.obj) + # ~ return + + # ~ def save(self, path: str, mimetype=DEFAULT_MIME_TYPE): + # ~ if _P.is_dir(path): + # ~ name = self.name + # ~ ext = mimetype.lower() + # ~ else: + # ~ p = _P(path) + # ~ path = p.path + # ~ name = p.name + # ~ ext = p.ext.lower() + + # ~ path = _P.join(path, f'{name}.{ext}') + # ~ args = dict( + # ~ URL = _P.to_url(path), + # ~ MimeType = MIME_TYPE[ext], + # ~ ) + # ~ if not _export_image(self.obj, args): + # ~ path = '' + # ~ return path + + # ~ def save2(self, path: str): + # ~ size = len(self.obj.Bitmap.DIB) + # ~ data = self.obj.GraphicStream.readBytes((), size) + # ~ data = data[-1].value + # ~ path = _P.join(path, f'{self.name}.png') + # ~ _P.save_bin(path, b'') + # ~ return + + +class LODrawPage(BaseObject): + _type = 'draw_page' + + def __init__(self, obj): + super().__init__(obj) + + def __getitem__(self, index): + if isinstance(index, int): + shape = LOShape(self.obj[index]) + else: + for i, o in enumerate(self.obj): + shape = self.obj[i] + name = shape.Name or f'shape{i}' + if name == index: + shape = LOShape(shape) + break + return shape + + def __iter__(self): + self._index = 0 + return self + + def __next__(self): + if self._index == self.count: + raise StopIteration + shape = self[self._index] + self._index += 1 + return shape + + def __contains__(self, source_name): + result = False + for i, o in enumerate(self.obj): + shape = self.obj[i] + name = shape.Name or f'shape{i}' + if name == source_name: + result = True + break + return result + + @property + def name(self): + return self.obj.Name + + @property + def doc(self): + return self.obj.Forms.Parent + + @property + def width(self): + return self.obj.Width + + @property + def height(self): + return self.obj.Height + + @property + def count(self): + return self.obj.Count + + @property + def last(self): + return self[self.count - 1] + + def _create_instance(self, name): + return self.doc.createInstance(name) + + def add(self, type_shape, options={}): + properties = options.copy() + """Insert a shape in page, type shapes: + Line + Rectangle + Ellipse + Text + Connector + """ + index = self.count + default_height = DEFAULT_WH + if type_shape == 'Line': + default_height = 0 + w = properties.pop('Width', DEFAULT_WH) + h = properties.pop('Height', default_height) + x = properties.pop('X', DEFAULT_XY) + y = properties.pop('Y', DEFAULT_XY) + name = properties.pop('Name', f'{type_shape.lower()}{index}') + + service = f'com.sun.star.drawing.{type_shape}Shape' + shape = self._create_instance(service) + shape.Size = Size(w, h) + shape.Position = Point(x, y) + shape.Name = name + self.obj.add(shape) + + if properties: + set_properties(shape, properties) + + # ~ return LOShape(self.obj[index], index) + return LOShape(self.obj[index]) + + def remove(self, shape): + if hasattr(shape, 'obj'): + shape = shape.obj + return self.obj.remove(shape) + + def remove_all(self): + while self.count: + self.obj.remove(self.obj[0]) + return + + def insert_image(self, path, options={}): + args = options.copy() + index = self.count + w = args.get('Width', 3000) + h = args.get('Height', 3000) + x = args.get('X', 1000) + y = args.get('Y', 1000) + name = args.get('Name', f'image{index}') + + image = self.create_instance('com.sun.star.drawing.GraphicObjectShape') + if isinstance(path, str): + image.GraphicURL = _P.to_url(path) + else: + gp = create_instance('com.sun.star.graphic.GraphicProvider') + properties = dict_to_property({'InputStream': path}) + image.Graphic = gp.queryGraphic(properties) + + self.obj.add(image) + image.Size = Size(w, h) + image.Position = Point(x, y) + image.Name = name + return LOShape(self.obj[index], index) diff --git a/source/easymacro/easymain.py b/source/easymacro/easymain.py index 0185cd3..65a895a 100644 --- a/source/easymacro/easymain.py +++ b/source/easymacro/easymain.py @@ -15,8 +15,11 @@ from typing import Any, Union import uno import unohelper -from com.sun.star.beans import PropertyValue, NamedValue +from com.sun.star.beans import PropertyValue, NamedValue, StringPair from com.sun.star.datatransfer import XTransferable, DataFlavor +from com.sun.star.ui.dialogs import TemplateDescription + +from .messages import MESSAGES __all__ = [ @@ -144,6 +147,16 @@ _info_debug = f"Python: {sys.version}\n\n{platform.platform()}\n\n" + '\n'.join( INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{_info_debug}" +def _(msg): + if LANG == 'en': + return msg + + if not LANG in MESSAGES: + return msg + + return MESSAGES[LANG][msg] + + def dict_to_property(values: dict, uno_any: bool=False): """Convert dictionary to array of PropertyValue @@ -842,6 +855,8 @@ class Paths(object): `See API `_ """ + paths = '' + if not init_dir: init_dir = cls.documents init_dir = cls.to_url(init_dir) @@ -858,6 +873,7 @@ class Paths(object): paths = [cls.to_system(p) for p in file_picker.getSelectedFiles()] if not multiple: paths = paths[0] + return paths @classmethod diff --git a/source/easymacro/easyshape.py b/source/easymacro/easyshape.py index 9a67329..99a7f91 100644 --- a/source/easymacro/easyshape.py +++ b/source/easymacro/easyshape.py @@ -1,5 +1,8 @@ #!/usr/bin/env python3 +from com.sun.star.awt import Size, Point +from .easymain import BaseObject, set_properties + class LOShapes(object): _type = 'ShapeCollection' @@ -38,7 +41,7 @@ class LOShapes(object): return self._obj -class LOShape(): +class LOShape(BaseObject): IMAGE = 'com.sun.star.drawing.GraphicObjectShape' def __init__(self, obj): @@ -117,9 +120,30 @@ class LOShape(): @property def x(self): return self.position.X + @x.setter + def x(self, value): + self.obj.Position = Point(value, self.y) + @property def y(self): return self.position.Y + @y.setter + def y(self, value): + self.obj.Position = Point(self.x, value) + + @property + def possize(self): + data = { + 'Width': self.size.Width, + 'Height': self.size.Height, + 'X': self.position.X, + 'Y': self.position.Y, + } + return data + @possize.setter + def possize(self, value): + self.obj.Size = Size(value['Width'], value['Height']) + self.obj.Position = Point(value['X'], value['Y']) @property def string(self): @@ -142,3 +166,26 @@ class LOShape(): def description(self, value): self.obj.Description = value + @property + def in_background(self): + return self.obj.LayerID + @in_background.setter + def in_background(self, value): + self.obj.LayerID = value + + @property + def layerid(self): + return self.obj.LayerID + @layerid.setter + def layerid(self, value): + self.obj.LayerID = value + + @property + def is_range(self): + return False + + @property + def is_cell(self): + return False + + diff --git a/source/easymacro/easytools.py b/source/easymacro/easytools.py index f6a9172..1bb3d04 100644 --- a/source/easymacro/easytools.py +++ b/source/easymacro/easytools.py @@ -40,9 +40,9 @@ from com.sun.star.ui.dialogs import TemplateDescription from .easyuno import MessageBoxType from .easydocs import LODocuments -from .messages import MESSAGES from .easyplus import mureq from .easymain import ( + _, CTX, DATE_OFFSET, IS_MAC, @@ -96,16 +96,6 @@ FILES = { _EVENTS = {} -def _(msg): - if LANG == 'en': - return msg - - if not LANG in MESSAGES: - return msg - - return MESSAGES[LANG][msg] - - def debug(*messages) -> None: """Show messages debug