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,)