#!/usr/bin/env python3 # == Rapid Develop Macros in LibreOffice == # ~ This file is part of ZAZ. # ~ ZAZ 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. # ~ ZAZ 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 ZAZ. If not, see . import ctypes import datetime import errno import getpass import logging import os import platform import shlex import subprocess import sys import tempfile import threading import time import zipfile from datetime import datetime from functools import wraps from pathlib import Path, PurePath from pprint import pprint from subprocess import PIPE import uno import unohelper from com.sun.star.beans import PropertyValue from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS from com.sun.star.awt.MessageBoxResults import YES from com.sun.star.awt.PosSize import POSSIZE, SIZE from com.sun.star.awt import Size, Point from com.sun.star.datatransfer import XTransferable, DataFlavor from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA from com.sun.star.text.TextContentAnchorType import AS_CHARACTER from com.sun.star.lang import XEventListener from com.sun.star.awt import XActionListener from com.sun.star.awt import XMouseListener MSG_LANG = { 'es': { 'OK': 'Aceptar', 'Cancel': 'Cancelar', 'Select file': 'Seleccionar archivo', } } FILE_NAME_DEBUG = 'zaz-debug.log' LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s' LOG_DATE = '%d/%m/%Y %H:%M:%S' logging.addLevelName(logging.ERROR, '\033[1;41mERROR\033[1;0m') logging.addLevelName(logging.DEBUG, '\x1b[33mDEBUG\033[1;0m') logging.addLevelName(logging.INFO, '\x1b[32mINFO\033[1;0m') logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE) log = logging.getLogger(__name__) OS = platform.system() USER = getpass.getuser() PC = platform.node() DESKTOP = os.environ.get('DESKTOP_SESSION', '') INFO_DEBUG = '{}\n\n{}\n\n{}'.format(sys.version, platform.platform(), '\n'.join(sys.path)) IS_WIN = OS == 'Windows' LOG_NAME = 'ZAZ' CLIPBOARD_FORMAT_TEXT = 'text/plain;charset=utf-16' CALC = 'calc' WRITER = 'writer' OBJ_CELL = 'ScCellObj' OBJ_RANGE = 'ScCellRangeObj' OBJ_RANGES = 'ScCellRangesObj' OBJ_TYPE_RANGES = (OBJ_CELL, OBJ_RANGE, OBJ_RANGES) CTX = uno.getComponentContext() SM = CTX.getServiceManager() def create_instance(name, with_context=False): if with_context: instance = SM.createInstanceWithContext(name, CTX) else: instance = SM.createInstance(name) return instance def _get_config(key, node_name): name = 'com.sun.star.configuration.ConfigurationProvider' service = 'com.sun.star.configuration.ConfigurationAccess' cp = create_instance(name, True) node = PropertyValue(Name='nodepath', Value=node_name) try: ca = cp.createInstanceWithArguments(service, (node,)) if ca and (ca.hasByName(key)): data = ca.getPropertyValue(key) return data except Exception as e: log.error(e) return '' LANGUAGE = _get_config('ooLocale', 'org.openoffice.Setup/L10N/') LANG = LANGUAGE.split('-')[0] NAME = TITLE = _get_config('ooName', 'org.openoffice.Setup/Product') VERSION = _get_config('ooSetupVersion', 'org.openoffice.Setup/Product') def mri(obj): m = create_instance('mytools.Mri') if m is None: msg = 'Extension MRI not found' error(msg) return m.inspect(obj) return def catch_exception(f): @wraps(f) def func(*args, **kwargs): try: return f(*args, **kwargs) except Exception as e: log.error(f.__name__, exc_info=True) return func class LogWin(object): def __init__(self, doc): self.doc = doc def write(self, info): text = self.doc.Text cursor = text.createTextCursor() cursor.gotoEnd(False) text.insertString(cursor, str(info), 0) return def info(data): log.info(data) return def debug(info): if IS_WIN: # ~ app = LOApp(self.ctx, self.sm, self.desktop, self.toolkit) # ~ doc = app.getDoc(FILE_NAME_DEBUG) # ~ if not doc: # ~ doc = app.newDoc(WRITER) # ~ out = OutputDoc(doc) # ~ sys.stdout = out # ~ pprint(info) doc = LogWin(new_doc('writer').obj) doc.write(info) return log.debug(str(info)) return def error(info): log.error(info) return def save_log(path, data): with open(path, 'a') as out: out.write('{} -{}- '.format(str(datetime.now())[:19], LOG_NAME)) pprint(data, stream=out) return def run_in_thread(fn): def run(*k, **kw): t = threading.Thread(target=fn, args=k, kwargs=kw) t.start() return t return run def sleep(sec): time.sleep(sec) return def _(msg): L = LANGUAGE.split('-')[0] if L == 'en': return msg if not L in MSG_LANG: return msg return MSG_LANG[L][msg] def msgbox(message, title=TITLE, buttons=MSG_BUTTONS.BUTTONS_OK, type_msg='infobox'): """ Create message box type_msg: infobox, warningbox, errorbox, querybox, messbox 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() mb = toolkit.createMessageBox(parent, type_msg, buttons, title, str(message)) return mb.execute() def question(message, title=TITLE): res = msgbox(message, title, MSG_BUTTONS.BUTTONS_YES_NO, 'querybox') return res == YES def warning(message, title=TITLE): return msgbox(message, title, type_msg='warningbox') def errorbox(message, title=TITLE): return msgbox(message, title, type_msg='errorbox') def get_desktop(): return create_instance('com.sun.star.frame.Desktop', True) def get_dispatch(): return create_instance('com.sun.star.frame.DispatchHelper') def get_temp_file(): delete = True if IS_WIN: delete = False return tempfile.NamedTemporaryFile(delete=delete) def _path_url(path): if path.startswith('file://'): return path return uno.systemPathToFileUrl(path) def _path_system(path): if path.startswith('file://'): return os.path.abspath(uno.fileUrlToSystemPath(path)) return path def exists_app(name): try: dn = subprocess.DEVNULL subprocess.Popen([name, ''], stdout=dn, stderr=dn).terminate() except OSError as e: if e.errno == errno.ENOENT: return False return True def exists(path): return Path(path).exists() def get_type_doc(obj): services = { 'calc': 'com.sun.star.sheet.SpreadsheetDocument', 'writer': 'com.sun.star.text.TextDocument', 'impress': 'com.sun.star.presentation.PresentationDocument', 'draw': 'com.sun.star.drawing.DrawingDocument', 'base': 'com.sun.star.sdb.OfficeDatabaseDocument', 'math': 'com.sun.star.formula.FormulaProperties', 'basic': 'com.sun.star.script.BasicIDE', } for k, v in services.items(): if obj.supportsService(v): return k return '' def _properties(values): p = [PropertyValue(Name=n, Value=v) for n, v in values.items()] return tuple(p) # ~ Custom classes class LODocument(object): def __init__(self, obj): self._obj = obj self._init_values() def _init_values(self): self._type_doc = get_type_doc(self.obj) self._cc = self.obj.getCurrentController() return @property def obj(self): return self._obj @property def type(self): return self._type_doc @property def title(self): return self.obj.getTitle() @property def frame(self): return self._cc.getFrame() @property def is_saved(self): return self.obj.hasLocation() @property def is_modified(self): return self.obj.isModified() @property def is_read_only(self): return self.obj.isReadOnly() @property def path(self): return _path_system(self.obj.getURL()) @property def visible(self): w = self._cc.getFrame().getContainerWindow() return w.Visible @visible.setter def visible(self, value): w = self._cc.getFrame().getContainerWindow() w.setVisible(value) @property def zoom(self): return self._cc.ZoomValue @zoom.setter def zoom(self, value): self._cc.ZoomValue = value def create_instance(self, name): obj = self.obj.createInstance(name) return obj def save(self, path='', **kwargs): opt = _properties(kwargs) if path: self._obj.storeAsURL(_path_url(path), opt) else: self._obj.store() return True def close(self): self.obj.close(True) return def focus(self): w = self._cc.getFrame().getComponentWindow() w.setFocus() return def paste(self): sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard') transferable = sc.getContents() self._cc.insertTransferable(transferable) return self.obj.getCurrentSelection() class LOCalc(LODocument): def __init__(self, obj): super().__init__(obj) @property def obj(self): return self._obj @property def active(self): return LOCalcSheet(self._cc.getActiveSheet(), self) @property def selection(self): sel = self.obj.getCurrentSelection() if sel.ImplementationName in OBJ_TYPE_RANGES: sel = LOCellRange(sel, self) return sel def get_cell(self, index=None): """ index is str 'A1' index is tuple (row, col) """ if index is None: cell = self.selection.first else: cell = LOCellRange(self.active[index].obj, self) return cell def select(self, rango): r = rango if hasattr(rango, 'obj'): r = rango.obj elif isinstance(rango, str): r = self.get_cell(rango).obj self._cc.select(r) return class LOCalcSheet(object): def __init__(self, obj, doc): self._obj = obj self._doc = doc self._init_values() def __getitem__(self, index): return LOCellRange(self.obj[index], self.doc) def _init_values(self): return @property def obj(self): return self._obj @property def doc(self): return self._doc class LOWriter(LODocument): def __init__(self, obj): super().__init__(obj) @property def obj(self): return self._obj @property def string(self): return self._obj.getText().String @property def text(self): return self._obj.getText() @property def cursor(self): return self.text.createTextCursor() @property def selection(self): sel = self._cc.getSelection() return LOTextRange(sel[0]) def insert_content(self, cursor, data, replace=False): self.text.insertTextContent(cursor, data, replace) return # ~ tt = doc.createInstance('com.sun.star.text.TextTable') # ~ tt.initialize(5, 2) # ~ f = doc.createInstance('com.sun.star.text.TextFrame') # ~ f.setSize(Size(10000, 500)) def insert_image(self, path, **kwargs): cursor = kwargs.get('cursor', self.selection.cursor.getEnd()) w = kwargs.get('width', 1000) h = kwargs.get('Height', 1000) image = self.create_instance('com.sun.star.text.GraphicObject') image.GraphicURL = _path_url(path) image.AnchorType = AS_CHARACTER image.Width = w image.Height = h self.insert_content(cursor, image) return class LOTextRange(object): def __init__(self, obj): self._obj = obj @property def obj(self): return self._obj @property def string(self): return self.obj.String @property def text(self): return self.obj.getText() @property def cursor(self): return self.text.createTextCursorByRange(self.obj) class LOBase(LODocument): def __init__(self, obj): super().__init__(obj) class LODrawImpress(LODocument): def __init__(self, obj): super().__init__(obj) @property def draw_page(self): return self._cc.getCurrentPage() @catch_exception def insert_image(self, path, **kwargs): w = kwargs.get('width', 3000) h = kwargs.get('Height', 1000) x = kwargs.get('X', 1000) y = kwargs.get('Y', 1000) image = self.create_instance('com.sun.star.drawing.GraphicObjectShape') image.GraphicURL = _path_url(path) image.Size = Size(w, h) image.Position = Point(x, y) self.draw_page.add(image) return class LOImpress(LODrawImpress): def __init__(self, obj): super().__init__(obj) class LODraw(LODrawImpress): def __init__(self, obj): super().__init__(obj) class LOMath(LODocument): def __init__(self, obj): super().__init__(obj) class LOBasicIde(LODocument): def __init__(self, obj): super().__init__(obj) @property def selection(self): sel = self._cc.getSelection() return sel class LOCellRange(object): def __init__(self, obj, doc): self._obj = obj self._doc = doc self._init_values() def __enter__(self): return self def __exit__(self, *args): pass def __getitem__(self, index): return LOCellRange(self.obj[index], self.doc) def _init_values(self): self._type_obj = self.obj.ImplementationName self._type_content = EMPTY if self._type_obj == OBJ_CELL: self._type_content = self.obj.getType() return @property def obj(self): return self._obj @property def doc(self): return self._doc @property def type(self): return self._type_obj @property def type_content(self): return self._type_content @property def first(self): if self.type == OBJ_RANGES: obj = LOCellRange(self.obj[0][0,0], self.doc) else: obj = LOCellRange(self.obj[0,0], self.doc) return obj @property def value(self): v = None if self._type_content == VALUE: v = self.obj.getValue() elif self._type_content == TEXT: v = self.obj.getString() elif self._type_content == FORMULA: v = self.obj.getFormula() return v @value.setter def value(self, data): if isinstance(data, str): if data.startswith('='): self.obj.setFormula(data) else: self.obj.setString(data) elif isinstance(data, (int, float)): self.obj.setValue(data) @property def data(self): return self.obj.getDataArray() @data.setter def data(self, values): if isinstance(values, list): values = tuple(values) self.obj.setDataArray(values) def offset(self, col=1, row=0): a = self.address col = a.Column + col row = a.Row + row return LOCellRange(self.sheet[row,col], self.doc) @property def sheet(self): return self.obj.Spreadsheet @property def draw_page(self): return self.sheet.getDrawPage() @property def name(self): return self.obj.AbsoluteName @property def address(self): if self._type_obj == OBJ_CELL: a = self.obj.getCellAddress() elif self._type_obj == OBJ_RANGE: a = self.obj.getRangeAddress() else: a = self.obj.getRangeAddressesAsString() return a @property def current_region(self): cursor = self.sheet.createCursorByRange(self.obj[0,0]) cursor.collapseToCurrentRegion() return LOCellRange(self.sheet[cursor.AbsoluteName], self.doc) def insert_image(self, path, **kwargs): s = self.obj.Size w = kwargs.get('width', s.Width) h = kwargs.get('Height', s.Height) img = self.doc.create_instance('com.sun.star.drawing.GraphicObjectShape') img.GraphicURL = _path_url(path) self.draw_page.add(img) img.Anchor = self.obj img.setSize(Size(w, h)) return def select(self): self.doc._cc.select(self.obj) return class EventsListenerBase(unohelper.Base, XEventListener): def __init__(self, controller, window=None): self._controller = controller self._window = window def disposing(self, event): self._controller = None if not self._window is None: self._window.setMenuBar(None) class EventsButton(EventsListenerBase, XActionListener): def __init__(self, controller): super().__init__(controller) def actionPerformed(self, event): name = event.Source.Model.Name event_name = '{}_action'.format(name) if hasattr(self._controller, event_name): getattr(self._controller, event_name)(event) return class EventsMouse(EventsListenerBase, XMouseListener): def __init__(self, controller): super().__init__(controller) def mousePressed(self, event): name = event.Source.Model.Name event_name = '{}_click'.format(name) if event.ClickCount == 2: event_name = '{}_double_click'.format(name) if hasattr(self._controller, event_name): getattr(self._controller, event_name)(event) return def mouseReleased(self, event): pass def mouseEntered(self, event): pass def mouseExited(self, event): pass class UnoBaseObject(object): def __init__(self, obj): self._obj = obj self._model = self.obj.Model self._rules = {} @property def obj(self): return self._obj @property def model(self): return self._model @property def name(self): return self.model.Name @property def parent(self): return self.obj.getContext() @property def x(self): return self.model.PositionX @x.setter def x(self, value): self.model.PositionX = value @property def y(self): return self.model.PositionY @y.setter def y(self, value): self.model.PositionY = value @property def width(self): return self._model.Width @width.setter def width(self, value): self._model.Width = value @property def height(self): return self._model.Height @height.setter def height(self, value): self._model.Height = value @property def tag(self): return self.model.Tag @tag.setter def tag(self, value): self.model.Tag = value @property def step(self): return self.model.Step @step.setter def step(self, value): self.model.Step = value @property def rules(self): return self._rules @rules.setter def rules(self, value): self._rules = value def set_focus(self): self.obj.setFocus() return def center(self, horizontal=True, vertical=False): p = self.parent.Model w = p.Width h = p.Height if horizontal: x = w / 2 - self.width / 2 self.x = x if vertical: y = h / 2 - self.height / 2 self.y = y return def move(self, origin, x=0, y=5): w = 0 h = 0 if x: w = origin.width if y: h = origin.height x = origin.x + x + w y = origin.y + y + h self.x = x self.y = y return class UnoLabel(UnoBaseObject): def __init__(self, obj): super().__init__(obj) @property def value(self): return self.model.Label @value.setter def value(self, value): self.model.Label = value class UnoButton(UnoBaseObject): def __init__(self, obj): super().__init__(obj) # ~ self._set_icon() def _set_icon(self): icon_name = self.tag.strip() if icon_name: path_icon = _file_url('{}/img/{}'.format(CURRENT_PATH, icon_name)) self._model.ImageURL = path_icon if self.value: self._model.ImageAlign = 0 return @property def value(self): return self.model.Label @value.setter def value(self, value): self.model.Label = value class UnoText(UnoBaseObject): def __init__(self, obj): super().__init__(obj) @property def value(self): return self.model.Text @value.setter def value(self, value): self.model.Text = value def validate(self): return class UnoListBox(UnoBaseObject): def __init__(self, obj): super().__init__(obj) self._data = [] @property def value(self): return self.obj.SelectedItem @property def data(self): return self._data @data.setter def data(self, values): self._data = list(sorted(values)) self.model.StringItemList = self.data return class LODialog(object): def __init__(self, properties): self._obj = self._create(properties) self._init_values() def _init_values(self): self._model = self._obj.Model self._init_controls() self._events = None # ~ self._response = None return def _create(self, properties): path = properties.pop('Path', '') if path: dp = create_instance('com.sun.star.awt.DialogProvider2', True) return dp.createDialog(_path_url(path)) if 'Library' in properties: location = properties['Location'] if location == 'user': location = 'application' dp = create_instance('com.sun.star.awt.DialogProvider2', True) path = 'vnd.sun.star.script:{}.{}?location={}'.format( properties['Library'], properties['Name'], location) return dp.createDialog(path) dlg = create_instance('com.sun.star.awt.UnoControlDialog', True) model = create_instance('com.sun.star.awt.UnoControlDialogModel', True) toolkit = create_instance('com.sun.star.awt.Toolkit', True) set_properties(model, properties) dlg.setModel(model) dlg.setVisible(False) dlg.createPeer(toolkit, None) return dlg def _init_controls(self): return @property def obj(self): return self._obj @property def model(self): return self._model @property def events(self): return self._events @events.setter def events(self, controllers): self._events = controllers self._connect_listeners() def _connect_listeners(self): return def _add_listeners(self, control): if self.events is None: return listeners = { 'addActionListener': EventsButton, 'addMouseListener': EventsMouse, } for key, value in listeners.items(): if hasattr(control.obj, key): getattr(control.obj, key)(listeners[key](self.events)) return def open(self): return self.obj.execute() def close(self, value=0): return self.obj.endDialog(value) def _get_control_model(self, control): services = { 'label': 'com.sun.star.awt.UnoControlFixedTextModel', 'button': 'com.sun.star.awt.UnoControlButtonModel', 'text': 'com.sun.star.awt.UnoControlEditModel', 'listbox': 'com.sun.star.awt.UnoControlListBoxModel', 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel', 'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel', 'image': 'com.sun.star.awt.UnoControlImageControlModel', 'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel', 'radio': 'com.sun.star.awt.UnoControlRadioButtonModel', 'tree': 'com.sun.star.awt.tree.TreeControlModel', 'grid': 'com.sun.star.awt.grid.UnoControlGridModel', } return services[control] def _get_custom_class(self, tipo, obj): classes = { 'label': UnoLabel, 'button': UnoButton, 'text': UnoText, 'listbox': UnoListBox, # ~ 'link': UnoLink, # ~ 'tab': UnoTab, # ~ 'roadmap': UnoRoadmap, # ~ 'image': UnoImage, # ~ 'radio': UnoRadio, # ~ 'groupbox': UnoGroupBox, # ~ 'tree': UnoTree, # ~ 'grid': UnoGrid, } return classes[tipo](obj) @catch_exception def add_control(self, properties): tipo = properties.pop('Type').lower() model = self.model.createInstance(self._get_control_model(tipo)) set_properties(model, properties) name = properties['Name'] self.model.insertByName(name, model) control = self._get_custom_class(tipo, self.obj.getControl(name)) self._add_listeners(control) setattr(self, name, control) return # ~ Python >= 3.7 # ~ def __getattr__(name): def _get_class_doc(obj): classes = { 'calc': LOCalc, 'writer': LOWriter, 'base': LOBase, 'impress': LOImpress, 'draw': LODraw, 'math': LOMath, 'basic': LOBasicIde, } type_doc = get_type_doc(obj) return classes[type_doc](obj) def get_document(): doc = None desktop = get_desktop() try: doc = _get_class_doc(desktop.getCurrentComponent()) except Exception as e: log.error(e) return doc def get_selection(): return get_document().selection def get_cell(*args): if args: index = args if len(index) == 1: index = args[0] cell = get_document().get_cell(index) else: cell = get_selection().first return cell def active_cell(): return get_cell() def create_dialog(properties): return LODialog(properties) def set_properties(model, properties): if 'X' in properties: properties['PositionX'] = properties.pop('X') if 'Y' in properties: properties['PositionY'] = properties.pop('Y') keys = tuple(properties.keys()) values = tuple(properties.values()) model.setPropertyValues(keys, values) return def get_file(filters=(), multiple=False): file_picker = create_instance('com.sun.star.ui.dialogs.FilePicker') file_picker.setTitle(_('Select file')) file_picker.setMultiSelectionMode(multiple) if filters: file_picker.setCurrentFilter(filters[0][0]) for f in filters: file_picker.appendFilter(f[0], f[1]) if file_picker.execute(): if multiple: return [_path_system(f) for f in file_picker.getSelectedFiles()] return _path_system(file_picker.getSelectedFiles()[0]) return '' def get_info_path(path): path, filename = os.path.split(path) name, extension = os.path.splitext(filename) return (path, filename, name, extension) def inputbox(message, default='', title=TITLE): class ControllersInput(object): def __init__(self, dlg): self.d = dlg def cmd_ok_action(self, event): self.d.close(1) return args = { 'Title': title, 'Width': 200, 'Height': 80, } dlg = LODialog(args) dlg.events = ControllersInput(dlg) args = { 'Type': 'Label', 'Name': 'lbl_msg', 'Label': message, 'Width': 140, 'Height': 50, 'X': 5, 'Y': 5, 'MultiLine': True, 'Border': 1, } dlg.add_control(args) args = { 'Type': 'Text', 'Name': 'txt_value', 'Text': default, 'Width': 190, 'Height': 15, } dlg.add_control(args) dlg.txt_value.move(dlg.lbl_msg) args = { 'Type': 'button', 'Name': 'cmd_ok', 'Label': _('OK'), 'Width': 40, 'Height': 15, 'DefaultButton': True, 'PushButtonType': 1, } dlg.add_control(args) dlg.cmd_ok.move(dlg.lbl_msg, 10, 0) args = { 'Type': 'button', 'Name': 'cmd_cancel', 'Label': _('Cancel'), 'Width': 40, 'Height': 15, 'PushButtonType': 2, } dlg.add_control(args) dlg.cmd_cancel.move(dlg.cmd_ok) if dlg.open(): return dlg.txt_value.value return '' def new_doc(type_doc=CALC): path = 'private:factory/s{}'.format(type_doc) doc = get_desktop().loadComponentFromURL(path, '_default', 0, ()) return _get_class_doc(doc) def open_doc(path, **kwargs): """ Open document in path Usually options: Hidden: True or False AsTemplate: True or False ReadOnly: True or False Password: super_secret MacroExecutionMode: 4 = Activate macros Preview: True or False http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1frame_1_1XComponentLoader.html http://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1document_1_1MediaDescriptor.html """ path = _path_url(path) opt = _properties(kwargs) doc = get_desktop().loadComponentFromURL(path, '_blank', 0, opt) if doc is None: return return _get_class_doc(doc) def open_file(path): if IS_WIN: os.startfile(path) else: subprocess.Popen(['xdg-open', path]) return def join(*paths): return os.path.join(*paths) def is_dir(path): return Path(path).is_dir() def is_file(path): return Path(path).is_file() def get_file_size(path): return Path(path).stat().st_size def is_created(path): return is_file(path) and bool(get_file_size(path)) def replace_ext(path, ext): path, _, name, _ = get_info_path(path) return '{}/{}.{}'.format(path, name, ext) def zip_names(path): with zipfile.ZipFile(path) as z: names = z.namelist() return names def run(command, wait=False): # ~ debug(command) # ~ debug(shlex.split(command)) try: if wait: # ~ p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) # ~ p.wait() result = subprocess.check_output(command, shell=True) else: p = subprocess.Popen(shlex.split(command), stdin=None, stdout=None, stderr=None, close_fds=True) result, er = p.communicate() except subprocess.CalledProcessError as e: msg = ("run [ERROR]: output = %s, error code = %s\n" % (e.output, e.returncode)) error(msg) return False if result is None: return True return result.decode() def _zippwd(source, target, pwd): if IS_WIN: return False if not exists_app('zip'): return False cmd = 'zip' opt = '-j ' args = "{} --password {} ".format(cmd, pwd) if isinstance(source, (tuple, list)): if not target: return False args += opt + target + ' ' + ' '.join(source) else: if is_file(source) and not target: target = replace_ext(source, 'zip') elif is_dir(source) and not target: target = join(PurePath(source).parent, '{}.zip'.format(PurePath(source).name)) opt = '-r ' args += opt + target + ' ' + source result = run(args, True) if not result: return False return is_created(target) def zip(source, target='', mode='w', pwd=''): if pwd: return _zippwd(source, target, pwd) if isinstance(source, (tuple, list)): if not target: return False with zipfile.ZipFile(target, mode, compression=zipfile.ZIP_DEFLATED) as z: for path in source: _, name, _, _ = get_info_path(path) z.write(path, name) return is_created(target) if is_file(source): if not target: target = replace_ext(source, 'zip') z = zipfile.ZipFile(target, mode, compression=zipfile.ZIP_DEFLATED) _, name, _, _ = get_info_path(source) z.write(source, name) z.close() return is_created(target) if not target: target = join( PurePath(source).parent, '{}.zip'.format(PurePath(source).name)) z = zipfile.ZipFile(target, mode, compression=zipfile.ZIP_DEFLATED) root_len = len(os.path.abspath(source)) for root, dirs, files in os.walk(source): relative = os.path.abspath(root)[root_len:] for f in files: fullpath = join(root, f) file_name = join(relative, f) z.write(fullpath, file_name) z.close() return is_created(target) def unzip(source, path='', members=None, pwd=None): if not path: path, _, _, _ = get_info_path(source) with zipfile.ZipFile(source) as z: if not pwd is None: pwd = pwd.encode() if isinstance(members, str): members = (members,) z.extractall(path, members=members, pwd=pwd) return True def merge_zip(target, zips): try: with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED) as t: for path in zips: with zipfile.ZipFile(path, compression=zipfile.ZIP_DEFLATED) as s: for name in s.namelist(): t.writestr(name, s.open(name).read()) except Exception as e: error(e) return False return True def kill(path): p = Path(path) if p.is_file(): try: p.unlink() except: pass elif p.is_dir(): p.rmdir() return def get_size_screen(): if IS_WIN: user32 = ctypes.windll.user32 res = '{}x{}'.format(user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)) else: args = 'xrandr | grep "*" | cut -d " " -f4' res = run(args, True) return res.strip() def get_clipboard(): df = None text = '' sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard') transferable = sc.getContents() data = transferable.getTransferDataFlavors() for df in data: if df.MimeType == CLIPBOARD_FORMAT_TEXT: break if df: text = transferable.getTransferData(df) return text class TextTransferable(unohelper.Base, XTransferable): """Keep clipboard data and provide them.""" def __init__(self, text): df = DataFlavor() df.MimeType = CLIPBOARD_FORMAT_TEXT df.HumanPresentableName = "encoded text utf-16" self.flavors = [df] self.data = [text] def getTransferData(self, flavor): if not flavor: return for i, f in enumerate(self.flavors): if flavor.MimeType == f.MimeType: return self.data[i] return def getTransferDataFlavors(self): return tuple(self.flavors) def isDataFlavorSupported(self, flavor): if not flavor: return False mtype = flavor.MimeType for f in self.flavors: if mtype == f.MimeType: return True return False def set_clipboard(text): ts = TextTransferable(text) sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard') sc.setContents(ts, None) return def copy(doc=None): if doc is None: doc = get_document() if hasattr(doc, 'frame'): frame = doc.frame else: frame = doc.getCurrentController().getFrame() dispatch = get_dispatch() dispatch.executeDispatch(frame, '.uno:Copy', '', 0, ()) return def get_epoch(): now = datetime.datetime.now() return int(time.mktime(now.timetuple()))