Using getSelection() within XModifyListener not working

Java, C++, C#, Delphi... - Using the UNO bridges
Post Reply
kwalcock
Posts: 24
Joined: Thu Oct 09, 2014 11:54 am

Using getSelection() within XModifyListener not working

Post by kwalcock »

When my document is modified, I want to find out what is selected so that I can better figure out exactly what had been modified. I have a C++ program with a SAL_IMPLEMENT_MAIN_WITH_ARGS that tries to do this. It is extracted and simplified from the extension that is being built. I note the environment because I can't seem to achieve the same effect using a macro within OpenOffice.

I can call getSelection() directly from my code, but if I make a modify listener and call getSelection() after the event is broadcast, Write hangs. It never returns to my code from the listener. I think this is a bug in OpenOffice, but if anyone can refute that, I'd be glad to hear it. Here's the code:

Code: Select all

/******************************************************************************
Header
******************************************************************************/
// $Header$
/******************************************************************************
Include others
******************************************************************************/
#include "sdkBeg.hpp"
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/frame/XComponentLoader.hpp>
#include <com/sun/star/frame/XController.hpp>
#include <com/sun/star/frame/XDesktop.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/lang/EventObject.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#include <com/sun/star/text/XTextDocument.hpp>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/util/XModifiable.hpp>
#include <com/sun/star/util/XModifyListener.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>

#include <cppuhelper/bootstrap.hxx>
#include <cppuhelper/implbase1.hxx>

#include <sal/main.h> // Required for this to be a free-standing executable.
#include "sdkEnd.hpp"

#include <iostream>
/******************************************************************************
Using
******************************************************************************/
using namespace com::sun::star::beans;
using namespace com::sun::star::container;
using namespace com::sun::star::frame;
using namespace com::sun::star::lang;
using namespace com::sun::star::text;
using namespace com::sun::star::uno;
using namespace com::sun::star::util;
using namespace com::sun::star::view;
/******************************************************************************
ModifyBug
******************************************************************************/
class ModifyBug: public cppu::WeakImplHelper1<com::sun::star::util::XModifyListener> {
	protected:
		Reference<XComponent> savedXComponent; // needed for testing listener

		virtual void SAL_CALL modified(const com::sun::star::lang::EventObject& event)
				throw (com::sun::star::uno::RuntimeException);
		virtual void SAL_CALL disposing(const com::sun::star::lang::EventObject& event)
				throw (com::sun::star::uno::RuntimeException);

		Reference<XComponentContext> newXComponentContext();
		Reference<XInterface> newDesktop(Reference<XComponentContext> xComponentContext);
		Reference<XTextDocument> newXTextDocument(Reference<XInterface> desktop);

	public:
		ModifyBug() {
		}

		void run();
};

void SAL_CALL ModifyBug::disposing(const com::sun::star::lang::EventObject& event)
		throw (com::sun::star::uno::RuntimeException) {
	// TODO: remove listener
}

void getSelections(Reference<XComponent> xComponent) {
	Reference<XModel> xModel(xComponent, UNO_QUERY);
	Reference<XController> xController = xModel->getCurrentController();
	Reference<XSelectionSupplier> xSelectionSupplier(xController, UNO_QUERY);

	xSelectionSupplier->getSelection(); // Including this like makes it hang!
}

void SAL_CALL ModifyBug::modified(const com::sun::star::lang::EventObject& event)
		throw (com::sun::star::uno::RuntimeException) {
	getSelections(savedXComponent);
}

Reference<XComponentContext> ModifyBug::newXComponentContext() {
	Reference<XComponentContext> xComponentContext(cppu::bootstrap());

	return xComponentContext;
}

Reference<XInterface> ModifyBug::newDesktop(Reference<XComponentContext> xComponentContext) {
	Reference<XMultiComponentFactory> xMultiComponentFactory(xComponentContext->getServiceManager(), UNO_QUERY);
	Reference<XInterface> desktop = xMultiComponentFactory->createInstanceWithContext(
			rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop")), xComponentContext);

	return desktop;
}

Reference<XTextDocument> ModifyBug::newXTextDocument(Reference<XInterface> desktop) {
	Reference<XComponentLoader> xComponentLoader(desktop, UNO_QUERY);
	Reference<XComponent> document = xComponentLoader->loadComponentFromURL(
			rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("private:factory/swriter")),
			rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("_blank")), 0, Sequence<PropertyValue>());
	Reference<XTextDocument> xTextDocument(document, UNO_QUERY);

	return xTextDocument;
}

void ModifyBug::run() {
	try {
		Reference<XComponentContext> xComponentContext = newXComponentContext();
		Reference<XInterface> desktop = newDesktop(xComponentContext);
		Reference<XDesktop> xDesktop(desktop, UNO_QUERY);

		{
			Reference<XTextDocument> xTextDocument = newXTextDocument(desktop);
			Reference<XText> xText = xTextDocument->getText();
			Reference<XComponent> xComponent(xTextDocument, UNO_QUERY);
			Reference<XModifiable> xModifiable(xComponent, UNO_QUERY);
			Reference<XModifyBroadcaster> xModifyBroadcaster(xComponent, UNO_QUERY);

			savedXComponent = xComponent;
			xModifyBroadcaster->addModifyListener(this);

			getSelections(savedXComponent); // It (getSelection) can be called directly
			getSelections(savedXComponent); // and repeatedly

			xText->setString(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("hello"))); // It can _not_ be called indirectly
			xModifiable->setModified(sal_True); // It can't be called indirectly like this, either.

			xModifyBroadcaster->removeModifyListener(this);
			savedXComponent = Reference<XComponent>();
			xTextDocument->dispose();
		}
		xDesktop->terminate();
	}
	catch (...) {
		std::cerr << "Exception..." << std::endl;
	}
}

SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) {
	ModifyBug modifyBug;
	
	modifyBug.run();
	return 0;
}
/*****************************************************************************/
Last edited by RoryOF on Fri Nov 20, 2015 8:55 pm, edited 1 time in total.
Reason: Added [code] tags. [RoryOF, Moderator]
Apache OpenOffice 4.0.1
Windows, Linux, MacOS
Post Reply