Compare commits
40 Commits
Author | SHA1 | Date |
---|---|---|
El Mau | c2470ddd9d | |
El Mau | 4b66d38e32 | |
El Mau | d2d60e7281 | |
Mauricio | 0e750c0af0 | |
Barry-Thomas-Paul: Moss | 8dadb7e62e | |
Barry-Thomas-Paul: Moss | 9f2ac70cc8 | |
Mauricio | c93c182953 | |
Barry-Thomas-Paul: Moss | db3466b716 | |
Barry-Thomas-Paul: Moss | 0453092831 | |
Barry-Thomas-Paul: Moss | 7b9ac8eee0 | |
Barry-Thomas-Paul: Moss | 4aa0ca68c8 | |
Barry-Thomas-Paul: Moss | 923b39c7f2 | |
Mauricio | 90aa12adf2 | |
AmourSpirit | d52472dad7 | |
Barry-Thomas-Paul: Moss | 6ec45c1bb4 | |
Barry-Thomas-Paul: Moss | 910e5f54b1 | |
El Mau | c9b9bfdf0a | |
El Mau | 587148553e | |
El Mau | 4b7b0c359f | |
El Mau | 269f9adc75 | |
El Mau | 668e23353b | |
El Mau | d7d65bb8ba | |
El Mau | b3c783c1fe | |
El Mau | 2452480457 | |
El Mau | afd94fa5fe | |
El Mau | c940f6fcc6 | |
El Mau | 450daa630a | |
El Mau | 6ce81f91c6 | |
El Mau | b7e0d2a0fc | |
El Mau | 4d518c781e | |
El Mau | 354b5e1421 | |
El Mau | b1e24d4411 | |
LibreOfficiant | cac0b4fb59 | |
LibreOfficiant | 9910b5302b | |
Mauricio Baeza | 9e2f841017 | |
Mauricio Baeza | 223989495e | |
Mauricio Baeza | b31fa8247f | |
Mauricio Baeza | a49a1ad4d8 | |
Mauricio Baeza | 4eb0b51a6d | |
Mauricio Baeza | e64854c78c |
39
CHANGELOG
|
@ -1,3 +1,36 @@
|
|||
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
|
||||
|
||||
|
@ -5,16 +38,12 @@ 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
|
||||
|
||||
|
|
23
README.md
|
@ -5,25 +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`
|
||||
G1: `A5DdXxCKPw3QKWVdDVs7CzkNugNUW1sHu5zDJFWxCU2h`
|
||||
|
||||
BTC: `3FhiXcXmAesmQzrNEngjHFnvaJRhU1AGWV`
|
||||
```
|
||||
Euros
|
||||
IBAN: BE60 9671 0556 5870
|
||||
SWIFT / BIC: TRWIBEB1XXX
|
||||
```
|
||||
|
||||
You have others cryptos, welcome too!
|
||||
* [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
|
||||
|
|
26
conf.py
|
@ -26,7 +26,7 @@ import logging
|
|||
TYPE_EXTENSION = 1
|
||||
|
||||
# ~ https://semver.org/
|
||||
VERSION = '0.7.0'
|
||||
VERSION = '1.0.0'
|
||||
|
||||
# ~ Your great extension name, not used spaces
|
||||
NAME = 'ZAZPip'
|
||||
|
@ -41,14 +41,16 @@ ID = 'net.elmau.zaz.pip'
|
|||
USE_LOCALES = True
|
||||
DOMAIN = 'base'
|
||||
PATH_LOCALES = 'locales'
|
||||
PATH_PYGETTEXT = '/usr/lib/python3.8/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
|
||||
|
@ -56,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}.
|
||||
|
@ -76,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': {
|
||||
|
@ -89,6 +89,11 @@ INFO = {
|
|||
'description': 'Pip para LibreOffice',
|
||||
'license': LICENSE_ES,
|
||||
},
|
||||
'fr': {
|
||||
'display_name': 'ZAZ Pip',
|
||||
'description': 'Pip pour LibreOffice',
|
||||
'license': LICENSE_FR,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
@ -111,7 +116,7 @@ PARENT = 'AddonMenu'
|
|||
MENU_MAIN = {}
|
||||
MENUS = (
|
||||
{
|
||||
'title': {'en': 'Open Pip', 'es': 'Abrir Pip'},
|
||||
'title': {'en': 'Open Zaz-Pip', 'es': 'Abrir Zaz-Pip', 'fr': 'Ouvert Zaz-Pip'},
|
||||
'argument': 'open_dialog_pip',
|
||||
'context': '',
|
||||
'icon': 'icon',
|
||||
|
@ -153,7 +158,7 @@ DIRS = {
|
|||
'description': 'description',
|
||||
'images': 'images',
|
||||
'registration': 'registration',
|
||||
'files': 'files',
|
||||
'files': 'extension',
|
||||
'office': 'Office',
|
||||
'locales': PATH_LOCALES,
|
||||
'pythonpath': True,
|
||||
|
@ -397,6 +402,7 @@ DATA_DESCRIPTION = {
|
|||
'icon': ICON_EXT,
|
||||
'publisher': PUBLISHER,
|
||||
'update': URL_XML_UPDATE,
|
||||
'minimal': DEPENDENCIES_MINIMAL,
|
||||
}
|
||||
|
||||
DATA_ADDONS = {
|
||||
|
|
455
easymacro.py
|
@ -21,6 +21,7 @@
|
|||
|
||||
import base64
|
||||
import csv
|
||||
import ctypes
|
||||
import datetime
|
||||
import getpass
|
||||
import gettext
|
||||
|
@ -82,8 +83,9 @@ from com.sun.star.util import Time, Date, DateTime
|
|||
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
|
||||
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
|
||||
|
||||
from com.sun.star.awt import XActionListener
|
||||
from com.sun.star.lang import Locale
|
||||
from com.sun.star.lang import XEventListener
|
||||
from com.sun.star.awt import XActionListener
|
||||
from com.sun.star.awt import XMenuListener
|
||||
from com.sun.star.awt import XMouseListener
|
||||
from com.sun.star.awt import XMouseMotionListener
|
||||
|
@ -203,6 +205,12 @@ class ConditionOperator():
|
|||
CO = ConditionOperator
|
||||
|
||||
|
||||
class DataPilotFieldOrientation():
|
||||
from com.sun.star.sheet.DataPilotFieldOrientation \
|
||||
import HIDDEN, COLUMN, ROW, PAGE, DATA
|
||||
DPFO = DataPilotFieldOrientation
|
||||
|
||||
|
||||
OS = platform.system()
|
||||
IS_WIN = OS == 'Windows'
|
||||
IS_MAC = OS == 'Darwin'
|
||||
|
@ -308,6 +316,11 @@ def get_app_config(node_name: str, key: str=''):
|
|||
|
||||
LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale')
|
||||
LANG = LANGUAGE.split('-')[0]
|
||||
try:
|
||||
COUNTRY = LANGUAGE.split('-')[1]
|
||||
except:
|
||||
COUNTRY = ''
|
||||
LOCALE = Locale(LANG, COUNTRY, '')
|
||||
NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName')
|
||||
VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion')
|
||||
|
||||
|
@ -372,6 +385,8 @@ def mri(obj: Any) -> None:
|
|||
error(msg)
|
||||
return
|
||||
|
||||
if hasattr(obj, 'obj'):
|
||||
obj = obj.obj
|
||||
m.inspect(obj)
|
||||
return
|
||||
|
||||
|
@ -1166,6 +1181,9 @@ class LODocument(object):
|
|||
return
|
||||
|
||||
def to_pdf(self, path: str='', args: dict={}):
|
||||
"""
|
||||
https://wiki.documentfoundation.org/Macros/Python_Guide/PDF_export_filter_data
|
||||
"""
|
||||
path_pdf = path
|
||||
filter_name = '{}_pdf_Export'.format(self.type)
|
||||
filter_data = dict_to_property(args, True)
|
||||
|
@ -1520,6 +1538,142 @@ class LOSheetCharts(object):
|
|||
return LOChart(name, self.obj[name], self._sheet.draw_page)
|
||||
|
||||
|
||||
class LOSheetTableField(object):
|
||||
|
||||
def __init__(self, obj):
|
||||
self._obj = obj
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
@property
|
||||
def obj(self):
|
||||
return self._obj
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.obj.Name
|
||||
|
||||
@property
|
||||
def orientation(self):
|
||||
return self.obj.Orientation
|
||||
@orientation.setter
|
||||
def orientation(self, value):
|
||||
self.obj.Orientation = value
|
||||
|
||||
|
||||
# ~ com.sun.star.sheet.DataPilotFieldOrientation.ROW
|
||||
class LOSheetTable(object):
|
||||
|
||||
def __init__(self, obj):
|
||||
self._obj = obj
|
||||
self._source = None
|
||||
|
||||
def __getitem__(self, index):
|
||||
field = self.obj.DataPilotFields[index]
|
||||
return LOSheetTableField(field)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
@property
|
||||
def obj(self):
|
||||
return self._obj
|
||||
|
||||
@property
|
||||
def filter(self):
|
||||
return self.obj.ShowFilterButton
|
||||
@filter.setter
|
||||
def filter(self, value):
|
||||
self.obj.ShowFilterButton = value
|
||||
|
||||
@property
|
||||
def source(self):
|
||||
return self._source
|
||||
@source.setter
|
||||
def source(self, value):
|
||||
self._source = value
|
||||
self.obj.SourceRange = value.range_address
|
||||
|
||||
@property
|
||||
def rows(self):
|
||||
return self.obj.RowFields
|
||||
@rows.setter
|
||||
def rows(self, values):
|
||||
if not isinstance(values, tuple):
|
||||
values = (values,)
|
||||
for v in values:
|
||||
with self[v] as f:
|
||||
f.orientation = DPFO.ROW
|
||||
@property
|
||||
def columns(self):
|
||||
return self.obj.ColumnFields
|
||||
@columns.setter
|
||||
def columns(self, values):
|
||||
if not isinstance(values, tuple):
|
||||
values = (values,)
|
||||
for v in values:
|
||||
with self[v] as f:
|
||||
f.orientation = DPFO.COLUMN
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self.obj.DataFields
|
||||
@data.setter
|
||||
def data(self, values):
|
||||
if not isinstance(values, tuple):
|
||||
values = (values,)
|
||||
for v in values:
|
||||
with self[v] as f:
|
||||
f.orientation = DPFO.DATA
|
||||
|
||||
|
||||
class LOSheetTables(object):
|
||||
|
||||
def __init__(self, obj, sheet):
|
||||
self._obj = obj
|
||||
self._sheet = sheet
|
||||
|
||||
def __getitem__(self, index):
|
||||
return LOSheetTable(self.obj[index])
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self.obj
|
||||
|
||||
@property
|
||||
def obj(self):
|
||||
return self._obj
|
||||
|
||||
@property
|
||||
def count(self):
|
||||
return self.obj.Count
|
||||
|
||||
@property
|
||||
def names(self):
|
||||
return self.obj.ElementNames
|
||||
|
||||
def new(self, name, target):
|
||||
table = self.obj.createDataPilotDescriptor()
|
||||
self.obj.insertNewByName(name, target.address, table)
|
||||
return LOSheetTable(self.obj[name])
|
||||
|
||||
def remove(self, name):
|
||||
self.obj.removeByName(name)
|
||||
return
|
||||
|
||||
|
||||
class LOFormControl(LOBaseObject):
|
||||
EVENTS = {
|
||||
'action': 'actionPerformed',
|
||||
|
@ -2045,6 +2199,10 @@ class LOCalcSheet(object):
|
|||
def charts(self):
|
||||
return LOSheetCharts(self.obj.Charts, self)
|
||||
|
||||
@property
|
||||
def tables(self):
|
||||
return LOSheetTables(self.obj.DataPilotTables, self)
|
||||
|
||||
@property
|
||||
def rows(self):
|
||||
return LOSheetRows(self, self.obj.Rows)
|
||||
|
@ -2558,6 +2716,7 @@ class LOCalcRange(object):
|
|||
cell = None
|
||||
if isinstance(value, dict):
|
||||
for k, v in value.items():
|
||||
# ~ print(1, 'RENDER', k, v)
|
||||
cell = self._render_value(k, v, key)
|
||||
return cell
|
||||
elif isinstance(value, (list, tuple)):
|
||||
|
@ -2569,7 +2728,11 @@ class LOCalcRange(object):
|
|||
search = f'{{{parent}.{key}}}'
|
||||
ranges = self.find_all(search)
|
||||
|
||||
for cell in ranges or range(0):
|
||||
if ranges is None:
|
||||
return
|
||||
|
||||
# ~ for cell in ranges or range(0):
|
||||
for cell in ranges:
|
||||
self._set_new_value(cell, search, value)
|
||||
return LOCalcRange(cell)
|
||||
|
||||
|
@ -2718,6 +2881,72 @@ class LOCalcRange(object):
|
|||
self.obj.fillAuto(0, source)
|
||||
return
|
||||
|
||||
def _cast(self, t, v):
|
||||
if not t:
|
||||
return v
|
||||
|
||||
if t == datetime.date:
|
||||
nv = datetime.date.fromordinal(int(v) + DATE_OFFSET)
|
||||
else:
|
||||
nv = t(v)
|
||||
return nv
|
||||
|
||||
def get_data(self, types):
|
||||
values = [
|
||||
[self._cast(types[i], v) for i, v in enumerate(row)]
|
||||
for row in self.data
|
||||
]
|
||||
return values
|
||||
|
||||
|
||||
class LOWriterStyles(object):
|
||||
|
||||
def __init__(self, styles):
|
||||
self._styles = styles
|
||||
|
||||
@property
|
||||
def names(self):
|
||||
return {s.DisplayName: s.Name for s in self._styles}
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(tuple(self.names.values()))
|
||||
|
||||
|
||||
class LOWriterStylesFamilies(object):
|
||||
|
||||
def __init__(self, styles):
|
||||
self._styles = styles
|
||||
|
||||
def __getitem__(self, index):
|
||||
styles = {
|
||||
'Character': 'CharacterStyles',
|
||||
'Paragraph': 'ParagraphStyles',
|
||||
'Page': 'PageStyles',
|
||||
'Frame': 'FrameStyles',
|
||||
'Numbering': 'NumberingStyles',
|
||||
'Table': 'TableStyles',
|
||||
'Cell': 'CellStyles',
|
||||
}
|
||||
name = styles.get(index, index)
|
||||
return LOWriterStyles(self._styles[name])
|
||||
|
||||
def __iter__(self):
|
||||
self._index = 0
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
obj = LOWriterStyles(self._styles[self._index])
|
||||
self._index += 1
|
||||
return obj
|
||||
# ~ raise StopIteration
|
||||
|
||||
@property
|
||||
def names(self):
|
||||
return self._styles.ElementNames
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(self.names)
|
||||
|
||||
|
||||
class LOWriterPageStyle(LOBaseObject):
|
||||
|
||||
|
@ -2755,18 +2984,23 @@ class LOWriterTextRange(object):
|
|||
self._doc = doc
|
||||
self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph'
|
||||
self._is_table = self.obj.ImplementationName == 'SwXTextTable'
|
||||
self._is_text = self.obj.ImplementationName == 'SwXTextPortion'
|
||||
self._parts = []
|
||||
if self._is_paragraph:
|
||||
self._parts = [LOWriterTextRange(p, doc) for p in obj]
|
||||
|
||||
def __iter__(self):
|
||||
self._index = 0
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
for i, p in enumerate(self.obj):
|
||||
if i == self._index:
|
||||
obj = LOWriterTextRange(p, self._doc)
|
||||
self._index += 1
|
||||
return obj
|
||||
raise StopIteration
|
||||
try:
|
||||
obj = self._parts[self._index]
|
||||
except IndexError:
|
||||
raise StopIteration
|
||||
|
||||
self._index += 1
|
||||
return obj
|
||||
|
||||
@property
|
||||
def obj(self):
|
||||
|
@ -2785,11 +3019,37 @@ class LOWriterTextRange(object):
|
|||
@property
|
||||
def value(self):
|
||||
return self.string
|
||||
@value.setter
|
||||
def value(self, value):
|
||||
self.string = value
|
||||
|
||||
@property
|
||||
def style(self):
|
||||
s = ''
|
||||
if self.is_paragraph:
|
||||
s = self.obj.ParaStyleName
|
||||
elif self.is_text:
|
||||
s = self.obj.CharStyleName
|
||||
return s
|
||||
@style.setter
|
||||
def style(self, value):
|
||||
if self.is_paragraph:
|
||||
self.obj.ParaStyleName = value
|
||||
elif self.is_text:
|
||||
self.obj.CharStyleName = value
|
||||
|
||||
@property
|
||||
def is_paragraph(self):
|
||||
return self._is_paragraph
|
||||
|
||||
@property
|
||||
def is_table(self):
|
||||
return self._is_table
|
||||
|
||||
@property
|
||||
def is_text(self):
|
||||
return self._is_text
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
return self.obj.Text
|
||||
|
@ -2802,6 +3062,13 @@ class LOWriterTextRange(object):
|
|||
def dp(self):
|
||||
return self._doc.dp
|
||||
|
||||
def delete(self):
|
||||
cursor = self.cursor
|
||||
cursor.gotoStartOfParagraph(False)
|
||||
cursor.gotoNextParagraph(True)
|
||||
cursor.String = ''
|
||||
return
|
||||
|
||||
def offset(self):
|
||||
cursor = self.cursor.getEnd()
|
||||
return LOWriterTextRange(cursor, self._doc)
|
||||
|
@ -2846,25 +3113,26 @@ class LOWriterTextRanges(object):
|
|||
def __init__(self, obj, doc):
|
||||
self._obj = obj
|
||||
self._doc = doc
|
||||
self._paragraphs = [LOWriterTextRange(p, doc) for p in obj]
|
||||
|
||||
def __len__(self):
|
||||
return len(self._paragraphs)
|
||||
|
||||
def __getitem__(self, index):
|
||||
for i, p in enumerate(self.obj):
|
||||
if i == index:
|
||||
obj = LOWriterTextRange(p, self._doc)
|
||||
break
|
||||
return obj
|
||||
return self._paragraphs[index]
|
||||
|
||||
def __iter__(self):
|
||||
self._index = 0
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
for i, p in enumerate(self.obj):
|
||||
if i == self._index:
|
||||
obj = LOWriterTextRange(p, self._doc)
|
||||
self._index += 1
|
||||
return obj
|
||||
raise StopIteration
|
||||
try:
|
||||
obj = self._paragraphs[self._index]
|
||||
except IndexError:
|
||||
raise StopIteration
|
||||
|
||||
self._index += 1
|
||||
return obj
|
||||
|
||||
@property
|
||||
def obj(self):
|
||||
|
@ -2887,10 +3155,17 @@ class LOWriterTextTable(object):
|
|||
|
||||
@property
|
||||
def data(self):
|
||||
return self._obj.DataArray
|
||||
return self.obj.DataArray
|
||||
@data.setter
|
||||
def data(self, values):
|
||||
self._obj.DataArray = values
|
||||
self.obj.DataArray = values
|
||||
|
||||
@property
|
||||
def style(self):
|
||||
return self.obj.TableTemplateName
|
||||
@style.setter
|
||||
def style(self, value):
|
||||
self.obj.autoFormat(value)
|
||||
|
||||
|
||||
class LOWriterTextTables(object):
|
||||
|
@ -2920,7 +3195,7 @@ class LOWriter(LODocument):
|
|||
|
||||
@property
|
||||
def text(self):
|
||||
return LOWriterTextRange(self.obj.Text, self)
|
||||
return self.paragraphs
|
||||
|
||||
@property
|
||||
def paragraphs(self):
|
||||
|
@ -2973,6 +3248,10 @@ class LOWriter(LODocument):
|
|||
ps = self.obj.StyleFamilies['PageStyles']
|
||||
return LOWriterPageStyles(ps)
|
||||
|
||||
@property
|
||||
def styles(self):
|
||||
return LOWriterStylesFamilies(self.obj.StyleFamilies)
|
||||
|
||||
@property
|
||||
def search_descriptor(self):
|
||||
return self.obj.createSearchDescriptor()
|
||||
|
@ -3403,15 +3682,19 @@ class BaseRow:
|
|||
|
||||
class BaseQuery(object):
|
||||
PY_TYPES = {
|
||||
'SQL_LONG': 'getLong',
|
||||
'SQL_VARYING': 'getString',
|
||||
'SQL_FLOAT': 'getFloat',
|
||||
'SQL_BOOLEAN': 'getBoolean',
|
||||
'SQL_TYPE_DATE': 'getDate',
|
||||
'SQL_TYPE_TIME': 'getTime',
|
||||
'SQL_TIMESTAMP': 'getTimestamp',
|
||||
'VARCHAR': 'getString',
|
||||
'INTEGER': 'getLong',
|
||||
'DATE': 'getDate',
|
||||
# ~ 'SQL_LONG': 'getLong',
|
||||
# ~ 'SQL_VARYING': 'getString',
|
||||
# ~ 'SQL_FLOAT': 'getFloat',
|
||||
# ~ 'SQL_BOOLEAN': 'getBoolean',
|
||||
# ~ 'SQL_TYPE_DATE': 'getDate',
|
||||
# ~ 'SQL_TYPE_TIME': 'getTime',
|
||||
# ~ 'SQL_TIMESTAMP': 'getTimestamp',
|
||||
}
|
||||
TYPES_DATE = ('SQL_TYPE_DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP')
|
||||
# ~ TYPES_DATE = ('SQL_TYPE_DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP')
|
||||
TYPES_DATE = ('DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP')
|
||||
|
||||
def __init__(self, query):
|
||||
self._query = query
|
||||
|
@ -3437,6 +3720,7 @@ class BaseQuery(object):
|
|||
|
||||
def _to_python(self, index):
|
||||
type_field = self._meta.getColumnTypeName(index)
|
||||
# ~ print('TF', type_field)
|
||||
value = getattr(self._query, self.PY_TYPES[type_field])(index)
|
||||
if type_field in self.TYPES_DATE:
|
||||
value = _struct_to_date(value)
|
||||
|
@ -3562,10 +3846,11 @@ class LOBase(object):
|
|||
self._con.getTables().refresh()
|
||||
return
|
||||
|
||||
def initialize(self, database_proxy, tables):
|
||||
def initialize(self, database_proxy, tables=[]):
|
||||
db = FirebirdDatabase(self)
|
||||
database_proxy.initialize(db)
|
||||
db.create_tables(tables)
|
||||
if tables:
|
||||
db.create_tables(tables)
|
||||
return
|
||||
|
||||
def _validate_sql(self, sql, params):
|
||||
|
@ -3676,6 +3961,7 @@ class LODocs(object):
|
|||
return doc
|
||||
|
||||
def __len__(self):
|
||||
# ~ len(self._desktop.Components)
|
||||
for i, _ in enumerate(self._desktop.Components):
|
||||
pass
|
||||
return i + 1
|
||||
|
@ -4445,6 +4731,13 @@ class UnoText(UnoBaseObject):
|
|||
def value(self, value):
|
||||
self.model.Text = value
|
||||
|
||||
@property
|
||||
def echochar(self):
|
||||
return chr(self.model.EchoChar)
|
||||
@echochar.setter
|
||||
def echochar(self, value):
|
||||
self.model.EchoChar = ord(value[0])
|
||||
|
||||
def validate(self):
|
||||
return
|
||||
|
||||
|
@ -5285,6 +5578,11 @@ class LODialog(object):
|
|||
self.obj.dispose()
|
||||
return value
|
||||
|
||||
def set_values(self, data):
|
||||
for k, v in data.items():
|
||||
self._controls[k].value = v
|
||||
return
|
||||
|
||||
|
||||
class LOSheets(object):
|
||||
|
||||
|
@ -5832,6 +6130,7 @@ _CB = ClipBoard
|
|||
|
||||
class Paths(object):
|
||||
FILE_PICKER = 'com.sun.star.ui.dialogs.FilePicker'
|
||||
FOLDER_PICKER = 'com.sun.star.ui.dialogs.FolderPicker'
|
||||
|
||||
def __init__(self, path=''):
|
||||
if path.startswith('file://'):
|
||||
|
@ -5941,7 +6240,7 @@ class Paths(object):
|
|||
|
||||
@classmethod
|
||||
def get_dir(cls, init_dir=''):
|
||||
folder_picker = create_instance(cls.FILE_PICKER)
|
||||
folder_picker = create_instance(cls.FOLDER_PICKER)
|
||||
if not init_dir:
|
||||
init_dir = cls.documents
|
||||
init_dir = cls.to_url(init_dir)
|
||||
|
@ -5950,7 +6249,7 @@ class Paths(object):
|
|||
|
||||
path = ''
|
||||
if folder_picker.execute():
|
||||
path = cls.to_system(folder_picker.getDisplayDirectory())
|
||||
path = cls.to_system(folder_picker.getDirectory())
|
||||
return path
|
||||
|
||||
@classmethod
|
||||
|
@ -6219,6 +6518,50 @@ class Paths(object):
|
|||
_P = Paths
|
||||
|
||||
|
||||
class Dates(object):
|
||||
|
||||
@classmethod
|
||||
def date(cls, year, month, day):
|
||||
d = datetime.date(year, month, day)
|
||||
return d
|
||||
|
||||
|
||||
class SpellChecker(object):
|
||||
|
||||
def __init__(self):
|
||||
service = 'com.sun.star.linguistic2.SpellChecker'
|
||||
self._spellchecker = create_instance(service, True)
|
||||
self._locale = LOCALE
|
||||
|
||||
@property
|
||||
def locale(self):
|
||||
slocal = f'{self._locale.Language}-{self._locale.Country}'
|
||||
return slocale
|
||||
@locale.setter
|
||||
def locale(self, value):
|
||||
lang = value.split('-')
|
||||
self._locale = Locale(lang[0], lang[1], '')
|
||||
|
||||
def is_valid(self, word):
|
||||
result = self._spellchecker.isValid(word, self._locale, ())
|
||||
return result
|
||||
|
||||
def spell(self, word):
|
||||
result = self._spellchecker.spell(word, self._locale, ())
|
||||
if result:
|
||||
result = result.getAlternatives()
|
||||
if not isinstance(result, tuple):
|
||||
result = ()
|
||||
return result
|
||||
|
||||
|
||||
def spell(word, locale=''):
|
||||
sc = SpellChecker()
|
||||
if locale:
|
||||
sc.locale = locale
|
||||
return sc.spell(word)
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
if name == 'active':
|
||||
return LODocs().active
|
||||
|
@ -6244,6 +6587,8 @@ def __getattr__(name):
|
|||
return LOShortCuts()
|
||||
if name == 'clipboard':
|
||||
return ClipBoard
|
||||
if name == 'dates':
|
||||
return Dates
|
||||
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
||||
|
||||
|
||||
|
@ -6330,48 +6675,6 @@ def get_fonts():
|
|||
return device.FontDescriptors
|
||||
|
||||
|
||||
# ~ From request
|
||||
# ~ https://github.com/psf/requests/blob/master/requests/structures.py#L15
|
||||
class CaseInsensitiveDict(MutableMapping):
|
||||
|
||||
def __init__(self, data=None, **kwargs):
|
||||
self._store = OrderedDict()
|
||||
if data is None:
|
||||
data = {}
|
||||
self.update(data, **kwargs)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
# Use the lowercased key for lookups, but store the actual
|
||||
# key alongside the value.
|
||||
self._store[key.lower()] = (key, value)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._store[key.lower()][1]
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._store[key.lower()]
|
||||
|
||||
def __iter__(self):
|
||||
return (casedkey for casedkey, mappedvalue in self._store.values())
|
||||
|
||||
def __len__(self):
|
||||
return len(self._store)
|
||||
|
||||
def lower_items(self):
|
||||
"""Like iteritems(), but with all lowercase keys."""
|
||||
values = (
|
||||
(lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items()
|
||||
)
|
||||
return values
|
||||
|
||||
# Copy is required
|
||||
def copy(self):
|
||||
return CaseInsensitiveDict(self._store.values())
|
||||
|
||||
def __repr__(self):
|
||||
return str(dict(self.items()))
|
||||
|
||||
|
||||
# ~ https://en.wikipedia.org/wiki/Web_colors
|
||||
def get_color(value):
|
||||
COLORS = {
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
<node oor:name="AddonMenu">
|
||||
<node oor:name="net.elmau.zaz.pip" 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>
|
||||
<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/>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -13,9 +13,9 @@ class ZAZPip(unohelper.Base, XJobExecutor):
|
|||
def __init__(self, ctx):
|
||||
self.ctx = ctx
|
||||
|
||||
def trigger(self, args):
|
||||
def trigger(self, option):
|
||||
main.ID_EXTENSION = ID_EXTENSION
|
||||
main.run(args, __file__)
|
||||
main.run(__file__)
|
||||
return
|
||||
|
||||
|
||||
|
|
|
@ -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">
|
||||
<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="0.7.0"/>
|
||||
<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="fr" xlink:href="description/desc_fr.txt"/>
|
||||
</extension-description>
|
||||
<icon>
|
||||
<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"/>
|
||||
<license-text xlink:href="registration/license_fr.txt" lang="fr"/>
|
||||
</simple-license>
|
||||
</registration>
|
||||
</description>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Pip pour LibreOffice
|
|
@ -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 |
|
@ -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 |
|
@ -1,23 +1,23 @@
|
|||
<?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 32 32"
|
||||
viewBox="0 0 18 18"
|
||||
enable-background="new 0 0 100 100"
|
||||
xml:space="preserve"
|
||||
id="svg12"
|
||||
sodipodi:docname="python.svg"
|
||||
width="32"
|
||||
height="32"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><sodipodi:namedview
|
||||
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"
|
||||
|
@ -27,24 +27,25 @@
|
|||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1006"
|
||||
inkscape:window-height="1001"
|
||||
id="namedview9"
|
||||
showgrid="false"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:zoom="4.655591"
|
||||
inkscape:cx="-28.841168"
|
||||
inkscape:cy="23.577791"
|
||||
inkscape:zoom="26.336"
|
||||
inkscape:cx="10.631835"
|
||||
inkscape:cy="8.2966283"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="37"
|
||||
inkscape:window-y="42"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12"
|
||||
inkscape:document-rotation="0" /><metadata
|
||||
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" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs16" /><g
|
||||
id="g23"
|
||||
transform="matrix(0.39999852,0,0,0.39999286,-3.9998495,-3.999893)"><path
|
||||
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"
|
||||
|
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -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 |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 9.0 KiB |
|
@ -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>
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
|
@ -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
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
import base64
|
||||
import csv
|
||||
import ctypes
|
||||
import datetime
|
||||
import getpass
|
||||
import gettext
|
||||
|
@ -30,6 +31,7 @@ import logging
|
|||
import os
|
||||
import platform
|
||||
import re
|
||||
import site
|
||||
import shlex
|
||||
import shutil
|
||||
import socket
|
||||
|
@ -82,8 +84,9 @@ from com.sun.star.util import Time, Date, DateTime
|
|||
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
|
||||
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
|
||||
|
||||
from com.sun.star.awt import XActionListener
|
||||
from com.sun.star.lang import Locale
|
||||
from com.sun.star.lang import XEventListener
|
||||
from com.sun.star.awt import XActionListener
|
||||
from com.sun.star.awt import XMenuListener
|
||||
from com.sun.star.awt import XMouseListener
|
||||
from com.sun.star.awt import XMouseMotionListener
|
||||
|
@ -165,6 +168,9 @@ OBJ_GRAPHIC = 'SwXTextGraphicObject'
|
|||
|
||||
OBJ_TEXTS = 'SwXTextRanges'
|
||||
OBJ_TEXT = 'SwXTextRange'
|
||||
IS_FLATPAK = bool(os.getenv("FLATPAK_ID", ""))
|
||||
IS_APP_IMAGE = bool(os.getenv("APPIMAGE", ""))
|
||||
|
||||
|
||||
|
||||
# ~ from com.sun.star.sheet.FilterOperator import EMPTY, NO_EMPTY, EQUAL, NOT_EQUAL
|
||||
|
@ -203,6 +209,12 @@ class ConditionOperator():
|
|||
CO = ConditionOperator
|
||||
|
||||
|
||||
class DataPilotFieldOrientation():
|
||||
from com.sun.star.sheet.DataPilotFieldOrientation \
|
||||
import HIDDEN, COLUMN, ROW, PAGE, DATA
|
||||
DPFO = DataPilotFieldOrientation
|
||||
|
||||
|
||||
OS = platform.system()
|
||||
IS_WIN = OS == 'Windows'
|
||||
IS_MAC = OS == 'Darwin'
|
||||
|
@ -308,6 +320,11 @@ def get_app_config(node_name: str, key: str=''):
|
|||
|
||||
LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale')
|
||||
LANG = LANGUAGE.split('-')[0]
|
||||
try:
|
||||
COUNTRY = LANGUAGE.split('-')[1]
|
||||
except:
|
||||
COUNTRY = ''
|
||||
LOCALE = Locale(LANG, COUNTRY, '')
|
||||
NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName')
|
||||
VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion')
|
||||
|
||||
|
@ -372,6 +389,8 @@ def mri(obj: Any) -> None:
|
|||
error(msg)
|
||||
return
|
||||
|
||||
if hasattr(obj, 'obj'):
|
||||
obj = obj.obj
|
||||
m.inspect(obj)
|
||||
return
|
||||
|
||||
|
@ -580,13 +599,24 @@ def call_macro(args, in_thread=False):
|
|||
result = _call_macro(args)
|
||||
return result
|
||||
|
||||
|
||||
def get_env():
|
||||
"""
|
||||
Gets Environment used for subprocess.
|
||||
"""
|
||||
my_env = os.environ.copy()
|
||||
py_path = ""
|
||||
p_sep = ";" if IS_WIN else ":"
|
||||
for d in sys.path:
|
||||
py_path = py_path + d + p_sep
|
||||
my_env["PYTHONPATH"] = py_path
|
||||
return my_env
|
||||
|
||||
def run(command, capture=False, split=True):
|
||||
if not split:
|
||||
return subprocess.check_output(command, shell=True).decode()
|
||||
return subprocess.check_output(command, shell=True, env=get_env()).decode()
|
||||
|
||||
cmd = shlex.split(command)
|
||||
result = subprocess.run(cmd, capture_output=capture, text=True, shell=IS_WIN)
|
||||
result = subprocess.run(cmd, capture_output=capture, text=True, shell=IS_WIN, env=get_env())
|
||||
if capture:
|
||||
result = result.stdout
|
||||
else:
|
||||
|
@ -597,7 +627,7 @@ def run(command, capture=False, split=True):
|
|||
def popen(command):
|
||||
try:
|
||||
proc = subprocess.Popen(shlex.split(command), shell=IS_WIN,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=get_env())
|
||||
for line in proc.stdout:
|
||||
yield line.decode().rstrip()
|
||||
except Exception as e:
|
||||
|
@ -610,6 +640,60 @@ def sleep(seconds):
|
|||
return
|
||||
|
||||
|
||||
|
||||
def get_site_packages_dir() -> str:
|
||||
"""Gets the site-packages folder for the current user."""
|
||||
major_minor = f"{sys.version_info.major}.{sys.version_info.minor}"
|
||||
|
||||
def get_windows_site_packages_dir() -> str:
|
||||
nonlocal major_minor
|
||||
if site.USER_SITE:
|
||||
site_packages = Path(site.USER_SITE).resolve()
|
||||
else:
|
||||
site_packages = (
|
||||
Path.home() / f"'/AppData/Roaming/Python/Python{major_minor}/site-packages'"
|
||||
)
|
||||
site_packages.mkdir(parents=True, exist_ok=True)
|
||||
return str(site_packages)
|
||||
|
||||
def get_flatpak_site_packages_dir() -> str:
|
||||
# should never be all users
|
||||
nonlocal major_minor
|
||||
sand_box = os.getenv("FLATPAK_SANDBOX_DIR", "") or str(
|
||||
Path.home() / ".var/app/org.libreoffice.LibreOffice/sandbox"
|
||||
)
|
||||
site_packages = Path(sand_box) / f"lib/python{major_minor}/site-packages"
|
||||
site_packages.mkdir(parents=True, exist_ok=True)
|
||||
return str(site_packages)
|
||||
|
||||
def get_mac_site_packages_dir() -> str:
|
||||
nonlocal major_minor
|
||||
if site.USER_SITE:
|
||||
site_packages = Path(site.USER_SITE).resolve()
|
||||
else:
|
||||
site_packages = (
|
||||
Path.home() / f"Library/LibreOfficePython/{major_minor}/lib/python/site-packages"
|
||||
)
|
||||
site_packages.mkdir(parents=True, exist_ok=True)
|
||||
return str(site_packages)
|
||||
|
||||
def get_default_site_packages_dir() -> str:
|
||||
nonlocal major_minor
|
||||
if site.USER_SITE:
|
||||
site_packages = Path(site.USER_SITE).resolve()
|
||||
else:
|
||||
site_packages = Path.home() / f".local/lib/python{major_minor}/site-packages"
|
||||
site_packages.mkdir(parents=True, exist_ok=True)
|
||||
return str(site_packages)
|
||||
|
||||
if IS_WIN:
|
||||
return get_windows_site_packages_dir()
|
||||
if IS_MAC:
|
||||
return get_mac_site_packages_dir()
|
||||
if IS_FLATPAK:
|
||||
return get_flatpak_site_packages_dir()
|
||||
return get_default_site_packages_dir()
|
||||
|
||||
class TimerThread(threading.Thread):
|
||||
|
||||
def __init__(self, event, seconds, macro):
|
||||
|
@ -1166,6 +1250,9 @@ class LODocument(object):
|
|||
return
|
||||
|
||||
def to_pdf(self, path: str='', args: dict={}):
|
||||
"""
|
||||
https://wiki.documentfoundation.org/Macros/Python_Guide/PDF_export_filter_data
|
||||
"""
|
||||
path_pdf = path
|
||||
filter_name = '{}_pdf_Export'.format(self.type)
|
||||
filter_data = dict_to_property(args, True)
|
||||
|
@ -1520,6 +1607,142 @@ class LOSheetCharts(object):
|
|||
return LOChart(name, self.obj[name], self._sheet.draw_page)
|
||||
|
||||
|
||||
class LOSheetTableField(object):
|
||||
|
||||
def __init__(self, obj):
|
||||
self._obj = obj
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
@property
|
||||
def obj(self):
|
||||
return self._obj
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.obj.Name
|
||||
|
||||
@property
|
||||
def orientation(self):
|
||||
return self.obj.Orientation
|
||||
@orientation.setter
|
||||
def orientation(self, value):
|
||||
self.obj.Orientation = value
|
||||
|
||||
|
||||
# ~ com.sun.star.sheet.DataPilotFieldOrientation.ROW
|
||||
class LOSheetTable(object):
|
||||
|
||||
def __init__(self, obj):
|
||||
self._obj = obj
|
||||
self._source = None
|
||||
|
||||
def __getitem__(self, index):
|
||||
field = self.obj.DataPilotFields[index]
|
||||
return LOSheetTableField(field)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
@property
|
||||
def obj(self):
|
||||
return self._obj
|
||||
|
||||
@property
|
||||
def filter(self):
|
||||
return self.obj.ShowFilterButton
|
||||
@filter.setter
|
||||
def filter(self, value):
|
||||
self.obj.ShowFilterButton = value
|
||||
|
||||
@property
|
||||
def source(self):
|
||||
return self._source
|
||||
@source.setter
|
||||
def source(self, value):
|
||||
self._source = value
|
||||
self.obj.SourceRange = value.range_address
|
||||
|
||||
@property
|
||||
def rows(self):
|
||||
return self.obj.RowFields
|
||||
@rows.setter
|
||||
def rows(self, values):
|
||||
if not isinstance(values, tuple):
|
||||
values = (values,)
|
||||
for v in values:
|
||||
with self[v] as f:
|
||||
f.orientation = DPFO.ROW
|
||||
@property
|
||||
def columns(self):
|
||||
return self.obj.ColumnFields
|
||||
@columns.setter
|
||||
def columns(self, values):
|
||||
if not isinstance(values, tuple):
|
||||
values = (values,)
|
||||
for v in values:
|
||||
with self[v] as f:
|
||||
f.orientation = DPFO.COLUMN
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self.obj.DataFields
|
||||
@data.setter
|
||||
def data(self, values):
|
||||
if not isinstance(values, tuple):
|
||||
values = (values,)
|
||||
for v in values:
|
||||
with self[v] as f:
|
||||
f.orientation = DPFO.DATA
|
||||
|
||||
|
||||
class LOSheetTables(object):
|
||||
|
||||
def __init__(self, obj, sheet):
|
||||
self._obj = obj
|
||||
self._sheet = sheet
|
||||
|
||||
def __getitem__(self, index):
|
||||
return LOSheetTable(self.obj[index])
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self.obj
|
||||
|
||||
@property
|
||||
def obj(self):
|
||||
return self._obj
|
||||
|
||||
@property
|
||||
def count(self):
|
||||
return self.obj.Count
|
||||
|
||||
@property
|
||||
def names(self):
|
||||
return self.obj.ElementNames
|
||||
|
||||
def new(self, name, target):
|
||||
table = self.obj.createDataPilotDescriptor()
|
||||
self.obj.insertNewByName(name, target.address, table)
|
||||
return LOSheetTable(self.obj[name])
|
||||
|
||||
def remove(self, name):
|
||||
self.obj.removeByName(name)
|
||||
return
|
||||
|
||||
|
||||
class LOFormControl(LOBaseObject):
|
||||
EVENTS = {
|
||||
'action': 'actionPerformed',
|
||||
|
@ -2045,6 +2268,10 @@ class LOCalcSheet(object):
|
|||
def charts(self):
|
||||
return LOSheetCharts(self.obj.Charts, self)
|
||||
|
||||
@property
|
||||
def tables(self):
|
||||
return LOSheetTables(self.obj.DataPilotTables, self)
|
||||
|
||||
@property
|
||||
def rows(self):
|
||||
return LOSheetRows(self, self.obj.Rows)
|
||||
|
@ -2558,6 +2785,7 @@ class LOCalcRange(object):
|
|||
cell = None
|
||||
if isinstance(value, dict):
|
||||
for k, v in value.items():
|
||||
# ~ print(1, 'RENDER', k, v)
|
||||
cell = self._render_value(k, v, key)
|
||||
return cell
|
||||
elif isinstance(value, (list, tuple)):
|
||||
|
@ -2569,7 +2797,11 @@ class LOCalcRange(object):
|
|||
search = f'{{{parent}.{key}}}'
|
||||
ranges = self.find_all(search)
|
||||
|
||||
for cell in ranges or range(0):
|
||||
if ranges is None:
|
||||
return
|
||||
|
||||
# ~ for cell in ranges or range(0):
|
||||
for cell in ranges:
|
||||
self._set_new_value(cell, search, value)
|
||||
return LOCalcRange(cell)
|
||||
|
||||
|
@ -2718,6 +2950,72 @@ class LOCalcRange(object):
|
|||
self.obj.fillAuto(0, source)
|
||||
return
|
||||
|
||||
def _cast(self, t, v):
|
||||
if not t:
|
||||
return v
|
||||
|
||||
if t == datetime.date:
|
||||
nv = datetime.date.fromordinal(int(v) + DATE_OFFSET)
|
||||
else:
|
||||
nv = t(v)
|
||||
return nv
|
||||
|
||||
def get_data(self, types):
|
||||
values = [
|
||||
[self._cast(types[i], v) for i, v in enumerate(row)]
|
||||
for row in self.data
|
||||
]
|
||||
return values
|
||||
|
||||
|
||||
class LOWriterStyles(object):
|
||||
|
||||
def __init__(self, styles):
|
||||
self._styles = styles
|
||||
|
||||
@property
|
||||
def names(self):
|
||||
return {s.DisplayName: s.Name for s in self._styles}
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(tuple(self.names.values()))
|
||||
|
||||
|
||||
class LOWriterStylesFamilies(object):
|
||||
|
||||
def __init__(self, styles):
|
||||
self._styles = styles
|
||||
|
||||
def __getitem__(self, index):
|
||||
styles = {
|
||||
'Character': 'CharacterStyles',
|
||||
'Paragraph': 'ParagraphStyles',
|
||||
'Page': 'PageStyles',
|
||||
'Frame': 'FrameStyles',
|
||||
'Numbering': 'NumberingStyles',
|
||||
'Table': 'TableStyles',
|
||||
'Cell': 'CellStyles',
|
||||
}
|
||||
name = styles.get(index, index)
|
||||
return LOWriterStyles(self._styles[name])
|
||||
|
||||
def __iter__(self):
|
||||
self._index = 0
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
obj = LOWriterStyles(self._styles[self._index])
|
||||
self._index += 1
|
||||
return obj
|
||||
# ~ raise StopIteration
|
||||
|
||||
@property
|
||||
def names(self):
|
||||
return self._styles.ElementNames
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(self.names)
|
||||
|
||||
|
||||
class LOWriterPageStyle(LOBaseObject):
|
||||
|
||||
|
@ -2755,18 +3053,23 @@ class LOWriterTextRange(object):
|
|||
self._doc = doc
|
||||
self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph'
|
||||
self._is_table = self.obj.ImplementationName == 'SwXTextTable'
|
||||
self._is_text = self.obj.ImplementationName == 'SwXTextPortion'
|
||||
self._parts = []
|
||||
if self._is_paragraph:
|
||||
self._parts = [LOWriterTextRange(p, doc) for p in obj]
|
||||
|
||||
def __iter__(self):
|
||||
self._index = 0
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
for i, p in enumerate(self.obj):
|
||||
if i == self._index:
|
||||
obj = LOWriterTextRange(p, self._doc)
|
||||
self._index += 1
|
||||
return obj
|
||||
raise StopIteration
|
||||
try:
|
||||
obj = self._parts[self._index]
|
||||
except IndexError:
|
||||
raise StopIteration
|
||||
|
||||
self._index += 1
|
||||
return obj
|
||||
|
||||
@property
|
||||
def obj(self):
|
||||
|
@ -2785,11 +3088,37 @@ class LOWriterTextRange(object):
|
|||
@property
|
||||
def value(self):
|
||||
return self.string
|
||||
@value.setter
|
||||
def value(self, value):
|
||||
self.string = value
|
||||
|
||||
@property
|
||||
def style(self):
|
||||
s = ''
|
||||
if self.is_paragraph:
|
||||
s = self.obj.ParaStyleName
|
||||
elif self.is_text:
|
||||
s = self.obj.CharStyleName
|
||||
return s
|
||||
@style.setter
|
||||
def style(self, value):
|
||||
if self.is_paragraph:
|
||||
self.obj.ParaStyleName = value
|
||||
elif self.is_text:
|
||||
self.obj.CharStyleName = value
|
||||
|
||||
@property
|
||||
def is_paragraph(self):
|
||||
return self._is_paragraph
|
||||
|
||||
@property
|
||||
def is_table(self):
|
||||
return self._is_table
|
||||
|
||||
@property
|
||||
def is_text(self):
|
||||
return self._is_text
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
return self.obj.Text
|
||||
|
@ -2802,6 +3131,13 @@ class LOWriterTextRange(object):
|
|||
def dp(self):
|
||||
return self._doc.dp
|
||||
|
||||
def delete(self):
|
||||
cursor = self.cursor
|
||||
cursor.gotoStartOfParagraph(False)
|
||||
cursor.gotoNextParagraph(True)
|
||||
cursor.String = ''
|
||||
return
|
||||
|
||||
def offset(self):
|
||||
cursor = self.cursor.getEnd()
|
||||
return LOWriterTextRange(cursor, self._doc)
|
||||
|
@ -2846,25 +3182,26 @@ class LOWriterTextRanges(object):
|
|||
def __init__(self, obj, doc):
|
||||
self._obj = obj
|
||||
self._doc = doc
|
||||
self._paragraphs = [LOWriterTextRange(p, doc) for p in obj]
|
||||
|
||||
def __len__(self):
|
||||
return len(self._paragraphs)
|
||||
|
||||
def __getitem__(self, index):
|
||||
for i, p in enumerate(self.obj):
|
||||
if i == index:
|
||||
obj = LOWriterTextRange(p, self._doc)
|
||||
break
|
||||
return obj
|
||||
return self._paragraphs[index]
|
||||
|
||||
def __iter__(self):
|
||||
self._index = 0
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
for i, p in enumerate(self.obj):
|
||||
if i == self._index:
|
||||
obj = LOWriterTextRange(p, self._doc)
|
||||
self._index += 1
|
||||
return obj
|
||||
raise StopIteration
|
||||
try:
|
||||
obj = self._paragraphs[self._index]
|
||||
except IndexError:
|
||||
raise StopIteration
|
||||
|
||||
self._index += 1
|
||||
return obj
|
||||
|
||||
@property
|
||||
def obj(self):
|
||||
|
@ -2887,10 +3224,17 @@ class LOWriterTextTable(object):
|
|||
|
||||
@property
|
||||
def data(self):
|
||||
return self._obj.DataArray
|
||||
return self.obj.DataArray
|
||||
@data.setter
|
||||
def data(self, values):
|
||||
self._obj.DataArray = values
|
||||
self.obj.DataArray = values
|
||||
|
||||
@property
|
||||
def style(self):
|
||||
return self.obj.TableTemplateName
|
||||
@style.setter
|
||||
def style(self, value):
|
||||
self.obj.autoFormat(value)
|
||||
|
||||
|
||||
class LOWriterTextTables(object):
|
||||
|
@ -2920,7 +3264,7 @@ class LOWriter(LODocument):
|
|||
|
||||
@property
|
||||
def text(self):
|
||||
return LOWriterTextRange(self.obj.Text, self)
|
||||
return self.paragraphs
|
||||
|
||||
@property
|
||||
def paragraphs(self):
|
||||
|
@ -2973,6 +3317,10 @@ class LOWriter(LODocument):
|
|||
ps = self.obj.StyleFamilies['PageStyles']
|
||||
return LOWriterPageStyles(ps)
|
||||
|
||||
@property
|
||||
def styles(self):
|
||||
return LOWriterStylesFamilies(self.obj.StyleFamilies)
|
||||
|
||||
@property
|
||||
def search_descriptor(self):
|
||||
return self.obj.createSearchDescriptor()
|
||||
|
@ -3403,15 +3751,19 @@ class BaseRow:
|
|||
|
||||
class BaseQuery(object):
|
||||
PY_TYPES = {
|
||||
'SQL_LONG': 'getLong',
|
||||
'SQL_VARYING': 'getString',
|
||||
'SQL_FLOAT': 'getFloat',
|
||||
'SQL_BOOLEAN': 'getBoolean',
|
||||
'SQL_TYPE_DATE': 'getDate',
|
||||
'SQL_TYPE_TIME': 'getTime',
|
||||
'SQL_TIMESTAMP': 'getTimestamp',
|
||||
'VARCHAR': 'getString',
|
||||
'INTEGER': 'getLong',
|
||||
'DATE': 'getDate',
|
||||
# ~ 'SQL_LONG': 'getLong',
|
||||
# ~ 'SQL_VARYING': 'getString',
|
||||
# ~ 'SQL_FLOAT': 'getFloat',
|
||||
# ~ 'SQL_BOOLEAN': 'getBoolean',
|
||||
# ~ 'SQL_TYPE_DATE': 'getDate',
|
||||
# ~ 'SQL_TYPE_TIME': 'getTime',
|
||||
# ~ 'SQL_TIMESTAMP': 'getTimestamp',
|
||||
}
|
||||
TYPES_DATE = ('SQL_TYPE_DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP')
|
||||
# ~ TYPES_DATE = ('SQL_TYPE_DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP')
|
||||
TYPES_DATE = ('DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP')
|
||||
|
||||
def __init__(self, query):
|
||||
self._query = query
|
||||
|
@ -3437,6 +3789,7 @@ class BaseQuery(object):
|
|||
|
||||
def _to_python(self, index):
|
||||
type_field = self._meta.getColumnTypeName(index)
|
||||
# ~ print('TF', type_field)
|
||||
value = getattr(self._query, self.PY_TYPES[type_field])(index)
|
||||
if type_field in self.TYPES_DATE:
|
||||
value = _struct_to_date(value)
|
||||
|
@ -3562,10 +3915,11 @@ class LOBase(object):
|
|||
self._con.getTables().refresh()
|
||||
return
|
||||
|
||||
def initialize(self, database_proxy, tables):
|
||||
def initialize(self, database_proxy, tables=[]):
|
||||
db = FirebirdDatabase(self)
|
||||
database_proxy.initialize(db)
|
||||
db.create_tables(tables)
|
||||
if tables:
|
||||
db.create_tables(tables)
|
||||
return
|
||||
|
||||
def _validate_sql(self, sql, params):
|
||||
|
@ -3676,6 +4030,7 @@ class LODocs(object):
|
|||
return doc
|
||||
|
||||
def __len__(self):
|
||||
# ~ len(self._desktop.Components)
|
||||
for i, _ in enumerate(self._desktop.Components):
|
||||
pass
|
||||
return i + 1
|
||||
|
@ -3860,6 +4215,7 @@ class EventsFocus(EventsListenerBase, XFocusListener):
|
|||
if service in self.CONTROLS:
|
||||
obj = event.Source.Model
|
||||
obj.BackgroundColor = COLOR_ON_FOCUS
|
||||
obj.TextColor = TEXT_COLOR_ON_FOCUS
|
||||
return
|
||||
|
||||
def focusLost(self, event):
|
||||
|
@ -4445,6 +4801,13 @@ class UnoText(UnoBaseObject):
|
|||
def value(self, value):
|
||||
self.model.Text = value
|
||||
|
||||
@property
|
||||
def echochar(self):
|
||||
return chr(self.model.EchoChar)
|
||||
@echochar.setter
|
||||
def echochar(self, value):
|
||||
self.model.EchoChar = ord(value[0])
|
||||
|
||||
def validate(self):
|
||||
return
|
||||
|
||||
|
@ -5285,6 +5648,11 @@ class LODialog(object):
|
|||
self.obj.dispose()
|
||||
return value
|
||||
|
||||
def set_values(self, data):
|
||||
for k, v in data.items():
|
||||
self._controls[k].value = v
|
||||
return
|
||||
|
||||
|
||||
class LOSheets(object):
|
||||
|
||||
|
@ -5832,6 +6200,7 @@ _CB = ClipBoard
|
|||
|
||||
class Paths(object):
|
||||
FILE_PICKER = 'com.sun.star.ui.dialogs.FilePicker'
|
||||
FOLDER_PICKER = 'com.sun.star.ui.dialogs.FolderPicker'
|
||||
|
||||
def __init__(self, path=''):
|
||||
if path.startswith('file://'):
|
||||
|
@ -5885,7 +6254,10 @@ class Paths(object):
|
|||
elif IS_MAC:
|
||||
path = self.join(self.config('Module'), '..', 'Resources', PYTHON)
|
||||
else:
|
||||
path = sys.executable
|
||||
if IS_APP_IMAGE:
|
||||
path = self.join(self.config("Module"), PYTHON)
|
||||
else:
|
||||
path = sys.executable
|
||||
return path
|
||||
|
||||
@classmethod
|
||||
|
@ -5941,7 +6313,7 @@ class Paths(object):
|
|||
|
||||
@classmethod
|
||||
def get_dir(cls, init_dir=''):
|
||||
folder_picker = create_instance(cls.FILE_PICKER)
|
||||
folder_picker = create_instance(cls.FOLDER_PICKER)
|
||||
if not init_dir:
|
||||
init_dir = cls.documents
|
||||
init_dir = cls.to_url(init_dir)
|
||||
|
@ -5950,7 +6322,7 @@ class Paths(object):
|
|||
|
||||
path = ''
|
||||
if folder_picker.execute():
|
||||
path = cls.to_system(folder_picker.getDisplayDirectory())
|
||||
path = cls.to_system(folder_picker.getDirectory())
|
||||
return path
|
||||
|
||||
@classmethod
|
||||
|
@ -6007,7 +6379,7 @@ class Paths(object):
|
|||
if IS_WIN:
|
||||
os.startfile(path)
|
||||
else:
|
||||
pid = subprocess.Popen(['xdg-open', path]).pid
|
||||
pid = subprocess.Popen(['xdg-open', path, ], env=get_env()).pid
|
||||
return
|
||||
|
||||
@classmethod
|
||||
|
@ -6219,6 +6591,50 @@ class Paths(object):
|
|||
_P = Paths
|
||||
|
||||
|
||||
class Dates(object):
|
||||
|
||||
@classmethod
|
||||
def date(cls, year, month, day):
|
||||
d = datetime.date(year, month, day)
|
||||
return d
|
||||
|
||||
|
||||
class SpellChecker(object):
|
||||
|
||||
def __init__(self):
|
||||
service = 'com.sun.star.linguistic2.SpellChecker'
|
||||
self._spellchecker = create_instance(service, True)
|
||||
self._locale = LOCALE
|
||||
|
||||
@property
|
||||
def locale(self):
|
||||
slocal = f'{self._locale.Language}-{self._locale.Country}'
|
||||
return slocale
|
||||
@locale.setter
|
||||
def locale(self, value):
|
||||
lang = value.split('-')
|
||||
self._locale = Locale(lang[0], lang[1], '')
|
||||
|
||||
def is_valid(self, word):
|
||||
result = self._spellchecker.isValid(word, self._locale, ())
|
||||
return result
|
||||
|
||||
def spell(self, word):
|
||||
result = self._spellchecker.spell(word, self._locale, ())
|
||||
if result:
|
||||
result = result.getAlternatives()
|
||||
if not isinstance(result, tuple):
|
||||
result = ()
|
||||
return result
|
||||
|
||||
|
||||
def spell(word, locale=''):
|
||||
sc = SpellChecker()
|
||||
if locale:
|
||||
sc.locale = locale
|
||||
return sc.spell(word)
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
if name == 'active':
|
||||
return LODocs().active
|
||||
|
@ -6244,6 +6660,8 @@ def __getattr__(name):
|
|||
return LOShortCuts()
|
||||
if name == 'clipboard':
|
||||
return ClipBoard
|
||||
if name == 'dates':
|
||||
return Dates
|
||||
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
||||
|
||||
|
||||
|
@ -6330,48 +6748,6 @@ def get_fonts():
|
|||
return device.FontDescriptors
|
||||
|
||||
|
||||
# ~ From request
|
||||
# ~ https://github.com/psf/requests/blob/master/requests/structures.py#L15
|
||||
class CaseInsensitiveDict(MutableMapping):
|
||||
|
||||
def __init__(self, data=None, **kwargs):
|
||||
self._store = OrderedDict()
|
||||
if data is None:
|
||||
data = {}
|
||||
self.update(data, **kwargs)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
# Use the lowercased key for lookups, but store the actual
|
||||
# key alongside the value.
|
||||
self._store[key.lower()] = (key, value)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._store[key.lower()][1]
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._store[key.lower()]
|
||||
|
||||
def __iter__(self):
|
||||
return (casedkey for casedkey, mappedvalue in self._store.values())
|
||||
|
||||
def __len__(self):
|
||||
return len(self._store)
|
||||
|
||||
def lower_items(self):
|
||||
"""Like iteritems(), but with all lowercase keys."""
|
||||
values = (
|
||||
(lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items()
|
||||
)
|
||||
return values
|
||||
|
||||
# Copy is required
|
||||
def copy(self):
|
||||
return CaseInsensitiveDict(self._store.values())
|
||||
|
||||
def __repr__(self):
|
||||
return str(dict(self.items()))
|
||||
|
||||
|
||||
# ~ https://en.wikipedia.org/wiki/Web_colors
|
||||
def get_color(value):
|
||||
COLORS = {
|
||||
|
@ -6536,6 +6912,7 @@ def get_color(value):
|
|||
|
||||
|
||||
COLOR_ON_FOCUS = get_color('LightYellow')
|
||||
TEXT_COLOR_ON_FOCUS = get_color('black')
|
||||
|
||||
|
||||
class LOServer(object):
|
||||
|
@ -6587,7 +6964,7 @@ class LOServer(object):
|
|||
|
||||
for i in range(3):
|
||||
self._server = subprocess.Popen(self.CMD,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=get_env())
|
||||
time.sleep(3)
|
||||
if self.is_running:
|
||||
break
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import easymacro as app
|
||||
|
||||
|
||||
|
@ -9,8 +10,10 @@ _ = 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.elmau.net/elmau'
|
||||
URL_GIT = 'https://git.cuates.net/elmau/zaz-pip'
|
||||
ICON_OK = 'ok.svg'
|
||||
ICON_QUESTION = 'question.svg'
|
||||
|
||||
|
@ -31,14 +34,28 @@ PACKAGES = {
|
|||
|
||||
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(args, path_locales):
|
||||
def run(path_locales):
|
||||
global _
|
||||
|
||||
_ = app.install_locales(path_locales)
|
||||
globals()[args]()
|
||||
|
||||
open_dialog_pip()
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
@ -62,34 +79,33 @@ class Controllers(object):
|
|||
return
|
||||
|
||||
def cmd_install_pip_action(self, event):
|
||||
msg = _('Do you want install PIP?')
|
||||
msg = _("Do you want to install 'Python installer package' (PIP)?")
|
||||
if not app.question(msg, TITLE):
|
||||
return
|
||||
|
||||
self._install_pip()
|
||||
return
|
||||
|
||||
@app.run_in_thread
|
||||
def _install_pip(self):
|
||||
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(_('Download PIP...'))
|
||||
self.d.lst_log.insert(_('Downloading PIP…'))
|
||||
data, h, err = app.url_open(URL_PIP, verify=False)
|
||||
if err:
|
||||
msg = _('Do you have internet connection?')
|
||||
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 = _('File PIP not save')
|
||||
msg = _('Unable to copy PIP installation file')
|
||||
app.errorbox(msg)
|
||||
return
|
||||
self.d.lst_log.insert(_('PIP save correctly...'))
|
||||
self.d.lst_log.insert(_('PIP installation file has been saved'))
|
||||
|
||||
try:
|
||||
self.d.lst_log.insert(_('Start installing PIP...'))
|
||||
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):
|
||||
|
@ -103,16 +119,45 @@ class Controllers(object):
|
|||
self.d.lbl_pip.value = label
|
||||
self.d.cmd_install_pip.visible = False
|
||||
self.d.cmd_admin_pip.visible = True
|
||||
msg = _('PIP installed sucesfully')
|
||||
msg = _('PIP was installed successfully')
|
||||
app.msgbox(msg)
|
||||
else:
|
||||
msg = _('PIP not installed, see log')
|
||||
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
|
||||
|
@ -135,7 +180,8 @@ class Controllers(object):
|
|||
|
||||
def txt_search_key_released(self, event):
|
||||
if event.KeyCode == app.KEY['enter']:
|
||||
self.cmd_search_action(None)
|
||||
# ~ self.cmd_search_action(None)
|
||||
self.cmd_install_action(None)
|
||||
return
|
||||
|
||||
if not self.d.txt_search.value.strip():
|
||||
|
@ -179,7 +225,7 @@ class Controllers(object):
|
|||
if line:
|
||||
self.d.lst_package.select()
|
||||
else:
|
||||
self.d.lst_package.insert(_('Not found...'), 'error.png', show=False)
|
||||
self.d.lst_package.insert(_('Package not found…'), 'error.png', show=False)
|
||||
return
|
||||
|
||||
def cmd_search_action(self, event):
|
||||
|
@ -194,12 +240,12 @@ class Controllers(object):
|
|||
def cmd_install_action(self, event):
|
||||
name = self.d.txt_search.value.strip()
|
||||
if not name:
|
||||
msg = _('Enter package name to install')
|
||||
msg = _('Enter the package name to install')
|
||||
app.warning(msg)
|
||||
self.d.txt_search.set_focus()
|
||||
return
|
||||
|
||||
msg = _(f'Install package: {name} ?')
|
||||
msg = _('Do you really want to install package: {}?').format(name)
|
||||
if not app.question(msg):
|
||||
return
|
||||
|
||||
|
@ -213,7 +259,10 @@ class Controllers(object):
|
|||
self.d.lst_log.visible = True
|
||||
|
||||
line = ''
|
||||
cmd = ' install --upgrade --user'
|
||||
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}')
|
||||
|
@ -225,15 +274,40 @@ class Controllers(object):
|
|||
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'
|
||||
opt = _('install')
|
||||
if self._states['list']:
|
||||
opt = 'upgrade'
|
||||
opt = _('upgrade')
|
||||
|
||||
name = self.d.lst_package.value
|
||||
msg = _('Do you want {}:\n\n{} ?').format(opt, name)
|
||||
msg = _('Do you want to {}:\n\n{}?').format(opt, name)
|
||||
if not app.question(msg, TITLE):
|
||||
return
|
||||
|
||||
|
@ -255,6 +329,7 @@ class Controllers(object):
|
|||
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):
|
||||
|
@ -264,7 +339,7 @@ class Controllers(object):
|
|||
return
|
||||
|
||||
name = self.d.lst_package.value
|
||||
msg = _('Do you want uninstall:\n\n{} ?').format(name)
|
||||
msg = _('Do you want to uninstall:\n\n{}?').format(name)
|
||||
if not app.question(msg):
|
||||
return
|
||||
|
||||
|
@ -291,13 +366,56 @@ class Controllers(object):
|
|||
if not path:
|
||||
return
|
||||
|
||||
msg = _(f'Confirm install from:\n\n{path}')
|
||||
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
|
||||
|
@ -351,7 +469,7 @@ def _create_dialog():
|
|||
exists_pip = True
|
||||
if not label:
|
||||
exists_pip = False
|
||||
label = _('PIP not installed')
|
||||
label = _("'Python installer package' (PIP) is not installed")
|
||||
args = {
|
||||
'Type': 'Label',
|
||||
'Name': 'lbl_pip',
|
||||
|
@ -408,6 +526,17 @@ def _create_dialog():
|
|||
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',
|
||||
|
@ -534,6 +663,10 @@ def _create_dialog():
|
|||
}
|
||||
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)
|
||||
|
@ -544,12 +677,150 @@ def _create_dialog():
|
|||
dialog.lst_package.center()
|
||||
dialog.txt_search.center()
|
||||
dialog.center(controls)
|
||||
dialog.center((dialog.txt_search, dialog.cmd_explore))
|
||||
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
|
||||
|
|
|
@ -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/>.
|
29
zaz.py
|
@ -75,10 +75,16 @@ class LiboXML(object):
|
|||
'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': 'http://openoffice.org/extensions/description/2006',
|
||||
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
|
||||
'xmlns:d': 'http://openoffice.org/extensions/description/2006',
|
||||
'xmlns': xmlns,
|
||||
'xmlns:xlink': xmlns_xlink,
|
||||
'xmlns:d': xmlns,
|
||||
'xmlns:l': xmlns_l,
|
||||
}
|
||||
NS_ADDONS = {
|
||||
'xmlns:xs': 'http://www.w3.org/2001/XMLSchema',
|
||||
|
@ -87,7 +93,7 @@ class LiboXML(object):
|
|||
NS_UPDATE = {
|
||||
'xmlns': 'http://openoffice.org/extensions/update/2006',
|
||||
'xmlns:d': 'http://openoffice.org/extensions/description/2006',
|
||||
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
|
||||
'xmlns:xlink': xmlns_xlink,
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
|
@ -158,6 +164,13 @@ class LiboXML(object):
|
|||
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():
|
||||
|
@ -413,14 +426,14 @@ def _compress_oxt():
|
|||
z.write(fullpath, file_name, zipfile.ZIP_DEFLATED)
|
||||
z.close()
|
||||
|
||||
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
|
||||
|
@ -525,7 +538,7 @@ 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
|
||||
|
||||
|
||||
|
@ -742,7 +755,7 @@ def _new(args):
|
|||
|
||||
path = _join(args.target, args.name)
|
||||
_mkdir(path)
|
||||
_mkdir(_join(path, 'files'))
|
||||
_mkdir(_join(path, 'ext'))
|
||||
_mkdir(_join(path, 'images'))
|
||||
path_logo = 'images/pymacros.png'
|
||||
copyfile(path_logo, _join(path, 'images/logo.png'))
|
||||
|
|