From 3659b4ff0cf91725bdc8bfaab6650b4a7635154e Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Thu, 24 Dec 2020 21:06:18 -0600 Subject: [PATCH] Update zaz --- VERSION | 3 +- conf.py | 274 +++--------------------- files/ZAZFavorites_v0.6.0.oxt | Bin 76850 -> 76834 bytes source/Addons.xcu | 45 ++-- source/Office/Accelerators.xcu | 8 +- source/description.xml | 18 +- zaz.py | 370 +++++++++++++++++++++++++++++---- 7 files changed, 391 insertions(+), 327 deletions(-) mode change 100644 => 100755 zaz.py diff --git a/VERSION b/VERSION index 8ea2ddf..09a3acf 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1 @@ -0.5.0 - +0.6.0 \ No newline at end of file diff --git a/conf.py b/conf.py index dca511e..5a59b71 100644 --- a/conf.py +++ b/conf.py @@ -25,24 +25,25 @@ import logging # ~ 3 = Calc addin TYPE_EXTENSION = 1 +# ~ Your great extension name, not used spaces +NAME = 'ZAZFavorites' + # ~ https://semver.org/ VERSION = '0.6.0' -# ~ Your great extension name, not used spaces -NAME = 'ZAZFavorites' # ~ Should be unique, used URL inverse ID = 'net.elmau.zaz.Favorites' # ~ If you extension will be multilanguage set: True # ~ This feature used gettext, set pythonpath and easymacro in True -# ~ Yu can used PoEdit for edit PO files and generate MO files. +# ~ You can used PoEdit for edit PO files and generate MO files. # ~ https://poedit.net/ USE_LOCALES = True DOMAIN = 'base' PATH_LOCALES = 'locales' -# ~ locate pygettext.py -PATH_PYGETTEXT = '/usr/lib/python3.7/Tools/i18n/pygettext.py' +PATH_PYGETTEXT = '/usr/lib/python3.9/Tools/i18n/pygettext.py' +# ~ You can use PoEdit for update locales too PATH_MSGMERGE = 'msgmerge' @@ -57,9 +58,6 @@ ICON = 'images/logo.png' # ~ Name inside extensions ICON_EXT = f'{NAME.lower()}.png' -# ~ For example -# ~ DEPENDENCIES_MINIMAL = '6.0' -DEPENDENCIES_MINIMAL = '' # ~ Change for you favorite license LICENSE_EN = f"""This file is part of {NAME}. @@ -93,17 +91,6 @@ INFO = { } -CONTEXT = { - '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', -} - - # ~ Menus, only for TYPE_EXTENSION = 1 # ~ Parent can be: AddonMenu or OfficeMenuBar # ~ For icons con name: NAME_16.bmp, used only NAME @@ -259,7 +246,7 @@ elif TYPE_EXTENSION == 3: METHODS = _methods() -FILE_PY = f"""import uno +DATA_PY = f"""import uno import unohelper {SRV_IMPORT} @@ -279,177 +266,6 @@ g_ImplementationHelper = unohelper.ImplementationHelper() g_ImplementationHelper.addImplementation({NAME}, ID_EXTENSION, SERVICE) """ - -tmp = ' {}' -node = [tmp.format(k, v['display_name']) for k, v in INFO.items()] -NODE_DISPLAY_NAME = '\n'.join(node) - -tmp = ' ' -node = [tmp.format(k) for k, v in INFO.items()] -NODE_EXTENSION_DESCRIPTION = '\n'.join(node) - -NODE_ICON = '' -if ICON: - NODE_ICON = f' ' - -NODE_PUBLISHER = '' -if PUBLISHER: - tmp = ' {}' - node = [tmp.format(v['link'], k, v['text']) for k, v in PUBLISHER.items()] - NODE_PUBLISHER = '\n'.join(node) - -NODE_DEPENDENCIES_MINIMAL = '' -if DEPENDENCIES_MINIMAL: - NODE_DEPENDENCIES_MINIMAL = f"""\n - - """ - -tmp = ' ' -node = [tmp.format(DIRS['registration'], k) for k in INFO.keys()] -NODE_LICENSE = '\n'.join(node) - -NODE_UPDATE = '' -if URL_XML_UPDATE: - NODE_UPDATE = f""" - - - """ - -FILE_DESCRIPTION = f""" - - - - -{NODE_DISPLAY_NAME} - - -{NODE_EXTENSION_DESCRIPTION} - - -{NODE_ICON} - - -{NODE_PUBLISHER} - - - -{NODE_LICENSE} - - {NODE_DEPENDENCIES_MINIMAL}{NODE_UPDATE} - -""" - -NODE_MENU = """ - -{titles} - - - service:{id}?{argument} - - - _self - - - {context} - - - %origin%/{folder}/{icon} - - """ - -opt = 'fuse' -if PARENT == 'OfficeMenuBar': - opt = 'replace' - - -def _get_context(args): - if not args: - return '' - c = [] - for v in args.split(','): - c.append(CONTEXT[v]) - return ','.join(c) - - -menus = [] -toolbar = [] -tmp = ' {}' -for i, m in enumerate(MENUS): - titles = [tmp.format(k, v) for k, v in m['title'].items()] - values = { - 'id': ID, - 'index': i+101, - 'opt': opt, - 'titles': '\n'.join(titles), - 'argument': m['argument'], - 'context': _get_context(m['context']), - 'folder': DIRS['images'], - 'icon': m['icon'], - } - menus.append(NODE_MENU.format(**values)) - if m['toolbar']: - values['index'] = f't{i+1}' - toolbar.append(NODE_MENU.format(**values)) - -NODE_TOOLBAR = '' -NODE_MENUS = '' -if TYPE_EXTENSION == 1: - if PARENT == 'AddonMenu': - NODE_MENUS = '\n'.join(menus) - elif PARENT == 'OfficeMenuBar': - tmp = ' {}' - titles = '\n'.join([tmp.format(k, v) for k, v in MENU_MAIN.items()]) - SUBMENUS = '\n ' + '\n'.join(menus) + '\n ' - NODE_MENUS = f""" - - {titles} - - - _self - - {SUBMENUS} - """ - - if toolbar: - node_toolbars = '\n'.join(toolbar) - NODE_TOOLBAR = f""" - - {node_toolbars} - - """ - -FILE_ADDONS = f""" - - - -{NODE_MENUS} - -{NODE_TOOLBAR} - - -""" - - -FILE_UPDATE = '' -if URL_XML_UPDATE: - FILE_UPDATE = f""" - - - - - - - - - - - -""" - - def _functions(): a = '[in] any {}' t = ' any {}({});' @@ -566,72 +382,42 @@ FILE_ADDIN = f""" """ -NODE_SHORTCUT = """ {0} - {0} - {0}service:{2}?{3} - {0} - {0} -""" - -NODE_SHORTCUTS = '' -if TYPE_EXTENSION == 1: - node_global = [] - node_module = {} - for m in MENUS: - if not m.get('shortcut', ''): - continue - if m['context']: - for c in m['context'].split(','): - if not c in node_module: - node_module[c] = [] - node = NODE_SHORTCUT.format(' ', m['shortcut'], ID, m['argument']) - node_module[c].append(node) - continue - node = NODE_SHORTCUT.format('', m['shortcut'], ID, m['argument']) - node_global.append(node) - if node_global: - NODE_SHORTCUTS = ' \n' - NODE_SHORTCUTS += '\n'.join(node_global) - NODE_SHORTCUTS += ' ' - if node_module: - NODE_SHORTCUTS += ' \n' - for c, n in node_module.items(): - NODE_SHORTCUTS += ' \n'.format(CONTEXT[c]) - NODE_SHORTCUTS += '\n'.join(n) - NODE_SHORTCUTS += ' \n' - NODE_SHORTCUTS += ' ' - -FILE_SHORTCUTS = f""" - - -{NODE_SHORTCUTS} - - -""" - - DATA_MANIFEST = [FILES['py'], f"Office/{FILES['shortcut']}", 'Addons.xcu'] if TYPE_EXTENSION > 1: DATA_MANIFEST.append(FILES['rdb']) if TYPE_EXTENSION == 3: DATA_MANIFEST.append('CalcAddIn.xcu') +DATA_DESCRIPTION = { + 'identifier': {'value': ID}, + 'version': {'value': VERSION}, + 'display-name': {k: v['display_name'] for k, v in INFO.items()}, + 'icon': ICON_EXT, + 'publisher': PUBLISHER, + 'update': URL_XML_UPDATE, +} + +DATA_ADDONS = { + 'parent': PARENT, + 'images': DIRS['images'], + 'main': MENU_MAIN, + 'menus': MENUS, +} DATA = { - 'py': FILE_PY, + 'py': DATA_PY, 'manifest': DATA_MANIFEST, - 'description': FILE_DESCRIPTION, - 'addons': FILE_ADDONS, - 'update': FILE_UPDATE, + 'description': DATA_DESCRIPTION, + 'addons': DATA_ADDONS, + 'update': URL_OXT, 'idl': FILE_IDL, 'addin': FILE_ADDIN, - 'shortcut': FILE_SHORTCUTS, } +with open('VERSION', 'w') as f: + f.write(VERSION) + + # ~ LICENSE_ACCEPT_BY = 'user' # or admin # ~ LICENSE_SUPPRESS_ON_UPDATE = True diff --git a/files/ZAZFavorites_v0.6.0.oxt b/files/ZAZFavorites_v0.6.0.oxt index 9ea1d3ad2dcf492d57bcf95276963b9193bb0853..8266ab0298cb491b520dc837222172d62e147939 100644 GIT binary patch delta 1631 zcmZ8h2{hDO9G*La7thp?u{~ppF*Ayku|}3u&l1uiaqLRPl)W;|BfK<(441Oh7$uTt z#+!-AQc;YxY_CWq+N>>jq4yu>ymwyRbME=h?>p!BJKw$E{VsPvj6ER6aB;wh$)QlF zRjAt~Ij((iJWc>Wp=L2CloY~R2L#YU!}VhPBeODH9qw(!wLG6A+xw(B7|}C&qRy#H z8;K1y7)wqR|IDvW=S=XOX=X*~Fm z3G)lvG4_aLW9WOnn6X{F)oIgY%!qa1z5LWieWrv>eTLYOQ1Yd`A;;^Rztni#zS)B$Wzc`oP5nCtE93z@=iGGwis#@^<;0?$%| z%n)?jw*HB&Xw5#xt)qgcOH1$ND?fT)PO(INZ%0s+f^R8eM}Qa#wFa>xATZoNEckdt zFfCLsCgfPYTVv=ebzI$?E-u=(Cacsb!EM6#^n2qyVrlu^epb@EdSaJennZorx3~Bi zu68bHtlhRQ&!cTMPO?sSp~(G&M8`Zs%FAt5ulE6MnM-%Urzb1!-d-s@zGs$h@4K#e z%}A_Q5qROh?ggviv!B)>m4%~!o*Ki1hjZU7J1xGNAzg4*n0$4rE*tjCcnrA(eQn5T zlJaa)*5IDy6IjozWql3~CG#wq`{~m%YjIFvu{U0(R&9s|KeSK+tY!<275Y zy|h5c+j-qk$P4IkcC0bTTI3TFgWi?Jdqf*;h^XwvrVBgzi}q{Y4thcuq(qoAtA00$ zrs+Lti3?LzcHB3WFjFqnO+6gaHD#DbEi8Xs5lE}~T9bO`)0?t_i_ECK2@+&Gi{~=@ zMjPMoPy%?|Y_;>jDlwMRyrwJ<&W9!T$CK2PcB#y} zx$0ARb|TJcFrzI)LM=N}w|ZyGO3)xq2PpH>F-nr?+aL|0^VUN7|?{=R7LC&mQOr!IKw~MNV&h@ z+Jw;FGUawTb>(=Urgd=nq5fiIo6@jMs#H(wv(}w^YJ?veHDZ> zJl#4{rs8#P=+{rRr=FJ^ulcy_zR0&R3bdOzF=EzZ#$7jCP$iL>rjma>uC)0K`GojV zLAT>p{`!w^E`=rx_>8y*Z!TGo+!ZU1HN|)7Yv;E$Z`?bMAYZL_kp!aX;n^iQ3BI#HGM_BG>}_Ayo%~Y#1hj zQdpq_2%@PSIzR=a!}mJC78pW(5>OYht|Wx5f}tcpTp52Lxv@xtg+fi&piv6{&PI?E zw-xe8U>nGS^CVz_;o|{RR{#V!K?bt$5E&?AKFP08YS5elaF8dWw3PsKRRU^oiVP^2 zq+eDl0yL$7^%%S=fYz!&1tw4c1q{Lp1VoCSQV>P?aGnBezyLJY1*$8;{(E0&)DObE sVT>*yidwJeBCU5|9a66Ju>B&dOc3$L$o~E?iV(dXP$UwG$csh&1CvdUSpS9(~_(2P*Y&m&t+rNp?D@|dBA zydtmTku7T~YD&o?+LW@jgtC&<{-(2?vvtq8=X1{IkMHaA{oGsJhril~M_iq7cohr= zBa7)R&2_6ae4ZN#Fc@b%1|yHMw!3ykNAZjkcJ4jr5fG7PqH^$UC86lU!}ax0C!CyS zR}@@zt*U{G-CZ_xICEF`ik zYM%@oJXn@7>e6%S$*$> zlN8?M{wQ|NR<#-@f@eXS$4Z-JVg;|v6@!`NGB>UgKcOOCawr%Hy&y=<(wes_xj8Mm z$A6=_M7G7qrO>mrx}zac=1E#aj<N%Un$qtXNsV%HW33}3(OTUp2D|Xwz!xNF zp>Dap^%hD5&+xOV!UYyTJ0xDgmz9^Ib@4BE+w;RNbE$Ur>$2ZPHSODOJa56mb-FL% zQpWrG^7pVxnVzeZ30nVONDJ*lw$eUKeQ{>~HhY%9O7 zF&F65-|qTL$uq~}&c<$4vFq++ZqTr4w@%R=`Yan>scfuMsR@e~eQ6Wqni*Yn*chz% zdJV48yuN>NDC5jocJr6y;3<{P^c;^*d_LK8lCzlT+nx1DA|Ae(UNx~xL7X+;{etwa z?p!*pX>#Fi=o5RfQkUR2XCz48p-h;$uGGJ?Cm_vhV4Rw-*KPbRT+Hc5EW`o(Ke%xw zI~sIt%2+aa1&;B1e1Foe=+G6zebPfa_Q#sX-5qlqS>BO^}CiR6s%Qqn;%E@pOSneY^VF0djFp z^|Li~4{ZJV{2DuYZaZ&2?J@Xy=GcR^MXPSL&n`?41&oY3_9h)0@DLG6GQ5{UVz&2X z=f0@3-CF(ZnH{<-i;Il2^(WXKmZ!n|t5mW;~l=&BDuZ%fSinH?Yc@6iK+`=(ESvoSPA8x_a4k zo(M1CXx{CyJ9slm&rNBe!mT?_BS-yVxrWY`P}~($J+a4ESGs4+l=J5nqDzOh|8FPQsR#VfsY0qg*uCWYR}U8G1BSMg`_Xc!>%JaQ zN;VwR2Nr+}^=K%Rz#UR(gatIPLK?M|1~fqd9HaqzU=OwFfFfmW=|B^EgOnv9kzoQI zC{m<3wjOO4>SSXulTBER+P4HKic&TsS$+r^w$K3sh~O9>4nh8cRlZ;KA6nSdc9&__2I^Dp8My - - + + + - - - Favorites... - Favoritos... - - - service:net.elmau.zaz.Favorites?config - - - _self - - - - - - %origin%/images/favorite - - + + + Favorites... + Favoritos... + + + + + + service:net.elmau.zaz.Favorites?config + + + _self + + + %origin%/images/favorite + + - - + diff --git a/source/Office/Accelerators.xcu b/source/Office/Accelerators.xcu index 608f3b1..9ef01af 100644 --- a/source/Office/Accelerators.xcu +++ b/source/Office/Accelerators.xcu @@ -1,9 +1,5 @@ - - + + diff --git a/source/description.xml b/source/description.xml index e2d1235..35b95b0 100644 --- a/source/description.xml +++ b/source/description.xml @@ -1,26 +1,26 @@ - + - - + + Favorites files Archivos favoritos - - + + - + El Mau El Mau - - - + + + diff --git a/zaz.py b/zaz.py old mode 100644 new mode 100755 index 9cad0c8..5238ec2 --- a/zaz.py +++ b/zaz.py @@ -4,6 +4,8 @@ # ~ This file is part of ZAZ. +# ~ https://git.elmau.net/elmau/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 @@ -19,6 +21,7 @@ import argparse import os +import py_compile import re import sys import zipfile @@ -43,9 +46,22 @@ from conf import ( log) +EASYMACRO = 'easymacro.py' + + class LiboXML(object): + CONTEXT = { + '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', + } TYPES = { 'py': 'application/vnd.sun.star.uno-component;type=Python', + 'pyc': 'application/binary', 'zip': 'application/binary', 'xcu': 'application/vnd.sun.star.configuration-data', 'rdb': 'application/vnd.sun.star.uno-typelibrary;type=RDB', @@ -53,18 +69,34 @@ class LiboXML(object): 'help': 'application/vnd.sun.star.help', 'component': 'application/vnd.sun.star.uno-components', } - NAME_SPACES = { + NS_MANIFEST = { 'manifest_version': '1.2', 'manifest': 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0', 'xmlns:loext': 'urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0', } + NS_DESCRIPTION = { + 'xmlns': 'http://openoffice.org/extensions/description/2006', + 'xmlns:xlink': 'http://www.w3.org/1999/xlink', + 'xmlns:d': 'http://openoffice.org/extensions/description/2006', + } + NS_ADDONS = { + 'xmlns:xs': 'http://www.w3.org/2001/XMLSchema', + 'xmlns:oor': 'http://openoffice.org/2001/registry', + } + NS_UPDATE = { + 'xmlns': 'http://openoffice.org/extensions/update/2006', + 'xmlns:d': 'http://openoffice.org/extensions/description/2006', + 'xmlns:xlink': 'http://www.w3.org/1999/xlink', + } def __init__(self): self._manifest = None self._paths = [] + self._path_images = '' + self._toolbars = [] def _save_path(self, attr): - self._paths.append(attr['{{{}}}full-path'.format(self.NAME_SPACES['manifest'])]) + self._paths.append(attr['{{{}}}full-path'.format(self.NS_MANIFEST['manifest'])]) return def _clean(self, name, nodes): @@ -86,18 +118,18 @@ class LiboXML(object): def new_manifest(self, data): attr = { - 'manifest:version': self.NAME_SPACES['manifest_version'], - 'xmlns:manifest': self.NAME_SPACES['manifest'], - 'xmlns:loext': self.NAME_SPACES['xmlns:loext'], + 'manifest:version': self.NS_MANIFEST['manifest_version'], + 'xmlns:manifest': self.NS_MANIFEST['manifest'], + 'xmlns:loext': self.NS_MANIFEST['xmlns:loext'], } self._manifest = ET.Element('manifest:manifest', attr) return self.add_data_manifest(data) def parse_manifest(self, data): - ET.register_namespace('manifest', self.NAME_SPACES['manifest']) + ET.register_namespace('manifest', self.NS_MANIFEST['manifest']) self._manifest = ET.fromstring(data) - data = {'xmlns:loext': self.NAME_SPACES['xmlns:loext']} - self._manifest.attrib.update(**data) + attr = {'xmlns:loext': self.NS_MANIFEST['xmlns:loext']} + self._manifest.attrib.update(**attr) self._clean('manifest', self._manifest) return @@ -116,6 +148,217 @@ class LiboXML(object): ET.SubElement(self._manifest, node_name, attr) return self._get_xml(self._manifest) + def new_description(self, data): + doc = ET.Element('description', self.NS_DESCRIPTION) + + key = 'identifier' + ET.SubElement(doc, key, data[key]) + + key = 'version' + ET.SubElement(doc, key, data[key]) + + key = 'display-name' + node = ET.SubElement(doc, key) + for k, v in data[key].items(): + sn = ET.SubElement(node, 'name', {'lang': k}) + sn.text = v + + node = ET.SubElement(doc, 'extension-description') + for k in data[key].keys(): + attr = { + 'lang': k, + 'xlink:href': f'description/desc_{k}.txt', + } + ET.SubElement(node, 'src', attr) + + key = 'icon' + node = ET.SubElement(doc, key) + attr = {'xlink:href': f"images/{data[key]}"} + ET.SubElement(node, 'default', attr) + + key = 'publisher' + node = ET.SubElement(doc, key) + for k, v in data[key].items(): + attr = { + 'xlink:href': v['link'], + 'lang': k, + } + sn = ET.SubElement(node, 'name', attr) + sn.text = v['text'] + + key = 'display-name' + node = ET.SubElement(doc, 'registration') + attr = { + 'accept-by': 'user', + 'suppress-on-update': 'true', + } + node = ET.SubElement(node, 'simple-license', attr) + for k in data[key].keys(): + attr = { + 'xlink:href': f"{DIRS['registration']}/license_{k}.txt", + 'lang': k + } + ET.SubElement(node, 'license-text', attr) + + if data['update']: + node = ET.SubElement(doc, 'update-information') + ET.SubElement(node, 'src', {'xlink:href': data['update']}) + + return self._get_xml(doc) + + def _get_context(self, args): + if not args: + return '' + context = ','.join([self.CONTEXT[v] for v in args.split(',')]) + return context + + def _add_node_value(self, node, name, value='_self'): + attr = {'oor:name': name, 'oor:type': 'xs:string'} + sn = ET.SubElement(node, 'prop', attr) + sn = ET.SubElement(sn, 'value') + sn.text = value + return + + def _add_menu(self, id_extension, node, index, menu, in_menu_bar=True): + if in_menu_bar: + attr = { + 'oor:name': index, + 'oor:op': 'replace', + } + subnode = ET.SubElement(node, 'node', attr) + else: + subnode = node + + attr = {'oor:name': 'Title', 'oor:type': 'xs:string'} + sn1 = ET.SubElement(subnode, 'prop', attr) + for k, v in menu['title'].items(): + sn2 = ET.SubElement(sn1, 'value', {'xml:lang': k}) + sn2.text = v + value = self._get_context(menu['context']) + self._add_node_value(subnode, 'Context', value) + + if 'submenu' in menu: + sn = ET.SubElement(subnode, 'node', {'oor:name': 'Submenu'}) + for i, m in enumerate(menu['submenu']): + self._add_menu(id_extension, sn, f'{index}.s{i}', m) + if m.get('toolbar', False): + self._toolbars.append(m) + return + + value = f"service:{id_extension}?{menu['argument']}" + self._add_node_value(subnode, 'URL', value) + self._add_node_value(subnode, 'Target') + value = f"%origin%/{self._path_images}/{menu['icon']}" + self._add_node_value(subnode, 'ImageIdentifier', value) + return + + def new_addons(self, id_extension, data): + in_menu_bar = data['parent'] == 'OfficeMenuBar' + self._path_images = data['images'] + attr = { + 'oor:name': 'Addons', + 'oor:package': 'org.openoffice.Office', + } + attr.update(self.NS_ADDONS) + doc = ET.Element('oor:component-data', attr) + parent = ET.SubElement(doc, 'node', {'oor:name': 'AddonUI'}) + node = ET.SubElement(parent, 'node', {'oor:name': data['parent']}) + + op = 'fuse' + if in_menu_bar: + op = 'replace' + + attr = {'oor:name': id_extension, 'oor:op': op} + node = ET.SubElement(node, 'node', attr) + + if in_menu_bar: + attr = {'oor:name': 'Title', 'oor:type': 'xs:string'} + subnode = ET.SubElement(node, 'prop', attr) + for k, v in data['main'].items(): + sn = ET.SubElement(subnode, 'value', {'xml:lang': k}) + sn.text = v + + self._add_node_value(node, 'Target') + node = ET.SubElement(node, 'node', {'oor:name': 'Submenu'}) + + for i, menu in enumerate(data['menus']): + self._add_menu(id_extension, node, f'm{i}', menu, in_menu_bar) + if menu.get('toolbar', False): + self._toolbars.append(menu) + + if self._toolbars: + attr = {'oor:name': 'OfficeToolBar'} + toolbar = ET.SubElement(parent, 'node', attr) + attr = {'oor:name': id_extension, 'oor:op': 'replace'} + toolbar = ET.SubElement(toolbar, 'node', attr) + for t, menu in enumerate(self._toolbars): + self._add_menu(id_extension, toolbar, f't{t}', menu) + + return self._get_xml(doc) + + def _add_shortcut(self, node, key, id_extension, arg): + attr = {'oor:name': key, 'oor:op': 'fuse'} + subnode = ET.SubElement(node, 'node', attr) + subnode = ET.SubElement(subnode, 'prop', {'oor:name': 'Command'}) + subnode = ET.SubElement(subnode, 'value', {'xml:lang': 'en-US'}) + subnode.text = f"service:{id_extension}?{arg}" + return + + def _get_acceleartors(self, menu): + if 'submenu' in menu: + for m in menu['submenu']: + return self._get_acceleartors(m) + + if not menu.get('shortcut', ''): + return '' + + return menu + + def new_accelerators(self, id_extension, menus): + attr = { + 'oor:name': 'Accelerators', + 'oor:package': 'org.openoffice.Office', + } + attr.update(self.NS_ADDONS) + doc = ET.Element('oor:component-data', attr) + parent = ET.SubElement(doc, 'node', {'oor:name': 'PrimaryKeys'}) + + data = [] + for m in menus: + info = self._get_acceleartors(m) + if info: + data.append(info) + + node_global = None + node_modules = None + for m in data: + if m['context']: + if node_modules is None: + node_modules = ET.SubElement( + parent, 'node', {'oor:name': 'Modules'}) + for app in m['context'].split(','): + node = ET.SubElement( + node_modules, 'node', {'oor:name': self.CONTEXT[app]}) + self._add_shortcut( + node, m['shortcut'], id_extension, m['argument']) + else: + if node_global is None: + node_global = ET.SubElement( + parent, 'node', {'oor:name': 'Global'}) + self._add_shortcut( + node_global, m['shortcut'], id_extension, m['argument']) + + return self._get_xml(doc) + + def new_update(self, extension, url_oxt): + doc = ET.Element('description', self.NS_UPDATE) + ET.SubElement(doc, 'identifier', {'value': extension['id']}) + ET.SubElement(doc, 'version', {'value': extension['version']}) + node = ET.SubElement(doc, 'update-download') + ET.SubElement(node, 'src', {'xlink:href': url_oxt}) + node = ET.SubElement(doc, 'release-notes') + return self._get_xml(doc) + def _get_xml(self, doc): xml = parseString(ET.tostring(doc, encoding='utf-8')) return xml.toprettyxml(indent=' ', encoding='utf-8').decode('utf-8') @@ -155,11 +398,7 @@ def _get_files(path, filters=''): def _compress_oxt(): log.info('Compress OXT extension...') - path = DIRS['files'] - if not _exists(path): - _mkdir(path) - - path_oxt = _join(path, FILES['oxt']) + path_oxt = _join(DIRS['files'], FILES['oxt']) z = zipfile.ZipFile(path_oxt, 'w', compression=zipfile.ZIP_DEFLATED) root_len = len(os.path.abspath(DIRS['source'])) @@ -173,10 +412,6 @@ def _compress_oxt(): z.write(fullpath, file_name, zipfile.ZIP_DEFLATED) z.close() - if DATA['update']: - path_xml = _join(path, FILES['update']) - _save(path_xml, DATA['update']) - log.info('Extension OXT created sucesfully...') return @@ -294,6 +529,10 @@ def _compile_idl(): def _update_files(): + path_files = DIRS['files'] + if not _exists(path_files): + _mkdir(path_files) + path_source = DIRS['source'] for k, v in INFO.items(): @@ -315,7 +554,7 @@ def _update_files(): copyfile(source, target) if FILES['easymacro']: - source = 'easymacro.py' + source = EASYMACRO target = _join(path_source, 'pythonpath', source) copyfile(source, target) @@ -325,16 +564,21 @@ def _update_files(): data = xml.new_manifest(DATA['manifest']) _save(path, data) - path = _join(path_source, DIRS['office']) - _mkdir(path) - path = _join(path_source, DIRS['office'], FILES['shortcut']) - _save(path, DATA['shortcut']) - - path = _join(path_source, FILES['addons']) - _save(path, DATA['addons']) - path = _join(path_source, FILES['description']) - _save(path, DATA['description']) + data = xml.new_description(DATA['description']) + _save(path, data) + + if TYPE_EXTENSION == 1: + path = _join(path_source, FILES['addons']) + data = xml.new_addons(EXTENSION['id'], DATA['addons']) + _save(path, data) + + path = _join(path_source, DIRS['office']) + _mkdir(path) + path = _join(path_source, DIRS['office'], FILES['shortcut']) + data = xml.new_accelerators(EXTENSION['id'], DATA['addons']['menus']) + _save(path, data) + if TYPE_EXTENSION == 3: path = _join(path_source, FILES['addin']) @@ -342,16 +586,21 @@ def _update_files(): if USE_LOCALES: msg = "Don't forget generate DOMAIN.pot for locales" - log.info(msg) for lang in EXTENSION['languages']: path = _join(path_source, DIRS['locales'], lang, 'LC_MESSAGES') Path(path).mkdir(parents=True, exist_ok=True) + log.info(msg) + + if DATA['update']: + path_xml = _join(path_files, FILES['update']) + data = xml.new_update(EXTENSION, DATA['update']) + _save(path_xml, data) _compile_idl() return -def _new(): +def _create(): if not _validate_new(): return @@ -373,7 +622,7 @@ def _get_info_path(path): def _zip_embed(source, files): PATH = 'Scripts/python/' - EASYMACRO = 'easymacro.' + FILE_PYC = 'easymacro.pyc' p, f, name, e = _get_info_path(source) now = datetime.now().strftime('_%Y%m%d_%H%M%S') @@ -381,12 +630,10 @@ def _zip_embed(source, files): copyfile(source, path_source) target = source - with zipfile.PyZipFile(EASYMACRO + 'zip', mode='w') as zf: - zf.writepy(EASYMACRO + 'py') - + py_compile.compile(EASYMACRO, FILE_PYC) xml = LiboXML() - path_easymacro = PATH + EASYMACRO + 'zip' + path_easymacro = PATH + FILE_PYC names = [f[1] for f in files] + [path_easymacro] nodes = [] with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED) as zt: @@ -405,14 +652,14 @@ def _zip_embed(source, files): data.append(name) zt.write(path, name) - zt.write(EASYMACRO + 'zip', path_easymacro) + zt.write(FILE_PYC, path_easymacro) data.append(path_easymacro) xml.parse_manifest(xml_manifest) xml_manifest = xml.add_data_manifest(data) zt.writestr(path_manifest, xml_manifest) - os.unlink(EASYMACRO + 'zip') + os.unlink(FILE_PYC) return @@ -450,8 +697,6 @@ def _embed(args): def _locales(args): - EASYMACRO = 'easymacro.py' - if args.files: files = args.files.split(',') else: @@ -483,8 +728,39 @@ def _update(): return +def _new(args): + if not args.target: + msg = 'Add argument target: -t PATH_TARGET' + log.error(msg) + return + + if not args.name: + msg = 'Add argument name: -n name-new-extension' + log.error(msg) + return + + path = _join(args.target, args.name) + _mkdir(path) + _mkdir(_join(path, 'files')) + _mkdir(_join(path, 'images')) + path_logo = 'images/pymacros.png' + copyfile(path_logo, _join(path, 'images/logo.png')) + copyfile('zaz.py', _join(path, 'zaz.py')) + copyfile(EASYMACRO, _join(path, 'easymacro.py')) + copyfile('conf.py.example', _join(path, 'conf.py')) + + msg = 'Folders and files copy successfully for new extension.' + log.info(msg) + msg = f'Change to folder: {path}' + log.info(msg) + return + def main(args): + if args.new: + _new(args) + return + if args.update: _update() return @@ -497,14 +773,16 @@ def main(args): _embed(args) return - if args.new: - _new() + if args.create: + _create() return if not _validate_update(): return - _update_files() + if not args.only_compress: + _update_files() + _compress_oxt() if args.install: @@ -517,9 +795,13 @@ def main(args): def _process_command_line_arguments(): parser = argparse.ArgumentParser( description='Make LibreOffice extensions') - parser.add_argument('-i', '--install', dest='install', action='store_true', + parser.add_argument('-new', '--new', dest='new', action='store_true', default=False, required=False) - parser.add_argument('-n', '--new', dest='new', action='store_true', + parser.add_argument('-t', '--target', dest='target', default='') + parser.add_argument('-n', '--name', dest='name', default='', required=False) + parser.add_argument('-c', '--create', dest='create', action='store_true', + default=False, required=False) + parser.add_argument('-i', '--install', dest='install', action='store_true', default=False, required=False) parser.add_argument('-e', '--embed', dest='embed', action='store_true', default=False, required=False) @@ -529,6 +811,8 @@ def _process_command_line_arguments(): default=False, required=False) parser.add_argument('-u', '--update', dest='update', action='store_true', default=False, required=False) + parser.add_argument('-oc', '--only_compress', dest='only_compress', + action='store_true', default=False, required=False) return parser.parse_args()