This mostly working. Except cause error when terminating. See the bottom here.
from __future__ import annotations
from typing import Any, cast, TYPE_CHECKING
import uno
import unohelper
from com.sun.star.util import XModifyListener
from com.sun.star.uno import RuntimeException
from ooodev.io.log import logging as log
if TYPE_CHECKING:
from com.sun.star.lang import EventObject
class CellCustomPropListener(unohelper.Base, XModifyListener):
_instances = {}
def __new__(cls, cell_range: Any):
unique = cell_range.AbsoluteName
if unique not in cls._instances:
inst = super().__new__(cls)
inst._is_init = False
cls._instances[unique] = inst
return cls._instances[unique]
def __init__(self, cell_range: Any) -> None:
if self._is_init:
return
self._cell_range = cell_range
XModifyListener.__init__(self)
self._cell_range.addModifyListener(self)
self._current = cell_range.AbsoluteName
self._is_init = True
def modified(self, event: EventObject) -> None:
try:
src = cast(Any, event.Source)
self._cell_range = event.Source
if self._current != self._cell_range.AbsoluteName: # type: ignore
self.__class__._instances.pop(self._current)
self.__class__._instances[self._cell_range.AbsoluteName] = self # type: ignore
self._current = self._cell_range.AbsoluteName # type: ignore
src.removeModifyListener(self)
# the following pattern prevents endless loops meanwhile modifying
# the cell itself
# … stolen from
# https://forum.openoffice.org/en/forum/viewtopic.php?p=175732#p175732
# update cell if needed here
log.debug(f"CellCustomPropListener: modified: {src.AbsoluteName}")
src.addModifyListener(self)
except RuntimeException:
# cell is deleted
log.debug("CellCustomPropListener: modified: Cell is deleted")
try:
log.debug("CellCustomPropListener: modified: Attempting to clean up")
if self._current and self._current in self.__class__._instances:
self.__class__._instances.pop(self._current)
log.debug(f"CellCustomPropListener: modified: Cleaned up {self._current}")
self._current = ""
except Exception as e:
log.error(f"CellCustomPropListener: modified: {e}")
def disposing(self):
if self._current in self.__class__._instances:
self.__class__._instances.pop(self._current)
@classmethod
def clear(cls):
cls._instances.clear()
log.debug("CellCustomPropListener: clear: Cleared all instances")
Python runner
from __future__ import annotations
import logging
import uno
from ooodev.calc import CalcDoc
from ooodev.loader import Lo
from ooodev.loader.inst.options import Options
from ooodev.calc.cell.cell_custom_prop_listener import CellCustomPropListener
def main():
loader = Lo.load_office(connector=Lo.ConnectPipe(), opt=Options(log_level=logging.DEBUG))
doc = CalcDoc.create_doc(loader=loader, visible=True)
try:
sheet = doc.sheets[0]
sheet2 = doc.sheets.insert_sheet("Sheet2")
cell1 = sheet["B2"]
CellCustomPropListener(cell1.component)
cell1.value = 10
print()
cell2 = sheet["B2"]
CellCustomPropListener(cell2.component)
cell2.value = 12
print()
cell_c4 = sheet["C4"]
CellCustomPropListener(cell_c4.component)
cell_c4.value = 12
print()
cell3 = sheet["B2"]
CellCustomPropListener(cell3.component)
cell3.value = 14
print()
cell_c4.value = "Done"
print()
cell = sheet2["A1"]
CellCustomPropListener(cell.component)
cell.value = 10
cell = sheet2["B1"]
CellCustomPropListener(cell.component)
cell.value = 12
cell_b3 = sheet2["B3"]
CellCustomPropListener(cell_b3.component)
cell_b3.value = 12
CellCustomPropListener.clear()
finally:
doc.close()
Lo.close_office()
if __name__ == "__main__":
main()
Log output
31/05/2024 15:21:12 - DEBUG - CellCustomPropListener: modified: $Sheet1.$B$2
31/05/2024 15:21:12 - DEBUG - CellCustomPropListener: modified: $Sheet1.$B$2
31/05/2024 15:21:12 - DEBUG - CellCustomPropListener: modified: $Sheet1.$C$4
31/05/2024 15:21:12 - DEBUG - CellCustomPropListener: modified: $Sheet1.$B$2
31/05/2024 15:21:12 - DEBUG - CellCustomPropListener: modified: $Sheet1.$C$4
31/05/2024 15:21:12 - DEBUG - CellCustomPropListener: modified: $Sheet2.$A$1
31/05/2024 15:21:12 - DEBUG - CellCustomPropListener: modified: $Sheet2.$B$1
31/05/2024 15:22:08 - DEBUG - CellCustomPropListener: modified: $Sheet2.$B$3
31/05/2024 15:22:08 - DEBUG - CellCustomPropListener: clear: Cleared all instances
Error output.
double free or corruption (out)
Unspecified Application Error
Fatal exception: Signal 6
Stack:
/usr/lib/libreoffice/program/libuno_sal.so.3(+0x41be2)[0x78f108a18be2]
/usr/lib/libreoffice/program/libuno_sal.so.3(+0x41d9a)[0x78f108a18d9a]
...
/lib/x86_64-linux-gnu/libc.so.6(+0x94ac3)[0x78f103094ac3]
/lib/x86_64-linux-gnu/libc.so.6(+0x126850)[0x78f103126850]
Leaking python objects bridged to UNO for reason pyuno runtime is not initialized, (the pyuno.bootstrap needs to be called before using any uno classes) at ./pyuno/source/module/pyuno_runtime.cxx:358
Leaking python objects bridged to UNO for reason pyuno runtime is not initialized, (the pyuno.bootstrap needs to be called before using any uno classes) at ./pyuno/source/module/pyuno_runtime.cxx:358
Traceback (most recent call last):
File "/home/paul/.pyenv/versions/3.10.5/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/home/paul/.pyenv/versions/3.10.5/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/paul/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/__main__.py", line 39, in <module>
cli.main()
File "/home/paul/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 430, in main
run()
File "/home/paul/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 284, in run_file
runpy.run_path(target, run_name="__main__")
File "/home/paul/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 321, in run_path
return _run_module_code(code, init_globals, run_name,
File "/home/paul/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 135, in _run_module_code
_run_code(code, mod_globals, init_globals,
File "/home/paul/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 124, in _run_code
exec(code, run_globals)
File "/home/paul/Documents/Projects/Python/LibreOffice/ooouno-dev-tools/tmp/calc_prop_listen.py", line 65, in <module>
main()
File "/home/paul/Documents/Projects/Python/LibreOffice/ooouno-dev-tools/tmp/calc_prop_listen.py", line 60, in main
doc.close()
File "/home/paul/Documents/Projects/Python/LibreOffice/ooouno-dev-tools/ooodev/utils/partial/doc_io_partial.py", line 89, in close
result = self.__lo_inst.close(closable, deliver_ownership)
File "/home/paul/Documents/Projects/Python/LibreOffice/ooouno-dev-tools/ooodev/loader/inst/lo_inst.py", line 1379, in close
closeable.close(cargs.event_data)
I am getting errors when LibreOffice is terminating. I suspect all the listeners need to be released from the cells before closing.