Compare commits

...

55 Commits

Author SHA1 Message Date
El Mau c2470ddd9d Add support for Flatplak and AppImage versions 2023-11-05 21:35:58 -06:00
El Mau 4b66d38e32 Make new OXT 2023-11-05 21:32:36 -06:00
El Mau d2d60e7281 Update version 2023-11-05 21:30:39 -06:00
Mauricio 0e750c0af0 Merge pull request 'cpython' (#14) from AmourSpirit/zaz-pip:cpython into develop
Reviewed-on: #14
2023-11-03 11:23:41 -06:00
Barry-Thomas-Paul: Moss 8dadb7e62e fix for debug error on Windows 2023-11-02 22:45:55 -04:00
Barry-Thomas-Paul: Moss 9f2ac70cc8 link cpython 2023-11-02 22:05:56 -04:00
Mauricio c93c182953 Merge pull request 'flatpak' (#13) from AmourSpirit/zaz-pip:flatpak into develop
Reviewed-on: #13
2023-11-01 19:18:49 -06:00
Barry-Thomas-Paul: Moss db3466b716 minor correcton for site_packages.exists() 2023-10-31 20:13:43 -04:00
Barry-Thomas-Paul: Moss 0453092831 fix for white text on bright yellow edit box in dark theme 2023-10-31 19:39:45 -04:00
Barry-Thomas-Paul: Moss 7b9ac8eee0 working with flatpak 2023-10-31 19:28:22 -04:00
Barry-Thomas-Paul: Moss 4aa0ca68c8 added pip_runner that add site_packages to sys.path 2023-10-31 16:19:18 -04:00
Barry-Thomas-Paul: Moss 923b39c7f2 pip installing in flatpak 2023-10-31 15:57:41 -04:00
Mauricio 90aa12adf2 Merge pull request 'develop' (#11) from AmourSpirit/zaz-pip:develop into develop
Reviewed-on: #11
2023-10-29 16:51:44 -06:00
AmourSpirit d52472dad7 Merge pull request 'app_image' (#1) from app_image into develop
Reviewed-on: AmourSpirit/zaz-pip#1
2023-10-19 17:09:26 -06:00
Barry-Thomas-Paul: Moss 6ec45c1bb4 Update to work with AppImage
Linxu ppImage Works with this minor fix.
Linux FlatPak still not working yet.
2023-10-19 19:06:50 -04:00
Barry-Thomas-Paul: Moss 910e5f54b1 update for Linxu AppImage 2023-10-19 15:29:02 -04:00
El Mau c9b9bfdf0a Fix issue #10 2022-04-23 21:49:30 -05:00
El Mau 587148553e Fix - Issue #10 2022-04-23 21:48:50 -05:00
El Mau 4b7b0c359f Fix issue #9 2022-03-26 23:03:54 -06:00
El Mau 269f9adc75 Fix - Issue #9 2022-03-26 16:07:22 -06:00
El Mau 668e23353b Update README 2022-03-26 11:46:41 -06:00
El Mau d7d65bb8ba Fix - Issue #9 2022-03-26 11:45:03 -06:00
El Mau b3c783c1fe Add Proxy dialog title to translate 2022-03-25 09:29:59 -06:00
El Mau 2452480457 Add french translation. Issue #8 2022-03-17 12:39:49 -06:00
El Mau afd94fa5fe Add french translation 2022-03-17 12:38:07 -06:00
El Mau c940f6fcc6 Fix issue #6 2022-02-04 21:29:23 -06:00
El Mau 450daa630a Update changelog 2022-02-04 21:27:30 -06:00
El Mau 6ce81f91c6 Fix to open terminal in Gnome 2022-02-04 21:26:17 -06:00
El Mau b7e0d2a0fc Update extension 2022-01-28 13:49:49 -06:00
El Mau 4d518c781e Issue #6 2022-01-28 13:45:10 -06:00
El Mau 354b5e1421 Release v0.9.0 2022-01-27 12:02:38 -06:00
El Mau b1e24d4411 Add minimal version 2022-01-27 09:45:07 -06:00
LibreOfficiant cac0b4fb59 Corrections to the english labels
Note: x-terminal-emulator is a generic command for all *NIX Desktop Environment *terminal commands.

Signed-off-by: LibreOfficiant <libreofficiant@noreply.localhost>
2022-01-27 07:53:37 -06:00
LibreOfficiant 9910b5302b Corrections to english messages
Including minor typos
2022-01-21 09:36:21 -06:00
Mauricio Baeza 9e2f841017 Add config proxy. Issue #1 2021-06-14 16:38:25 -05:00
Mauricio Baeza 223989495e Modify size icons 2021-06-14 16:37:30 -05:00
Mauricio Baeza b31fa8247f Modify size icons 2021-06-14 16:34:30 -05:00
Mauricio Baeza a49a1ad4d8 Add config proxy 2021-06-12 23:04:37 -05:00
Mauricio Baeza 4eb0b51a6d Add button and image for config proxy 2021-06-05 23:03:36 -05:00
Mauricio Baeza e64854c78c Update easymacro.py 2021-06-05 22:06:13 -05:00
Mauricio Baeza 2d3f412349 Disable search 2021-01-08 21:15:57 -06:00
Mauricio Baeza 3c21ae6a87 Disable search 2021-01-08 21:15:38 -06:00
Mauricio Baeza d502f36313 Diable search 2021-01-08 21:14:15 -06:00
Mauricio Baeza 46b4855f60 Update easymacro.py 2020-12-20 21:44:13 -06:00
Mauricio Baeza 2e7a390a13 Update easymacro 2020-11-18 22:35:13 -06:00
Mauricio Baeza 54b2ed7913 Validate in Windows 2020-11-18 16:47:07 -06:00
Mauricio Baeza 475840d7e8 Install with file requeriments.txt 2020-11-18 12:47:12 -06:00
Mauricio Baeza 3d10072e9a Change filters 2020-11-17 23:24:57 -06:00
Mauricio Baeza c6ecd5a83f Add control for select file 2020-11-17 23:16:06 -06:00
Mauricio Baeza 0804c922f1 Replace icons png for svg 2020-11-17 22:54:10 -06:00
Mauricio Baeza 0099908afc Validate install PIP in Windows 2020-11-12 23:10:42 -06:00
Mauricio Baeza 41681330d3 Add install button 2020-11-12 19:35:29 -06:00
Mauricio Baeza 233a7c1fbf Update zaz and easymacro 2020-11-12 15:33:31 -06:00
Mauricio Baeza 6d450aed0a Change get python path 2020-03-13 23:12:30 -06:00
Mauricio Baeza 0d2c5cff91 Update zaz.py 2020-03-13 22:47:08 -06:00
43 changed files with 13151 additions and 8508 deletions

3
.gitignore vendored
View File

@ -3,8 +3,7 @@ __pycache__/
*.po~
*.log
images/
/images
docs/
# Virtualenv

View File

@ -1,19 +1,49 @@
v 1.0.0 [05-nov-2023]
- Thanks to https://git.cuates.net/AmourSpirit zaz-pip now work in:
* Mac Os
* Windows
* Linux, sudo installed LibreOffice
* Linux, Snap installed LibreOffice
* Linux, Flatpak installed LibreOffice
* Linux, AppImage LibreOffice
v 0.10.2 [22-apr-2022]
- Fix - issue #10
v 0.10.1 [26-mar-2022]
- Fix - issue #9
v 0.10.0 [19-mar-2022]
- Add french translation
v 0.9.0 [04-feb-2022]
- Fix - Add minimal version required, issue #5
- Fix - Corrections to english messages, issue #6
- Fix - Update and complete Spanish translation, thanks to me, :)
v 0.8.0 [13-jun-2021]
- Update easymacro.py
- Add proxy config
v 0.7.0 [05-jan-2020]
- Disable search
v 0.6.0 [18-nov-2020]
- Add install with requirements.txt
v 0.5.0 [09-jul-2020]
- Test install pandas
v 0.4.0 [10-mar-2020]
- Update easymacro.py
- Fix: in OSx Catalina
v 0.3.0 [12-nov-2019]
- Update easymacro.py
- Test install numpy
v 0.2.0 [18-oct-2019]
---------------------
- Add spanish
- Add Spanish translation
v 0.1.0 [18-oct-2019]
---------------------
- Initial version

View File

@ -5,24 +5,32 @@ Extension for install and admin Python Pip in LibreOffice.
Thanks!
https://gitlab.com/mauriciobaeza/zaz
https://git.cuates.net/elmau/zaz
### Software libre, no gratis
### Free Software, not gratis software
This extension have a cost of maintenance of 1 euro every year.
BCH: `qztd3l00xle5tffdqvh2snvadkuau2ml0uqm4n875d`
BTC: `3FhiXcXmAesmQzrNEngjHFnvaJRhU1AGWV`
G1: `A5DdXxCKPw3QKWVdDVs7CzkNugNUW1sHu5zDJFWxCU2h`
You have others cryptos, welcome too!
```
Euros
IBAN: BE60 9671 0556 5870
SWIFT / BIC: TRWIBEB1XXX
```
* [Look the wiki](https://git.cuates.net/elmau/zaz-pip/wiki/home)
* [Mira la wiki](https://git.cuates.net/elmau/zaz-pip/wiki/home_es)
* [Look the wiki](https://gitlab.com/mauriciobaeza/zaz-pip/wikis/home)
* [Mira la wiki](https://gitlab.com/mauriciobaeza/zaz-pip/wikis/home_es)
Thanks for code:
* @AmourSpirit
Thanks for translations:
* Help Us
* English - @LibreOfficiant
* French - @LibreOfficiant

View File

@ -1,2 +1 @@
0.4.0
1.0.0

291
conf.py
View File

@ -26,7 +26,7 @@ import logging
TYPE_EXTENSION = 1
# ~ https://semver.org/
VERSION = '0.4.0'
VERSION = '1.0.0'
# ~ Your great extension name, not used spaces
NAME = 'ZAZPip'
@ -36,20 +36,21 @@ ID = 'net.elmau.zaz.pip'
# ~ 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.10/Tools/i18n/pygettext.py'
PATH_MSGMERGE = 'msgmerge'
# ~ Show in extension manager
URL_GIT = 'https://git.cuates.net/elmau/zaz-pip'
PUBLISHER = {
'en': {'text': 'El Mau', 'link': 'https://gitlab.com/mauriciobaeza'},
'es': {'text': 'El Mau', 'link': 'https://gitlab.com/mauriciobaeza'},
'en': {'text': 'El Mau', 'link': URL_GIT},
'es': {'text': 'El Mau', 'link': URL_GIT},
'fr': {'text': 'El Mau', 'link': URL_GIT},
}
# ~ Name in this folder for copy
@ -57,9 +58,7 @@ ICON = 'images/logo.png'
# ~ Name inside extensions
ICON_EXT = f'{NAME.lower()}.png'
# ~ For example
# ~ DEPENDENCIES_MINIMAL = '6.0'
DEPENDENCIES_MINIMAL = ''
DEPENDENCIES_MINIMAL = '7.0'
# ~ Change for you favorite license
LICENSE_EN = f"""This file is part of {NAME}.
@ -77,7 +76,7 @@ LICENSE_EN = f"""This file is part of {NAME}.
You should have received a copy of the GNU General Public License
along with {NAME}. If not, see <https://www.gnu.org/licenses/>.
"""
LICENSE_ES = LICENSE_EN
LICENSE_FR = LICENSE_ES = LICENSE_EN
INFO = {
'en': {
@ -90,17 +89,11 @@ INFO = {
'description': 'Pip para LibreOffice',
'license': LICENSE_ES,
},
}
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',
'fr': {
'display_name': 'ZAZ Pip',
'description': 'Pip pour LibreOffice',
'license': LICENSE_FR,
},
}
@ -123,8 +116,8 @@ PARENT = 'AddonMenu'
MENU_MAIN = {}
MENUS = (
{
'title': {'en': 'Open Pip', 'es': 'Abrir Pip'},
'argument': 'open',
'title': {'en': 'Open Zaz-Pip', 'es': 'Abrir Zaz-Pip', 'fr': 'Ouvert Zaz-Pip'},
'argument': 'open_dialog_pip',
'context': '',
'icon': 'icon',
'toolbar': False,
@ -165,7 +158,7 @@ DIRS = {
'description': 'description',
'images': 'images',
'registration': 'registration',
'files': 'files',
'files': 'extension',
'office': 'Office',
'locales': PATH_LOCALES,
'pythonpath': True,
@ -260,7 +253,7 @@ elif TYPE_EXTENSION == 3:
METHODS = _methods()
FILE_PY = f"""import uno
DATA_PY = f"""import uno
import unohelper
{SRV_IMPORT}
@ -280,177 +273,6 @@ g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation({NAME}, ID_EXTENSION, SERVICE)
"""
tmp = ' <name lang="{}">{}</name>'
node = [tmp.format(k, v['display_name']) for k, v in INFO.items()]
NODE_DISPLAY_NAME = '\n'.join(node)
tmp = ' <src lang="{0}" xlink:href="description/desc_{0}.txt" />'
node = [tmp.format(k) for k, v in INFO.items()]
NODE_EXTENSION_DESCRIPTION = '\n'.join(node)
NODE_ICON = ''
if ICON:
NODE_ICON = f' <default xlink:href="images/{ICON_EXT}" />'
NODE_PUBLISHER = ''
if PUBLISHER:
tmp = ' <name xlink:href="{}" lang="{}">{}</name>'
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 <dependencies>
<OpenOffice.org-minimal-version value="{DEPENDENCIES_MINIMAL}" d:name="LibreOffice {DEPENDENCIES_MINIMAL}"/>
</dependencies>"""
tmp = ' <license-text xlink:href="{0}/license_{1}.txt" lang="{1}" />'
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"""
<update-information>
<src xlink:href="{URL_XML_UPDATE}" />
</update-information>"""
FILE_DESCRIPTION = f"""<?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">
<identifier value="{ID}" />
<version value="{VERSION}" />
<display-name>
{NODE_DISPLAY_NAME}
</display-name>
<extension-description>
{NODE_EXTENSION_DESCRIPTION}
</extension-description>
<icon>
{NODE_ICON}
</icon>
<publisher>
{NODE_PUBLISHER}
</publisher>
<registration>
<simple-license accept-by="user" suppress-on-update="true" >
{NODE_LICENSE}
</simple-license>
</registration>{NODE_DEPENDENCIES_MINIMAL}{NODE_UPDATE}
</description>
"""
NODE_MENU = """ <node oor:name="{id}.{index}" oor:op="{opt}">
<prop oor:name="Title" oor:type="xs:string">
{titles}
</prop>
<prop oor:name="URL" oor:type="xs:string">
<value>service:{id}?{argument}</value>
</prop>
<prop oor:name="Target" oor:type="xs:string">
<value>_self</value>
</prop>
<prop oor:name="Context" oor:type="xs:string">
<value>{context}</value>
</prop>
<prop oor:name="ImageIdentifier" oor:type="xs:string">
<value>%origin%/{folder}/{icon}</value>
</prop>
</node>"""
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 = ' <value xml:lang="{}">{}</value>'
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 = ' <value xml:lang="{}">{}</value>'
titles = '\n'.join([tmp.format(k, v) for k, v in MENU_MAIN.items()])
SUBMENUS = '<node oor:name="Submenu">\n ' + '\n'.join(menus) + '\n </node>'
NODE_MENUS = f""" <node oor:name="{ID}" oor:op="replace">
<prop oor:name="Title" oor:type="xs:string">
{titles}
</prop>
<prop oor:name="Target" oor:type="xs:string">
<value>_self</value>
</prop>
{SUBMENUS}
</node>"""
if toolbar:
node_toolbars = '\n'.join(toolbar)
NODE_TOOLBAR = f""" <node oor:name="OfficeToolBar">
<node oor:name="{ID}" oor:op="replace">
{node_toolbars}
</node>
</node>"""
FILE_ADDONS = f"""<?xml version='1.0' encoding='UTF-8'?>
<oor:component-data xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" oor:name="Addons" oor:package="org.openoffice.Office">
<node oor:name="AddonUI">
<node oor:name="{PARENT}">
{NODE_MENUS}
</node>
{NODE_TOOLBAR}
</node>
</oor:component-data>
"""
FILE_UPDATE = ''
if URL_XML_UPDATE:
FILE_UPDATE = f"""<?xml version="1.0" encoding="UTF-8"?>
<description
xmlns="http://openoffice.org/extensions/update/2006"
xmlns:d="http://openoffice.org/extensions/description/2006"
xmlns:xlink="http://www.w3.org/1999/xlink">
<identifier value="{ID}" />
<version value="{VERSION}" />
<update-download>
<src xlink:href="{URL_OXT}"/>
</update-download>
<release-notes>
</release-notes>
</description>"""
def _functions():
a = '[in] any {}'
t = ' any {}({});'
@ -567,72 +389,43 @@ FILE_ADDIN = f"""<?xml version="1.0" encoding="UTF-8"?>
</oor:component-data>"""
NODE_SHORTCUT = """ {0}<node oor:name="{1}" oor:op="fuse">
{0}<prop oor:name="Command">
{0}<value xml:lang="en-US">service:{2}?{3}</value>
{0}</prop>
{0}</node>
"""
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 = ' <node oor:name="Global">\n'
NODE_SHORTCUTS += '\n'.join(node_global)
NODE_SHORTCUTS += ' </node>'
if node_module:
NODE_SHORTCUTS += ' <node oor:name="Modules">\n'
for c, n in node_module.items():
NODE_SHORTCUTS += ' <node oor:name="{}">\n'.format(CONTEXT[c])
NODE_SHORTCUTS += '\n'.join(n)
NODE_SHORTCUTS += ' </node>\n'
NODE_SHORTCUTS += ' </node>'
FILE_SHORTCUTS = f"""<?xml version="1.0" encoding="UTF-8"?>
<oor:component-data
xmlns:oor="http://openoffice.org/2001/registry"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
oor:name="Accelerators"
oor:package="org.openoffice.Office">
<node oor:name="PrimaryKeys">
{NODE_SHORTCUTS}
</node>
</oor:component-data>
"""
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,
'minimal': DEPENDENCIES_MINIMAL,
}
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

File diff suppressed because it is too large Load Diff

BIN
extension/ZAZPip_v1.0.0.oxt Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,26 +1,26 @@
<?xml version='1.0' encoding='UTF-8'?>
<oor:component-data xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" oor:name="Addons" oor:package="org.openoffice.Office">
<node oor:name="AddonUI">
<?xml version="1.0" encoding="utf-8"?>
<oor:component-data xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:oor="http://openoffice.org/2001/registry" oor:name="Addons" oor:package="org.openoffice.Office">
<node oor:name="AddonUI">
<node oor:name="AddonMenu">
<node oor:name="net.elmau.zaz.pip.101" oor:op="fuse">
<prop oor:name="Title" oor:type="xs:string">
<value xml:lang="en">Open Pip</value>
<value xml:lang="es">Abrir Pip</value>
</prop>
<prop oor:name="URL" oor:type="xs:string">
<value>service:net.elmau.zaz.pip?open</value>
</prop>
<prop oor:name="Target" oor:type="xs:string">
<value>_self</value>
</prop>
<prop oor:name="Context" oor:type="xs:string">
<value></value>
</prop>
<prop oor:name="ImageIdentifier" oor:type="xs:string">
<value>%origin%/images/icon</value>
</prop>
</node>
<node oor:name="net.elmau.zaz.pip" oor:op="fuse">
<prop oor:name="Title" oor:type="xs:string">
<value xml:lang="en">Open Zaz-Pip</value>
<value xml:lang="es">Abrir Zaz-Pip</value>
<value xml:lang="fr">Ouvert Zaz-Pip</value>
</prop>
<prop oor:name="Context" oor:type="xs:string">
<value/>
</prop>
<prop oor:name="URL" oor:type="xs:string">
<value>service:net.elmau.zaz.pip?open_dialog_pip</value>
</prop>
<prop oor:name="Target" oor:type="xs:string">
<value>_self</value>
</prop>
<prop oor:name="ImageIdentifier" oor:type="xs:string">
<value>%origin%/images/icon</value>
</prop>
</node>
</node>
</node>
</node>
</oor:component-data>

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" manifest:version="1.2">
<manifest:file-entry manifest:full-path="job.xcu" manifest:media-type="application/vnd.sun.star.configuration-data" />
<manifest:file-entry manifest:full-path="ZAZPip.py" manifest:media-type="application/vnd.sun.star.uno-component;type=Python"/>
<manifest:file-entry manifest:full-path="pip_runner.py" manifest:media-type="application/vnd.sun.star.uno-component;type=Python" />
<manifest:file-entry manifest:full-path="Office/Accelerators.xcu" manifest:media-type="application/vnd.sun.star.configuration-data"/>
<manifest:file-entry manifest:full-path="Addons.xcu" manifest:media-type="application/vnd.sun.star.configuration-data"/>
</manifest:manifest>

View File

@ -1,14 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<oor:component-data
xmlns:oor="http://openoffice.org/2001/registry"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
oor:name="Accelerators"
oor:package="org.openoffice.Office">
<?xml version="1.0" encoding="utf-8"?>
<oor:component-data xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:oor="http://openoffice.org/2001/registry" oor:name="Accelerators" oor:package="org.openoffice.Office">
<node oor:name="PrimaryKeys">
<node oor:name="Global">
<node oor:name="P_SHIFT_MOD1_MOD2" oor:op="fuse">
<prop oor:name="Command">
<value xml:lang="en-US">service:net.elmau.zaz.pip?open</value>
<value xml:lang="en-US">service:net.elmau.zaz.pip?open_dialog_pip</value>
</prop>
</node>
</node>

View File

@ -1,502 +1,23 @@
import uno
import unohelper
from com.sun.star.task import XJobExecutor
import easymacro as app
import main
ID_EXTENSION = 'net.elmau.zaz.pip'
SERVICE = ('com.sun.star.task.Job',)
TITLE = 'ZAZ-PIP'
URL_PIP = 'https://bootstrap.pypa.io/get-pip.py'
PIP = 'pip'
PACKAGES = {
'psycopg2-binary': 'ok.png',
'peewee': 'ok.png',
'numpy': 'ok.png',
'pillow': 'ok.png',
'pytesseract': 'ok.png',
}
_ = app.install_locales(__file__)
class Controllers(object):
OK1 = 'Successfully installed'
OK2 = 'Requirement already'
OK3 = 'Successfully uninstalled'
def __init__(self, dialog):
self.d = dialog
self.path_python = app.get_path_python()
self._states = {
'list': False,
'install': False,
'search': False,
'versions': False,
}
def _set_state(self, state):
for k in self._states.keys():
self._states[k] = False
self._states[state] = True
return
def cmd_install_pip_action(self, event):
msg = _('Do you want install PIP?')
if not app.question(msg, 'ZAZ-Pip'):
return
self._install_pip()
return
@app.run_in_thread
def _install_pip(self):
self.d.link_proyect.visible = False
self.d.lst_log.visible = True
path_pip = app.get_temp_file(True)
self.d.lst_log.insert('Download PIP...')
data, err = app.url_open(URL_PIP, verify=False)
if err:
msg = _('Do you have internet connection?')
app.errorbox('{}\n\n{}'.format(msg, err))
return
app.save_file(path_pip, 'wb', data)
if not app.is_created(path_pip):
msg = _('File PIP not save')
app.errorbox(msg)
return
self.d.lst_log.insert(_('PIP save correctly...'))
try:
self.d.lst_log.insert(_('Start installing PIP...'))
cmd = '"{}" "{}" --user'.format(self.path_python, path_pip)
for line in app.popen(cmd):
if isinstance(line, tuple):
app.errorbox(line)
break
self.d.lst_log.insert(line)
cmd = self._cmd_pip('-V')
label = app.run(cmd, True)
if label:
self.d.lbl_pip.value = label
self.d.cmd_install_pip.visible = False
self.d.cmd_admin_pip.visible = True
msg = _('PIP installed sucesfully')
app.msgbox(msg)
else:
msg = _('PIP not installed, see log')
app.warning(msg)
except Exception as e:
app.errorbox(e)
return
def _cmd_pip(self, args):
cmd = '"{}" -m pip {}'.format(self.path_python, args)
return cmd
def cmd_admin_pip_action(self, event):
self.d.lst_log.possize(self.d.lst_package)
self.d.lst_log.step = 1
self.d.step = 1
self.cmd_home_action(None)
return
def cmd_close_action(self, event):
self.d.close()
return
def cmd_home_action(self, event):
self.d.txt_search.value = ''
self._list()
return
def txt_search_key_released(self, event):
if event.KeyCode == app.KEY['enter']:
self.cmd_search_action(None)
return
if not self.d.txt_search.value.strip():
self.cmd_home_action(None)
return
@app.run_in_thread
def _list(self):
self._set_state('list')
self.d.lst_log.visible = False
self.d.lst_package.visible = True
cmd = self._cmd_pip(' list --format=json')
self.d.lst_package.clear()
result = app.run(cmd, True)
packages = app.json_loads(result)
for p in packages:
t = '{} - ({})'.format(p['name'], p['version'])
self.d.lst_package.insert(t, 'ok.png')
self.d.lst_package.select()
self.d.txt_search.set_focus()
return
@app.run_in_thread
def _search(self, value):
self._set_state('search')
line = ''
cmd = self._cmd_pip(' search {}'.format(value))
self.d.lst_package.clear()
for line in app.popen(cmd):
parts = line.split(')')
name = parts[0].strip() + ')'
description = parts[-1].strip()
parts = name.split('(')
name_verify = parts[0].strip()
package = '{} {}'.format(name, description)
image = PACKAGES.get(name_verify, 'question.png')
self.d.lst_package.insert(package, image)
if line:
self.d.lst_package.select()
else:
self.d.lst_package.insert(_('Not found...'), 'error.png', show=False)
return
def cmd_search_action(self, event):
search = self.d.txt_search.value.strip()
if not search:
self.d.txt_search.set_focus()
return
self._search(search)
return
@app.run_in_thread
def _install(self, value):
self._set_state('install')
self.d.lst_package.visible = False
self.d.lst_log.visible = True
line = ''
name = value.split(' ')[0].strip()
cmd = self._cmd_pip(' install --upgrade --user {}'.format(name))
self.d.lst_log.clear()
for line in app.popen(cmd):
if self.OK1 in line or self.OK2 in line:
self.d.lst_log.insert(line, 'ok.png')
else:
self.d.lst_log.insert(line)
return
@app.catch_exception
def lst_package_double_click(self, event):
opt = 'install'
if self._states['list']:
opt = 'upgrade'
name = self.d.lst_package.value
msg = _('Do you want {}:\n\n{} ?').format(opt, name)
if not app.question(msg, TITLE):
return
self._install(name)
return
@app.run_in_thread
def _uninstall(self, value):
self._set_state('install')
self.d.lst_package.visible = False
self.d.lst_log.visible = True
line = ''
name = value.split(' ')[0].strip()
cmd = self._cmd_pip(' uninstall -y {}'.format(name))
self.d.lst_log.clear()
for line in app.popen(cmd):
if self.OK3 in line:
self.d.lst_log.insert(line, 'ok.png')
else:
self.d.lst_log.insert(line)
return
def cmd_uninstall_action(self, event):
if not self._states['list']:
msg = _('Select installed package')
app.warning(msg)
return
name = self.d.lst_package.value
msg = _('Do you want uninstall:\n\n{} ?').format(name)
if not app.question(msg):
return
self._uninstall(name)
return
@app.catch_exception
def cmd_shell_action(self, name):
if app.IS_WIN:
cmd = '"{}"'.format(self.path_python)
app.open_file(cmd)
else:
cmd = 'exec "{}"'
if app.IS_MAC:
cmd = 'open "{}"'
elif app.DESKTOP == 'gnome':
cmd = 'gnome-terminal -- {}'
cmd = cmd.format(self.path_python)
app.run(cmd)
return
class ZAZPip(unohelper.Base, XJobExecutor):
def __init__(self, ctx):
self.ctx = ctx
def trigger(self, args):
dialog = self._create_dialog()
dialog.open()
def trigger(self, option):
main.ID_EXTENSION = ID_EXTENSION
main.run(__file__)
return
def _create_dialog(self):
args= {
'Name': 'dialog',
'Title': 'Zaz-Pip',
'Width': 200,
'Height': 220,
}
dialog = app.create_dialog(args)
dialog.id_extension = ID_EXTENSION
dialog.events = Controllers(dialog)
lbl_title = '{} {} - {}'.format(app.NAME, app.VERSION, app.OS)
args = {
'Type': 'Label',
'Name': 'lbl_title',
'Label': lbl_title,
'Width': 100,
'Height': 15,
'Border': 1,
'Align': 1,
'VerticalAlign': 1,
'Step': 10,
'FontHeight': 12,
}
dialog.add_control(args)
dialog.center(dialog.lbl_title, y=5)
path_python = app.get_path_python()
cmd = '"{}" -V'.format(path_python)
label = app.run(cmd, True)
args = {
'Type': 'Label',
'Name': 'lbl_python',
'Label': str(label),
'Width': 100,
'Height': 15,
'Border': 1,
'Align': 1,
'VerticalAlign': 1,
'Step': 10,
'FontHeight': 11,
}
dialog.add_control(args)
dialog.center(dialog.lbl_python, y=25)
cmd = '"{}" -m pip -V'.format(path_python)
label = app.run(cmd, True)
exists_pip = True
if not label:
exists_pip = False
label = _('PIP not installed')
args = {
'Type': 'Label',
'Name': 'lbl_pip',
'Label': label,
'Width': 160,
'Height': 30,
'Border': 1,
'Align': 1,
'VerticalAlign': 1,
'Step': 10,
'MultiLine': True,
}
dialog.add_control(args)
dialog.center(dialog.lbl_pip, y=45)
args = {
'Type': 'Button',
'Name': 'cmd_admin_pip',
'Label': _('Admin PIP'),
'Width': 60,
'Height': 18,
'Step': 10,
'ImageURL': 'python.png',
'ImagePosition': 1,
}
dialog.add_control(args)
dialog.center(dialog.cmd_admin_pip, y=80)
args = {
'Type': 'Button',
'Name': 'cmd_install_pip',
'Label': _('Install PIP'),
'Width': 60,
'Height': 18,
'Step': 10,
'ImageURL': 'install.png',
'ImagePosition': 1,
}
dialog.add_control(args)
dialog.center(dialog.cmd_install_pip, y=80)
args = {
'Type': 'Link',
'Name': 'link_proyect',
'URL': 'https://gitlab.com/mauriciobaeza/',
'Label': 'https://gitlab.com/mauriciobaeza/',
'Border': 1,
'Width': 130,
'Height': 15,
'Align': 1,
'VerticalAlign': 1,
'Step': 10,
}
dialog.add_control(args)
dialog.center(dialog.link_proyect, y=-5)
args = {
'Type': 'Listbox',
'Name': 'lst_log',
'Width': 160,
'Height': 105,
'Step': 10,
}
dialog.add_control(args)
dialog.center(dialog.lst_log, y=105)
args = {
'Type': 'Label',
'Name': 'lbl_package',
'Label': _('Packages'),
'Width': 100,
'Height': 15,
'Border': 1,
'Align': 1,
'VerticalAlign': 1,
'Step': 1,
}
dialog.add_control(args)
args = {
'Type': 'Text',
'Name': 'txt_search',
'Width': 180,
'Height': 12,
'Step': 1,
'Border': 0,
}
dialog.add_control(args)
args = {
'Type': 'Listbox',
'Name': 'lst_package',
'Width': 180,
'Height': 128,
'Step': 1,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_close',
'Label': _('~Close'),
'Width': 60,
'Height': 18,
'Step': 1,
'ImageURL': 'close.png',
'ImagePosition': 1,
# ~ 'PushButtonType': 2,
}
dialog.add_control(args)
dialog.center(dialog.cmd_close, y=-5)
args = {
'Type': 'Button',
'Name': 'cmd_home',
'Width': 18,
'Height': 18,
'Step': 1,
'ImageURL': 'home.png',
'FocusOnClick': False,
'Y': 2,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_search',
'Width': 18,
'Height': 18,
'Step': 1,
'ImageURL': 'search.png',
'FocusOnClick': False,
'Y': 2,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_uninstall',
'Width': 18,
'Height': 18,
'Step': 1,
'ImageURL': 'uninstall.png',
'FocusOnClick': False,
'Y': 2,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_shell',
'Width': 18,
'Height': 18,
'Step': 1,
'ImageURL': 'shell.png',
'FocusOnClick': False,
'Y': 2,
}
dialog.add_control(args)
controls = (dialog.cmd_home, dialog.cmd_search,
dialog.cmd_uninstall, dialog.cmd_shell)
dialog.lbl_package.move(dialog.cmd_home)
dialog.txt_search.move(dialog.lbl_package)
dialog.lst_package.move(dialog.txt_search)
dialog.lbl_package.center()
dialog.lst_package.center()
dialog.txt_search.center()
dialog.center(controls)
dialog.step = 10
dialog.cmd_install_pip.visible = not exists_pip
dialog.cmd_admin_pip.visible = exists_pip
dialog.lst_log.visible = False
return dialog
g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(ZAZPip, ID_EXTENSION, SERVICE)

View File

@ -1,26 +1,33 @@
<?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">
<identifier value="net.elmau.zaz.pip" />
<version value="0.4.0" />
<?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" xmlns:l="http://libreoffice.org/extensions/description/2011">
<identifier value="net.elmau.zaz.pip"/>
<version value="1.0.0"/>
<dependencies>
<l:LibreOffice-minimal-version value="7.0"/>
</dependencies>
<display-name>
<name lang="en">ZAZ Pip</name>
<name lang="es">ZAZ Pip</name>
<name lang="fr">ZAZ Pip</name>
</display-name>
<extension-description>
<src lang="en" xlink:href="description/desc_en.txt" />
<src lang="es" xlink:href="description/desc_es.txt" />
<src lang="en" xlink:href="description/desc_en.txt"/>
<src lang="es" xlink:href="description/desc_es.txt"/>
<src lang="fr" xlink:href="description/desc_fr.txt"/>
</extension-description>
<icon>
<default xlink:href="images/zazpip.png" />
<default xlink:href="images/zazpip.png"/>
</icon>
<publisher>
<name xlink:href="https://gitlab.com/mauriciobaeza" lang="en">El Mau</name>
<name xlink:href="https://gitlab.com/mauriciobaeza" lang="es">El Mau</name>
<name xlink:href="https://git.cuates.net/elmau/zaz-pip" lang="en">El Mau</name>
<name xlink:href="https://git.cuates.net/elmau/zaz-pip" lang="es">El Mau</name>
<name xlink:href="https://git.cuates.net/elmau/zaz-pip" lang="fr">El Mau</name>
</publisher>
<registration>
<simple-license accept-by="user" suppress-on-update="true" >
<license-text xlink:href="registration/license_en.txt" lang="en" />
<license-text xlink:href="registration/license_es.txt" lang="es" />
<simple-license accept-by="user" suppress-on-update="true">
<license-text xlink:href="registration/license_en.txt" lang="en"/>
<license-text xlink:href="registration/license_es.txt" lang="es"/>
<license-text xlink:href="registration/license_fr.txt" lang="fr"/>
</simple-license>
</registration>
</description>

View File

@ -0,0 +1 @@
Pip pour LibreOffice

52
source/images/close.svg Normal file
View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 32 32"
version="1.1"
x="0px"
y="0px"
id="svg18"
width="32"
height="32">
<metadata
id="metadata24">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>9.4</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs22" />
<title
id="title2">9.4</title>
<desc
id="desc4">Created with Sketch.</desc>
<g
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
id="g12"
transform="scale(0.66666667)">
<g
fill-rule="nonzero"
fill="#000000"
id="g10">
<g
id="g8">
<path
d="m 26.828427,24 6.366079,6.366079 c 0.779879,0.779879 0.784376,2.039815 -0.0021,2.826309 -0.781048,0.781049 -2.047059,0.781368 -2.826309,0.0021 L 24,26.828427 17.633921,33.194506 c -0.779879,0.779879 -2.039815,0.784376 -2.826309,-0.0021 -0.781049,-0.781048 -0.781368,-2.047059 -0.0021,-2.826309 L 21.171573,24 14.805494,17.633921 c -0.779879,-0.779879 -0.784376,-2.039815 0.0021,-2.826309 0.781048,-0.781049 2.047059,-0.781368 2.826309,-0.0021 L 24,21.171573 30.366079,14.805494 c 0.779879,-0.779879 2.039815,-0.784376 2.826309,0.0021 0.781049,0.781048 0.781368,2.047059 0.0021,2.826309 z M 24,48 C 10.745166,48 0,37.254834 0,24 0,10.745166 10.745166,0 24,0 37.254834,0 48,10.745166 48,24 48,37.254834 37.254834,48 24,48 Z m 0,-4 C 35.045695,44 44,35.045695 44,24 44,12.954305 35.045695,4 24,4 12.954305,4 4,12.954305 4,24 4,35.045695 12.954305,44 24,44 Z"
id="path6" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

4
source/images/delete.svg Executable file
View File

@ -0,0 +1,4 @@
<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.17218 14.8284L12.0006 12M14.829 9.17157L12.0006 12M12.0006 12L9.17218 9.17157M12.0006 12L14.829 14.8284" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 505 B

37
source/images/home.svg Normal file
View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
version="1.1"
style="image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
viewBox="0 0 31.999998 31.999998"
x="0px"
y="0px"
fill-rule="evenodd"
clip-rule="evenodd"
id="svg16"
width="31.999998"
height="31.999998"><metadata
id="metadata20"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4"><style
type="text/css"
id="style2">
.fil0 {fill:black}
</style></defs><g
id="g25"
transform="scale(0.09968847)"><g
id="g10"><path
class="fil0"
d="M 230,80 V 37 h 20 v 60 z m -93,91 h 47 v -38 h -47 z m 0,15 h 47 v 78 h 46 V 151 h 20 V 284 H 72 V 151 h 20 v 113 h 45 z M 161,62 42,162 29,147 161,37 292,147 279,162 Z"
id="path6" /><path
class="fil0"
d="m 82,0 c 52,0 104,0 156,0 46,0 83,37 83,82 0,52 0,104 0,156 0,46 -37,83 -83,83 -52,0 -104,0 -156,0 C 37,321 0,284 0,238 0,186 0,134 0,82 0,37 37,0 82,0 Z m 0,16 c 52,0 104,0 156,0 37,0 66,30 66,66 0,52 0,104 0,156 0,37 -29,66 -66,66 -52,0 -104,0 -156,0 C 46,304 16,275 16,238 16,186 16,134 16,82 16,46 46,16 82,16 Z"
id="path8" /></g></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
source/images/icon_16.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

62
source/images/install.svg Normal file
View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xml:space="preserve"
version="1.1"
style="image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
viewBox="0 0 31.999998 31.999998"
x="0px"
y="0px"
fill-rule="evenodd"
clip-rule="evenodd"
id="svg16"
width="31.999998"
height="31.999998"
sodipodi:docname="install.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="1006"
id="namedview10"
showgrid="false"
inkscape:zoom="18.185904"
inkscape:cx="27.610641"
inkscape:cy="13.076849"
inkscape:window-x="0"
inkscape:window-y="37"
inkscape:window-maximized="0"
inkscape:current-layer="svg16" /><metadata
id="metadata20"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4"><style
type="text/css"
id="style2">
.fil0 {fill:black}
</style></defs><g
id="g49"><path
class="fil0"
d="m 8.1744545,0 c 5.1838005,0 10.3676005,0 15.5514015,0 4.585669,0 8.274143,3.6884734 8.274143,8.1744545 0,5.1838005 0,10.3676005 0,15.5514015 0,4.585669 -3.688474,8.274143 -8.274143,8.274143 -5.183801,0 -10.367601,0 -15.5514015,0 C 3.6884734,31.999999 0,28.311525 0,23.725856 0,18.542055 0,13.358255 0,8.1744545 0,3.6884734 3.6884734,0 8.1744545,0 Z m 0,1.5950155 c 5.1838005,0 10.3676005,0 15.5514015,0 3.688473,0 6.579439,2.9906541 6.579439,6.579439 0,5.1838005 0,10.3676005 0,15.5514015 0,3.688473 -2.890966,6.579439 -6.579439,6.579439 -5.183801,0 -10.367601,0 -15.5514015,0 -3.5887849,0 -6.579439,-2.890966 -6.579439,-6.579439 0,-5.183801 0,-10.367601 0,-15.5514015 0,-3.5887849 2.9906541,-6.579439 6.579439,-6.579439 z"
id="path8"
style="stroke-width:0.0996885" /><g
id="g6"
transform="matrix(0.31518698,0,0,0.29534593,1.9554552,2.2893253)"><path
d="M 59.309998,55.640045 45,69.070038 30.690002,55.640045 H 10.090027 V 77.029999 H 79.909973 V 55.640045 Z m -40.77002,13.599976 c -1.599976,0 -2.899963,-1.299988 -2.899963,-2.910034 0,-1.599976 1.299987,-2.899964 2.899963,-2.899964 1.610046,0 2.910034,1.299988 2.910034,2.899964 0,1.610046 -1.299988,2.910034 -2.910034,2.910034 z m 9.110046,0 c -1.600036,0 -2.900024,-1.299988 -2.900024,-2.910034 0,-1.599976 1.299988,-2.899964 2.900024,-2.899964 1.599976,0 2.899964,1.299988 2.899964,2.899964 0,1.610046 -1.299988,2.910034 -2.899964,2.910034 z"
id="path2" /><polygon
points="45,63.070038 59.640015,49.329987 59.640015,40.320038 49.619995,49.730011 49.619995,12.970001 40.380005,12.970001 40.380005,49.730011 30.359985,40.320038 30.359985,49.329987 "
id="polygon4" /></g></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

50
source/images/ok.svg Normal file
View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0"
x="0px"
y="0px"
viewBox="0 0 24 24"
enable-background="new 0 0 100 100"
xml:space="preserve"
id="svg10"
width="24"
height="24"
sodipodi:docname="ok.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1006"
id="namedview8"
showgrid="false"
inkscape:zoom="25.71875"
inkscape:cx="9.0330528"
inkscape:cy="13.975581"
inkscape:window-x="0"
inkscape:window-y="37"
inkscape:window-maximized="1"
inkscape:current-layer="svg10"
inkscape:document-rotation="0" /><metadata
id="metadata16"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs14" /><g
id="g20"
transform="matrix(0.26666667,0,0,0.26666667,-1.3333334,-1.3333334)"><path
d="M 50,5 C 25.2,5 5,25.2 5,50 5,74.8 25.2,95 50,95 74.8,95 95,74.8 95,50 95,25.2 74.8,5 50,5 Z m 0,80 C 30.7,85 15,69.3 15,50 15,30.7 30.7,15 50,15 69.3,15 85,30.7 85,50 85,69.3 69.3,85 50,85 Z"
id="path2" /><polygon
points="45,67.1 72.1,40 65,32.9 45,52.9 35,42.9 27.9,50 "
id="polygon4" /></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

54
source/images/proxy.svg Normal file
View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.0"
x="0px"
y="0px"
viewBox="0 0 18 18"
enable-background="new 0 0 100 100"
xml:space="preserve"
id="svg10"
width="18"
height="18"
sodipodi:docname="proxy.svg"
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1001"
id="namedview8"
showgrid="false"
inkscape:zoom="18.185903"
inkscape:cx="18.640812"
inkscape:cy="9.7053196"
inkscape:window-x="0"
inkscape:window-y="42"
inkscape:window-maximized="1"
inkscape:current-layer="svg10"
inkscape:document-rotation="0"
inkscape:pagecheckerboard="0" /><metadata
id="metadata16"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs14" /><g
id="g6"
transform="matrix(0.04557718,0,0,0.03664295,-2.0253858,0.04823028)"><path
d="M 309.713,296.246 C 362.693,271.617 399.53,217.861 399.53,155.331 399.53,69.545 330.345,0 245,0 159.655,0 90.47,69.545 90.47,155.332 c 0,62.523 36.831,116.275 89.801,140.908 16.753,57.946 50.682,125.857 55.671,135.645 l 5.764,11.421 c -72.419,0.308 -130.615,10.624 -130.615,23.332 0,12.903 59.953,23.362 133.909,23.362 73.956,0 133.909,-10.459 133.909,-23.362 0,-12.707 -58.186,-23.022 -130.596,-23.332 l 5.801,-11.421 c 4.945,-9.848 38.843,-77.736 55.599,-135.639 z m -100.04,-8.507 -3.868,-13.378 -12.628,-5.872 c -43.8,-20.369 -72.101,-64.785 -72.101,-113.157 0,-68.775 55.593,-124.727 123.925,-124.727 68.333,0 123.925,55.952 123.925,124.727 0,48.378 -28.306,92.797 -72.113,113.162 l -12.627,5.87 -3.87,13.376 c -8.981,31.034 -23.516,65.872 -35.322,92.015 -11.674,-25.799 -26.267,-60.698 -35.321,-92.016 z"
id="path2" /><ellipse
cx="245"
cy="155.332"
rx="51.351002"
ry="51.617001"
id="ellipse4" /></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

58
source/images/python.svg Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.0"
x="0px"
y="0px"
viewBox="0 0 18 18"
enable-background="new 0 0 100 100"
xml:space="preserve"
id="svg12"
sodipodi:docname="python.svg"
width="18"
height="18"
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1001"
id="namedview9"
showgrid="false"
inkscape:showpageshadow="false"
inkscape:zoom="26.336"
inkscape:cx="10.631835"
inkscape:cy="8.2966283"
inkscape:window-x="0"
inkscape:window-y="42"
inkscape:window-maximized="1"
inkscape:current-layer="svg12"
inkscape:document-rotation="0"
inkscape:pagecheckerboard="0" /><metadata
id="metadata18"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs16" /><g
id="g23"
transform="matrix(0.22772641,0,0,0.22616483,-2.2771868,-2.2616282)"><path
d="M 86.674,33.332 H 66.66 V 13.327 c -11.106,-4.604 -23.04,-4.265 -33.334,0 v 20.005 h -20 c -4.603,11.107 -4.264,23.039 0,33.336 h 20 v 20.007 c 11.107,4.603 23.041,4.264 33.334,0 V 66.668 h 20.014 c 4.602,-11.11 4.264,-23.043 0,-33.336 z M 33.326,56.668 v 3.333 H 18.053 c -1.863,-6.563 -1.863,-13.445 0,-20.002 h 31.94 v -6.667 h -10 V 18.055 c 3.255,-0.922 6.614,-1.389 10.02,-1.389 3.391,0 6.732,0.466 9.98,1.387 v 25.28 c 0,1.841 -1.494,3.333 -3.333,3.333 H 43.327 c -5.521,0.001 -10.001,4.478 -10.001,10.002 z m 48.62,3.333 H 49.994 v 6.667 h 10 v 15.279 c -3.255,0.921 -6.611,1.387 -10.019,1.387 -3.389,0 -6.732,-0.466 -9.98,-1.387 V 56.668 c 0,-1.844 1.493,-3.334 3.333,-3.334 H 56.66 c 5.521,0 10,-4.476 10,-10 v -3.335 h 15.286 c 1.863,6.561 1.863,13.442 0,20.002 z"
id="path2" /><circle
cx="48.326"
cy="25"
r="3.3329999"
id="circle4" /><circle
cx="51.659"
cy="75"
r="3.3329999"
id="circle6" /></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 24 24"
xml:space="preserve"
id="svg12"
width="24"
height="24"><metadata
id="metadata18"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs16" /><g
id="g23"
transform="matrix(0.24590164,0,0,0.24590164,-0.3442623,-0.19672131)"><path
d="m 50.2,22.7 c -8,0 -14.6,6.5 -14.6,14.6 0,2.1 1.7,3.7 3.7,3.7 2,0 3.7,-1.7 3.7,-3.7 0,-3.9 3.2,-7.1 7.1,-7.1 4.1,0 7.1,2.9 7.1,6.8 0,0 0,0.1 0,0.3 0,2.2 -0.6,7.4 -7.7,8.5 -1.8,0.3 -3.2,1.8 -3.2,3.7 v 10.1 c 0,2.1 1.7,3.7 3.7,3.7 2,0 3.7,-1.7 3.7,-3.7 V 52.5 C 63.1,49.6 64.6,41.5 64.6,37 64.8,29 58.2,22.7 50.2,22.7 Z"
id="path2" /><path
d="m 50.2,67.8 c -2.7,0 -4.8,2.2 -4.8,4.8 0,2.6 2.2,4.8 4.8,4.8 2.6,0 4.8,-2.2 4.8,-4.8 0,-2.6 -2.2,-4.8 -4.8,-4.8 z"
id="path4" /><path
d="M 50.2,0.8 C 23.3,0.8 1.4,22.7 1.4,49.6 1.4,76.5 23.3,98.4 50.2,98.4 77.1,98.4 99,76.5 99,49.6 99,22.7 77.1,0.8 50.2,0.8 Z m 0,90.2 C 27.4,91 8.8,72.4 8.8,49.6 8.8,26.8 27.4,8.2 50.2,8.2 73,8.2 91.6,26.8 91.6,49.6 91.5,72.4 73,91 50.2,91 Z"
id="path6" /></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

8
source/images/save.svg Normal file
View File

@ -0,0 +1,8 @@
<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 7.5V5C3 3.89543 3.89543 3 5 3H16.1716C16.702 3 17.2107 3.21071 17.5858 3.58579L20.4142 6.41421C20.7893 6.78929 21 7.29799 21 7.82843V19C21 20.1046 20.1046 21 19 21H5C3.89543 21 3 20.1046 3 19V16.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 21V17" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18 21V13.6C18 13.2686 17.7314 13 17.4 13H15" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 3V8.4C16 8.73137 15.7314 9 15.4 9H13.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 3V6" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1 12H12M12 12L9 9M12 12L9 15" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 942 B

41
source/images/search.svg Normal file
View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 32 32"
xml:space="preserve"
id="svg18"
width="32"
height="32"><metadata
id="metadata24"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs22" /><style
type="text/css"
id="style2">
.st0{fill:none;}
</style><g
id="g31"
transform="matrix(1.0666667,0,0,1.0666667,-1.0666667,-1.0666667)"><path
class="st0"
d="m 18.1,13.3 c -0.8,-0.8 -1.8,-1.2 -2.8,-1.2 -1,0 -2,0.4 -2.8,1.2 -0.8,0.8 -1.2,1.8 -1.2,2.8 0,1 0.4,2.1 1.2,2.8 1.5,1.5 4.1,1.5 5.7,0 1.5,-1.5 1.5,-4 -0.1,-5.6 z"
id="path4" /><rect
x="3"
y="3"
class="st0"
width="26"
height="2"
id="rect6" /><path
class="st0"
d="M 3,7 V 29 H 29 V 7 Z M 24.1,26.3 18.8,21 c -1,0.7 -2.2,1.1 -3.5,1.1 -1.6,0 -3.1,-0.6 -4.2,-1.8 -1.1,-1.1 -1.8,-2.6 -1.8,-4.2 0,-1.6 0.6,-3.1 1.8,-4.2 2.3,-2.3 6.1,-2.3 8.5,0 2.1,2.1 2.3,5.4 0.6,7.7 l 5.3,5.3 z"
id="path8" /><path
d="M 1,1 V 31 H 31 V 1 Z M 29,3 V 5 H 3 V 3 Z M 3,29 V 7 h 26 v 22 z"
id="path10" /><path
d="M 19.5,11.9 C 17.2,9.6 13.4,9.6 11,11.9 9.9,13 9.2,14.5 9.2,16.1 c 0,1.6 0.6,3.1 1.8,4.2 1.1,1.1 2.6,1.8 4.2,1.8 1.3,0 2.5,-0.4 3.5,-1.1 l 5.3,5.3 1.4,-1.4 -5.3,-5.3 c 1.7,-2.3 1.5,-5.6 -0.6,-7.7 z m -7,7.1 c -0.8,-0.8 -1.2,-1.8 -1.2,-2.8 0,-1 0.4,-2.1 1.2,-2.8 0.8,-0.8 1.8,-1.2 2.8,-1.2 1,0 2,0.4 2.8,1.2 1.6,1.6 1.6,4.1 0,5.7 -1.5,1.4 -4.1,1.4 -5.6,-0.1 z"
id="path12" /></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

48
source/images/shell.svg Normal file
View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 32 32"
enable-background="new 0 0 100 100"
xml:space="preserve"
id="svg14"
width="32"
height="32"><metadata
id="metadata20"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs18"><rect
x="394.24149"
y="162.41183"
width="82.899773"
height="54.685486"
id="rect30" /></defs><g
id="g45"
transform="matrix(0.41720991,0,0,0.41720991,-124.39114,-55.888818)"><g
id="g26"
transform="translate(285.95002,122.75851)"><path
fill-rule="evenodd"
clip-rule="evenodd"
d="m 28.7,60.4 c -0.7,-0.7 -0.7,-2 0,-2.7 l 8.6,-8.6 c 0.7,-0.7 2,-0.7 2.7,0 0.7,0.7 0.7,2 0,2.7 l -8.6,8.6 c -0.7,0.7 -2,0.7 -2.7,0 z"
id="path2" /><path
fill-rule="evenodd"
clip-rule="evenodd"
d="m 37.3,51.8 -8.6,-8.6 c -0.7,-0.7 -0.7,-2 0,-2.7 0.7,-0.7 2,-0.7 2.7,0 l 8.6,8.6 c 0.7,0.7 0.7,2 0,2.7 -0.7,0.7 -2,0.7 -2.7,0 z"
id="path4" /><path
fill-rule="evenodd"
clip-rule="evenodd"
d="m 47.3,59.1 c 0,-1.1 0.9,-1.9 1.9,-1.9 h 12.1 c 1.1,0 1.9,0.9 1.9,1.9 0,1 -0.8,1.9 -1.8,1.9 H 49.2 c -1,0 -1.9,-0.9 -1.9,-1.9 z"
id="path6" /><path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 85.6,11.2 H 15.4 c -1.8,0 -3.2,1.4 -3.2,3.2 v 70.3 c 0,1.8 1.4,3.2 3.2,3.2 h 70.3 c 1.8,0 3.2,-1.4 3.2,-3.2 V 14.4 c -0.1,-1.8 -1.5,-3.2 -3.3,-3.2 z m -63.8,6.4 c 1.8,0 3.2,1.4 3.2,3.2 0,1.8 -1.4,3.2 -3.2,3.2 -1.8,0 -3.2,-1.4 -3.2,-3.2 0,-1.8 1.4,-3.2 3.2,-3.2 z m 60.6,62.2 c 0,0.9 -0.7,1.6 -1.6,1.6 H 20.2 c -0.9,0 -1.6,-0.7 -1.6,-1.6 V 31.9 c 0,-0.9 0.7,-1.6 1.6,-1.6 h 60.7 c 0.9,0 1.6,0.7 1.6,1.6 v 47.9 z"
id="path8" /></g><text
xml:space="preserve"
id="text28"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect30);fill:#000000;fill-opacity:1;stroke:none;" /></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xml:space="preserve"
version="1.1"
style="image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
viewBox="0 0 31.999998 31.999998"
x="0px"
y="0px"
fill-rule="evenodd"
clip-rule="evenodd"
id="svg16"
width="31.999998"
height="31.999998"
sodipodi:docname="uninstall.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="1006"
id="namedview10"
showgrid="false"
inkscape:zoom="18.185904"
inkscape:cx="27.610641"
inkscape:cy="13.076849"
inkscape:window-x="0"
inkscape:window-y="37"
inkscape:window-maximized="0"
inkscape:current-layer="svg16" /><metadata
id="metadata20"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4"><style
type="text/css"
id="style2">
.fil0 {fill:black}
</style></defs><g
id="g60"><path
class="fil0"
d="m 8.1744545,0 c 5.1838005,0 10.3676005,0 15.5514015,0 4.585669,0 8.274143,3.6884734 8.274143,8.1744545 0,5.1838005 0,10.3676005 0,15.5514015 0,4.585669 -3.688474,8.274143 -8.274143,8.274143 -5.183801,0 -10.367601,0 -15.5514015,0 C 3.6884734,31.999999 0,28.311525 0,23.725856 0,18.542055 0,13.358255 0,8.1744545 0,3.6884734 3.6884734,0 8.1744545,0 Z m 0,1.5950155 c 5.1838005,0 10.3676005,0 15.5514015,0 3.688473,0 6.579439,2.9906541 6.579439,6.579439 0,5.1838005 0,10.3676005 0,15.5514015 0,3.688473 -2.890966,6.579439 -6.579439,6.579439 -5.183801,0 -10.367601,0 -15.5514015,0 -3.5887849,0 -6.579439,-2.890966 -6.579439,-6.579439 0,-5.183801 0,-10.367601 0,-15.5514015 0,-3.5887849 2.9906541,-6.579439 6.579439,-6.579439 z"
id="path8"
style="stroke-width:0.0996885" /><path
d="m 20.649194,18.722386 -4.364368,-0.02503 -4.656282,0.02503 H 5.1357003 v 6.317436 H 27.142038 V 18.722386 Z M 7.7990149,22.739084 c -0.5042916,0 -0.9140306,-0.383946 -0.9140306,-0.859467 0,-0.472546 0.409739,-0.856493 0.9140306,-0.856493 0.5074655,0 0.9172048,0.383947 0.9172048,0.856493 0,0.475521 -0.4097393,0.859467 -0.9172048,0.859467 z m 2.8713681,0 c -0.504311,0 -0.91405,-0.383946 -0.91405,-0.859467 0,-0.472546 0.409739,-0.856493 0.91405,-0.856493 0.504291,0 0.914031,0.383947 0.914031,0.856493 0,0.475521 -0.40974,0.859467 -0.914031,0.859467 z"
id="path2"
style="stroke-width:0.305105"
sodipodi:nodetypes="ccccccccssssssssss" /><polygon
points="49.619995,12.970001 40.380005,12.970001 40.380005,49.730011 30.359985,40.320038 30.359985,49.329987 45,63.070038 59.640015,49.329987 59.640015,40.320038 49.619995,49.730011 "
id="polygon4"
transform="matrix(-0.31518698,0,0,-0.27401538,30.322283,21.402123)" /></g></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
source/images/zazpip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

20
source/job.xcu Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE oor:component-data SYSTEM "../../../../component-update.dtd">
<oor:component-data oor:name="Jobs" oor:package="org.openoffice.Office"
xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<node oor:name="Jobs">
<node oor:name="PipRunnerJob" oor:op="fuse">
<prop oor:name="Service">
<value>net.elmau.zaz.pip.PipRunner</value>
</prop>
</node>
</node>
<node oor:name="Events">
<node oor:name="OnStartApp" oor:op="fuse">
<node oor:name="JobList">
<node oor:name="PipRunnerJob" oor:op="fuse" />
</node>
</node>
</node>
</oor:component-data>

View File

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2019-10-19 15:19-0500\n"
"POT-Creation-Date: 2022-03-26 11:23-0600\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"
@ -15,73 +15,144 @@ msgstr ""
"Generated-By: pygettext.py 1.5\n"
#: source/ZAZPip.py:49
msgid "Do you want install PIP?"
#: source/pythonpath/main.py:81
msgid "Do you want to install 'Python installer package' (PIP)?"
msgstr ""
#: source/ZAZPip.py:67
msgid "Do you have internet connection?"
#: source/pythonpath/main.py:93
msgid "Downloading PIP…"
msgstr ""
#: source/ZAZPip.py:73
msgid "File PIP not save"
#: source/pythonpath/main.py:96
msgid "Unable to connect to internet"
msgstr ""
#: source/ZAZPip.py:76
msgid "PIP save correctly..."
#: source/pythonpath/main.py:102
msgid "Unable to copy PIP installation file"
msgstr ""
#: source/ZAZPip.py:80
msgid "Start installing PIP..."
#: source/pythonpath/main.py:105
msgid "PIP installation file has been saved"
msgstr ""
#: source/ZAZPip.py:94
msgid "PIP installed sucesfully"
#: source/pythonpath/main.py:108
msgid "Starting PIP installation…"
msgstr ""
#: source/ZAZPip.py:97
msgid "PIP not installed, see log"
#: source/pythonpath/main.py:122
msgid "PIP was installed sucessfully"
msgstr ""
#: source/ZAZPip.py:173
msgid "Not found..."
#: source/pythonpath/main.py:125
msgid "PIP installation has failed, see log"
msgstr ""
#: source/ZAZPip.py:209
#: source/pythonpath/main.py:198
msgid "Package not found…"
msgstr ""
#: source/pythonpath/main.py:213
msgid "Enter the package name to install"
msgstr ""
#: source/pythonpath/main.py:218
msgid "Do you really want to install package: {}?"
msgstr ""
#: source/pythonpath/main.py:247
msgid "install"
msgstr ""
#: source/pythonpath/main.py:249
msgid "upgrade"
msgstr ""
#: source/pythonpath/main.py:252
msgid ""
"Do you want {}:\n"
"Do you want to {}:\n"
"\n"
"{} ?"
"{}?"
msgstr ""
#: source/ZAZPip.py:235
#: source/pythonpath/main.py:278
msgid "Select installed package"
msgstr ""
#: source/ZAZPip.py:240
#: source/pythonpath/main.py:283
msgid ""
"Do you want uninstall:\n"
"Do you want to uninstall:\n"
"\n"
"{} ?"
"{}?"
msgstr ""
#: source/ZAZPip.py:327
msgid "PIP not installed"
#: source/pythonpath/main.py:310
msgid ""
"Do you want to install from:\n"
"\n"
"{}"
msgstr ""
#: source/ZAZPip.py:346
#: source/pythonpath/main.py:337
msgid "Do you want to save this Proxy settings?"
msgstr ""
#: source/pythonpath/main.py:343
msgid "Proxy settings saved sucessfully"
msgstr ""
#: source/pythonpath/main.py:349
msgid "Do you want to remove Proxy settings?"
msgstr ""
#: source/pythonpath/main.py:355
msgid "Proxy settings deleted sucessfully"
msgstr ""
#: source/pythonpath/main.py:413
msgid "'Python installer package' (PIP) is not installed"
msgstr ""
#: source/pythonpath/main.py:432
msgid "Admin PIP"
msgstr ""
#: source/ZAZPip.py:359
#: source/pythonpath/main.py:445
msgid "Install PIP"
msgstr ""
#: source/ZAZPip.py:397
#: source/pythonpath/main.py:494
msgid "Packages"
msgstr ""
#: source/ZAZPip.py:429
#: source/pythonpath/main.py:536
msgid "~Close"
msgstr ""
#: source/pythonpath/main.py:635
msgid "Zaz-Pip - Proxy settings"
msgstr ""
#: source/pythonpath/main.py:646
msgid "Host: "
msgstr ""
#: source/pythonpath/main.py:669
msgid "Port: "
msgstr ""
#: source/pythonpath/main.py:690
msgid "User: "
msgstr ""
#: source/pythonpath/main.py:711
msgid "Password: "
msgstr ""
#: source/pythonpath/main.py:733
msgid "Save"
msgstr ""
#: source/pythonpath/main.py:745
msgid "Delete"
msgstr ""

View File

@ -5,84 +5,155 @@
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"
"POT-Creation-Date: 2022-03-26 11:23-0600\n"
"PO-Revision-Date: 2021-01-21 16:32-0500\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: en\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?"
#: source/pythonpath/main.py:81
msgid "Do you want to install 'Python installer package' (PIP)?"
msgstr ""
#: source/ZAZPip.py:67
msgid "Do you have internet connection?"
#: source/pythonpath/main.py:93
msgid "Downloading PIP…"
msgstr ""
#: source/ZAZPip.py:73
msgid "File PIP not save"
#: source/pythonpath/main.py:96
msgid "Unable to connect to internet"
msgstr ""
#: source/ZAZPip.py:76
msgid "PIP save correctly..."
#: source/pythonpath/main.py:102
msgid "Unable to copy PIP installation file"
msgstr ""
#: source/ZAZPip.py:80
msgid "Start installing PIP..."
#: source/pythonpath/main.py:105
msgid "PIP installation file has been saved"
msgstr ""
#: source/ZAZPip.py:94
msgid "PIP installed sucesfully"
#: source/pythonpath/main.py:108
msgid "Starting PIP installation…"
msgstr ""
#: source/ZAZPip.py:97
msgid "PIP not installed, see log"
#: source/pythonpath/main.py:122
msgid "PIP was installed sucessfully"
msgstr ""
#: source/ZAZPip.py:173
msgid "Not found..."
#: source/pythonpath/main.py:125
msgid "PIP installation has failed, see log"
msgstr ""
#: source/ZAZPip.py:209
#: source/pythonpath/main.py:198
msgid "Package not found…"
msgstr ""
#: source/pythonpath/main.py:213
msgid "Enter the package name to install"
msgstr ""
#: source/pythonpath/main.py:218
msgid "Do you really want to install package: {}?"
msgstr ""
#: source/pythonpath/main.py:247
msgid "install"
msgstr ""
#: source/pythonpath/main.py:249
msgid "upgrade"
msgstr ""
#: source/pythonpath/main.py:252
msgid ""
"Do you want {}:\n"
"Do you want to {}:\n"
"\n"
"{} ?"
"{}?"
msgstr ""
#: source/ZAZPip.py:235
#: source/pythonpath/main.py:278
msgid "Select installed package"
msgstr ""
#: source/ZAZPip.py:240
#: source/pythonpath/main.py:283
msgid ""
"Do you want uninstall:\n"
"Do you want to uninstall:\n"
"\n"
"{} ?"
"{}?"
msgstr ""
#: source/ZAZPip.py:327
msgid "PIP not installed"
#: source/pythonpath/main.py:310
msgid ""
"Do you want to install from:\n"
"\n"
"{}"
msgstr ""
#: source/ZAZPip.py:346
#: source/pythonpath/main.py:337
msgid "Do you want to save this Proxy settings?"
msgstr ""
#: source/pythonpath/main.py:343
msgid "Proxy settings saved sucessfully"
msgstr ""
#: source/pythonpath/main.py:349
msgid "Do you want to remove Proxy settings?"
msgstr ""
#: source/pythonpath/main.py:355
msgid "Proxy settings deleted sucessfully"
msgstr ""
#: source/pythonpath/main.py:413
msgid "'Python installer package' (PIP) is not installed"
msgstr ""
#: source/pythonpath/main.py:432
msgid "Admin PIP"
msgstr ""
#: source/ZAZPip.py:359
#: source/pythonpath/main.py:445
msgid "Install PIP"
msgstr ""
#: source/ZAZPip.py:397
#: source/pythonpath/main.py:494
msgid "Packages"
msgstr ""
#: source/ZAZPip.py:429
#: source/pythonpath/main.py:536
msgid "~Close"
msgstr ""
#: source/pythonpath/main.py:635
msgid "Zaz-Pip - Proxy settings"
msgstr ""
#: source/pythonpath/main.py:646
msgid "Host: "
msgstr ""
#: source/pythonpath/main.py:669
msgid "Port: "
msgstr ""
#: source/pythonpath/main.py:690
msgid "User: "
msgstr ""
#: source/pythonpath/main.py:711
msgid "Password: "
msgstr ""
#: source/pythonpath/main.py:733
msgid "Save"
msgstr ""
#: source/pythonpath/main.py:745
msgid "Delete"
msgstr ""

View File

@ -5,90 +5,182 @@
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"
"POT-Creation-Date: 2022-03-26 11:23-0600\n"
"PO-Revision-Date: 2022-03-26 11:28-0600\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"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 3.0.1\n"
#: source/ZAZPip.py:49
msgid "Do you want install PIP?"
msgstr "¿Desea instalar PIP?"
#: source/pythonpath/main.py:81
msgid "Do you want to install 'Python installer package' (PIP)?"
msgstr "¿Desea instalar el instalador de paquetes Python (PIP)?"
#: source/ZAZPip.py:67
msgid "Do you have internet connection?"
msgstr "¿Tiene conexión a Internet?"
#: source/pythonpath/main.py:93
msgid "Downloading PIP…"
msgstr "Descargando PIP…"
#: source/ZAZPip.py:73
msgid "File PIP not save"
msgstr "No se guardo el archivo PIP"
#: source/pythonpath/main.py:96
msgid "Unable to connect to internet"
msgstr "No se puede conectar a Internet"
#: source/ZAZPip.py:76
msgid "PIP save correctly..."
msgstr "Archivo PIP guardado correctamente..."
#: source/pythonpath/main.py:102
msgid "Unable to copy PIP installation file"
msgstr "No se puede copiar el archivo de instalación de PIP"
#: source/ZAZPip.py:80
msgid "Start installing PIP..."
msgstr "Iniciando instalación de PIP..."
#: source/pythonpath/main.py:105
msgid "PIP installation file has been saved"
msgstr "Se ha guardado el archivo de instalación de PIP"
#: source/ZAZPip.py:94
msgid "PIP installed sucesfully"
#: source/pythonpath/main.py:108
msgid "Starting PIP installation…"
msgstr "Iniciando la instalación de PIP…"
#: source/pythonpath/main.py:122
msgid "PIP was installed sucessfully"
msgstr "PIP instalado correctamente"
#: source/ZAZPip.py:97
msgid "PIP not installed, see log"
msgstr "PIP no fue instalado, vea el registro"
#: source/pythonpath/main.py:125
msgid "PIP installation has failed, see log"
msgstr "Ha fallado la instalación de PIP, vea el registro"
#: source/ZAZPip.py:173
msgid "Not found..."
msgstr "No encontrado..."
#: source/pythonpath/main.py:198
msgid "Package not found…"
msgstr "Paquete no encontrado…"
#: source/ZAZPip.py:209
#: source/pythonpath/main.py:213
msgid "Enter the package name to install"
msgstr "Introduzca el nombre del paquete a instalar"
#: source/pythonpath/main.py:218
msgid "Do you really want to install package: {}?"
msgstr "¿Desea instalar el paquete: {}?"
#: source/pythonpath/main.py:247
msgid "install"
msgstr "instalar"
#: source/pythonpath/main.py:249
msgid "upgrade"
msgstr "actualizar"
#: source/pythonpath/main.py:252
msgid ""
"Do you want {}:\n"
"Do you want to {}:\n"
"\n"
"{} ?"
"{}?"
msgstr ""
"¿Desea {}:\n"
"\n"
"{} ?"
#: source/ZAZPip.py:235
#: source/pythonpath/main.py:278
msgid "Select installed package"
msgstr "Seleccione un paquete instalado"
#: source/ZAZPip.py:240
#: source/pythonpath/main.py:283
msgid ""
"Do you want uninstall:\n"
"Do you want to uninstall:\n"
"\n"
"{} ?"
"{}?"
msgstr ""
"¿Desea desinstalar:\n"
"\n"
"{} ?"
#: source/ZAZPip.py:327
msgid "PIP not installed"
msgstr "PIP no esta instalado"
#: source/pythonpath/main.py:310
msgid ""
"Do you want to install from:\n"
"\n"
"{}"
msgstr ""
"¿Desea desinstalar desde:\n"
"\n"
"{} ?"
#: source/ZAZPip.py:346
#: source/pythonpath/main.py:337
msgid "Do you want to save this Proxy settings?"
msgstr "¿Desea guardar la configuración del Proxy?"
#: source/pythonpath/main.py:343
msgid "Proxy settings saved sucessfully"
msgstr "PIP instalado correctamente"
#: source/pythonpath/main.py:349
msgid "Do you want to remove Proxy settings?"
msgstr "¿Desea eliminar la configuración del Proxy?"
#: source/pythonpath/main.py:355
msgid "Proxy settings deleted sucessfully"
msgstr "Configuración del Proxy borrada correctamente"
#: source/pythonpath/main.py:413
msgid "'Python installer package' (PIP) is not installed"
msgstr "El \"instalador de paquetes de Python\" (PIP) no está instalado"
#: source/pythonpath/main.py:432
msgid "Admin PIP"
msgstr "Administrar PIP"
#: source/ZAZPip.py:359
#: source/pythonpath/main.py:445
msgid "Install PIP"
msgstr "Instalar PIP"
#: source/ZAZPip.py:397
#: source/pythonpath/main.py:494
msgid "Packages"
msgstr "Paquetes"
#: source/ZAZPip.py:429
#: source/pythonpath/main.py:536
msgid "~Close"
msgstr "~Cerrar"
#: source/pythonpath/main.py:635
msgid "Zaz-Pip - Proxy settings"
msgstr "Zaz-Pip - Configuración del Proxy"
#: source/pythonpath/main.py:646
msgid "Host: "
msgstr "Host: "
#: source/pythonpath/main.py:669
msgid "Port: "
msgstr "Puerto: "
#: source/pythonpath/main.py:690
msgid "User: "
msgstr "Usuario: "
#: source/pythonpath/main.py:711
msgid "Password: "
msgstr "Contraseña: "
#: source/pythonpath/main.py:733
msgid "Save"
msgstr "Guardar"
#: source/pythonpath/main.py:745
msgid "Delete"
msgstr "Eliminar"
#~ msgid "Do you have internet connection?"
#~ msgstr "¿Tiene conexión a Internet?"
#~ msgid "File PIP not save"
#~ msgstr "No se guardo el archivo PIP"
#~ msgid "PIP save correctly..."
#~ msgstr "Archivo PIP guardado correctamente..."
#~ msgid "Start installing PIP..."
#~ msgstr "Iniciando instalación de PIP..."
#~ msgid "Not found..."
#~ msgstr "No encontrado..."
#~ msgid "PIP not installed"
#~ msgstr "PIP no esta instalado"

Binary file not shown.

View File

@ -0,0 +1,168 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2022-03-26 11:23-0600\n"
"PO-Revision-Date: 2022-03-26 11:41-0600\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 3.0.1\n"
#: source/pythonpath/main.py:81
msgid "Do you want to install 'Python installer package' (PIP)?"
msgstr "Souhaitez-vous installer 'Python installer package' (PIP) ?"
#: source/pythonpath/main.py:93
msgid "Downloading PIP…"
msgstr "Téléchargement de PIP…"
#: source/pythonpath/main.py:96
msgid "Unable to connect to internet"
msgstr "Pas de connection à internet"
#: source/pythonpath/main.py:102
msgid "Unable to copy PIP installation file"
msgstr "La réception du fichier d'installation de PIP a échoué"
#: source/pythonpath/main.py:105
msgid "PIP installation file has been saved"
msgstr "Fichier d'installation de PIP reçu"
#: source/pythonpath/main.py:108
msgid "Starting PIP installation…"
msgstr "Démarrage de l'installation de PIP…"
#: source/pythonpath/main.py:122
msgid "PIP was installed sucessfully"
msgstr "PIP est maintenant installé"
#: source/pythonpath/main.py:125
msgid "PIP installation has failed, see log"
msgstr "Echec à l'installation de PIP, consultez le fichier Log'"
#: source/pythonpath/main.py:198
msgid "Package not found…"
msgstr "Paquet non trouvé…"
#: source/pythonpath/main.py:213
msgid "Enter the package name to install"
msgstr "Nom du paquet à installer"
#: source/pythonpath/main.py:218
msgid "Do you really want to install package: {}?"
msgstr "Souhaitez-vous désinstaller :{} ?"
#: source/pythonpath/main.py:247
msgid "install"
msgstr "installer"
#: source/pythonpath/main.py:249
msgid "upgrade"
msgstr "mise à niveau"
#: source/pythonpath/main.py:252
msgid ""
"Do you want to {}:\n"
"\n"
"{}?"
msgstr ""
"Souhaitez-vous {}\n"
"\n"
"\"{}"
#: source/pythonpath/main.py:278
msgid "Select installed package"
msgstr "Choisissez un paquet déjà installé"
#: source/pythonpath/main.py:283
msgid ""
"Do you want to uninstall:\n"
"\n"
"{}?"
msgstr ""
"Souhaitez-vous désinstaller :\n"
"\n"
"{} ?"
#: source/pythonpath/main.py:310
msgid ""
"Do you want to install from:\n"
"\n"
"{}"
msgstr ""
"Souhaitez-vous installer :\n"
"\n"
"{} ?"
#: source/pythonpath/main.py:337
msgid "Do you want to save this Proxy settings?"
msgstr "Enregistrer les données du mandataire (Proxy) ?"
#: source/pythonpath/main.py:343
msgid "Proxy settings saved sucessfully"
msgstr "Les données mandataire (Proxy) sont enregistrées"
#: source/pythonpath/main.py:349
msgid "Do you want to remove Proxy settings?"
msgstr "Supprimer les données du mandataire (Proxy)?"
#: source/pythonpath/main.py:355
msgid "Proxy settings deleted sucessfully"
msgstr "Les données mandataire (Proxy) sont supprimées"
#: source/pythonpath/main.py:413
msgid "'Python installer package' (PIP) is not installed"
msgstr "'Python installer package' (PIP) absent"
#: source/pythonpath/main.py:432
msgid "Admin PIP"
msgstr "Administrer PIP"
#: source/pythonpath/main.py:445
msgid "Install PIP"
msgstr "Installer PIP"
#: source/pythonpath/main.py:494
msgid "Packages"
msgstr "Paquets"
#: source/pythonpath/main.py:536
msgid "~Close"
msgstr "~Fermer"
#: source/pythonpath/main.py:635
msgid "Zaz-Pip - Proxy settings"
msgstr "Zaz-PIP Données mandataire (Proxy)"
#: source/pythonpath/main.py:646
msgid "Host: "
msgstr "Hôte: "
#: source/pythonpath/main.py:669
msgid "Port: "
msgstr "Port: "
#: source/pythonpath/main.py:690
msgid "User: "
msgstr "Utilisateur: "
#: source/pythonpath/main.py:711
msgid "Password: "
msgstr "Mot de passe: "
#: source/pythonpath/main.py:733
msgid "Save"
msgstr "Enregistrer"
#: source/pythonpath/main.py:745
msgid "Delete"
msgstr "Supprimer"

57
source/pip_runner.py Normal file
View File

@ -0,0 +1,57 @@
# region Imports
from __future__ import unicode_literals, annotations
import os
import sys
from typing import TYPE_CHECKING, Tuple
from pathlib import Path
import uno
import unohelper
from com.sun.star.task import XJob
if TYPE_CHECKING:
# just for design time
from com.sun.star.beans import NamedValue
# endregion Imports
# region Constants
implementation_name = "net.elmau.zaz.pip.PipRunner"
implementation_services = ("com.sun.star.task.Job",)
# endregion Constants
# region XJob
class PipRunner(unohelper.Base, XJob):
def __init__(self, ctx):
self._is_flatpak = bool(os.getenv("FLATPAK_ID", ""))
if self._is_flatpak:
site_packages = self.get_flatpak_site_packages_dir()
ss = str(site_packages)
if site_packages.exists() and ss not in sys.path:
sys.path.append(ss)
def execute(self, *args: Tuple[NamedValue, ...]) -> None:
pass
def get_flatpak_site_packages_dir(self) -> Path:
# should never be all users
sand_box = os.getenv("FLATPAK_SANDBOX_DIR", "") or str(
Path.home() / ".var/app/org.libreoffice.LibreOffice/sandbox"
)
major_minor = f"{sys.version_info.major}.{sys.version_info.minor}"
site_packages = Path(sand_box) / f"lib/python{major_minor}/site-packages"
site_packages.mkdir(parents=True, exist_ok=True)
return site_packages
# endregion XJob
# region Implementation
g_TypeTable = {}
g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(PipRunner, implementation_name, implementation_services)
# endregion Implementation

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,214 @@
from __future__ import annotations
from typing import cast
import os
import sys
import tempfile
import subprocess
from pathlib import Path
from typing import Any, List, Dict
import easymacro as app
from contextlib import contextmanager
import uno
@contextmanager
def change_dir(directory):
"""
A context manager that changes the current working directory to the specified directory
temporarily and then changes it back when the context is exited.
"""
current_dir = os.getcwd()
os.chdir(directory)
try:
yield
finally:
os.chdir(current_dir)
class InstallPipFromWheel:
"""Download and install PIP from wheel url"""
def __init__(self, pip_wheel_url: str, lo_identifier: str) -> None:
self._pip_url = pip_wheel_url
self._lo_identifier = lo_identifier
def install(self, dst: str | Path = "") -> None:
"""
Install pip from wheel file.
Downloads the pip wheel file from the url provided in the config file and unzips it to the destination directory.
Args:
dst (str | Path, Optional): The destination directory where the pip wheel file will be installed. If not provided, the ``pythonpath`` location will be used.
Returns:
None:
Raises:
None:
"""
if not self._pip_url:
app.error("PIP installation has failed - No wheel url")
return
if not dst:
root_pth = Path(app.Paths.from_id(self._lo_identifier))
dst = root_pth / "pythonpath"
with tempfile.TemporaryDirectory() as temp_dir:
# temp_dir = tempfile.gettempdir()
path_pip = Path(temp_dir)
filename = path_pip / "pip-wheel.whl"
data, _, err = app.url_open(self._pip_url, verify=False)
if err:
app.error("Unable to download PIP installation wheel file")
return
filename.write_bytes(data)
if filename.exists():
app.info("PIP wheel file has been saved")
else:
app.error("PIP wheel file has not been saved")
return
try:
self._unzip_wheel(filename=filename, dst=dst)
except Exception:
return
# now that pip has been installed from wheel force a reinstall to ensure it is the latest version
self._force_install_pip()
def _unzip_wheel(self, filename: Path, dst: str | Path) -> None:
"""Unzip the downloaded wheel file"""
if isinstance(dst, str):
dst = Path(dst)
try:
# app.zip.unzip(source=str(filename), target=str(dst))
self.unzip_file(zip_file=filename, dest_dir=dst)
if dst.exists():
app.debug(f"PIP wheel file has been unzipped to {dst}")
else:
app.error("PIP wheel file has not been unzipped")
raise Exception("PIP wheel file has not been unzipped")
except Exception as err:
app.error(f"Unable to unzip wheel file: {err}", exc_info=True)
raise
def _force_install_pip(self) -> None:
"""Now that pip has been installed, force reinstall it to ensure it is the latest version"""
cmd = [app.paths.python, "-m", "pip", "install", "--upgrade", "pip"]
app.popen(command=" ".join(cmd))
def unzip_file(self, zip_file: str | Path, dest_dir: str | Path = "") -> None:
"""
Unzip the given zip file to the specified destination directory.
Args:
zip_file (str | Path): The zip file to unzip.
dest_dir (str | Path, optional): The destination directory to unzip to.
Returns:
None:
"""
from zipfile import ZipFile
zip_file_path = Path(zip_file) if isinstance(zip_file, str) else zip_file
if not zip_file_path.is_file():
raise ValueError(f"Expected file, got '{zip_file_path}'")
if not zip_file_path.is_absolute():
zip_file_path = zip_file_path.absolute()
if not zip_file_path.exists():
raise FileNotFoundError(f"File '{zip_file_path}' not found")
if isinstance(dest_dir, str):
dest_dir = zip_file_path.parent if dest_dir == "" else Path(dest_dir)
else:
dest_dir = dest_dir.absolute()
if not dest_dir.is_dir():
raise ValueError(f"Expected folder, got '{dest_dir}'")
if not dest_dir.exists():
try:
dest_dir.mkdir(parents=True)
except Exception as e:
raise FileNotFoundError(
f"Folder '{dest_dir}' not found, unable to create folder."
) from e
if not dest_dir.exists():
raise FileNotFoundError(f"Folder '{dest_dir}' not found")
with change_dir(dest_dir):
with ZipFile(zip_file_path) as f:
f.extractall(dest_dir)
# with change_dir(dest_dir):
# shutil.unpack_archive(zip_file_path, dest_dir)
class FlatpakInstaller:
"""class for the PIP install."""
def __init__(self, pip_wheel_url: str, lo_identifier: str) -> None:
self.path_python = app.Paths.python
app.debug(f"Python path: {self.path_python}")
self._pip_url = pip_wheel_url
self._lo_identifier = lo_identifier
self._site_packages = cast(str, app.get_flatpak_site_packages_dir())
def install_pip(self) -> None:
if self.is_pip_installed():
app.info("PIP is already installed")
return
if self._install_wheel():
if self.is_pip_installed():
app.info("PIP was installed successfully")
else:
app.error("PIP installation has failed")
return
def _get_pip_cmd(self, filename: Path) -> List[str]:
return [str(self.path_python), f"{filename}", "--user"]
def _get_env(self) -> Dict[str, str]:
"""
Gets Environment used for subprocess.
"""
my_env = os.environ.copy()
py_path = ""
p_sep = ";" if app.IS_WIN else ":"
for d in sys.path:
py_path = py_path + d + p_sep
my_env["PYTHONPATH"] = py_path
return my_env
def _cmd_pip(self, *args: str) -> List[str]:
cmd: List[str] = [str(self.path_python), "-m", "pip", *args]
return cmd
def _install_wheel(self) -> bool:
result = False
installer = InstallPipFromWheel(
pip_wheel_url=self._pip_url, lo_identifier=self._lo_identifier
)
try:
installer.install(self._site_packages)
if self._site_packages not in sys.path:
sys.path.append(self._site_packages)
result = True
except Exception as err:
app.error(err)
return result
return result
def is_pip_installed(self) -> bool:
"""Check if PIP is installed."""
# cmd = self._cmd_pip("--version")
# cmd = '"{}" -m pip -V'.format(self.path_python)
cmd = [str(self.path_python), "-m", "pip", "-V"]
result = subprocess.run(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self._get_env()
)
return result.returncode == 0

View File

@ -0,0 +1,146 @@
"""
On some systems such as Mac and AppImage (Linux) the python extension suffix does not match the
cpython suffix used by the embedded python interpreter.
This class creates symlinks for all .so files in dest folder that match the current python embedded suffix.
For example a file named ``indexers.cpython-38-x86_64-linux-gnu.so`` would be symlinked to ``indexers.cpython-3.8.so``.
This renaming allows the python interpreter to find the import.
"""
from __future__ import annotations
from typing import List
from pathlib import Path
from importlib import machinery
import easymacro as app
class LinkCPython:
def __init__(self, pth: str) -> None:
"""
Constructor
Args:
pth (str): Path to site-packages folder.
"""
self._current_suffix = self._get_current_suffix()
app.debug("CPythonLink.__init__")
self._link_root = Path(pth)
if not self._link_root.exists():
raise FileNotFoundError(f"Path does not exist {self._link_root}")
app.debug("CPythonLink.__init__ done")
def _get_current_suffix(self) -> str:
"""Gets suffix currently used by the embedded python interpreter such as ``cpython-3.8``"""
for suffix in machinery.EXTENSION_SUFFIXES:
if suffix.startswith(".cpython-") and suffix.endswith(".so"):
# remove leading . and trailing .so
return suffix[1:][:-3]
return ""
def _get_all_files(self, path: Path) -> List[Path]:
return [p for p in path.glob(f"**/*{self.file_suffix}.so") if p.is_file()]
def _get_all_links(self, path: Path) -> List[Path]:
return [p for p in path.glob(f"**/*{self.current_suffix}.so") if p.is_symlink()]
def _create_symlink(self, src: Path, dst: Path, overwrite: bool) -> None:
if dst.is_symlink():
if overwrite:
app.debug(f"Removing existing symlink {dst}")
dst.unlink()
else:
app.debug(f"Symlink already exists {dst}")
return
dst.symlink_to(src)
app.debug(f"Created symlink {dst} -> {src}")
def _find_current_installed_suffix(self, path: Path) -> str:
"""
Finds the current suffix from the current installed python so files such as ``cpython-38-x86_64-linux-gnu``.
Args:
path (Path): Path to search in. Usually site-packages.
Returns:
str: suffix if found, otherwise empty string.
"""
return next(
(str(p).rsplit(".", 2)[1] for p in path.glob("**/*.cpython-*.so") if not p.is_symlink()),
"",
)
def link(self, overwrite:bool = False) -> None:
"""
Creates symlinks for all .so files in site-packages that match the current suffix.
Args:
overwrite (bool, optional): Override any existing sys links. Defaults to False.
"""
app.debug("CPythonLink.link starting")
if not self._link_root:
app.debug("No site-packages found")
return
if not self.file_suffix:
app.debug("No current file suffix found")
return
if not self._link_root.exists():
app.debug(f"Site-packages does not exist {self._link_root}")
return
app.debug(f"Python current suffix: {self._current_suffix}")
app.debug(f"Found file suffix: {self.file_suffix}")
files = self._get_all_files(self._link_root)
if not files:
app.debug(f"No files found in {self._link_root}")
return
cp_old = self.file_suffix
cp_new = self._current_suffix
if cp_old == cp_new:
app.debug(f"Suffixes match, no need to link: {cp_old} == {cp_new}")
return
for file in files:
ln_name = file.name.replace(cp_old, cp_new)
src = file
if not src.is_absolute():
src = file.resolve()
dst = src.parent / ln_name
self._create_symlink(src, dst, overwrite)
app.debug("CPythonLink.link done")
def unlink(self) -> None:
"""Unlinks all broken sys links"""
links = self._get_all_links(self._link_root)
if not links:
app.debug(f"No links found in {self._link_root}")
return
for link in links:
if not link.exists():
app.debug(f"Removing broken symlink {link}")
link.unlink()
# region Properties
@property
def cpy_name(self) -> str:
"""Gets/Sets CPython name, e.g. cpython-3.8"""
return self._current_suffix
@cpy_name.setter
def cpy_name(self, value: str) -> None:
self._current_suffix = value
@property
def current_suffix(self) -> str:
"""Current Suffix such as ``cpython-3.8``"""
return self._current_suffix
@property
def file_suffix(self) -> str:
"""Current Suffix such as ``cpython-38-x86_64-linux-gnu``"""
try:
return self._file_suffix
except AttributeError:
self._file_suffix = self._find_current_installed_suffix(self._link_root)
return self._file_suffix
# endregion Properties

826
source/pythonpath/main.py Normal file
View File

@ -0,0 +1,826 @@
#!/usr/bin/env python3
import os
import easymacro as app
ID_EXTENSION = ''
_ = None
TITLE = 'ZAZ-PIP'
URL_PIP = 'https://bootstrap.pypa.io/get-pip.py'
URL_PIP_WHEEL = 'https://files.pythonhosted.org/packages/47/6a/453160888fab7c6a432a6e25f8afe6256d0d9f2cbd25971021da6491d899/pip-23.3.1-py3-none-any.whl'
URL_TEST = 'http://duckduckgo.com'
PIP = 'pip'
URL_GIT = 'https://git.cuates.net/elmau/zaz-pip'
ICON_OK = 'ok.svg'
ICON_QUESTION = 'question.svg'
PACKAGES = {
'cffi': ICON_OK,
'cryptography': ICON_OK,
'httpx': ICON_OK,
'lxml': ICON_OK,
'numpy': ICON_OK,
'pandas': ICON_OK,
'psycopg2-binary': ICON_OK,
'peewee': ICON_OK,
'pillow': ICON_OK,
'pytesseract': ICON_OK,
'sounddevice': ICON_OK,
}
def open_dialog_pip():
dialog = _create_dialog()
proxy = app.get_config('proxy', {}, TITLE)
if proxy:
app.debug(proxy)
HOST = proxy['txt_proxy_host']
PORT = proxy['txt_proxy_port']
USER = proxy['txt_proxy_user']
PASS = proxy['txt_proxy_pass']
os.environ['http_proxy'] = f'http://{USER}:{PASS}@{HOST}:{PORT}'
os.environ['https_proxy'] = f'http://{USER}:{PASS}@{HOST}:{PORT}'
dialog.open()
return
def run(path_locales):
global _
_ = app.install_locales(path_locales)
open_dialog_pip()
return
class Controllers(object):
OK1 = 'Successfully installed'
OK2 = 'Requirement already'
OK3 = 'Successfully uninstalled'
def __init__(self, dialog):
self.d = dialog
self.path_python = app.paths.python
def _set_state(self, state):
self._states = {
'list': False,
'install': False,
'search': False,
'versions': False,
}
self._states[state] = True
return
def cmd_install_pip_action(self, event):
msg = _("Do you want to install 'Python installer package' (PIP)?")
if not app.question(msg, TITLE):
return
self._install_pip()
return
def _install_pip_normal(self) -> None:
self.d.link_proyect.visible = False
self.d.lst_log.visible = True
path_pip = app.paths.tmp()
self.d.lst_log.insert(_('Downloading PIP…'))
data, h, err = app.url_open(URL_PIP, verify=False)
if err:
msg = _('Unable to connect to internet')
app.errorbox('{}\n\n{}'.format(msg, err))
return
app.paths.save_bin(path_pip, data)
if not app.paths.exists(path_pip):
msg = _('Unable to copy PIP installation file')
app.errorbox(msg)
return
self.d.lst_log.insert(_('PIP installation file has been saved'))
try:
self.d.lst_log.insert(_("Starting PIP installation…"))
cmd = f'"{self.path_python}" "{path_pip}" --user'
for line in app.popen(cmd):
if isinstance(line, tuple):
app.errorbox(line)
break
self.d.lst_log.insert(line)
cmd = self._cmd_pip('-V')
label = app.run(cmd, True)
if label:
self.d.lbl_pip.value = label
self.d.cmd_install_pip.visible = False
self.d.cmd_admin_pip.visible = True
msg = _('PIP was installed successfully')
app.msgbox(msg)
else:
msg = _('PIP installation has failed, see log')
app.warning(msg)
except Exception as e:
app.errorbox(e)
return
def _install_pip_flatpak(self) -> None:
try:
from install_flatpak import FlatpakInstaller
installer = FlatpakInstaller(pip_wheel_url=URL_PIP_WHEEL, lo_identifier=ID_EXTENSION)
installer.install_pip()
msg = _('PIP was installed successfully')
# app.msgbox(msg)
cmd = self._cmd_pip('-V')
label = app.run(cmd, True)
if label:
self.d.lbl_pip.value = label
self.d.cmd_install_pip.visible = False
self.d.cmd_admin_pip.visible = True
msg = _('PIP was installed successfully')
app.msgbox(msg)
else:
msg = _('PIP installation has failed, see log')
app.warning(msg)
except Exception as e:
app.errorbox(e)
@app.run_in_thread
def _install_pip(self):
if app.IS_FLATPAK:
self._install_pip_flatpak()
else:
self._install_pip_normal()
return
def _cmd_pip(self, args):
cmd = '"{}" -m pip {}'.format(self.path_python, args)
return cmd
def cmd_admin_pip_action(self, event):
self.d.lst_log.ps_from(self.d.lst_package)
self.d.lst_log.step = 1
self.d.step = 1
self.cmd_home_action(None)
return
def cmd_close_action(self, event):
self.d.close()
return
def cmd_home_action(self, event):
self.d.txt_search.value = ''
self._list()
return
def txt_search_key_released(self, event):
if event.KeyCode == app.KEY['enter']:
# ~ self.cmd_search_action(None)
self.cmd_install_action(None)
return
if not self.d.txt_search.value.strip():
self.cmd_home_action(None)
return
@app.run_in_thread
def _list(self):
self._set_state('list')
self.d.lst_log.visible = False
self.d.lst_package.visible = True
cmd = self._cmd_pip(' list --format=json')
self.d.lst_package.clear()
result = app.run(cmd, True)
packages = app.json_loads(result)
for p in packages:
t = '{} - ({})'.format(p['name'], p['version'])
self.d.lst_package.insert(t, ICON_OK)
self.d.lst_package.select()
self.d.txt_search.set_focus()
return
@app.run_in_thread
def _search(self, value):
self._set_state('search')
line = ''
cmd = self._cmd_pip(' search {}'.format(value))
self.d.lst_package.clear()
for line in app.popen(cmd):
parts = line.split(')')
name = parts[0].strip() + ')'
description = parts[-1].strip()
parts = name.split('(')
name_verify = parts[0].strip()
package = '{} {}'.format(name, description)
image = PACKAGES.get(name_verify, ICON_QUESTION)
self.d.lst_package.insert(package, image)
if line:
self.d.lst_package.select()
else:
self.d.lst_package.insert(_('Package not found…'), 'error.png', show=False)
return
def cmd_search_action(self, event):
search = self.d.txt_search.value.strip()
if not search:
self.d.txt_search.set_focus()
return
self._search(search)
return
def cmd_install_action(self, event):
name = self.d.txt_search.value.strip()
if not name:
msg = _('Enter the package name to install')
app.warning(msg)
self.d.txt_search.set_focus()
return
msg = _('Do you really want to install package: {}?').format(name)
if not app.question(msg):
return
self._install(name)
return
@app.run_in_thread
def _install(self, value: str='', path: str=''):
self._set_state('install')
self.d.lst_package.visible = False
self.d.lst_log.visible = True
line = ''
if app.IS_FLATPAK:
cmd = f' install --upgrade --target={app.get_site_packages_dir()}'
else:
cmd = ' install --upgrade --user'
if value:
name = value.split(' ')[0].strip()
cmd = self._cmd_pip(f'{cmd} {name}')
else:
cmd = self._cmd_pip(f'{cmd} -r "{path}"')
self.d.lst_log.clear()
for line in app.popen(cmd):
if self.OK1 in line or self.OK2 in line:
self.d.lst_log.insert(line, 'ok.png')
else:
self.d.lst_log.insert(line)
self._link_cpython()
return
def _link_cpython(self):
if not app.IS_MAC and not app.IS_APP_IMAGE:
return
try:
app.debug("Linking CPython")
from link_cpython import LinkCPython
cpy_link = LinkCPython(pth=app.get_site_packages_dir())
cpy_link.link()
except Exception as err:
app.error(err)
return
def _unlink_cpython(self):
if not app.IS_MAC and not app.IS_APP_IMAGE:
return
try:
app.debug("Unlinking CPython")
from link_cpython import LinkCPython
cpy_link = LinkCPython(pth=app.get_site_packages_dir())
cpy_link.unlink()
except Exception as err:
app.error(err)
return
def lst_package_double_click(self, event):
opt = _('install')
if self._states['list']:
opt = _('upgrade')
name = self.d.lst_package.value
msg = _('Do you want to {}:\n\n{}?').format(opt, name)
if not app.question(msg, TITLE):
return
self._install(name)
return
@app.run_in_thread
def _uninstall(self, value):
self._set_state('install')
self.d.lst_package.visible = False
self.d.lst_log.visible = True
line = ''
name = value.split(' ')[0].strip()
cmd = self._cmd_pip(' uninstall -y {}'.format(name))
self.d.lst_log.clear()
for line in app.popen(cmd):
if self.OK3 in line:
self.d.lst_log.insert(line, 'ok.png')
else:
self.d.lst_log.insert(line)
self._unlink_cpython()
return
def cmd_uninstall_action(self, event):
if not self._states['list']:
msg = _('Select installed package')
app.warning(msg)
return
name = self.d.lst_package.value
msg = _('Do you want to uninstall:\n\n{}?').format(name)
if not app.question(msg):
return
self._uninstall(name)
return
def cmd_shell_action(self, event):
if app.IS_WIN:
cmd = '"{}"'.format(self.path_python)
app.paths.open(cmd)
else:
cmd = 'exec "{}"'
if app.IS_MAC:
cmd = 'open "{}"'
elif app.DESKTOP == 'gnome':
cmd = 'gnome-terminal -- {}'
cmd = cmd.format(self.path_python)
app.run(cmd)
return
def cmd_explore_action(self, event):
path = app.paths.get_file(filters='txt')
if not path:
return
msg = _('Do you want to install from:\n\n{}').format(path)
if not app.question(msg):
return
self._install(path=path)
return
def cmd_proxy_action(self, event):
dialog = _create_dialog_proxy()
data = app.get_config('proxy', {}, TITLE)
dialog.set_values(data)
dialog.open()
return
class ControllersProxy(object):
def __init__(self, dialog):
self.d = dialog
def cmd_proxy_save_action(self, event):
data = dict(
txt_proxy_host = self.d.txt_proxy_host.value,
txt_proxy_port = self.d.txt_proxy_port.value,
txt_proxy_user = self.d.txt_proxy_user.value,
txt_proxy_pass = self.d.txt_proxy_pass.value,
)
msg = _('Do you want to save this Proxy settings?')
if not app.question(msg):
return
app.set_config('proxy', data, TITLE)
msg = _('Proxy settings saved sucessfully')
app.msgbox(msg)
self.d.close()
return
def cmd_proxy_delete_action(self, event):
msg = _("Do you want to remove Proxy settings?")
if not app.question(msg):
return
app.set_config('proxy', {}, TITLE)
msg = _('Proxy settings deleted sucessfully')
app.msgbox(msg)
self.d.close()
return
def _create_dialog():
BUTTON_WH = 20
args= {
'Name': 'dialog',
'Title': 'Zaz-Pip',
'Width': 200,
'Height': 220,
}
dialog = app.create_dialog(args)
dialog.id = ID_EXTENSION
dialog.events = Controllers
lbl_title = '{} {} - {}'.format(app.NAME, app.VERSION, app.OS)
args = {
'Type': 'Label',
'Name': 'lbl_title',
'Label': lbl_title,
'Width': 100,
'Height': 15,
'Border': 1,
'Align': 1,
'VerticalAlign': 1,
'Step': 10,
'FontHeight': 12,
}
dialog.add_control(args)
dialog.center(dialog.lbl_title, y=5)
path_python = app.paths.python
cmd = '"{}" -V'.format(path_python)
label = app.run(cmd, True)
args = {
'Type': 'Label',
'Name': 'lbl_python',
'Label': str(label),
'Width': 100,
'Height': 15,
'Border': 1,
'Align': 1,
'VerticalAlign': 1,
'Step': 10,
'FontHeight': 11,
}
dialog.add_control(args)
dialog.center(dialog.lbl_python, y=25)
cmd = '"{}" -m pip -V'.format(path_python)
label = app.run(cmd, True)
exists_pip = True
if not label:
exists_pip = False
label = _("'Python installer package' (PIP) is not installed")
args = {
'Type': 'Label',
'Name': 'lbl_pip',
'Label': label,
'Width': 160,
'Height': 30,
'Border': 1,
'Align': 1,
'VerticalAlign': 1,
'Step': 10,
'MultiLine': True,
}
dialog.add_control(args)
dialog.center(dialog.lbl_pip, y=45)
args = {
'Type': 'Button',
'Name': 'cmd_admin_pip',
'Label': _('Admin PIP'),
'Width': 70,
'Height': BUTTON_WH,
'Step': 10,
'ImageURL': 'python.svg',
'ImagePosition': 1,
}
dialog.add_control(args)
dialog.center(dialog.cmd_admin_pip, y=80)
args = {
'Type': 'Button',
'Name': 'cmd_install_pip',
'Label': _('Install PIP'),
'Width': 60,
'Height': BUTTON_WH,
'Step': 10,
'ImageURL': 'install.svg',
'ImagePosition': 1,
}
dialog.add_control(args)
dialog.center(dialog.cmd_install_pip, y=80)
args = {
'Type': 'Link',
'Name': 'link_proyect',
'URL': URL_GIT,
'Label': URL_GIT,
'Border': 1,
'Width': 130,
'Height': 15,
'Align': 1,
'VerticalAlign': 1,
'Step': 10,
}
dialog.add_control(args)
dialog.center(dialog.link_proyect, y=-5)
args = {
'Type': 'Button',
'Name': 'cmd_proxy',
'Width': 15,
'Height': 15,
'Step': 10,
'ImageURL': 'proxy.svg',
'FocusOnClick': False,
}
dialog.add_control(args)
args = {
'Type': 'Listbox',
'Name': 'lst_log',
'Width': 160,
'Height': 105,
'Step': 10,
}
dialog.add_control(args)
dialog.center(dialog.lst_log, y=105)
args = {
'Type': 'Label',
'Name': 'lbl_package',
'Label': _('Packages'),
'Width': 100,
'Height': 15,
'Border': 1,
'Align': 1,
'VerticalAlign': 1,
'Step': 1,
}
lbl = dialog.add_control(args)
args = {
'Type': 'Text',
'Name': 'txt_search',
'Width': 165,
'Height': 12,
'Step': 1,
'Border': 0,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_explore',
'Label': '...',
'Width': 12,
'Height': 12,
'Step': 1,
}
dialog.add_control(args)
args = {
'Type': 'Listbox',
'Name': 'lst_package',
'Width': 180,
'Height': 128,
'Step': 1,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_close',
'Label': _('~Close'),
'Width': 70,
'Height': BUTTON_WH,
'Step': 1,
'ImageURL': 'close.svg',
'ImagePosition': 1,
}
dialog.add_control(args)
dialog.center(dialog.cmd_close, y=-5)
args = {
'Type': 'Button',
'Name': 'cmd_home',
'Width': BUTTON_WH,
'Height': BUTTON_WH,
'Step': 1,
'ImageURL': 'home.svg',
'FocusOnClick': False,
'Y': 2,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_search',
'Width': BUTTON_WH,
'Height': BUTTON_WH,
'Step': 1,
'ImageURL': 'search.svg',
'FocusOnClick': False,
'Enabled': False,
'Y': 2,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_uninstall',
'Width': BUTTON_WH,
'Height': BUTTON_WH,
'Step': 1,
'ImageURL': 'uninstall.svg',
'FocusOnClick': False,
'Y': 2,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_install',
'Width': BUTTON_WH,
'Height': BUTTON_WH,
'Step': 1,
'ImageURL': 'install.svg',
'FocusOnClick': False,
'Y': 2,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_shell',
'Width': BUTTON_WH,
'Height': BUTTON_WH,
'Step': 1,
'ImageURL': 'shell.svg',
'FocusOnClick': False,
'Y': 2,
}
dialog.add_control(args)
dialog.cmd_proxy.move(dialog.link_proyect, x=5, y=0)
controls = (dialog.link_proyect, dialog.cmd_proxy)
dialog.center(controls)
controls = (dialog.cmd_home, dialog.cmd_search,
dialog.cmd_install, dialog.cmd_uninstall, dialog.cmd_shell)
dialog.lbl_package.move(dialog.cmd_home)
dialog.txt_search.move(dialog.lbl_package)
dialog.cmd_explore.move(dialog.txt_search, x=0, y=0)
dialog.lst_package.move(dialog.txt_search)
dialog.lbl_package.center()
dialog.lst_package.center()
dialog.txt_search.center()
dialog.center(controls)
controls = (dialog.txt_search, dialog.cmd_explore)
dialog.center(controls)
dialog.step = 10
dialog.cmd_install_pip.visible = not exists_pip
dialog.cmd_admin_pip.visible = exists_pip
dialog.lst_log.visible = False
return dialog
def _create_dialog_proxy():
args= {
'Name': 'dlg_proxy',
'Title': _('Zaz-Pip - Proxy settings'),
'Width': 150,
'Height': 100,
}
dialog = app.create_dialog(args)
dialog.id = ID_EXTENSION
dialog.events = ControllersProxy
args = {
'Type': 'Label',
'Name': 'lbl_proxy_host',
'Label': _('Host: '),
'Width': 40,
'Height': 12,
'Border': 1,
'Align': 2,
'VerticalAlign': 1,
'X': 5,
'Y': 5,
}
dialog.add_control(args)
args = {
'Type': 'Text',
'Name': 'txt_proxy_host',
'Width': 95,
'Height': 12,
'Border': 0,
}
dialog.add_control(args)
args = {
'Type': 'Label',
'Name': 'lbl_proxy_port',
'Label': _('Port: '),
'Width': 40,
'Height': 12,
'Border': 1,
'Align': 2,
'VerticalAlign': 1,
}
dialog.add_control(args)
args = {
'Type': 'Text',
'Name': 'txt_proxy_port',
'Width': 95,
'Height': 12,
'Border': 0,
}
dialog.add_control(args)
args = {
'Type': 'Label',
'Name': 'lbl_proxy_user',
'Label': _('User: '),
'Width': 40,
'Height': 12,
'Border': 1,
'Align': 2,
'VerticalAlign': 1,
}
dialog.add_control(args)
args = {
'Type': 'Text',
'Name': 'txt_proxy_user',
'Width': 95,
'Height': 12,
'Border': 0,
}
dialog.add_control(args)
args = {
'Type': 'Label',
'Name': 'lbl_proxy_pass',
'Label': _('Password: '),
'Width': 40,
'Height': 12,
'Border': 1,
'Align': 2,
'VerticalAlign': 1,
}
dialog.add_control(args)
args = {
'Type': 'Text',
'Name': 'txt_proxy_pass',
'Width': 95,
'Height': 12,
'Border': 0,
}
txt = dialog.add_control(args)
txt.echochar = '*'
args = {
'Type': 'Button',
'Name': 'cmd_proxy_save',
'Label': _('Save'),
'Width': 50,
'Height': 15,
'ImageURL': 'save.svg',
'ImagePosition': 1,
'FocusOnClick': False,
}
dialog.add_control(args)
args = {
'Type': 'Button',
'Name': 'cmd_proxy_delete',
'Label': _('Delete'),
'Width': 50,
'Height': 15,
'ImageURL': 'delete.svg',
'ImagePosition': 1,
'FocusOnClick': False,
}
dialog.add_control(args)
dialog.txt_proxy_host.move(dialog.lbl_proxy_host, x=5, y=0)
dialog.lbl_proxy_port.move(dialog.lbl_proxy_host)
dialog.txt_proxy_port.move(dialog.lbl_proxy_port, x=5, y=0)
dialog.lbl_proxy_user.move(dialog.lbl_proxy_port)
dialog.txt_proxy_user.move(dialog.lbl_proxy_user, x=5, y=0)
dialog.lbl_proxy_pass.move(dialog.lbl_proxy_user)
dialog.txt_proxy_pass.move(dialog.lbl_proxy_pass, x=5, y=0)
dialog.cmd_proxy_save.move(dialog.lbl_proxy_pass, y=10)
dialog.cmd_proxy_delete.move(dialog.lbl_proxy_pass, y=10)
controls = (dialog.cmd_proxy_save, dialog.cmd_proxy_delete)
dialog.center(controls)
return dialog

View File

@ -0,0 +1,14 @@
This file is part of ZAZPip.
ZAZPip 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.
ZAZPip 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 ZAZPip. If not, see <https://www.gnu.org/licenses/>.

390
zaz.py Normal file → Executable file
View File

@ -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,23 @@ from conf import (
log)
EASYMACRO_TMP = 'easymacro2.py'
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 +70,40 @@ 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',
}
xmlns = 'http://openoffice.org/extensions/description/2006'
xmlns_xlink = 'http://www.w3.org/1999/xlink'
xmlns_l = 'http://libreoffice.org/extensions/description/2011'
NS_DESCRIPTION = {
'xmlns': xmlns,
'xmlns:xlink': xmlns_xlink,
'xmlns:d': xmlns,
'xmlns:l': xmlns_l,
}
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': xmlns_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 +125,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 +155,224 @@ 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 = 'minimal'
if data[key]:
node = ET.SubElement(doc, 'dependencies')
# ~ attr = {'value': data[key], 'name': f'LibreOffice {data[key]}'}
attr = {'value': data[key]}
ET.SubElement(node, 'l:LibreOffice-minimal-version', attr)
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 +412,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,18 +426,14 @@ 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...')
log.info('Extension OXT created successfully...')
return
def _install_and_test():
path_oxt = (_join(DIRS['files'], FILES['oxt']),)
call(PATHS['install'] + path_oxt)
log.info('Install extension sucesfully...')
log.info('Install extension successfully...')
log.info('Start LibreOffice...')
call(PATHS['soffice'])
return
@ -289,11 +538,15 @@ def _compile_idl():
call([PATHS['regmerge'], path_rdb, '/UCR', path_urd])
os.remove(path_urd)
log.info('Compilate IDL sucesfully...')
log.info('Compilate IDL successfully...')
return
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 +568,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 +578,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 +600,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 +636,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 +644,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 +666,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 +711,6 @@ def _embed(args):
def _locales(args):
EASYMACRO = 'easymacro.py'
if args.files:
files = args.files.split(',')
else:
@ -483,8 +742,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, 'ext'))
_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_TMP, _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 +787,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 +809,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 +825,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()