Listener for a spreadsheet rename event

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
Ralf
Posts: 6
Joined: Mon Oct 29, 2012 1:07 am

Listener for a spreadsheet rename event

Post by Ralf »

Hello,
is there an event listener in the UNO API which is fired when the user renames a calc spreadsheet interactively? I can't find one.

Regards
Ralf
LibreOffice 3.5 on Ubuntu 12.04
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Listener for a spreadsheet rename event

Post by Charlie Young »

Ralf wrote:Hello,
is there an event listener in the UNO API which is fired when the user renames a calc spreadsheet interactively? I can't find one.

Regards
Ralf
Do you mean rename the document, or rename a sheet within it?
Apache OpenOffice 4.1.1
Windows XP
Ralf
Posts: 6
Joined: Mon Oct 29, 2012 1:07 am

Re: Listener for a spreadsheet rename event

Post by Ralf »

I ment a single sheet within the calc document.
LibreOffice 3.5 on Ubuntu 12.04
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Listener for a spreadsheet rename event

Post by Charlie Young »

Ralf wrote:I ment a single sheet within the calc document.
I tried XPropertyChangeListener and XVetoableChangeListener, which looked promising, but I didn't have any luck there. An XModifyListener attached to the document is triggered by renaming a sheet, but by lots of other things as well, so that was a bust.

But, if undo is enabled, we can attach an XUndoManagerListener to ThisComponent.UndoManager, and then check newly added undo actions for "Rename Sheet."

Here I'm just displaying the old name and the new one. As usual, all the listener methods have to be implemented, even though I'm only using one of them for now.

Code: Select all


Global oListener As Object
	
Sub SetupListener()
	Dim oDoc As Object
							
   	oDoc = ThisComponent
   	oListener = createUnoListener("Undoer_", "com.sun.star.document.XUndoManagerListener")
   	oDoc.UndoManager.addUndoManagerListener(oListener)
	
End Sub

Sub Undoer_undoActionAdded(oEvent)
	Dim oDoc As Object
	Dim oSheet As Object
	Dim UnDoMgr As Object
	Dim oldName As String
	Dim newName As String
	
	oDoc = ThisComponent
	oSheet = oDoc.CurrentController.ActiveSheet
	UnDoMgr = oDoc.getUndoManager()
	
	If UnDoMgr.getCurrentUndoActionTitle() = "Rename Sheet" Then
		UnDoMgr.removeUndoManagerListener(oListener)
		UnDoMgr.undo()
		oldName = oSheet.getName()
		UnDoMgr.redo()
		newName = oSheet.getName()
		MsgBox(oldName)
		MsgBox(newName)
		UnDoMgr.addUndoManagerListener(oListener)
	EndIf
	
End Sub

Sub Undoer_actionUndone(oEvent)
	   
End Sub

Sub Undoer_actionRedone(oEvent)
	   
End Sub

Sub Undoer_allActionsCleared(oEvent)
	   
End Sub

Sub Undoer_cancelledContext(oEvent)
		
End Sub

Sub Undoer_disposing(oEvent)
	   
End Sub

Sub Undoer_enteredContext(oEvent)
	   
End Sub

Sub Undoer_enteredHiddenContext(oEvent)
	
End Sub

Sub Undoer_leftContext(oEvent)
	
End Sub

Sub Undoer_leftHiddenContext(oEvent)
	
End Sub

Sub Undoer_redoActionsCleared(oEvent)
	
End Sub

Sub Undoer_resetAll(oEvent)
	   
End Sub

Sub ClearListener
	Dim oDoc As Object
	Dim UnDoMgr As Object
	oDoc = ThisComponent
	
	UnDoMgr = oDoc.getUndoManager()
	UnDoMgr.removeUndoManagerListener(oListener)
	
End Sub

Apache OpenOffice 4.1.1
Windows XP
Ralf
Posts: 6
Joined: Mon Oct 29, 2012 1:07 am

Re: Listener for a spreadsheet rename event

Post by Ralf »

You remove the UndoManagerListener in Sub Undoer_undoActionAdded() just because you execute UnDoMgr.undo() to get oldName for the MsgBox. For a "normal" application, UnDoMgr.removeUndoManagerListener() would not be required.
Is that assumption correct?
LibreOffice 3.5 on Ubuntu 12.04
User avatar
Charlie Young
Volunteer
Posts: 1559
Joined: Fri May 14, 2010 1:07 am

Re: Listener for a spreadsheet rename event

Post by Charlie Young »

Ralf wrote:You remove the UndoManagerListener in Sub Undoer_undoActionAdded() just because you execute UnDoMgr.undo() to get oldName for the MsgBox. For a "normal" application, UnDoMgr.removeUndoManagerListener() would not be required.
Is that assumption correct?
Nice catch. I put the remove then add back, in as a precaution, because I feared a race condition. I never bothered testing it without the remove/add, but now it seems it isn't required anyway. I don't think it hurts much, but if it isn't necessary, don't bother. Apparently the undo/redo doesn't add a new undoAction.
Apache OpenOffice 4.1.1
Windows XP
Ralf
Posts: 6
Joined: Mon Oct 29, 2012 1:07 am

Re: Listener for a spreadsheet rename event

Post by Ralf »

Code: Select all

If UnDoMgr.getCurrentUndoActionTitle() = "Rename Sheet" Then
  ...
EndIf
I like your proposal, Charlie!
There is still one issue left. You define the undo action title as "Rename Sheet". With my German installaton the title is defined as "Tabelle umbenennen". Is there a (UNO API internal) possibility to suppress the internationalization, and force English message strings?
LibreOffice 3.5 on Ubuntu 12.04
User avatar
karolus
Volunteer
Posts: 1160
Joined: Sat Jul 02, 2011 9:47 am

Re: Listener for a spreadsheet rename event

Post by karolus »

Hallo Ralf

Warum änderst du nicht "Rename Sheet" zu "Tabelle umbenennen" ?
Why don't you change "_______''______" to "__________'''______" ?
Edit:Translate..
Karolus
Last edited by karolus on Mon Nov 05, 2012 11:43 pm, edited 1 time in total.
AOO4, Libreoffice 6.1 on Rasbian OS (on ARM)
Libreoffice 7.4 on Debian 12 (Bookworm) (on RaspberryPI4)
Libreoffice 7.6 flatpak on Debian 12 (Bookworm) (on RaspberryPI4)
Ralf
Posts: 6
Joined: Mon Oct 29, 2012 1:07 am

Re: Listener for a spreadsheet rename event

Post by Ralf »

Hello Karolus,

(Weil ich dieses Projekt auch Anderen zur Verfügung stellen werde. Zur Not kann ich entsprechende Derivate kompilieren, würde allerdings eine elegantere Lösung vorziehen.)

because I have planned to provide this code to others. I could compile a derivate for every language but I prefer an elegant solution.

Ralf
Last edited by Ralf on Tue Nov 06, 2012 3:40 pm, edited 1 time in total.
LibreOffice 3.5 on Ubuntu 12.04
User avatar
Hagar Delest
Moderator
Posts: 32667
Joined: Sun Oct 07, 2007 9:07 pm
Location: France

Re: Listener for a spreadsheet rename event

Post by Hagar Delest »

Please remember that this is an English forum. Your discussion may be of interest for other users. You could at least give a translation in English.
Else, there is the German forum, you can make a thread over there and link to this one.
LibreOffice 7.6.2.1 on Xubuntu 23.10 and 7.6.4.1 portable on Windows 10
Ralf
Posts: 6
Joined: Mon Oct 29, 2012 1:07 am

Re: Listener for a spreadsheet rename event

Post by Ralf »

Here is an other solution than using 'XUndoManagerListener' with its localised 'UndoManagerEvent.UndoActionTitle'.
This solution maintains a local variable 'Base::activeSheetName'. This variable is updated with every 'XActivationEventListener' event and it is evaluated with every 'XModifyListener' event to detect a sheet-rename. I think there is no big difference in using 'XUndoManagerListener' instead of 'XModifyListener', because they seem to fire mostly at the same occasions.

Here is an example code implementation in C++, I skipped the declaration sections.

Class Base connects to Office Calc or opens an instance of Calc, it instantiates and registers the required listeners, and provides the member functions to update local variable Base::activeSheetName:

Code: Select all

Base::Base(OUString fileURL) :
    xActivationEventListener(static_cast<XActivationEventListener*>(new ActivationEventListener(this))),
    xModifyListener(static_cast<XModifyListener*>(new ModifyListener(this))),
    xUndoManagerListener(static_cast<XUndoManagerListener*>(new UndoManagerListener())),
    xComponentContext(bootstrap(), UNO_QUERY_THROW),
    xServiceManager(xComponentContext->getServiceManager(), UNO_QUERY_THROW),
    xDesktop(xServiceManager->createInstanceWithContext(OUString::createFromAscii("com.sun.star.frame.Desktop"), xComponentContext), UNO_QUERY_THROW),
    xComponentLoader(xDesktop, UNO_QUERY_THROW),
    xComponent(xComponentLoader->loadComponentFromURL(fileURL, OUString::createFromAscii("_blank"), 0, Sequence<PropertyValue>()), UNO_QUERY_THROW),
    xSpreadsheetDocument(xComponent, UNO_QUERY_THROW),
    xModel(xSpreadsheetDocument, UNO_QUERY_THROW),
    xSpreadsheetView(xModel->getCurrentController(), UNO_QUERY_THROW),
    xActivationBroadcaster(xSpreadsheetView, UNO_QUERY_THROW),
    xModifyBroadcaster(xSpreadsheetDocument, UNO_QUERY_THROW),
    xUndoManagerSupplier(xSpreadsheetDocument, UNO_QUERY_THROW)
{
    cout << "Constructor" << endl;
    xActivationBroadcaster->addActivationEventListener(xActivationEventListener);
    xModifyBroadcaster->addModifyListener(xModifyListener);
    xUndoManagerSupplier->getUndoManager()->addUndoManagerListener(xUndoManagerListener);
    activeSheet(xSpreadsheetView->getActiveSheet());
}

void Base::activeSheet(const Reference<XSpreadsheet>& sheet)
{
    xActiveSheet = sheet;
    Reference<XNamed> xNamed(sheet, UNO_QUERY_THROW);
    activeSheetName = xNamed->getName();
    cout << "Base::activeSheet: " << activeSheetName << endl;
}

void Base::renameSheet()
{
    Reference<XNamed> xNamed(xActiveSheet, UNO_QUERY_THROW);
    if (activeSheetName != xNamed->getName()) {
        cout << "Base::renameSheet: Old name: " << activeSheetName << " New name: " << xNamed->getName() << endl;
        activeSheetName = xNamed->getName();
    }
}
ActivationEventListener detects a change of the actve sheet and updates the active sheet in class Base accordingly:

Code: Select all

ActivationEventListener::ActivationEventListener(Base* b)
{
    base = b;
    cout << "ActivationEventListener::ActivationEventListener: Constructor" << endl;
}

ActivationEventListener::~ActivationEventListener()
{
    cout << "ActivationEventListener::~ActivationEventListener: Destructor" << endl;
}

void SAL_CALL ActivationEventListener::activeSpreadsheetChanged(const ActivationEvent& event) throw (RuntimeException)
{
    cout << "ActivationEventListener::activeSpreadsheetChanged: " << "ActivationEvent" << endl;
    base->activeSheet(event.ActiveSheet);
}

void SAL_CALL ActivationEventListener::disposing(const EventObject& event) throw (RuntimeException)
{
    cout << "ActivationEventListener::disposing: " << "Object listened to will be disposed." << endl;
}
ModifyListener calls Base::renameSheet() with every invocation and lets class Base decide, whether this event was a sheet-rename or not:

Code: Select all

ModifyListener::ModifyListener(Base* b)
{
    base = b;
    cout << "ModifyListener::ModifyListener: Constructor" << endl;
}

ModifyListener::~ModifyListener()
{
    cout << "ModifyListener::~ModifyListener: Destructor" << endl;
}

void SAL_CALL ModifyListener::modified(const EventObject& event) throw (RuntimeException)
{
    cout << "ModifyListener::modified: " << "EventObject" << endl;
    base->renameSheet();
}

void SAL_CALL ModifyListener::disposing(const EventObject& event) throw (RuntimeException)
{
    cout << "ModifyListener::disposing: " << "Object listened to will be disposed." << endl;
}
LibreOffice 3.5 on Ubuntu 12.04
Post Reply