Small code contribution PyUno

Hi all-

I am working on code for a guided choice in a listbox that goes from left to right narrowing down choices. Here is a start on it. You can modify and adapt it, so that when you click the dialog listbox that it redoes the list entries i leave that up to the receiver. Gemini helped me with it big time. Here is the code. Hope you like the code i am just a newbie at pyuno. You guys and Andreas to help me with the problem and bug report i had. I want to get better at automating libreoffice base. thanks

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import uno, unohelper
from com.sun.star.awt import XDialogEventHandler
# Correctly import the specific exception
from com.sun.star.lang import IllegalArgumentException, WrappedTargetException
from com.sun.star.uno import Exception as UnoException

_DLG_PROVIDER = "com.sun.star.awt.DialogProvider2"
DIALOG_URL = "vnd.sun.star.script:Standard.Dialog1?location=application"

# Define the helper function outside the class
def _nested_dict_to_list(d, indent=0):
    """Recursively flatten a dictionary into a list of strings with indentation."""
    items = []
    for key, value in d.items():
        items.append("  " * indent + str(key))
        if isinstance(value, dict):
            items.extend(_nested_dict_to_list(value, indent + 1))
        elif isinstance(value, list):
            for item in value:
                items.append("  " * (indent + 1) + "- " + str(item))
    return items

class Console(unohelper.Base, XDialogEventHandler):
    """ Access2Base Console Handler """
    
    def show(self, ctx, smgr, data=None):
        if data is None:
            data = {
                "PURCHASED": {
                    "PENDING_ORDER": ["APPROVED"],
                    "AWAITING_APPROVAL": ["PENDING_APPROVAL"],
                    "QUALITY_CHECK": ["EXPIRED"],
                },
                "RETURNED_TO_SUPPLIER": {
                    "RETURNED_PENDING": ["PENDING_APPROVAL", "APPROVED", "CANCELLED", "ISSUED"],
                },
            }
    
        try:
            dp = smgr.createInstanceWithContext(_DLG_PROVIDER, ctx)
            dialog = dp.createDialogWithHandler(DIALOG_URL, self)
            dialog.setTitle("Konsole")
            
            # --- Robust retrieval and interaction with the listbox ---
            listbox_control = dialog.getControl("ListBox1")
            
            if listbox_control:
                # Get the model of the listbox and set the StringItemList property
                listbox_model = listbox_control.getModel()
                
                # Generate the list of strings
                list_items = _nested_dict_to_list(data)
                
                # The model expects a tuple
                listbox_model.StringItemList = tuple(list_items)
            else:
                self._msgbox("Listbox control 'Listbox1' not found.", "Dialog Error")
                # Do not execute the dialog if the required control is missing
                return

            # Execute the dialog
            dialog.execute()
            
        except IllegalArgumentException as e:
            self._msgbox(f"Dialog not found: {DIALOG_URL}\nError: {e.Message}", "Dialog Error")
        except WrappedTargetException as e:
            # Handle potential UNO exceptions that are wrapped inside other exceptions
            self._msgbox(f"Wrapped UNO Exception: {e.Message}", "UNO Error")
        except Exception as e:
            # Fallback for any other unexpected errors
            self._msgbox(f"An unexpected error occurred: {e}", "Error")

    def handleEvent(self, event):
        return False
        
    def getSupportedMethodNames(self):
        return ()

    def _msgbox(self, prompt, title):
        """Helper function for displaying message boxes."""
        try:
            ctx = uno.getComponentContext()
            toolkit = ctx.getServiceManager().createInstance("com.sun.star.awt.Toolkit")
            parent = toolkit.getDesktopWindow()
            mb = toolkit.createMessageBox(parent, "infobox", 1, title, prompt)
            mb.execute()
        except Exception:
            print(f"[{title}] {prompt}")

def ConsoleHandler():
    """Main entry point for the LibreOffice macro."""
    try:
        ctx = XSCRIPTCONTEXT.getComponentContext()
        smgr = ctx.getServiceManager()
        Console().show(ctx, smgr)
    except NameError:
        print("This function cannot be run outside of LibreOffice.")

g_exportedScripts = (ConsoleHandler,)

if __name__ == "__main__":
    from IDE_utils import Runner
    with Runner():
        print("Simulating ConsoleHandler, but skipping GUI interactions.")
type or paste code here
import os
import datetime
import uno

def log_message(message):
    """Appends a timestamped message to a log file in the home directory."""
    try:
        log_file_path = os.path.join(os.path.expanduser('~'), 'macro_log.txt')
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        with open(log_file_path, 'a') as log_file:
            log_file.write(f"[{timestamp}] {message}\n")
    except Exception:
        pass

def find_form_from_control_model(control_model):
    """Traverses up the object hierarchy to find the parent form model."""
    parent = control_model.Parent
    while parent is not None:
        if hasattr(parent, 'getImplementationName') and "Form" in parent.getImplementationName():
            return parent
        if hasattr(parent, 'Parent'):
            parent = parent.Parent
        else:
            return None
    return None

def show_subkey_dialog_and_update_form(oForm, form_controller):
    """
    Shows a subkey dialog based on a selected reason and updates the main form.
    """
    log_message("Executing show_subkey_dialog_and_update_form function...")

    data = {
        "PURCHASED": {
            "PENDING_ORDER": ["APPROVED"],
            "AWAITING_APPROVAL": ["PENDING_APPROVAL"],
            "QUALITY_CHECK": ["EXPIRED"],
        },
        "RETURNED_TO_SUPPLIER": {
            "RETURNED_PENDING": ["PENDING_APPROVAL", "APPROVED", "CANCELLED", "ISSUED"],
        },
    }

    try:
        selected_reason_model = oForm.getByName("lstReason")
        selected_reason = selected_reason_model.SelectedItem
        log_message(f"Selected reason: {selected_reason}")

        if not selected_reason:
            log_message("No reason selected. Exiting macro.")
            return

        sub_keys = list(data.get(selected_reason, {}).keys())
        log_message(f"Found sub-keys: {sub_keys}")

        if not sub_keys:
            log_message(f"No sub-keys found for reason: {selected_reason}. Exiting.")
            return

        # Update the form controls based on the selected reason
        lstSubReason_model = oForm.getByName("lstSubReason")
        lstFinalStatus_model = oForm.getByName("lstFinalStatus")

        # Use the first subkey for demonstration
        simulated_subkey = sub_keys[0]
        final_status_options = data[selected_reason][simulated_subkey]

        lstSubReason_model.StringItemList = (simulated_subkey,)
        lstFinalStatus_model.StringItemList = tuple(final_status_options)

        lstSubReason_control = form_controller.getControl(lstSubReason_model)
        lstSubReason_control.selectItemPos(0, True)

        lstFinalStatus_control = form_controller.getControl(lstFinalStatus_model)
        lstFinalStatus_control.selectItemPos(0, True)

        log_message("Form controls updated successfully.")

    except Exception as e:
        log_message(f"Error in show_subkey_dialog_and_update_form: {e}")
        return


def show_subkey_dialog_wrapper(*args):
    """
    A wrapper function to handle the macro execution, with logging.
    """
    oForm = None
    form_controller = None
    log_message("show_subkey_dialog_wrapper started.")

    try:
        if args and len(args) > 0 and hasattr(args[0], 'Source'):
            log_message("Event object detected. Processing event source.")
            oEvent = args[0]
            oButtonModel = oEvent.Source.Model
            oFormModel = find_form_from_control_model(oButtonModel)

            if oFormModel:
                oForm = oFormModel.getImplementation()
                form_document = oFormModel.getParent()
                if form_document and hasattr(form_document, 'getCurrentController'):
                    form_controller = form_document.getCurrentController()
                    log_message("Successfully retrieved form and controller from event.")
                else:
                    log_message("Error: Could not get form document or controller from event source.")
            else:
                log_message("Error: Could not find parent form model from event source.")
        else:
            log_message("No event object detected. Assuming manual execution.")
            desktop = XSCRIPTCONTEXT.getDesktop()
            form_document = desktop.getCurrentComponent()
            if form_document and hasattr(form_document, 'Drawpage'):
                try:
                    oForm = form_document.Drawpage.Forms.getByName("MainForm")
                    form_controller = form_document.getCurrentController()
                    log_message("Successfully retrieved form and controller for manual run.")
                except Exception as e:
                    log_message(f"Error retrieving form or controller for manual run: {e}")
            else:
                log_message("Error: Could not find an open Base form document for manual run.")
                return

    except Exception as e:
        log_message(f"An exception occurred in show_subkey_dialog_wrapper: {e}")
        return

    if oForm and form_controller:
        log_message("Calling subkey dialog and form update function.")
        show_subkey_dialog_and_update_form(oForm, form_controller)
    else:
        log_message("Error: Exiting because form or controller is not available.")

    g_exportedScripts = (show_subkey_dialog_wrapper,)

def _nested_dict_to_list(d, indent=0):
    """Recursively flatten a dictionary into a list of strings with indentation."""
    items = []
    for key, value in d.items():
        items.append(f'{key:>{2*indent+len(key)}}')
        if isinstance(value, dict):
            items.extend(_nested_dict_to_list(value, indent + 1))
        elif isinstance(value, list):
            for item in value:
                items.append(f'{"  " * (indent + 1)}-{item}')
    return items

the comment is misleading, the unohelper.Base-Class is complete unrelated to Access2Base