diff --git a/easymacro.py b/easymacro.py index d081e3e..40072a3 100644 --- a/easymacro.py +++ b/easymacro.py @@ -2892,7 +2892,7 @@ class LOWriterStyles(object): return {s.DisplayName: s.Name for s in self._styles} def __str__(self): - return '\n'.join(self.names) + return '\n'.join(tuple(self.names.values())) class LOWriterStylesFamilies(object): @@ -2967,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): @@ -3003,10 +3008,18 @@ class LOWriterTextRange(object): @property def style(self): - return self.obj.ParaStyleName + 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): - self.obj.ParaStyleName = value + if self.is_paragraph: + self.obj.ParaStyleName = value + elif self.is_text: + self.obj.CharStyleName = value @property def is_paragraph(self): @@ -3016,6 +3029,10 @@ class LOWriterTextRange(object): 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 diff --git a/files/ZazDoc_v0.1.0.oxt b/files/ZazDoc_v0.1.0.oxt index fc4197d..f802f4e 100644 Binary files a/files/ZazDoc_v0.1.0.oxt and b/files/ZazDoc_v0.1.0.oxt differ diff --git a/source/pythonpath/easymacro.py b/source/pythonpath/easymacro.py index d081e3e..40072a3 100644 --- a/source/pythonpath/easymacro.py +++ b/source/pythonpath/easymacro.py @@ -2892,7 +2892,7 @@ class LOWriterStyles(object): return {s.DisplayName: s.Name for s in self._styles} def __str__(self): - return '\n'.join(self.names) + return '\n'.join(tuple(self.names.values())) class LOWriterStylesFamilies(object): @@ -2967,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): @@ -3003,10 +3008,18 @@ class LOWriterTextRange(object): @property def style(self): - return self.obj.ParaStyleName + 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): - self.obj.ParaStyleName = value + if self.is_paragraph: + self.obj.ParaStyleName = value + elif self.is_text: + self.obj.CharStyleName = value @property def is_paragraph(self): @@ -3016,6 +3029,10 @@ class LOWriterTextRange(object): 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 diff --git a/source/pythonpath/main.py b/source/pythonpath/main.py index c2d1d6a..b7d7e40 100644 --- a/source/pythonpath/main.py +++ b/source/pythonpath/main.py @@ -7,18 +7,12 @@ ID_EXTENSION = '' _ = None - -def _replace_styles(): - dlg = _create_dialog_replace_styles() - dlg.open() - return - - class Controllers(object): def __init__(self, dlg): self.d = dlg - self.styles = {} + self.para_styles = {} + self.char_styles = {} @app.catch_exception def cmd_replace_by_paragraph_action(self, event): @@ -42,8 +36,8 @@ class Controllers(object): if not app.question(msg): return - source = self.styles[source] - target = self.styles[target] + source = self.para_styles[source] + target = self.para_styles[target] doc = app.active i = 0 @@ -58,6 +52,45 @@ class Controllers(object): app.debug(f'{i} replaces') return + @app.catch_exception + def cmd_replace_by_character_action(self, event): + source = self.d.lst_character_source.value + target = self.d.lst_character_target.value + + if not source: + msg = _('Select style source') + app.errorbox(msg) + return + if not target: + msg = _('Select style target') + app.errorbox(msg) + return + if source == target: + msg = _('Select different styles') + app.errorbox(msg) + return + + msg = _('Replace selected styles?') + if not app.question(msg): + return + + source = self.char_styles[source] + target = self.char_styles[target] + + doc = app.active + i = 0 + for paragraph in doc.paragraphs: + if not paragraph.is_paragraph: + continue + for p in paragraph: + if p.style == source: + p.style = target + i += 1 + + self.d.close() + app.debug(f'{i} replaces') + return + def cmd_close_action(self, event): self.d.close() return @@ -68,7 +101,7 @@ def _create_dialog_replace_styles(): 'Name': 'dialog', 'Title': _('Replace Styles'), 'Width': 220, - 'Height': 100, + 'Height': 125, } dlg = app.create_dialog(args) dlg.id = ID_EXTENSION @@ -77,9 +110,9 @@ def _create_dialog_replace_styles(): args = { 'Type': 'Label', 'Name': 'lbl_paragraphs', - 'Label': _('~Replace by paragraph'), + 'Label': _('Replace by paragraph'), 'Width': 70, - 'Height': 15, + 'Height': 10, 'X': 10, 'Y': 10, } @@ -113,6 +146,43 @@ def _create_dialog_replace_styles(): } dlg.add_control(args) + args = { + 'Type': 'Label', + 'Name': 'lbl_character', + 'Label': _('Replace by character'), + 'Width': 70, + 'Height': 10, + } + dlg.add_control(args) + + args = { + 'Type': 'ListBox', + 'Name': 'lst_character_source', + 'Width': 85, + 'Height': 15, + 'Dropdown': True, + } + dlg.add_control(args) + + args = { + 'Type': 'ListBox', + 'Name': 'lst_character_target', + 'Width': 85, + 'Height': 15, + 'Dropdown': True, + } + dlg.add_control(args) + + args = { + 'Type': 'Button', + 'Name': 'cmd_replace_by_character', + 'Width': 15, + 'Height': 15, + 'ImageURL': 'replace.svg', + 'ImagePosition': 1, + } + dlg.add_control(args) + args = { 'Type': 'Button', 'Name': 'cmd_close', @@ -124,22 +194,37 @@ def _create_dialog_replace_styles(): } dlg.add_control(args) - dlg.lst_paragraph_source.move(dlg.lbl_paragraphs) + dlg.lst_paragraph_source.move(dlg.lbl_paragraphs, 0, 5) dlg.lst_paragraph_target.move(dlg.lst_paragraph_source, 5, 0) dlg.cmd_replace_by_paragraph.move(dlg.lst_paragraph_target, 5, 0) - dlg.cmd_close.move(dlg.lst_paragraph_source, 0, 20) - dlg.cmd_close.center() + + dlg.lbl_character.move(dlg.lst_paragraph_source, 0, 10) + dlg.lst_character_source.move(dlg.lbl_character, 0, 5) + dlg.lst_character_target.move(dlg.lst_character_source, 5, 0) + dlg.cmd_replace_by_character.move(dlg.lst_character_target, 5, 0) + + dlg.cmd_close.move(dlg.lst_character_source, 0, 15, True) doc = app.active styles = doc.styles['Paragraph'].names dlg.lst_paragraph_source.data = tuple(styles.keys()) dlg.lst_paragraph_target.data = tuple(styles.keys()) - dlg.events.styles = styles + dlg.events.para_styles = styles + + styles = doc.styles['Character'].names + dlg.lst_character_source.data = tuple(styles.keys()) + dlg.lst_character_target.data = tuple(styles.keys()) + dlg.events.char_styles = styles return dlg -@app.catch_exception +def _replace_styles(): + dlg = _create_dialog_replace_styles() + dlg.open() + return + + def run(args, path_locales): global _