Class Events

Events class is a locally scoped class.

Once an instance of Events is created it can be used to subscribe to any internal event of OooDev.

Example

In the following example local_events is created in the open_remove_save() method.

While open_remove_save() is running any row index listed in protected_rows will not be deleted even if they are passed into open_remove_save()

As soon as the open_remove_save() method is executed local_events goes out of scope. When local_events is out of scope the events it was subscribe to get released. Also setting local_events = None would release any events it was subscribed to.

from typing import Any
from ooodev.loader.lo import Lo
from ooodev.office.calc import Calc
from ooodev.events.lo_events import Events
from ooodev.events.args.calc.sheet_cancel_args import SheetCancelArgs
from ooodev.events.calc_named_event import CalcNamedEvent


protected_rows = (1, 3, 10, 15, 18)

def protect_row(source:Any, args:SheetCancelArgs) -> None:
    nonlocal protected_rows
    if args.index in protected_rows:
        args.cancel = True

def open_remove_save(fnm:str, *indexes:int) -> None:
    if len(indexes) == 0:
        return

    local_events = Events()
    events.on(CalcNamedEvent.SHEET_ROW_DELETING, protect_row)
    idxs = list(indexes)
    idxs.sort()
    idxs.reverse() # must remove from hightest to lowest.

    with Lo.Loader(Lo.ConnectSocket()) as loader:
        doc = Calc.open_doc(fnm=fnm, loader=loader)
        sheet = Calc.get_sheet(doc=doc, index=0)
        for idx in idxs:
            Calc.delete_row(sheet=sheet, idx=idx)

        Lo.save(doc)

Events uses weak reference internally. For this reason assigning events in a class instance may not work as expected.

For instance assigning a class method as an event handler will not work unless the class method is a static method.

Sometimes it may be useful to pass a class instance to the event so a class property can be set. The way Events enables class instance to be sent to a method is by way of EventArgs.event_source property.

Example

In the following example class constructor creates Events instance and assigns to class instance. It is important that the Events instance be assigned to class or it will go out of scope when constructor is done and that will result in no events being triggered for class.

When Events is constructed it passes in the current class instance
self.events = Events(source=self)
This allows the instance to be accessed when event is triggered.

Note that on_disposed() is a static method. Events is not able to attach to instance methods.

The object passed into Events constructor (class instance in this case) are assigned to the EventArg.event_source property. Now class instance properties can be set when the event is triggered event.event_source.bridge_disposed = True.

For a complete example see Office Window Monitor

#!/usr/bin/env python
from __future__ import annotations
import time
import sys
from typing import Any

from ooodev.adapter.lang.event_events import EventEvents
from ooodev.events.args.event_args import EventArgs
from ooodev.events.lo_events import Events
from ooodev.events.lo_named_event import LoNamedEvent
from ooodev.office.calc import Calc
from ooodev.gui import GUI
from ooodev.loader.lo import Lo


class DocMonitor:
    def __init__(self) -> None:
        self.closed = False
        self.bridge_disposed = False
        loader = Lo.load_office(Lo.ConnectPipe(), opt=Lo.Options(verbose=True))

        self.doc = Calc.create_doc(loader=loader)

        self._fn_on_disposed = self.on_disposed

        self.events = Events(source=self)
        self.events.on(LoNamedEvent.BRIDGE_DISPOSED, self._fn_on_disposed)

        self._bridge_events = EventEvents()
        self._bridge_events.add_event_disposing(self._fn_on_disposing)
        Lo.bridge.addEventListener(self._bridge_events.events_listener_event)

        GUI.set_visible(True, self.doc)

    def on_disposed(self, source: Any, event_args: EventArgs) -> None:
        # just another way of knowing when bridge is gone.
        print("LO: Office bridge has gone!!")
        self.bridge_disposed = True


def main_loop() -> None:
    dw = DocMonitor()

    # check an see if user passed in a auto terminate option
    if len(sys.argv) > 1:
        if str(sys.argv[1]).casefold() in ("t", "true", "y", "yes"):
            Lo.delay(5000)
            Lo.close_office()

    # while Writer is open, keep running the script unless specifically ended by user
    while 1:
        if dw.bridge_disposed is True:
            print("\nExiting due to office bridge is gone\n")
            raise SystemExit(1)
        time.sleep(0.1)


if __name__ == "__main__":
    print("Press 'ctl+c' to exit script early.")
    try:
        main_loop()
    except SystemExit as e:
        SystemExit(e.code)
    except KeyboardInterrupt:
        # ctrl+c exist the script early
        print("\nExiting by user request.\n", file=sys.stderr)
        SystemExit(0)

Note

Events are limited to OooDev.

For instance OooDev can capture when are row is being removed from a spreadsheet internally; However, OooDev is not aware when other methods are used such as user input.

For more indepth Events look into LibreOffice Listeners and Chapter 4. Listening, and Other Techniques.

class ooodev.events.lo_events.Events(source=None, trigger_args=None)[source]

Class for sharing events among classes and functions.

Note

If an events source is None then it is set to source or Events instance if source is None.

Parameters:
  • source (Any | None) –

  • trigger_args (GenericArgs | None) –

__init__(source=None, trigger_args=None)[source]

Construct for Events

Parameters:
  • source (Any | None, optional) – Source can be class or any object. The value of source is the value assigned to the EventArgs.event_source property. Defaults to current instance of this class.

  • trigger_args (GenericArgs, optional) – Args that are passed to events when they are triggered.

Return type:

None

add_observer(*args)

Adds observers that gets their trigger method called when this class trigger method is called.

Parameters:

args (EventObserver) – One or more observers to add.

Return type:

None

Note

Observers are removed automatically when they are out of scope.

clear()[source]

Clears all events.

New in version 0.13.7.

Return type:

None

has_event(event_name, callback)

Gets if event exists.

Parameters:
  • event_name (str) – Event name

  • callback (EventCallback) – Callback function

Returns:

True if event exists; Otherwise, False

Return type:

bool

has_event_name(event_name)

Gets if event exists.

Parameters:

event_name (str) – Event name

Returns:

True if event exists; Otherwise, False

Return type:

bool

on(event_name, callback)

Registers an event

Parameters:
  • event_name (str) – Unique event name

  • callback (Callable[[object, EventArgs], None]) – Callback function

remove(event_name, callback)

Removes an event callback

Parameters:
  • event_name (str) – Unique event name

  • callback (Callable[[object, EventArgs], None]) – Callback function

Returns:

True if callback has been removed; Otherwise, False.

False means the callback was not found.

Return type:

bool

remove_observer(observer)

Removes an observer.

Parameters:

observer (EventObserver) – Observers to remove.

Returns:

True if observer has been removed; Otherwise, False.

Return type:

bool

trigger(event_name, event_args)[source]

Trigger event(s) for a given name.

Parameters:
  • event_name (str) – Name of event to trigger

  • event_args (EventArgsT) – Event args passed to the callback for trigger.

  • args (Any, optional) – Optional positional args to pass to callback

  • kwargs (Any, optional) – Optional keyword args to pass to callback

Note

Events are removed automatically when they are out of scope.