diff --git a/CHANGELOG b/CHANGELOG index e5090d9..2f61d6e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,13 @@ +v 0.8.0 [06-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 +15,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 - v 0.1.0 [18-oct-2019] - Initial version - diff --git a/VERSION b/VERSION index bcaffe1..8adc70f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.0 \ No newline at end of file +0.8.0 \ No newline at end of file diff --git a/conf.py b/conf.py index 42e616c..5c8c889 100644 --- a/conf.py +++ b/conf.py @@ -26,7 +26,7 @@ import logging TYPE_EXTENSION = 1 # ~ https://semver.org/ -VERSION = '0.7.0' +VERSION = '0.8.0' # ~ Your great extension name, not used spaces NAME = 'ZAZPip' diff --git a/easymacro.py b/easymacro.py index 0745d96..2c7d5f3 100644 --- a/easymacro.py +++ b/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) @@ -2719,6 +2882,55 @@ class LOCalcRange(object): return +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): def __init__(self, obj): @@ -2755,18 +2967,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 +3002,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 +3045,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 +3096,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 +3138,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 +3178,7 @@ class LOWriter(LODocument): @property def text(self): - return LOWriterTextRange(self.obj.Text, self) + return self.paragraphs @property def paragraphs(self): @@ -2973,6 +3231,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 +3665,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 +3703,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 +3829,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): @@ -5832,6 +6100,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 +6210,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 +6219,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 +6488,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 +6557,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}'") diff --git a/files/ZAZPip_v0.7.0.oxt b/files/ZAZPip_v0.8.0.oxt similarity index 50% rename from files/ZAZPip_v0.7.0.oxt rename to files/ZAZPip_v0.8.0.oxt index 1b86d6a..ae2c1a7 100644 Binary files a/files/ZAZPip_v0.7.0.oxt and b/files/ZAZPip_v0.8.0.oxt differ diff --git a/source/description.xml b/source/description.xml index 655fa38..60aaaf1 100644 --- a/source/description.xml +++ b/source/description.xml @@ -1,7 +1,7 @@ - + ZAZ Pip ZAZ Pip diff --git a/source/pythonpath/easymacro.py b/source/pythonpath/easymacro.py index 0745d96..2c7d5f3 100644 --- a/source/pythonpath/easymacro.py +++ b/source/pythonpath/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) @@ -2719,6 +2882,55 @@ class LOCalcRange(object): return +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): def __init__(self, obj): @@ -2755,18 +2967,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 +3002,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 +3045,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 +3096,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 +3138,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 +3178,7 @@ class LOWriter(LODocument): @property def text(self): - return LOWriterTextRange(self.obj.Text, self) + return self.paragraphs @property def paragraphs(self): @@ -2973,6 +3231,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 +3665,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 +3703,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 +3829,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): @@ -5832,6 +6100,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 +6210,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 +6219,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 +6488,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 +6557,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}'")