diff --git a/.gitignore b/.gitignore index 399bdd7..0030b5e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,7 @@ __pycache__/ *.po~ *.log -images/ - +/images docs/ # Virtualenv diff --git a/easymacro.py b/easymacro.py index 16715df..16563ad 100644 --- a/easymacro.py +++ b/easymacro.py @@ -85,6 +85,7 @@ from com.sun.star.lang import XEventListener from com.sun.star.awt import XMouseListener from com.sun.star.awt import XMouseMotionListener from com.sun.star.awt import XFocusListener +from com.sun.star.awt import XKeyListener # ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt_1_1FontUnderline.html from com.sun.star.awt import FontUnderline @@ -184,6 +185,11 @@ DIR = { 'locales': 'locales', } DEFAULT_MIME_TYPE = 'png' + +KEY = { + 'enter': 1280, +} + MODIFIERS = { 'shift': KeyModifier.SHIFT, 'ctrl': KeyModifier.MOD1, @@ -1153,6 +1159,64 @@ class LODocument(object): return +class LOCellStyle(LOBaseObject): + + def __init__(self, obj): + super().__init__(obj) + + @property + def name(self): + return self.obj.Name + + @property + def properties(self): + properties = self.obj.PropertySetInfo.Properties + data = {p.Name: getattr(self.obj, p.Name) for p in properties} + return data + @properties.setter + def properties(self, values): + _set_properties(self.obj, values) + + +class LOCellStyles(object): + + def __init__(self, obj, doc): + self._obj = obj + self._doc = doc + + def __len__(self): + return len(self.obj) + + def __getitem__(self, index): + return LOCellStyle(self.obj[index]) + + def __setitem__(self, key, value): + self.obj[key] = value + + def __delitem__(self, key): + if not isinstance(key, str): + key = key.Name + del self.obj[key] + + def __contains__(self, item): + return item in self.obj + + @property + def obj(self): + return self._obj + + @property + def names(self): + return self.obj.ElementNames + + def new(self, name: str=''): + obj = self._doc.create_instance('com.sun.star.style.CellStyle') + if name: + self.obj[name] = obj + obj = LOCellStyle(obj) + return obj + + class LOCalc(LODocument): def __init__(self, obj): @@ -1208,6 +1272,14 @@ class LOCalc(LODocument): def tabs(self, value): self._cc.SheetTabs = value + @property + def cs(self): + return self.cell_styles + @property + def cell_styles(self): + obj = self.obj.StyleFamilies['CellStyles'] + return LOCellStyles(obj, self) + @property def db_ranges(self): # ~ return LOCalcDataBaseRanges(self.obj.DataBaseRanges) @@ -2121,6 +2193,18 @@ class LOWriterTextRange(object): self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph' self._is_table = self.obj.ImplementationName == 'SwXTextTable' + 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 + @property def obj(self): return self._obj @@ -2142,7 +2226,7 @@ class LOWriterTextRange(object): @property def text(self): - return self.obj.getText() + return self.obj.Text @property def cursor(self): @@ -2152,6 +2236,10 @@ class LOWriterTextRange(object): def dp(self): return self._doc.dp + @property + def is_table(self): + return self._is_table + def offset(self): cursor = self.cursor.getEnd() return LOWriterTextRange(cursor, self._doc) @@ -2181,7 +2269,23 @@ class LOWriterTextRanges(object): self._doc = doc def __getitem__(self, index): - return LOWriterTextRange(self.obj[index], self._doc) + for i, p in enumerate(self.obj): + if i == index: + obj = LOWriterTextRange(p, self._doc) + break + return 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 @property def obj(self): @@ -2194,6 +2298,14 @@ class LOWriter(LODocument): super().__init__(obj) self._type = WRITER + @property + def text(self): + return LOWriterTextRange(self.obj.Text, self) + + @property + def paragraphs(self): + return LOWriterTextRanges(self.obj.Text, self) + @property def selection(self): sel = self.obj.CurrentSelection @@ -2841,7 +2953,7 @@ def _add_listeners(events, control, name=''): 'addMouseListener': EventsMouse, 'addFocusListener': EventsFocus, # ~ 'addItemListener': EventsItem, - # ~ 'addKeyListener': EventsKey, + 'addKeyListener': EventsKey, # ~ 'addTabListener': EventsTab, } if hasattr(control, 'obj'): @@ -2984,6 +3096,27 @@ class EventsFocus(EventsListenerBase, XFocusListener): return +class EventsKey(EventsListenerBase, XKeyListener): + """ + event.KeyChar + event.KeyCode + event.KeyFunc + event.Modifiers + """ + + def __init__(self, controller, name): + super().__init__(controller, name) + + def keyPressed(self, event): + pass + + def keyReleased(self, event): + event_name = '{}_key_released'.format(self._name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + # ~ BorderColor = ? # ~ FontStyleName = ? # ~ HelpURL = ? diff --git a/files/ZAZPip_v0.6.0.oxt b/files/ZAZPip_v0.6.0.oxt new file mode 100644 index 0000000..c62bcdb Binary files /dev/null and b/files/ZAZPip_v0.6.0.oxt differ diff --git a/source/images/close.svg b/source/images/close.svg new file mode 100644 index 0000000..8b7bc47 --- /dev/null +++ b/source/images/close.svg @@ -0,0 +1,52 @@ + + + + + + image/svg+xml + + 9.4 + + + + + 9.4 + Created with Sketch. + + + + + + + + diff --git a/source/images/home.svg b/source/images/home.svg new file mode 100644 index 0000000..517ac7d --- /dev/null +++ b/source/images/home.svg @@ -0,0 +1,37 @@ + +image/svg+xml diff --git a/source/images/icon_16.bmp b/source/images/icon_16.bmp new file mode 100644 index 0000000..8eaab00 Binary files /dev/null and b/source/images/icon_16.bmp differ diff --git a/source/images/install.svg b/source/images/install.svg new file mode 100644 index 0000000..c878786 --- /dev/null +++ b/source/images/install.svg @@ -0,0 +1,62 @@ + +image/svg+xml diff --git a/source/images/ok.svg b/source/images/ok.svg new file mode 100644 index 0000000..f211040 --- /dev/null +++ b/source/images/ok.svg @@ -0,0 +1,50 @@ + +image/svg+xml diff --git a/source/images/python.svg b/source/images/python.svg new file mode 100644 index 0000000..9d3262f --- /dev/null +++ b/source/images/python.svg @@ -0,0 +1,57 @@ + +image/svg+xml diff --git a/source/images/question.svg b/source/images/question.svg new file mode 100644 index 0000000..2fc074d --- /dev/null +++ b/source/images/question.svg @@ -0,0 +1,27 @@ + +image/svg+xml diff --git a/source/images/search.svg b/source/images/search.svg new file mode 100644 index 0000000..d928e3b --- /dev/null +++ b/source/images/search.svg @@ -0,0 +1,41 @@ + +image/svg+xml diff --git a/source/images/shell.svg b/source/images/shell.svg new file mode 100644 index 0000000..2e4350a --- /dev/null +++ b/source/images/shell.svg @@ -0,0 +1,48 @@ + +image/svg+xml diff --git a/source/images/uninstall.svg b/source/images/uninstall.svg new file mode 100644 index 0000000..5a7c6bd --- /dev/null +++ b/source/images/uninstall.svg @@ -0,0 +1,63 @@ + +image/svg+xml diff --git a/source/images/zazpip.png b/source/images/zazpip.png new file mode 100644 index 0000000..2f210ed Binary files /dev/null and b/source/images/zazpip.png differ diff --git a/source/pythonpath/easymacro.py b/source/pythonpath/easymacro.py index c2e81bd..16563ad 100644 --- a/source/pythonpath/easymacro.py +++ b/source/pythonpath/easymacro.py @@ -85,6 +85,7 @@ from com.sun.star.lang import XEventListener from com.sun.star.awt import XMouseListener from com.sun.star.awt import XMouseMotionListener from com.sun.star.awt import XFocusListener +from com.sun.star.awt import XKeyListener # ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt_1_1FontUnderline.html from com.sun.star.awt import FontUnderline @@ -184,6 +185,11 @@ DIR = { 'locales': 'locales', } DEFAULT_MIME_TYPE = 'png' + +KEY = { + 'enter': 1280, +} + MODIFIERS = { 'shift': KeyModifier.SHIFT, 'ctrl': KeyModifier.MOD1, @@ -556,8 +562,7 @@ def popen(command): yield line.decode().rstrip() except Exception as e: error(e) - msg = f'Error No: {e.errno} - {e.strerror}' - yield msg + yield (e.errno, e.strerror) def sleep(seconds): @@ -1154,6 +1159,64 @@ class LODocument(object): return +class LOCellStyle(LOBaseObject): + + def __init__(self, obj): + super().__init__(obj) + + @property + def name(self): + return self.obj.Name + + @property + def properties(self): + properties = self.obj.PropertySetInfo.Properties + data = {p.Name: getattr(self.obj, p.Name) for p in properties} + return data + @properties.setter + def properties(self, values): + _set_properties(self.obj, values) + + +class LOCellStyles(object): + + def __init__(self, obj, doc): + self._obj = obj + self._doc = doc + + def __len__(self): + return len(self.obj) + + def __getitem__(self, index): + return LOCellStyle(self.obj[index]) + + def __setitem__(self, key, value): + self.obj[key] = value + + def __delitem__(self, key): + if not isinstance(key, str): + key = key.Name + del self.obj[key] + + def __contains__(self, item): + return item in self.obj + + @property + def obj(self): + return self._obj + + @property + def names(self): + return self.obj.ElementNames + + def new(self, name: str=''): + obj = self._doc.create_instance('com.sun.star.style.CellStyle') + if name: + self.obj[name] = obj + obj = LOCellStyle(obj) + return obj + + class LOCalc(LODocument): def __init__(self, obj): @@ -1209,6 +1272,14 @@ class LOCalc(LODocument): def tabs(self, value): self._cc.SheetTabs = value + @property + def cs(self): + return self.cell_styles + @property + def cell_styles(self): + obj = self.obj.StyleFamilies['CellStyles'] + return LOCellStyles(obj, self) + @property def db_ranges(self): # ~ return LOCalcDataBaseRanges(self.obj.DataBaseRanges) @@ -2122,6 +2193,18 @@ class LOWriterTextRange(object): self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph' self._is_table = self.obj.ImplementationName == 'SwXTextTable' + 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 + @property def obj(self): return self._obj @@ -2143,7 +2226,7 @@ class LOWriterTextRange(object): @property def text(self): - return self.obj.getText() + return self.obj.Text @property def cursor(self): @@ -2153,6 +2236,10 @@ class LOWriterTextRange(object): def dp(self): return self._doc.dp + @property + def is_table(self): + return self._is_table + def offset(self): cursor = self.cursor.getEnd() return LOWriterTextRange(cursor, self._doc) @@ -2182,7 +2269,23 @@ class LOWriterTextRanges(object): self._doc = doc def __getitem__(self, index): - return LOWriterTextRange(self.obj[index], self._doc) + for i, p in enumerate(self.obj): + if i == index: + obj = LOWriterTextRange(p, self._doc) + break + return 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 @property def obj(self): @@ -2195,6 +2298,14 @@ class LOWriter(LODocument): super().__init__(obj) self._type = WRITER + @property + def text(self): + return LOWriterTextRange(self.obj.Text, self) + + @property + def paragraphs(self): + return LOWriterTextRanges(self.obj.Text, self) + @property def selection(self): sel = self.obj.CurrentSelection @@ -2842,7 +2953,7 @@ def _add_listeners(events, control, name=''): 'addMouseListener': EventsMouse, 'addFocusListener': EventsFocus, # ~ 'addItemListener': EventsItem, - # ~ 'addKeyListener': EventsKey, + 'addKeyListener': EventsKey, # ~ 'addTabListener': EventsTab, } if hasattr(control, 'obj'): @@ -2985,6 +3096,27 @@ class EventsFocus(EventsListenerBase, XFocusListener): return +class EventsKey(EventsListenerBase, XKeyListener): + """ + event.KeyChar + event.KeyCode + event.KeyFunc + event.Modifiers + """ + + def __init__(self, controller, name): + super().__init__(controller, name) + + def keyPressed(self, event): + pass + + def keyReleased(self, event): + event_name = '{}_key_released'.format(self._name) + if hasattr(self._controller, event_name): + getattr(self._controller, event_name)(event) + return + + # ~ BorderColor = ? # ~ FontStyleName = ? # ~ HelpURL = ? diff --git a/source/pythonpath/main.py b/source/pythonpath/main.py index ebc9bd3..47e167c 100644 --- a/source/pythonpath/main.py +++ b/source/pythonpath/main.py @@ -11,20 +11,21 @@ TITLE = 'ZAZ-PIP' URL_PIP = 'https://bootstrap.pypa.io/get-pip.py' PIP = 'pip' URL_GIT = 'https://git.elmau.net/elmau' - +ICON_OK = 'ok.svg' +ICON_QUESTION = 'question.svg' PACKAGES = { - 'cffi': 'ok.png', - 'cryptography': 'ok.png', - 'httpx': 'ok.png', - 'lxml': 'ok.png', - 'numpy': 'ok.png', - 'pandas': 'ok.png', - 'psycopg2-binary': 'ok.png', - 'peewee': 'ok.png', - 'pillow': 'ok.png', - 'pytesseract': 'ok.png', - 'sounddevice': 'ok.png', + 'cffi': ICON_OK, + 'cryptography': ICON_OK, + 'httpx': ICON_OK, + 'lxml': ICON_OK, + 'numpy': ICON_OK, + 'pandas': ICON_OK, + 'psycopg2-binary': ICON_OK, + 'peewee': ICON_OK, + 'pillow': ICON_OK, + 'pytesseract': ICON_OK, + 'sounddevice': ICON_OK, } @@ -75,7 +76,6 @@ class Controllers(object): path_pip = app.paths.tmp() self.d.lst_log.insert(_('Download PIP...')) data, h, err = app.url_open(URL_PIP, verify=False) - app.msgbox(path_pip) if err: msg = _('Do you have internet connection?') app.errorbox('{}\n\n{}'.format(msg, err)) @@ -155,7 +155,7 @@ class Controllers(object): for p in packages: t = '{} - ({})'.format(p['name'], p['version']) - self.d.lst_package.insert(t, 'ok.png') + self.d.lst_package.insert(t, ICON_OK) self.d.lst_package.select() self.d.txt_search.set_focus() return @@ -173,7 +173,7 @@ class Controllers(object): parts = name.split('(') name_verify = parts[0].strip() package = '{} {}'.format(name, description) - image = PACKAGES.get(name_verify, 'question.png') + image = PACKAGES.get(name_verify, ICON_QUESTION) self.d.lst_package.insert(package, image) if line: @@ -191,6 +191,21 @@ class Controllers(object): self._search(search) return + def cmd_install_action(self, event): + name = self.d.txt_search.value.strip() + if not name: + msg = _('Enter package name to install') + app.warning(msg) + self.d.txt_search.set_focus() + return + + msg = _(f'Install package: {name} ?') + if not app.question(msg): + return + + self._install(name) + return + @app.run_in_thread def _install(self, value): self._set_state('install') @@ -301,7 +316,6 @@ def _create_dialog(): path_python = app.paths.python cmd = '"{}" -V'.format(path_python) - app.msgbox(cmd) label = app.run(cmd, True) args = { @@ -320,9 +334,7 @@ def _create_dialog(): dialog.center(dialog.lbl_python, y=25) cmd = '"{}" -m pip -V'.format(path_python) - app.msgbox(cmd) label = app.run(cmd, True) - app.msgbox(label) exists_pip = True if not label: exists_pip = False @@ -349,7 +361,7 @@ def _create_dialog(): 'Width': 70, 'Height': BUTTON_WH, 'Step': 10, - 'ImageURL': 'python.png', + 'ImageURL': 'python.svg', 'ImagePosition': 1, } dialog.add_control(args) @@ -432,7 +444,7 @@ def _create_dialog(): 'Width': 70, 'Height': BUTTON_WH, 'Step': 1, - 'ImageURL': 'close.png', + 'ImageURL': 'close.svg', 'ImagePosition': 1, # ~ 'PushButtonType': 2, } @@ -445,7 +457,7 @@ def _create_dialog(): 'Width': BUTTON_WH, 'Height': BUTTON_WH, 'Step': 1, - 'ImageURL': 'home.png', + 'ImageURL': 'home.svg', 'FocusOnClick': False, 'Y': 2, } @@ -457,7 +469,7 @@ def _create_dialog(): 'Width': BUTTON_WH, 'Height': BUTTON_WH, 'Step': 1, - 'ImageURL': 'search.png', + 'ImageURL': 'search.svg', 'FocusOnClick': False, 'Y': 2, } @@ -469,7 +481,7 @@ def _create_dialog(): 'Width': BUTTON_WH, 'Height': BUTTON_WH, 'Step': 1, - 'ImageURL': 'uninstall.png', + 'ImageURL': 'uninstall.svg', 'FocusOnClick': False, 'Y': 2, } @@ -481,7 +493,7 @@ def _create_dialog(): 'Width': BUTTON_WH, 'Height': BUTTON_WH, 'Step': 1, - 'ImageURL': 'install.png', + 'ImageURL': 'install.svg', 'FocusOnClick': False, 'Y': 2, } @@ -493,7 +505,7 @@ def _create_dialog(): 'Width': BUTTON_WH, 'Height': BUTTON_WH, 'Step': 1, - 'ImageURL': 'shell.png', + 'ImageURL': 'shell.svg', 'FocusOnClick': False, 'Y': 2, }