Add support for spanish

This commit is contained in:
Mauricio Baeza 2019-10-28 22:15:02 -06:00
commit d93665355f
14 changed files with 1594 additions and 111 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
*.po~
*.log *.log
images/ images/

View File

@ -1,2 +1,2 @@
0.1.0 0.2.0

View File

@ -26,7 +26,7 @@ import logging
TYPE_EXTENSION = 1 TYPE_EXTENSION = 1
# ~ https://semver.org/ # ~ https://semver.org/
VERSION = '0.1.0' VERSION = '0.2.0'
# ~ Your great extension name, not used spaces # ~ Your great extension name, not used spaces
NAME = 'ZAZPip' NAME = 'ZAZPip'
@ -207,6 +207,8 @@ PATHS = {
'soffice': ('soffice', PROGRAM, FILE_TEST), 'soffice': ('soffice', PROGRAM, FILE_TEST),
'install': ('unopkg', 'add', '-v', '-f', '-s'), 'install': ('unopkg', 'add', '-v', '-f', '-s'),
'profile': '/home/mau/.config/libreoffice/4/user', 'profile': '/home/mau/.config/libreoffice/4/user',
'gettext': PATH_PYGETTEXT,
'msgmerge': PATH_MSGMERGE,
} }

File diff suppressed because it is too large Load Diff

BIN
files/ZAZPip_v0.2.0.oxt Normal file

Binary file not shown.

View File

@ -1,10 +1,8 @@
import uno import uno
import unohelper import unohelper
import os
from com.sun.star.task import XJobExecutor from com.sun.star.task import XJobExecutor
import easymacro as app import easymacro as app
import site
ID_EXTENSION = 'net.elmau.zaz.pip' ID_EXTENSION = 'net.elmau.zaz.pip'
SERVICE = ('com.sun.star.task.Job',) SERVICE = ('com.sun.star.task.Job',)
@ -21,11 +19,7 @@ PACKAGES = {
} }
# ~ sudoPassword = 'mypass' _ = app.install_locales(__file__)
# ~ command = 'mount -t vboxsf myfolder /home/myuser/myfolder'.split()
# ~ cmd1 = subprocess.Popen(['echo',sudoPassword], stdout=subprocess.PIPE)
# ~ cmd2 = subprocess.Popen(['sudo','-S'] + command, stdin=cmd1.stdout, stdout=subprocess.PIPE)
# ~ output = cmd2.stdout.read.decode()
class Controllers(object): class Controllers(object):
@ -52,7 +46,7 @@ class Controllers(object):
return return
def cmd_install_pip_action(self, event): def cmd_install_pip_action(self, event):
msg = 'Do you want install PIP?' msg = _('Do you want install PIP?')
if not app.question(msg, 'ZAZ-Pip'): if not app.question(msg, 'ZAZ-Pip'):
return return
@ -70,20 +64,20 @@ class Controllers(object):
self.d.lst_log.insert('Download PIP...') self.d.lst_log.insert('Download PIP...')
data = app.url_open(URL_PIP) data = app.url_open(URL_PIP)
if not data: if not data:
msg = 'Do you have internet connection?' msg = _('Do you have internet connection?')
app.errorbox(msg) app.errorbox(msg)
return return
app.save_file(path_pip, 'wb', data) app.save_file(path_pip, 'wb', data)
if not app.is_created(path_pip): if not app.is_created(path_pip):
msg = 'File PIP not save' msg = _('File PIP not save')
app.errorbox(msg) app.errorbox(msg)
return return
self.d.lst_log.insert('PIP save correctly...') self.d.lst_log.insert(_('PIP save correctly...'))
try: try:
self.d.lst_log.insert('Start installing PIP...') self.d.lst_log.insert(_('Start installing PIP...'))
cmd = '"{}" "{}" --user'.format(self.path_python, path_pip) cmd = '"{}" "{}" --user'.format(self.path_python, path_pip)
for line in app.popen(cmd): for line in app.popen(cmd):
if isinstance(line, tuple): if isinstance(line, tuple):
@ -97,10 +91,10 @@ class Controllers(object):
self.d.lbl_pip.value = label self.d.lbl_pip.value = label
self.d.cmd_install_pip.visible = False self.d.cmd_install_pip.visible = False
self.d.cmd_admin_pip.visible = True self.d.cmd_admin_pip.visible = True
msg = 'PIP installed sucesfully' msg = _('PIP installed sucesfully')
app.msgbox(msg) app.msgbox(msg)
else: else:
msg = 'PIP not installed, see log.' msg = _('PIP not installed, see log')
app.warning(msg) app.warning(msg)
except Exception as e: except Exception as e:
app.errorbox(e) app.errorbox(e)
@ -120,7 +114,6 @@ class Controllers(object):
self.cmd_home_action(None) self.cmd_home_action(None)
return return
@app.catch_exception
def cmd_close_action(self, event): def cmd_close_action(self, event):
self.d.close() self.d.close()
return return
@ -176,7 +169,7 @@ class Controllers(object):
if line: if line:
self.d.lst_package.select() self.d.lst_package.select()
else: else:
self.d.lst_package.insert('Not found...', 'error.png', show=False) self.d.lst_package.insert(_('Not found...'), 'error.png', show=False)
return return
def cmd_search_action(self, event): def cmd_search_action(self, event):
@ -212,7 +205,7 @@ class Controllers(object):
opt = 'upgrade' opt = 'upgrade'
name = self.d.lst_package.value name = self.d.lst_package.value
msg = 'Do you want {}:\n\n{} ?'.format(opt, name) msg = _('Do you want {}:\n\n{} ?').format(opt, name)
if not app.question(msg, TITLE): if not app.question(msg, TITLE):
return return
@ -238,12 +231,12 @@ class Controllers(object):
def cmd_uninstall_action(self, event): def cmd_uninstall_action(self, event):
if not self._states['list']: if not self._states['list']:
msg = 'Select installed package' msg = _('Select installed package')
app.warning(msg) app.warning(msg)
return return
name = self.d.lst_package.value name = self.d.lst_package.value
msg = 'Do you want uninstall:\n\n{} ?'.format(name) msg = _('Do you want uninstall:\n\n{} ?').format(name)
if not app.question(msg): if not app.question(msg):
return return
@ -254,13 +247,13 @@ class Controllers(object):
def cmd_shell_action(self, name): def cmd_shell_action(self, name):
if app.IS_WIN: if app.IS_WIN:
cmd = '"{}"'.format(self.path_python) cmd = '"{}"'.format(self.path_python)
os.startfile(cmd) app.open_file(cmd)
else: else:
if app.DESKTOP == 'gnome': if app.DESKTOP == 'gnome':
cmd = 'gnome-terminal -- {}'.format(self.path_python) cmd = 'gnome-terminal -- {}'.format(self.path_python)
else: else:
cmd = 'exec {}'.format(self.path_python) cmd = 'exec {}'.format(self.path_python)
os.system(cmd) app.run(cmd)
return return
@ -277,7 +270,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
def _create_dialog(self): def _create_dialog(self):
args= { args= {
'Name': 'dialog', 'Name': 'dialog',
'Title': 'ZAZ-Pip', 'Title': 'ZAZ-PIP',
'Width': 200, 'Width': 200,
'Height': 220, 'Height': 220,
} }
@ -288,7 +281,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
args = { args = {
'Type': 'Label', 'Type': 'Label',
'Name': 'lbl_title', 'Name': 'lbl_title',
'Label': 'ZAZ Pip', 'Label': 'ZAZ PIP',
'Width': 50, 'Width': 50,
'Height': 15, 'Height': 15,
'Border': 1, 'Border': 1,
@ -330,7 +323,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
exists_pip = True exists_pip = True
if not label: if not label:
exists_pip = False exists_pip = False
label = 'PIP not installed' label = _('PIP not installed')
args = { args = {
'Type': 'Label', 'Type': 'Label',
'Name': 'lbl_pip', 'Name': 'lbl_pip',
@ -349,7 +342,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
args = { args = {
'Type': 'Button', 'Type': 'Button',
'Name': 'cmd_admin_pip', 'Name': 'cmd_admin_pip',
'Label': 'Admin PIP', 'Label': _('Admin PIP'),
'Width': 60, 'Width': 60,
'Height': 18, 'Height': 18,
'Step': 10, 'Step': 10,
@ -362,7 +355,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
args = { args = {
'Type': 'Button', 'Type': 'Button',
'Name': 'cmd_install_pip', 'Name': 'cmd_install_pip',
'Label': 'Install PIP', 'Label': _('Install PIP'),
'Width': 60, 'Width': 60,
'Height': 18, 'Height': 18,
'Step': 10, 'Step': 10,
@ -400,7 +393,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
args = { args = {
'Type': 'Label', 'Type': 'Label',
'Name': 'lbl_package', 'Name': 'lbl_package',
'Label': 'Packages', 'Label': _('Packages'),
'Width': 100, 'Width': 100,
'Height': 15, 'Height': 15,
'Border': 1, 'Border': 1,
@ -432,7 +425,7 @@ class ZAZPip(unohelper.Base, XJobExecutor):
args = { args = {
'Type': 'Button', 'Type': 'Button',
'Name': 'cmd_close', 'Name': 'cmd_close',
'Label': '~Close', 'Label': _('~Close'),
'Width': 60, 'Width': 60,
'Height': 18, 'Height': 18,
'Step': 1, 'Step': 1,

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<description xmlns="http://openoffice.org/extensions/description/2006" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:d="http://openoffice.org/extensions/description/2006"> <description xmlns="http://openoffice.org/extensions/description/2006" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:d="http://openoffice.org/extensions/description/2006">
<identifier value="net.elmau.zaz.pip" /> <identifier value="net.elmau.zaz.pip" />
<version value="0.1.0" /> <version value="0.2.0" />
<display-name> <display-name>
<name lang="en">ZAZ Pip</name> <name lang="en">ZAZ Pip</name>
<name lang="es">ZAZ Pip</name> <name lang="es">ZAZ Pip</name>

87
source/locales/base.pot Normal file
View File

@ -0,0 +1,87 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-10-19 15:19-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
#: source/ZAZPip.py:49
msgid "Do you want install PIP?"
msgstr ""
#: source/ZAZPip.py:67
msgid "Do you have internet connection?"
msgstr ""
#: source/ZAZPip.py:73
msgid "File PIP not save"
msgstr ""
#: source/ZAZPip.py:76
msgid "PIP save correctly..."
msgstr ""
#: source/ZAZPip.py:80
msgid "Start installing PIP..."
msgstr ""
#: source/ZAZPip.py:94
msgid "PIP installed sucesfully"
msgstr ""
#: source/ZAZPip.py:97
msgid "PIP not installed, see log"
msgstr ""
#: source/ZAZPip.py:173
msgid "Not found..."
msgstr ""
#: source/ZAZPip.py:209
msgid ""
"Do you want {}:\n"
"\n"
"{} ?"
msgstr ""
#: source/ZAZPip.py:235
msgid "Select installed package"
msgstr ""
#: source/ZAZPip.py:240
msgid ""
"Do you want uninstall:\n"
"\n"
"{} ?"
msgstr ""
#: source/ZAZPip.py:327
msgid "PIP not installed"
msgstr ""
#: source/ZAZPip.py:346
msgid "Admin PIP"
msgstr ""
#: source/ZAZPip.py:359
msgid "Install PIP"
msgstr ""
#: source/ZAZPip.py:397
msgid "Packages"
msgstr ""
#: source/ZAZPip.py:429
msgid "~Close"
msgstr ""

Binary file not shown.

View File

@ -0,0 +1,88 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2019-10-19 15:19-0500\n"
"PO-Revision-Date: 2019-10-19 15:20-0500\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 2.2.4\n"
"Last-Translator: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Language: en\n"
#: source/ZAZPip.py:49
msgid "Do you want install PIP?"
msgstr ""
#: source/ZAZPip.py:67
msgid "Do you have internet connection?"
msgstr ""
#: source/ZAZPip.py:73
msgid "File PIP not save"
msgstr ""
#: source/ZAZPip.py:76
msgid "PIP save correctly..."
msgstr ""
#: source/ZAZPip.py:80
msgid "Start installing PIP..."
msgstr ""
#: source/ZAZPip.py:94
msgid "PIP installed sucesfully"
msgstr ""
#: source/ZAZPip.py:97
msgid "PIP not installed, see log"
msgstr ""
#: source/ZAZPip.py:173
msgid "Not found..."
msgstr ""
#: source/ZAZPip.py:209
msgid ""
"Do you want {}:\n"
"\n"
"{} ?"
msgstr ""
#: source/ZAZPip.py:235
msgid "Select installed package"
msgstr ""
#: source/ZAZPip.py:240
msgid ""
"Do you want uninstall:\n"
"\n"
"{} ?"
msgstr ""
#: source/ZAZPip.py:327
msgid "PIP not installed"
msgstr ""
#: source/ZAZPip.py:346
msgid "Admin PIP"
msgstr ""
#: source/ZAZPip.py:359
msgid "Install PIP"
msgstr ""
#: source/ZAZPip.py:397
msgid "Packages"
msgstr ""
#: source/ZAZPip.py:429
msgid "~Close"
msgstr ""

Binary file not shown.

View File

@ -0,0 +1,94 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2019-10-19 15:19-0500\n"
"PO-Revision-Date: 2019-10-19 15:24-0500\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 2.2.4\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: source/ZAZPip.py:49
msgid "Do you want install PIP?"
msgstr "¿Desea instalar PIP?"
#: source/ZAZPip.py:67
msgid "Do you have internet connection?"
msgstr "¿Tiene conexión a Internet?"
#: source/ZAZPip.py:73
msgid "File PIP not save"
msgstr "No se guardo el archivo PIP"
#: source/ZAZPip.py:76
msgid "PIP save correctly..."
msgstr "Archivo PIP guardado correctamente..."
#: source/ZAZPip.py:80
msgid "Start installing PIP..."
msgstr "Iniciando instalación de PIP..."
#: source/ZAZPip.py:94
msgid "PIP installed sucesfully"
msgstr "PIP instalado correctamente"
#: source/ZAZPip.py:97
msgid "PIP not installed, see log"
msgstr "PIP no fue instalado, vea el registro"
#: source/ZAZPip.py:173
msgid "Not found..."
msgstr "No encontrado..."
#: source/ZAZPip.py:209
msgid ""
"Do you want {}:\n"
"\n"
"{} ?"
msgstr ""
"¿Desea {}:\n"
"\n"
"{} ?"
#: source/ZAZPip.py:235
msgid "Select installed package"
msgstr "Seleccione un paquete instalado"
#: source/ZAZPip.py:240
msgid ""
"Do you want uninstall:\n"
"\n"
"{} ?"
msgstr ""
"¿Desea desinstalar:\n"
"\n"
"{} ?"
#: source/ZAZPip.py:327
msgid "PIP not installed"
msgstr "PIP no esta instalado"
#: source/ZAZPip.py:346
msgid "Admin PIP"
msgstr "Administrar PIP"
#: source/ZAZPip.py:359
msgid "Install PIP"
msgstr "Instalar PIP"
#: source/ZAZPip.py:397
msgid "Packages"
msgstr "Paquetes"
#: source/ZAZPip.py:429
msgid "~Close"
msgstr "~Cerrar"

View File

@ -22,6 +22,7 @@ import csv
import ctypes import ctypes
import datetime import datetime
import errno import errno
import gettext
import getpass import getpass
import hashlib import hashlib
import json import json
@ -40,12 +41,13 @@ import time
import traceback import traceback
import zipfile import zipfile
from collections import OrderedDict # ~ from collections import OrderedDict
from collections.abc import MutableMapping # ~ from collections.abc import MutableMapping
from functools import wraps from functools import wraps
from operator import itemgetter from operator import itemgetter
from pathlib import Path, PurePath from pathlib import Path, PurePath
from pprint import pprint from pprint import pprint
from enum import IntEnum
from urllib.request import Request, urlopen from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError from urllib.error import URLError, HTTPError
from string import Template from string import Template
@ -77,6 +79,7 @@ from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
from com.sun.star.script import ScriptEventDescriptor
from com.sun.star.lang import XEventListener from com.sun.star.lang import XEventListener
from com.sun.star.awt import XActionListener from com.sun.star.awt import XActionListener
from com.sun.star.awt import XMouseListener from com.sun.star.awt import XMouseListener
@ -88,7 +91,15 @@ from com.sun.star.awt import XMenuListener
from com.sun.star.awt import XKeyListener from com.sun.star.awt import XKeyListener
from com.sun.star.awt import XItemListener from com.sun.star.awt import XItemListener
from com.sun.star.awt import XFocusListener from com.sun.star.awt import XFocusListener
from com.sun.star.awt import XTabListener
class FontSlant(IntEnum):
NONE = 0
OBLIQUE = 1
ITALIC = 2
DONTKNOW = 3
REVERSE_OBLIQUE = 4
REVERSE_ITALIC = 5
try: try:
from fernet import Fernet, InvalidToken from fernet import Fernet, InvalidToken
@ -100,6 +111,7 @@ ID_EXTENSION = ''
DIR = { DIR = {
'images': 'images', 'images': 'images',
'locales': 'locales',
} }
KEY = { KEY = {
@ -299,7 +311,6 @@ def info(data):
return return
@catch_exception
def debug(*info): def debug(*info):
if IS_WIN: if IS_WIN:
doc = get_document(FILE_NAME_DEBUG) doc = get_document(FILE_NAME_DEBUG)
@ -334,18 +345,17 @@ def run_in_thread(fn):
return run return run
def now(): def now(only_time=False):
return datetime.datetime.now() now = datetime.datetime.now()
if only_time:
return now.time()
return now
def today(): def today():
return datetime.date.today() return datetime.date.today()
def time():
return datetime.datetime.now().time()
def get_date(year, month, day, hour=-1, minute=-1, second=-1): def get_date(year, month, day, hour=-1, minute=-1, second=-1):
if hour > -1 or minute > -1 or second > -1: if hour > -1 or minute > -1 or second > -1:
h = hour h = hour
@ -598,9 +608,6 @@ class LODocument(object):
def _init_values(self): def _init_values(self):
self._type_doc = get_type_doc(self.obj) self._type_doc = get_type_doc(self.obj)
# ~ if self._type_doc == 'base':
# ~ self._cc = self.obj.DatabaseDocument.getCurrentController()
# ~ else:
self._cc = self.obj.getCurrentController() self._cc = self.obj.getCurrentController()
return return
@ -721,10 +728,117 @@ class LODocument(object):
return path_pdf return path_pdf
class FormControlBase(object):
EVENTS = {
'action': 'actionPerformed',
'click': 'mousePressed',
}
TYPES = {
'actionPerformed': 'XActionListener',
'mousePressed': 'XMouseListener',
}
def __init__(self, obj):
self._obj = obj
self._index = -1
self._rules = {}
@property
def obj(self):
return self._obj
@property
def name(self):
return self.obj.Name
@property
def form(self):
return self.obj.getParent()
@property
def index(self):
return self._index
@index.setter
def index(self, value):
self._index = value
@property
def events(self):
return self.form.getScriptEvents(self.index)
def remove_event(self, name=''):
for ev in self.events:
if name and \
ev.EventMethod == self.EVENTS[name] and \
ev.ListenerType == self.TYPES[ev.EventMethod]:
self.form.revokeScriptEvent(self.index,
ev.ListenerType, ev.EventMethod, ev.AddListenerParam)
break
else:
self.form.revokeScriptEvent(self.index,
ev.ListenerType, ev.EventMethod, ev.AddListenerParam)
return
def add_event(self, name, macro):
if not 'name' in macro:
macro['name'] = '{}_{}'.format(self.name, name)
event = ScriptEventDescriptor()
event.AddListenerParam = ''
event.EventMethod = self.EVENTS[name]
event.ListenerType = self.TYPES[event.EventMethod]
event.ScriptCode = _get_url_script(macro)
event.ScriptType = 'Script'
for ev in self.events:
if ev.EventMethod == event.EventMethod and \
ev.ListenerType == event.ListenerType:
self.form.revokeScriptEvent(self.index,
event.ListenerType, event.EventMethod, event.AddListenerParam)
break
self.form.registerScriptEvent(self.index, event)
return
class FormButton(FormControlBase):
def __init__(self, obj):
super().__init__(obj)
class LOForm(ObjectBase): class LOForm(ObjectBase):
def __init__(self, obj): def __init__(self, obj):
super().__init__(obj) super().__init__(obj)
self._init_controls()
def __getitem__(self, index):
if isinstance(index, int):
return self._controls[index]
else:
return getattr(self, index)
def _get_type_control(self, name):
types = {
# ~ 'stardiv.Toolkit.UnoFixedTextControl': 'label',
'com.sun.star.form.OButtonModel': 'formbutton',
# ~ 'stardiv.Toolkit.UnoEditControl': 'text',
# ~ 'stardiv.Toolkit.UnoRoadmapControl': 'roadmap',
# ~ 'stardiv.Toolkit.UnoFixedHyperlinkControl': 'link',
# ~ 'stardiv.Toolkit.UnoListBoxControl': 'listbox',
}
return types[name]
def _init_controls(self):
self._controls = []
for i, c in enumerate(self.obj.ControlModels):
tipo = self._get_type_control(c.ImplementationName)
control = get_custom_class(tipo, c)
control.index = i
self._controls.append(control)
setattr(self, c.Name, control)
@property @property
def name(self): def name(self):
@ -821,6 +935,67 @@ class LOCellStyles(object):
return return
class LOImage(object):
TYPES = {
'image/png': 'png',
'image/jpeg': 'jpg',
}
def __init__(self, obj):
self._obj = obj
@property
def obj(self):
return self._obj
@property
def address(self):
return self.obj.Anchor.AbsoluteName
@property
def name(self):
return self.obj.Name
@property
def mimetype(self):
return self.obj.Bitmap.MimeType
@property
def url(self):
return _path_system(self.obj.URL)
@url.setter
def url(self, value):
self.obj.URL = _path_url(value)
@property
def path(self):
return _path_system(self.obj.GraphicURL)
@path.setter
def path(self, value):
self.obj.GraphicURL = _path_url(value)
@property
def visible(self):
return self.obj.Visible
@visible.setter
def visible(self, value):
self_obj.Visible = value
def save(self, path):
if is_dir(path):
p = path
n = self.name
else:
p, fn, n, e = get_info_path(path)
ext = self.TYPES[self.mimetype]
path = join(p, '{}.{}'.format(n, ext))
size = len(self.obj.Bitmap.DIB)
data = self.obj.GraphicStream.readBytes((), size)
data = data[-1].value
save_file(path, 'wb', data)
return path
class LOCalc(LODocument): class LOCalc(LODocument):
def __init__(self, obj): def __init__(self, obj):
@ -1069,7 +1244,7 @@ class LOCalcSheet(object):
def _init_values(self): def _init_values(self):
self._events = None self._events = None
self._dp = self.obj.getDrawPage() self._dp = self.obj.getDrawPage()
return self._images = {i.Name: LOImage(i) for i in self._dp}
@property @property
def obj(self): def obj(self):
@ -1079,6 +1254,10 @@ class LOCalcSheet(object):
def doc(self): def doc(self):
return self._doc return self._doc
@property
def images(self):
return self._images
@property @property
def name(self): def name(self):
return self._obj.Name return self._obj.Name
@ -1255,6 +1434,42 @@ class LOWriter(LODocument):
self._cc.select(text) self._cc.select(text)
return return
def search(self, options):
descriptor = self.obj.createSearchDescriptor()
descriptor.setSearchString(options.get('Search', ''))
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
descriptor.SearchWords = options.get('Words', False)
if 'Attributes' in options:
attr = dict_to_property(options['Attributes'])
descriptor.setSearchAttributes(attr)
if hasattr(descriptor, 'SearchRegularExpression'):
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
if hasattr(descriptor, 'SearchType') and 'Type' in options:
descriptor.SearchType = options['Type']
if options.get('First', False):
found = self.obj.findFirst(descriptor)
else:
found = self.obj.findAll(descriptor)
return found
def replace(self, options):
descriptor = self.obj.createReplaceDescriptor()
descriptor.setSearchString(options['Search'])
descriptor.setReplaceString(options['Replace'])
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
descriptor.SearchWords = options.get('Words', False)
if 'Attributes' in options:
attr = dict_to_property(options['Attributes'])
descriptor.setSearchAttributes(attr)
if hasattr(descriptor, 'SearchRegularExpression'):
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
if hasattr(descriptor, 'SearchType') and 'Type' in options:
descriptor.SearchType = options['Type']
found = self.obj.replaceAll(descriptor)
return found
class LOTextRange(object): class LOTextRange(object):
@ -1610,6 +1825,10 @@ class LOCellRange(object):
rango.data = self.data rango.data = self.data
return return
def copy(self, source):
self.sheet.obj.copyRange(self.address, source.range_address)
return
def offset(self, row=1, col=0): def offset(self, row=1, col=0):
ra = self.obj.getRangeAddress() ra = self.obj.getRangeAddress()
col = ra.EndColumn + col col = ra.EndColumn + col
@ -1667,6 +1886,10 @@ class LOCellRange(object):
a = self.obj.getRangeAddressesAsString() a = self.obj.getRangeAddressesAsString()
return a return a
@property
def range_address(self):
return self.obj.getRangeAddress()
@property @property
def current_region(self): def current_region(self):
cursor = self.sheet.get_cursor(self.obj[0,0]) cursor = self.sheet.get_cursor(self.obj[0,0])
@ -1799,6 +2022,36 @@ class LOCellRange(object):
chart.cell = self chart.cell = self
return chart return chart
def search(self, options):
descriptor = self.obj.Spreadsheet.createSearchDescriptor()
descriptor.setSearchString(options.get('Search', ''))
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
descriptor.SearchWords = options.get('Words', False)
if hasattr(descriptor, 'SearchRegularExpression'):
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
if hasattr(descriptor, 'SearchType') and 'Type' in options:
descriptor.SearchType = options['Type']
if options.get('First', False):
found = self.obj.findFirst(descriptor)
else:
found = self.obj.findAll(descriptor)
return found
def replace(self, options):
descriptor = self.obj.Spreadsheet.createReplaceDescriptor()
descriptor.setSearchString(options['Search'])
descriptor.setReplaceString(options['Replace'])
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
descriptor.SearchWords = options.get('Words', False)
if hasattr(descriptor, 'SearchRegularExpression'):
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
if hasattr(descriptor, 'SearchType') and 'Type' in options:
descriptor.SearchType = options['Type']
found = self.obj.replaceAll(descriptor)
return found
class EventsListenerBase(unohelper.Base, XEventListener): class EventsListenerBase(unohelper.Base, XEventListener):
@ -1966,6 +2219,18 @@ class EventsKey(EventsListenerBase, XKeyListener):
return return
class EventsTab(EventsListenerBase, XTabListener):
def __init__(self, controller, name):
super().__init__(controller, name)
def activated(self, id):
event_name = '{}_activated'.format(self.name)
if hasattr(self._controller, event_name):
getattr(self._controller, event_name)(id)
return
class EventsKeyWindow(EventsListenerBase, XKeyListener): class EventsKeyWindow(EventsListenerBase, XKeyListener):
""" """
event.KeyChar event.KeyChar
@ -2067,7 +2332,6 @@ class EventsMenu(EventsListenerBase, XMenuListener):
def itemHighlighted(self, event): def itemHighlighted(self, event):
pass pass
@catch_exception
def itemSelected(self, event): def itemSelected(self, event):
name = event.Source.getCommand(event.MenuId) name = event.Source.getCommand(event.MenuId)
if name.startswith('menu'): if name.startswith('menu'):
@ -2308,7 +2572,7 @@ class UnoListBox(UnoBaseObject):
@property @property
def value(self): def value(self):
return self.obj.SelectedItem return self.obj.getSelectedItem()
@property @property
def count(self): def count(self):
@ -2322,6 +2586,10 @@ class UnoListBox(UnoBaseObject):
self.model.StringItemList = list(sorted(values)) self.model.StringItemList = list(sorted(values))
return return
def unselect(self):
self.obj.selectItem(self.value, False)
return
def select(self, pos=0): def select(self, pos=0):
if isinstance(pos, str): if isinstance(pos, str):
self.obj.selectItem(pos, True) self.obj.selectItem(pos, True)
@ -2330,7 +2598,7 @@ class UnoListBox(UnoBaseObject):
return return
def clear(self): def clear(self):
self.obj.removeItems(0, self.count) self.model.removeAllItems()
return return
def _set_image_url(self, image): def _set_image_url(self, image):
@ -2501,6 +2769,166 @@ class UnoRoadmap(UnoBaseObject):
return return
class UnoTree(UnoBaseObject):
def __init__(self, obj, ):
super().__init__(obj)
self._tdm = None
self._data = []
@property
def selection(self):
return self.obj.Selection
@property
def root(self):
if self._tdm is None:
return ''
return self._tdm.Root.DisplayValue
@root.setter
def root(self, value):
self._add_data_model(value)
def _add_data_model(self, name):
tdm = create_instance('com.sun.star.awt.tree.MutableTreeDataModel')
root = tdm.createNode(name, True)
root.DataValue = 0
tdm.setRoot(root)
self.model.DataModel = tdm
self._tdm = self.model.DataModel
self._add_data()
return
@property
def data(self):
return self._data
@data.setter
def data(self, values):
self._data = list(values)
self._add_data()
def _add_data(self):
if not self.data:
return
parents = {}
for node in self.data:
parent = parents.get(node[1], self._tdm.Root)
child = self._tdm.createNode(node[2], False)
child.DataValue = node[0]
parent.appendChild(child)
parents[node[0]] = child
self.obj.expandNode(self._tdm.Root)
return
class UnoPages(UnoBaseObject):
def __init__(self, obj):
super().__init__(obj)
self._events = None
def __getitem__(self, index):
return self.get_sheet(index)
@property
def current(self):
return self.obj.getActiveTabID()
def get_sheet(self, id):
if isinstance(id, int):
sheet = self.obj.Controls[id-1]
else:
sheet = self.obj.getControl(id.lower())
return sheet
@property
def sheets(self):
return self._sheets
@sheets.setter
def sheets(self, values):
i = len(self.obj.Controls)
for title in values:
i += 1
sheet = self.model.createInstance('com.sun.star.awt.UnoPageModel')
sheet.Title = title
self.model.insertByName('sheet{}'.format(i), sheet)
return
def insert(self, title):
id = len(self.obj.Controls) + 1
sheet = self.model.createInstance('com.sun.star.awt.UnoPageModel')
sheet.Title = title
self.model.insertByName('sheet{}'.format(id), sheet)
return id
def remove(self, id):
sheet = self.get_sheet(id)
for control in sheet.getControls():
sheet.Model.removeByName(control.Model.Name)
sheet.removeControl(control)
# ~ self._model.removeByName('page_{}'.format(ID))
self.obj.removeTab(id)
return
def activate(self, id):
self.obj.activateTab(id)
return
@property
def events(self):
return self._events
@events.setter
def events(self, controllers):
self._events = controllers
def _special_properties(self, tipo, properties):
columns = properties.pop('Columns', ())
if tipo == 'grid':
properties['ColumnModel'] = self._set_column_model(columns)
elif tipo == 'button' and 'ImageURL' in properties:
properties['ImageURL'] = self._set_image_url(properties['ImageURL'])
elif tipo == 'roadmap':
if not 'Height' in properties:
properties['Height'] = self.height
if 'Title' in properties:
properties['Text'] = properties.pop('Title')
elif tipo == 'pages':
if not 'Width' in properties:
properties['Width'] = self.width
if not 'Height' in properties:
properties['Height'] = self.height
return properties
def add_control(self, id, properties):
tipo = properties.pop('Type').lower()
root = properties.pop('Root', '')
sheets = properties.pop('Sheets', ())
properties = self._special_properties(tipo, properties)
sheet = self.get_sheet(id)
sheet_model = sheet.getModel()
model = sheet_model.createInstance(get_control_model(tipo))
set_properties(model, properties)
name = properties['Name']
sheet_model.insertByName(name, model)
control = sheet.getControl(name)
add_listeners(self.events, control, name)
control = get_custom_class(tipo, control)
if tipo == 'tree' and root:
control.root = root
elif tipo == 'pages' and sheets:
control.sheets = sheets
setattr(self, name, control)
return
def get_custom_class(tipo, obj): def get_custom_class(tipo, obj):
classes = { classes = {
'label': UnoLabel, 'label': UnoLabel,
@ -2510,15 +2938,34 @@ def get_custom_class(tipo, obj):
'grid': UnoGrid, 'grid': UnoGrid,
'link': UnoLabelLink, 'link': UnoLabelLink,
'roadmap': UnoRoadmap, 'roadmap': UnoRoadmap,
# ~ 'tab': UnoTab, 'tree': UnoTree,
'pages': UnoPages,
# ~ 'image': UnoImage, # ~ 'image': UnoImage,
# ~ 'radio': UnoRadio, # ~ 'radio': UnoRadio,
# ~ 'groupbox': UnoGroupBox, # ~ 'groupbox': UnoGroupBox,
# ~ 'tree': UnoTree, 'formbutton': FormButton,
} }
return classes[tipo](obj) return classes[tipo](obj)
def get_control_model(control):
services = {
'label': 'com.sun.star.awt.UnoControlFixedTextModel',
'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
'text': 'com.sun.star.awt.UnoControlEditModel',
'listbox': 'com.sun.star.awt.UnoControlListBoxModel',
'button': 'com.sun.star.awt.UnoControlButtonModel',
'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel',
'grid': 'com.sun.star.awt.grid.UnoControlGridModel',
'tree': 'com.sun.star.awt.tree.TreeControlModel',
'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel',
'image': 'com.sun.star.awt.UnoControlImageControlModel',
'radio': 'com.sun.star.awt.UnoControlRadioButtonModel',
'pages': 'com.sun.star.awt.UnoMultiPageModel',
}
return services[control]
def add_listeners(events, control, name=''): def add_listeners(events, control, name=''):
listeners = { listeners = {
'addActionListener': EventsButton, 'addActionListener': EventsButton,
@ -2526,6 +2973,7 @@ def add_listeners(events, control, name=''):
'addItemListener': EventsItem, 'addItemListener': EventsItem,
'addFocusListener': EventsFocus, 'addFocusListener': EventsFocus,
'addKeyListener': EventsKey, 'addKeyListener': EventsKey,
'addTabListener': EventsTab,
} }
if hasattr(control, 'obj'): if hasattr(control, 'obj'):
control = contro.obj control = contro.obj
@ -3035,11 +3483,12 @@ class LODialog(object):
def _get_type_control(self, name): def _get_type_control(self, name):
types = { types = {
'stardiv.Toolkit.UnoFixedTextControl': 'label', 'stardiv.Toolkit.UnoFixedTextControl': 'label',
'stardiv.Toolkit.UnoButtonControl': 'button',
'stardiv.Toolkit.UnoEditControl': 'text',
'stardiv.Toolkit.UnoRoadmapControl': 'roadmap',
'stardiv.Toolkit.UnoFixedHyperlinkControl': 'link', 'stardiv.Toolkit.UnoFixedHyperlinkControl': 'link',
'stardiv.Toolkit.UnoEditControl': 'text',
'stardiv.Toolkit.UnoButtonControl': 'button',
'stardiv.Toolkit.UnoListBoxControl': 'listbox', 'stardiv.Toolkit.UnoListBoxControl': 'listbox',
'stardiv.Toolkit.UnoRoadmapControl': 'roadmap',
'stardiv.Toolkit.UnoMultiPageControl': 'pages',
} }
return types[name] return types[name]
@ -3126,17 +3575,18 @@ class LODialog(object):
def _get_control_model(self, control): def _get_control_model(self, control):
services = { services = {
'button': 'com.sun.star.awt.UnoControlButtonModel',
'grid': 'com.sun.star.awt.grid.UnoControlGridModel',
'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel',
'image': 'com.sun.star.awt.UnoControlImageControlModel',
'label': 'com.sun.star.awt.UnoControlFixedTextModel', 'label': 'com.sun.star.awt.UnoControlFixedTextModel',
'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel', 'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
'listbox': 'com.sun.star.awt.UnoControlListBoxModel',
'radio': 'com.sun.star.awt.UnoControlRadioButtonModel',
'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel',
'text': 'com.sun.star.awt.UnoControlEditModel', 'text': 'com.sun.star.awt.UnoControlEditModel',
'listbox': 'com.sun.star.awt.UnoControlListBoxModel',
'button': 'com.sun.star.awt.UnoControlButtonModel',
'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel',
'grid': 'com.sun.star.awt.grid.UnoControlGridModel',
'tree': 'com.sun.star.awt.tree.TreeControlModel', 'tree': 'com.sun.star.awt.tree.TreeControlModel',
'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel',
'image': 'com.sun.star.awt.UnoControlImageControlModel',
'radio': 'com.sun.star.awt.UnoControlRadioButtonModel',
'pages': 'com.sun.star.awt.UnoMultiPageModel',
} }
return services[control] return services[control]
@ -3172,10 +3622,19 @@ class LODialog(object):
properties['Height'] = self.height properties['Height'] = self.height
if 'Title' in properties: if 'Title' in properties:
properties['Text'] = properties.pop('Title') properties['Text'] = properties.pop('Title')
elif tipo == 'pages':
if not 'Width' in properties:
properties['Width'] = self.width
if not 'Height' in properties:
properties['Height'] = self.height
return properties return properties
def add_control(self, properties): def add_control(self, properties):
tipo = properties.pop('Type').lower() tipo = properties.pop('Type').lower()
root = properties.pop('Root', '')
sheets = properties.pop('Sheets', ())
properties = self._special_properties(tipo, properties) properties = self._special_properties(tipo, properties)
model = self.model.createInstance(self._get_control_model(tipo)) model = self.model.createInstance(self._get_control_model(tipo))
set_properties(model, properties) set_properties(model, properties)
@ -3184,6 +3643,13 @@ class LODialog(object):
control = self.obj.getControl(name) control = self.obj.getControl(name)
add_listeners(self.events, control, name) add_listeners(self.events, control, name)
control = get_custom_class(tipo, control) control = get_custom_class(tipo, control)
if tipo == 'tree' and root:
control.root = root
elif tipo == 'pages' and sheets:
control.sheets = sheets
control.events = self.events
setattr(self, name, control) setattr(self, name, control)
return return
@ -3402,7 +3868,7 @@ def get_document(title=''):
return doc return doc
for d in desktop.getComponents(): for d in desktop.getComponents():
if d.Title == title: if hasattr(d, 'Title') and d.Title == title:
doc = d doc = d
break break
@ -3595,6 +4061,10 @@ def get_path_extension(id):
return path return path
def get_home():
return Path.home()
# ~ Export ok # ~ Export ok
def inputbox(message, default='', title=TITLE, echochar=''): def inputbox(message, default='', title=TITLE, echochar=''):
@ -3789,6 +4259,7 @@ def url_open(url, options={}, json=False):
req = Request(url) req = Request(url)
try: try:
response = urlopen(req) response = urlopen(req)
# ~ response.info()
except HTTPError as e: except HTTPError as e:
error(e) error(e)
except URLError as e: except URLError as e:
@ -4419,6 +4890,24 @@ def format(template, data):
return result return result
def _get_url_script(macro):
macro['language'] = macro.get('language', 'Python')
macro['location'] = macro.get('location', 'user')
data = macro.copy()
if data['language'] == 'Python':
data['module'] = '.py$'
elif data['language'] == 'Basic':
data['module'] = '.{}.'.format(macro['module'])
if macro['location'] == 'user':
data['location'] = 'application'
else:
data['module'] = '.'
url = 'vnd.sun.star.script:{library}{module}{name}?language={language}&location={location}'
path = url.format(**data)
return path
def _call_macro(macro): def _call_macro(macro):
#~ https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification #~ https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
name = 'com.sun.star.script.provider.MasterScriptProviderFactory' name = 'com.sun.star.script.provider.MasterScriptProviderFactory'
@ -4439,6 +4928,7 @@ def _call_macro(macro):
args = macro.get('args', ()) args = macro.get('args', ())
url = 'vnd.sun.star.script:{library}{module}{name}?language={language}&location={location}' url = 'vnd.sun.star.script:{library}{module}{name}?language={language}&location={location}'
path = url.format(**data) path = url.format(**data)
script = factory.createScriptProvider('').getScript(path) script = factory.createScriptProvider('').getScript(path)
return script.invoke(args, None, None)[0] return script.invoke(args, None, None)[0]
@ -4665,6 +5155,7 @@ def import_csv(path, **kwargs):
rows = tuple(csv.reader(f, **kwargs)) rows = tuple(csv.reader(f, **kwargs))
return rows return rows
def export_csv(path, data, **kwargs): def export_csv(path, data, **kwargs):
with open(path, 'w') as f: with open(path, 'w') as f:
writer = csv.writer(f, **kwargs) writer = csv.writer(f, **kwargs)
@ -4672,6 +5163,19 @@ def export_csv(path, data, **kwargs):
return return
def install_locales(path, domain='base', dir_locales=DIR['locales']):
p, *_ = get_info_path(path)
path_locales = join(p, dir_locales)
try:
lang = gettext.translation(domain, path_locales, languages=[LANG])
lang.install()
_ = lang.gettext
except Exception as e:
from gettext import gettext as _
error(e)
return _
class LIBOServer(object): class LIBOServer(object):
HOST = 'localhost' HOST = 'localhost'
PORT = '8100' PORT = '8100'

60
zaz.py
View File

@ -33,6 +33,7 @@ from xml.dom.minidom import parseString
from conf import ( from conf import (
DATA, DATA,
DIRS, DIRS,
DOMAIN,
EXTENSION, EXTENSION,
FILES, FILES,
INFO, INFO,
@ -138,6 +139,19 @@ def _save(path, data):
return return
def _get_files(path, filters=''):
paths = []
if filters in ('*', '*.*'):
filters = ''
for folder, _, files in os.walk(path):
if filters:
pattern = re.compile(r'\.(?:{})$'.format(filters), re.IGNORECASE)
paths += [_join(folder, f) for f in files if pattern.search(f)]
else:
paths += files
return paths
def _compress_oxt(): def _compress_oxt():
log.info('Compress OXT extension...') log.info('Compress OXT extension...')
@ -435,8 +449,50 @@ def _embed(args):
return return
def _locales(args):
EASYMACRO = 'easymacro.py'
if args.files:
files = args.files.split(',')
else:
files = _get_files(DIRS['source'], 'py')
paths = ' '.join([f for f in files if not EASYMACRO in f])
path_pot = _join(DIRS['source'], DIRS['locales'], '{}.pot'.format(DOMAIN))
call([PATHS['gettext'], '-o', path_pot, paths])
log.info('POT generate successfully...')
return
def _update():
path_locales = _join(DIRS['source'], DIRS['locales'])
path_pot = _join(DIRS['source'], DIRS['locales'], '{}.pot'.format(DOMAIN))
if not _exists(path_pot):
log.error('Not exists file POT...')
return
files = _get_files(path_locales, 'po')
if not files:
log.error('First, generate files PO...')
return
for f in files:
call([PATHS['msgmerge'], '-U', f, path_pot])
log.info('\tUpdate: {}'.format(f))
log.info('Locales update successfully...')
return
def main(args): def main(args):
if args.update:
_update()
return
if args.locales:
_locales(args)
return
if args.embed: if args.embed:
_embed(args) _embed(args)
return return
@ -469,6 +525,10 @@ def _process_command_line_arguments():
default=False, required=False) default=False, required=False)
parser.add_argument('-d', '--document', dest='document', default='') parser.add_argument('-d', '--document', dest='document', default='')
parser.add_argument('-f', '--files', dest='files', default='') parser.add_argument('-f', '--files', dest='files', default='')
parser.add_argument('-l', '--locales', dest='locales', action='store_true',
default=False, required=False)
parser.add_argument('-u', '--update', dest='update', action='store_true',
default=False, required=False)
return parser.parse_args() return parser.parse_args()