Add config proxy. Issue #1

This commit is contained in:
Mauricio Baeza 2021-06-14 16:38:25 -05:00
commit 9e2f841017
14 changed files with 1075 additions and 186 deletions

View File

@ -1,3 +1,13 @@
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] v 0.5.0 [09-jul-2020]
- Test install pandas - Test install pandas
@ -5,16 +15,12 @@ v 0.4.0 [10-mar-2020]
- Update easymacro.py - Update easymacro.py
- Fix: in OSx Catalina - Fix: in OSx Catalina
v 0.3.0 [12-nov-2019] v 0.3.0 [12-nov-2019]
- Update easymacro.py - Update easymacro.py
- Test install numpy - Test install numpy
v 0.2.0 [18-oct-2019] v 0.2.0 [18-oct-2019]
- Add spanish - Add spanish
v 0.1.0 [18-oct-2019] v 0.1.0 [18-oct-2019]
- Initial version - Initial version

View File

@ -5,7 +5,7 @@ Extension for install and admin Python Pip in LibreOffice.
Thanks! Thanks!
https://gitlab.com/mauriciobaeza/zaz https://git.cuates.net/elmau/zaz
### Software libre, no gratis ### Software libre, no gratis

View File

@ -1 +1 @@
0.7.0 0.8.0

View File

@ -26,7 +26,7 @@ import logging
TYPE_EXTENSION = 1 TYPE_EXTENSION = 1
# ~ https://semver.org/ # ~ https://semver.org/
VERSION = '0.7.0' VERSION = '0.8.0'
# ~ Your great extension name, not used spaces # ~ Your great extension name, not used spaces
NAME = 'ZAZPip' NAME = 'ZAZPip'
@ -46,9 +46,10 @@ PATH_MSGMERGE = 'msgmerge'
# ~ Show in extension manager # ~ Show in extension manager
URL_GIT = 'https://git.cuates.net/elmau/zaz-pip'
PUBLISHER = { PUBLISHER = {
'en': {'text': 'El Mau', 'link': 'https://gitlab.com/mauriciobaeza'}, 'en': {'text': 'El Mau', 'link': URL_GIT},
'es': {'text': 'El Mau', 'link': 'https://gitlab.com/mauriciobaeza'}, 'es': {'text': 'El Mau', 'link': URL_GIT},
} }
# ~ Name in this folder for copy # ~ Name in this folder for copy

View File

@ -21,6 +21,7 @@
import base64 import base64
import csv import csv
import ctypes
import datetime import datetime
import getpass import getpass
import gettext 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.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
from com.sun.star.awt import XActionListener from com.sun.star.lang import Locale
from com.sun.star.lang import XEventListener from com.sun.star.lang import XEventListener
from com.sun.star.awt import XActionListener
from com.sun.star.awt import XMenuListener from com.sun.star.awt import XMenuListener
from com.sun.star.awt import XMouseListener from com.sun.star.awt import XMouseListener
from com.sun.star.awt import XMouseMotionListener from com.sun.star.awt import XMouseMotionListener
@ -203,6 +205,12 @@ class ConditionOperator():
CO = ConditionOperator CO = ConditionOperator
class DataPilotFieldOrientation():
from com.sun.star.sheet.DataPilotFieldOrientation \
import HIDDEN, COLUMN, ROW, PAGE, DATA
DPFO = DataPilotFieldOrientation
OS = platform.system() OS = platform.system()
IS_WIN = OS == 'Windows' IS_WIN = OS == 'Windows'
IS_MAC = OS == 'Darwin' 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') LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale')
LANG = LANGUAGE.split('-')[0] 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') NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName')
VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion') VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion')
@ -372,6 +385,8 @@ def mri(obj: Any) -> None:
error(msg) error(msg)
return return
if hasattr(obj, 'obj'):
obj = obj.obj
m.inspect(obj) m.inspect(obj)
return return
@ -1166,6 +1181,9 @@ class LODocument(object):
return return
def to_pdf(self, path: str='', args: dict={}): def to_pdf(self, path: str='', args: dict={}):
"""
https://wiki.documentfoundation.org/Macros/Python_Guide/PDF_export_filter_data
"""
path_pdf = path path_pdf = path
filter_name = '{}_pdf_Export'.format(self.type) filter_name = '{}_pdf_Export'.format(self.type)
filter_data = dict_to_property(args, True) filter_data = dict_to_property(args, True)
@ -1520,6 +1538,142 @@ class LOSheetCharts(object):
return LOChart(name, self.obj[name], self._sheet.draw_page) 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): class LOFormControl(LOBaseObject):
EVENTS = { EVENTS = {
'action': 'actionPerformed', 'action': 'actionPerformed',
@ -2045,6 +2199,10 @@ class LOCalcSheet(object):
def charts(self): def charts(self):
return LOSheetCharts(self.obj.Charts, self) return LOSheetCharts(self.obj.Charts, self)
@property
def tables(self):
return LOSheetTables(self.obj.DataPilotTables, self)
@property @property
def rows(self): def rows(self):
return LOSheetRows(self, self.obj.Rows) return LOSheetRows(self, self.obj.Rows)
@ -2558,6 +2716,7 @@ class LOCalcRange(object):
cell = None cell = None
if isinstance(value, dict): if isinstance(value, dict):
for k, v in value.items(): for k, v in value.items():
# ~ print(1, 'RENDER', k, v)
cell = self._render_value(k, v, key) cell = self._render_value(k, v, key)
return cell return cell
elif isinstance(value, (list, tuple)): elif isinstance(value, (list, tuple)):
@ -2569,7 +2728,11 @@ class LOCalcRange(object):
search = f'{{{parent}.{key}}}' search = f'{{{parent}.{key}}}'
ranges = self.find_all(search) 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) self._set_new_value(cell, search, value)
return LOCalcRange(cell) return LOCalcRange(cell)
@ -2718,6 +2881,72 @@ class LOCalcRange(object):
self.obj.fillAuto(0, source) self.obj.fillAuto(0, source)
return 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): class LOWriterPageStyle(LOBaseObject):
@ -2755,18 +2984,23 @@ class LOWriterTextRange(object):
self._doc = doc self._doc = doc
self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph' self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph'
self._is_table = self.obj.ImplementationName == 'SwXTextTable' 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): def __iter__(self):
self._index = 0 self._index = 0
return self return self
def __next__(self): def __next__(self):
for i, p in enumerate(self.obj): try:
if i == self._index: obj = self._parts[self._index]
obj = LOWriterTextRange(p, self._doc) except IndexError:
self._index += 1 raise StopIteration
return obj
raise StopIteration self._index += 1
return obj
@property @property
def obj(self): def obj(self):
@ -2785,11 +3019,37 @@ class LOWriterTextRange(object):
@property @property
def value(self): def value(self):
return self.string 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 @property
def is_table(self): def is_table(self):
return self._is_table return self._is_table
@property
def is_text(self):
return self._is_text
@property @property
def text(self): def text(self):
return self.obj.Text return self.obj.Text
@ -2802,6 +3062,13 @@ class LOWriterTextRange(object):
def dp(self): def dp(self):
return self._doc.dp return self._doc.dp
def delete(self):
cursor = self.cursor
cursor.gotoStartOfParagraph(False)
cursor.gotoNextParagraph(True)
cursor.String = ''
return
def offset(self): def offset(self):
cursor = self.cursor.getEnd() cursor = self.cursor.getEnd()
return LOWriterTextRange(cursor, self._doc) return LOWriterTextRange(cursor, self._doc)
@ -2846,25 +3113,26 @@ class LOWriterTextRanges(object):
def __init__(self, obj, doc): def __init__(self, obj, doc):
self._obj = obj self._obj = obj
self._doc = doc self._doc = doc
self._paragraphs = [LOWriterTextRange(p, doc) for p in obj]
def __len__(self):
return len(self._paragraphs)
def __getitem__(self, index): def __getitem__(self, index):
for i, p in enumerate(self.obj): return self._paragraphs[index]
if i == index:
obj = LOWriterTextRange(p, self._doc)
break
return obj
def __iter__(self): def __iter__(self):
self._index = 0 self._index = 0
return self return self
def __next__(self): def __next__(self):
for i, p in enumerate(self.obj): try:
if i == self._index: obj = self._paragraphs[self._index]
obj = LOWriterTextRange(p, self._doc) except IndexError:
self._index += 1 raise StopIteration
return obj
raise StopIteration self._index += 1
return obj
@property @property
def obj(self): def obj(self):
@ -2887,10 +3155,17 @@ class LOWriterTextTable(object):
@property @property
def data(self): def data(self):
return self._obj.DataArray return self.obj.DataArray
@data.setter @data.setter
def data(self, values): 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): class LOWriterTextTables(object):
@ -2920,7 +3195,7 @@ class LOWriter(LODocument):
@property @property
def text(self): def text(self):
return LOWriterTextRange(self.obj.Text, self) return self.paragraphs
@property @property
def paragraphs(self): def paragraphs(self):
@ -2973,6 +3248,10 @@ class LOWriter(LODocument):
ps = self.obj.StyleFamilies['PageStyles'] ps = self.obj.StyleFamilies['PageStyles']
return LOWriterPageStyles(ps) return LOWriterPageStyles(ps)
@property
def styles(self):
return LOWriterStylesFamilies(self.obj.StyleFamilies)
@property @property
def search_descriptor(self): def search_descriptor(self):
return self.obj.createSearchDescriptor() return self.obj.createSearchDescriptor()
@ -3403,15 +3682,19 @@ class BaseRow:
class BaseQuery(object): class BaseQuery(object):
PY_TYPES = { PY_TYPES = {
'SQL_LONG': 'getLong', 'VARCHAR': 'getString',
'SQL_VARYING': 'getString', 'INTEGER': 'getLong',
'SQL_FLOAT': 'getFloat', 'DATE': 'getDate',
'SQL_BOOLEAN': 'getBoolean', # ~ 'SQL_LONG': 'getLong',
'SQL_TYPE_DATE': 'getDate', # ~ 'SQL_VARYING': 'getString',
'SQL_TYPE_TIME': 'getTime', # ~ 'SQL_FLOAT': 'getFloat',
'SQL_TIMESTAMP': 'getTimestamp', # ~ '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): def __init__(self, query):
self._query = query self._query = query
@ -3437,6 +3720,7 @@ class BaseQuery(object):
def _to_python(self, index): def _to_python(self, index):
type_field = self._meta.getColumnTypeName(index) type_field = self._meta.getColumnTypeName(index)
# ~ print('TF', type_field)
value = getattr(self._query, self.PY_TYPES[type_field])(index) value = getattr(self._query, self.PY_TYPES[type_field])(index)
if type_field in self.TYPES_DATE: if type_field in self.TYPES_DATE:
value = _struct_to_date(value) value = _struct_to_date(value)
@ -3562,10 +3846,11 @@ class LOBase(object):
self._con.getTables().refresh() self._con.getTables().refresh()
return return
def initialize(self, database_proxy, tables): def initialize(self, database_proxy, tables=[]):
db = FirebirdDatabase(self) db = FirebirdDatabase(self)
database_proxy.initialize(db) database_proxy.initialize(db)
db.create_tables(tables) if tables:
db.create_tables(tables)
return return
def _validate_sql(self, sql, params): def _validate_sql(self, sql, params):
@ -3676,6 +3961,7 @@ class LODocs(object):
return doc return doc
def __len__(self): def __len__(self):
# ~ len(self._desktop.Components)
for i, _ in enumerate(self._desktop.Components): for i, _ in enumerate(self._desktop.Components):
pass pass
return i + 1 return i + 1
@ -4445,6 +4731,13 @@ class UnoText(UnoBaseObject):
def value(self, value): def value(self, value):
self.model.Text = 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): def validate(self):
return return
@ -5285,6 +5578,11 @@ class LODialog(object):
self.obj.dispose() self.obj.dispose()
return value return value
def set_values(self, data):
for k, v in data.items():
self._controls[k].value = v
return
class LOSheets(object): class LOSheets(object):
@ -5832,6 +6130,7 @@ _CB = ClipBoard
class Paths(object): class Paths(object):
FILE_PICKER = 'com.sun.star.ui.dialogs.FilePicker' FILE_PICKER = 'com.sun.star.ui.dialogs.FilePicker'
FOLDER_PICKER = 'com.sun.star.ui.dialogs.FolderPicker'
def __init__(self, path=''): def __init__(self, path=''):
if path.startswith('file://'): if path.startswith('file://'):
@ -5941,7 +6240,7 @@ class Paths(object):
@classmethod @classmethod
def get_dir(cls, init_dir=''): def get_dir(cls, init_dir=''):
folder_picker = create_instance(cls.FILE_PICKER) folder_picker = create_instance(cls.FOLDER_PICKER)
if not init_dir: if not init_dir:
init_dir = cls.documents init_dir = cls.documents
init_dir = cls.to_url(init_dir) init_dir = cls.to_url(init_dir)
@ -5950,7 +6249,7 @@ class Paths(object):
path = '' path = ''
if folder_picker.execute(): if folder_picker.execute():
path = cls.to_system(folder_picker.getDisplayDirectory()) path = cls.to_system(folder_picker.getDirectory())
return path return path
@classmethod @classmethod
@ -6219,6 +6518,50 @@ class Paths(object):
_P = Paths _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): def __getattr__(name):
if name == 'active': if name == 'active':
return LODocs().active return LODocs().active
@ -6244,6 +6587,8 @@ def __getattr__(name):
return LOShortCuts() return LOShortCuts()
if name == 'clipboard': if name == 'clipboard':
return ClipBoard return ClipBoard
if name == 'dates':
return Dates
raise AttributeError(f"module '{__name__}' has no attribute '{name}'") raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
@ -6330,48 +6675,6 @@ def get_fonts():
return device.FontDescriptors 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 # ~ https://en.wikipedia.org/wiki/Web_colors
def get_color(value): def get_color(value):
COLORS = { COLORS = {

Binary file not shown.

BIN
files/ZAZPip_v0.8.0.oxt Normal file

Binary file not shown.

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<description xmlns="http://openoffice.org/extensions/description/2006" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:d="http://openoffice.org/extensions/description/2006"> <description xmlns="http://openoffice.org/extensions/description/2006" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:d="http://openoffice.org/extensions/description/2006">
<identifier value="net.elmau.zaz.pip"/> <identifier value="net.elmau.zaz.pip"/>
<version value="0.7.0"/> <version value="0.8.0"/>
<display-name> <display-name>
<name lang="en">ZAZ Pip</name> <name lang="en">ZAZ Pip</name>
<name lang="es">ZAZ Pip</name> <name lang="es">ZAZ Pip</name>
@ -14,8 +14,8 @@
<default xlink:href="images/zazpip.png"/> <default xlink:href="images/zazpip.png"/>
</icon> </icon>
<publisher> <publisher>
<name xlink:href="https://gitlab.com/mauriciobaeza" lang="en">El Mau</name> <name xlink:href="https://git.cuates.net/elmau/zaz-pip" 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="es">El Mau</name>
</publisher> </publisher>
<registration> <registration>
<simple-license accept-by="user" suppress-on-update="true"> <simple-license accept-by="user" suppress-on-update="true">

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

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

After

Width:  |  Height:  |  Size: 505 B

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

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

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,23 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg <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" version="1.0"
x="0px" x="0px"
y="0px" y="0px"
viewBox="0 0 32 32" viewBox="0 0 18 18"
enable-background="new 0 0 100 100" enable-background="new 0 0 100 100"
xml:space="preserve" xml:space="preserve"
id="svg12" id="svg12"
sodipodi:docname="python.svg" sodipodi:docname="python.svg"
width="32" width="18"
height="32" height="18"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><sodipodi:namedview 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" pagecolor="#ffffff"
bordercolor="#666666" bordercolor="#666666"
borderopacity="1" borderopacity="1"
@ -27,24 +27,25 @@
inkscape:pageopacity="0" inkscape:pageopacity="0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:window-width="2560" inkscape:window-width="2560"
inkscape:window-height="1006" inkscape:window-height="1001"
id="namedview9" id="namedview9"
showgrid="false" showgrid="false"
inkscape:showpageshadow="false" inkscape:showpageshadow="false"
inkscape:zoom="4.655591" inkscape:zoom="26.336"
inkscape:cx="-28.841168" inkscape:cx="10.631835"
inkscape:cy="23.577791" inkscape:cy="8.2966283"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="37" inkscape:window-y="42"
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="svg12" inkscape:current-layer="svg12"
inkscape:document-rotation="0" /><metadata inkscape:document-rotation="0"
inkscape:pagecheckerboard="0" /><metadata
id="metadata18"><rdf:RDF><cc:Work id="metadata18"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type 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="defs16" /><g
id="g23" 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" 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 id="path2" /><circle
cx="48.326" cx="48.326"

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

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

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

After

Width:  |  Height:  |  Size: 942 B

View File

@ -21,6 +21,7 @@
import base64 import base64
import csv import csv
import ctypes
import datetime import datetime
import getpass import getpass
import gettext 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.ControlCharacter import PARAGRAPH_BREAK
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
from com.sun.star.awt import XActionListener from com.sun.star.lang import Locale
from com.sun.star.lang import XEventListener from com.sun.star.lang import XEventListener
from com.sun.star.awt import XActionListener
from com.sun.star.awt import XMenuListener from com.sun.star.awt import XMenuListener
from com.sun.star.awt import XMouseListener from com.sun.star.awt import XMouseListener
from com.sun.star.awt import XMouseMotionListener from com.sun.star.awt import XMouseMotionListener
@ -203,6 +205,12 @@ class ConditionOperator():
CO = ConditionOperator CO = ConditionOperator
class DataPilotFieldOrientation():
from com.sun.star.sheet.DataPilotFieldOrientation \
import HIDDEN, COLUMN, ROW, PAGE, DATA
DPFO = DataPilotFieldOrientation
OS = platform.system() OS = platform.system()
IS_WIN = OS == 'Windows' IS_WIN = OS == 'Windows'
IS_MAC = OS == 'Darwin' 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') LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale')
LANG = LANGUAGE.split('-')[0] 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') NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName')
VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion') VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion')
@ -372,6 +385,8 @@ def mri(obj: Any) -> None:
error(msg) error(msg)
return return
if hasattr(obj, 'obj'):
obj = obj.obj
m.inspect(obj) m.inspect(obj)
return return
@ -1166,6 +1181,9 @@ class LODocument(object):
return return
def to_pdf(self, path: str='', args: dict={}): def to_pdf(self, path: str='', args: dict={}):
"""
https://wiki.documentfoundation.org/Macros/Python_Guide/PDF_export_filter_data
"""
path_pdf = path path_pdf = path
filter_name = '{}_pdf_Export'.format(self.type) filter_name = '{}_pdf_Export'.format(self.type)
filter_data = dict_to_property(args, True) filter_data = dict_to_property(args, True)
@ -1520,6 +1538,142 @@ class LOSheetCharts(object):
return LOChart(name, self.obj[name], self._sheet.draw_page) 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): class LOFormControl(LOBaseObject):
EVENTS = { EVENTS = {
'action': 'actionPerformed', 'action': 'actionPerformed',
@ -2045,6 +2199,10 @@ class LOCalcSheet(object):
def charts(self): def charts(self):
return LOSheetCharts(self.obj.Charts, self) return LOSheetCharts(self.obj.Charts, self)
@property
def tables(self):
return LOSheetTables(self.obj.DataPilotTables, self)
@property @property
def rows(self): def rows(self):
return LOSheetRows(self, self.obj.Rows) return LOSheetRows(self, self.obj.Rows)
@ -2558,6 +2716,7 @@ class LOCalcRange(object):
cell = None cell = None
if isinstance(value, dict): if isinstance(value, dict):
for k, v in value.items(): for k, v in value.items():
# ~ print(1, 'RENDER', k, v)
cell = self._render_value(k, v, key) cell = self._render_value(k, v, key)
return cell return cell
elif isinstance(value, (list, tuple)): elif isinstance(value, (list, tuple)):
@ -2569,7 +2728,11 @@ class LOCalcRange(object):
search = f'{{{parent}.{key}}}' search = f'{{{parent}.{key}}}'
ranges = self.find_all(search) 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) self._set_new_value(cell, search, value)
return LOCalcRange(cell) return LOCalcRange(cell)
@ -2718,6 +2881,72 @@ class LOCalcRange(object):
self.obj.fillAuto(0, source) self.obj.fillAuto(0, source)
return 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): class LOWriterPageStyle(LOBaseObject):
@ -2755,18 +2984,23 @@ class LOWriterTextRange(object):
self._doc = doc self._doc = doc
self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph' self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph'
self._is_table = self.obj.ImplementationName == 'SwXTextTable' 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): def __iter__(self):
self._index = 0 self._index = 0
return self return self
def __next__(self): def __next__(self):
for i, p in enumerate(self.obj): try:
if i == self._index: obj = self._parts[self._index]
obj = LOWriterTextRange(p, self._doc) except IndexError:
self._index += 1 raise StopIteration
return obj
raise StopIteration self._index += 1
return obj
@property @property
def obj(self): def obj(self):
@ -2785,11 +3019,37 @@ class LOWriterTextRange(object):
@property @property
def value(self): def value(self):
return self.string 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 @property
def is_table(self): def is_table(self):
return self._is_table return self._is_table
@property
def is_text(self):
return self._is_text
@property @property
def text(self): def text(self):
return self.obj.Text return self.obj.Text
@ -2802,6 +3062,13 @@ class LOWriterTextRange(object):
def dp(self): def dp(self):
return self._doc.dp return self._doc.dp
def delete(self):
cursor = self.cursor
cursor.gotoStartOfParagraph(False)
cursor.gotoNextParagraph(True)
cursor.String = ''
return
def offset(self): def offset(self):
cursor = self.cursor.getEnd() cursor = self.cursor.getEnd()
return LOWriterTextRange(cursor, self._doc) return LOWriterTextRange(cursor, self._doc)
@ -2846,25 +3113,26 @@ class LOWriterTextRanges(object):
def __init__(self, obj, doc): def __init__(self, obj, doc):
self._obj = obj self._obj = obj
self._doc = doc self._doc = doc
self._paragraphs = [LOWriterTextRange(p, doc) for p in obj]
def __len__(self):
return len(self._paragraphs)
def __getitem__(self, index): def __getitem__(self, index):
for i, p in enumerate(self.obj): return self._paragraphs[index]
if i == index:
obj = LOWriterTextRange(p, self._doc)
break
return obj
def __iter__(self): def __iter__(self):
self._index = 0 self._index = 0
return self return self
def __next__(self): def __next__(self):
for i, p in enumerate(self.obj): try:
if i == self._index: obj = self._paragraphs[self._index]
obj = LOWriterTextRange(p, self._doc) except IndexError:
self._index += 1 raise StopIteration
return obj
raise StopIteration self._index += 1
return obj
@property @property
def obj(self): def obj(self):
@ -2887,10 +3155,17 @@ class LOWriterTextTable(object):
@property @property
def data(self): def data(self):
return self._obj.DataArray return self.obj.DataArray
@data.setter @data.setter
def data(self, values): 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): class LOWriterTextTables(object):
@ -2920,7 +3195,7 @@ class LOWriter(LODocument):
@property @property
def text(self): def text(self):
return LOWriterTextRange(self.obj.Text, self) return self.paragraphs
@property @property
def paragraphs(self): def paragraphs(self):
@ -2973,6 +3248,10 @@ class LOWriter(LODocument):
ps = self.obj.StyleFamilies['PageStyles'] ps = self.obj.StyleFamilies['PageStyles']
return LOWriterPageStyles(ps) return LOWriterPageStyles(ps)
@property
def styles(self):
return LOWriterStylesFamilies(self.obj.StyleFamilies)
@property @property
def search_descriptor(self): def search_descriptor(self):
return self.obj.createSearchDescriptor() return self.obj.createSearchDescriptor()
@ -3403,15 +3682,19 @@ class BaseRow:
class BaseQuery(object): class BaseQuery(object):
PY_TYPES = { PY_TYPES = {
'SQL_LONG': 'getLong', 'VARCHAR': 'getString',
'SQL_VARYING': 'getString', 'INTEGER': 'getLong',
'SQL_FLOAT': 'getFloat', 'DATE': 'getDate',
'SQL_BOOLEAN': 'getBoolean', # ~ 'SQL_LONG': 'getLong',
'SQL_TYPE_DATE': 'getDate', # ~ 'SQL_VARYING': 'getString',
'SQL_TYPE_TIME': 'getTime', # ~ 'SQL_FLOAT': 'getFloat',
'SQL_TIMESTAMP': 'getTimestamp', # ~ '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): def __init__(self, query):
self._query = query self._query = query
@ -3437,6 +3720,7 @@ class BaseQuery(object):
def _to_python(self, index): def _to_python(self, index):
type_field = self._meta.getColumnTypeName(index) type_field = self._meta.getColumnTypeName(index)
# ~ print('TF', type_field)
value = getattr(self._query, self.PY_TYPES[type_field])(index) value = getattr(self._query, self.PY_TYPES[type_field])(index)
if type_field in self.TYPES_DATE: if type_field in self.TYPES_DATE:
value = _struct_to_date(value) value = _struct_to_date(value)
@ -3562,10 +3846,11 @@ class LOBase(object):
self._con.getTables().refresh() self._con.getTables().refresh()
return return
def initialize(self, database_proxy, tables): def initialize(self, database_proxy, tables=[]):
db = FirebirdDatabase(self) db = FirebirdDatabase(self)
database_proxy.initialize(db) database_proxy.initialize(db)
db.create_tables(tables) if tables:
db.create_tables(tables)
return return
def _validate_sql(self, sql, params): def _validate_sql(self, sql, params):
@ -3676,6 +3961,7 @@ class LODocs(object):
return doc return doc
def __len__(self): def __len__(self):
# ~ len(self._desktop.Components)
for i, _ in enumerate(self._desktop.Components): for i, _ in enumerate(self._desktop.Components):
pass pass
return i + 1 return i + 1
@ -4445,6 +4731,13 @@ class UnoText(UnoBaseObject):
def value(self, value): def value(self, value):
self.model.Text = 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): def validate(self):
return return
@ -5285,6 +5578,11 @@ class LODialog(object):
self.obj.dispose() self.obj.dispose()
return value return value
def set_values(self, data):
for k, v in data.items():
self._controls[k].value = v
return
class LOSheets(object): class LOSheets(object):
@ -5832,6 +6130,7 @@ _CB = ClipBoard
class Paths(object): class Paths(object):
FILE_PICKER = 'com.sun.star.ui.dialogs.FilePicker' FILE_PICKER = 'com.sun.star.ui.dialogs.FilePicker'
FOLDER_PICKER = 'com.sun.star.ui.dialogs.FolderPicker'
def __init__(self, path=''): def __init__(self, path=''):
if path.startswith('file://'): if path.startswith('file://'):
@ -5941,7 +6240,7 @@ class Paths(object):
@classmethod @classmethod
def get_dir(cls, init_dir=''): def get_dir(cls, init_dir=''):
folder_picker = create_instance(cls.FILE_PICKER) folder_picker = create_instance(cls.FOLDER_PICKER)
if not init_dir: if not init_dir:
init_dir = cls.documents init_dir = cls.documents
init_dir = cls.to_url(init_dir) init_dir = cls.to_url(init_dir)
@ -5950,7 +6249,7 @@ class Paths(object):
path = '' path = ''
if folder_picker.execute(): if folder_picker.execute():
path = cls.to_system(folder_picker.getDisplayDirectory()) path = cls.to_system(folder_picker.getDirectory())
return path return path
@classmethod @classmethod
@ -6219,6 +6518,50 @@ class Paths(object):
_P = Paths _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): def __getattr__(name):
if name == 'active': if name == 'active':
return LODocs().active return LODocs().active
@ -6244,6 +6587,8 @@ def __getattr__(name):
return LOShortCuts() return LOShortCuts()
if name == 'clipboard': if name == 'clipboard':
return ClipBoard return ClipBoard
if name == 'dates':
return Dates
raise AttributeError(f"module '{__name__}' has no attribute '{name}'") raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
@ -6330,48 +6675,6 @@ def get_fonts():
return device.FontDescriptors 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 # ~ https://en.wikipedia.org/wiki/Web_colors
def get_color(value): def get_color(value):
COLORS = { COLORS = {

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os
import easymacro as app import easymacro as app
@ -9,8 +10,9 @@ _ = None
TITLE = 'ZAZ-PIP' TITLE = 'ZAZ-PIP'
URL_PIP = 'https://bootstrap.pypa.io/get-pip.py' URL_PIP = 'https://bootstrap.pypa.io/get-pip.py'
URL_TEST = 'http://duckduckgo.com'
PIP = 'pip' PIP = 'pip'
URL_GIT = 'https://git.elmau.net/elmau' URL_GIT = 'https://git.cuates.net/elmau/zaz-pip'
ICON_OK = 'ok.svg' ICON_OK = 'ok.svg'
ICON_QUESTION = 'question.svg' ICON_QUESTION = 'question.svg'
@ -31,6 +33,17 @@ PACKAGES = {
def open_dialog_pip(): def open_dialog_pip():
dialog = _create_dialog() 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() dialog.open()
return return
@ -298,6 +311,49 @@ class Controllers(object):
self._install(path=path) self._install(path=path)
return 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 = _('Are you shure save data?')
if not app.question(msg):
return
app.set_config('proxy', data, TITLE)
msg = _('Save data sucesfully')
app.msgbox(msg)
self.d.close()
return
def cmd_proxy_delete_action(self, event):
msg = _("Are you shure delete data?")
if not app.question(msg):
return
app.set_config('proxy', {}, TITLE)
msg = _('Delete data sucesfully')
app.msgbox(msg)
self.d.close()
return
def _create_dialog(): def _create_dialog():
BUTTON_WH = 20 BUTTON_WH = 20
@ -408,6 +464,17 @@ def _create_dialog():
dialog.add_control(args) dialog.add_control(args)
dialog.center(dialog.link_proyect, y=-5) 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 = { args = {
'Type': 'Listbox', 'Type': 'Listbox',
'Name': 'lst_log', 'Name': 'lst_log',
@ -534,6 +601,10 @@ def _create_dialog():
} }
dialog.add_control(args) 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, controls = (dialog.cmd_home, dialog.cmd_search,
dialog.cmd_install, dialog.cmd_uninstall, dialog.cmd_shell) dialog.cmd_install, dialog.cmd_uninstall, dialog.cmd_shell)
dialog.lbl_package.move(dialog.cmd_home) dialog.lbl_package.move(dialog.cmd_home)
@ -544,12 +615,150 @@ def _create_dialog():
dialog.lst_package.center() dialog.lst_package.center()
dialog.txt_search.center() dialog.txt_search.center()
dialog.center(controls) 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.step = 10
dialog.cmd_install_pip.visible = not exists_pip dialog.cmd_install_pip.visible = not exists_pip
dialog.cmd_admin_pip.visible = exists_pip dialog.cmd_admin_pip.visible = exists_pip
dialog.lst_log.visible = False dialog.lst_log.visible = False
return dialog return dialog
def _create_dialog_proxy():
args= {
'Name': 'dlg_proxy',
'Title': 'Zaz-Pip - Config Proxy',
'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