summaryrefslogtreecommitdiff
path: root/sfx2/qa
diff options
context:
space:
mode:
authorFrank Schoenheit [fs] <frank.schoenheit@sun.com>2010-11-04 10:51:04 +0100
committerFrank Schoenheit [fs] <frank.schoenheit@sun.com>2010-11-04 10:51:04 +0100
commit29de4ac687a252f9926fb94456996c87c71b3ca2 (patch)
tree234cddc20439bc16a2ead1063277718ab3907f36 /sfx2/qa
parent760e5fa42cf9bb33bdf3e415c0e0bdb93f7681b0 (diff)
undoapi: added tests for OOo's auto-closing of Undo contexts after executing scripts which do not properly do this themselves
Diffstat (limited to 'sfx2/qa')
-rwxr-xr-xsfx2/qa/complex/sfx2/UndoManager.java649
1 files changed, 530 insertions, 119 deletions
diff --git a/sfx2/qa/complex/sfx2/UndoManager.java b/sfx2/qa/complex/sfx2/UndoManager.java
index eecceb5753f8..548d2cb31591 100755
--- a/sfx2/qa/complex/sfx2/UndoManager.java
+++ b/sfx2/qa/complex/sfx2/UndoManager.java
@@ -27,12 +27,29 @@
package complex.sfx2;
+import com.sun.star.accessibility.XAccessible;
+import com.sun.star.accessibility.XAccessibleAction;
+import com.sun.star.awt.Point;
+import com.sun.star.awt.Size;
+import com.sun.star.awt.XControl;
+import com.sun.star.awt.XControlModel;
+import com.sun.star.beans.NamedValue;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.NoSuchElementException;
+import com.sun.star.container.XChild;
+import com.sun.star.container.XIndexContainer;
+import com.sun.star.container.XNameContainer;
+import com.sun.star.container.XNameReplace;
+import com.sun.star.container.XSet;
import com.sun.star.document.EmptyUndoStackException;
import com.sun.star.document.UndoContextNotClosedException;
import com.sun.star.document.UndoFailedException;
import com.sun.star.document.UndoManagerEvent;
+import com.sun.star.document.XEmbeddedScripts;
+import com.sun.star.document.XEventsSupplier;
import com.sun.star.document.XUndoAction;
import com.sun.star.lang.EventObject;
+import com.sun.star.lang.IndexOutOfBoundsException;
import com.sun.star.lang.XEventListener;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -41,18 +58,35 @@ import com.sun.star.document.XUndoManagerSupplier;
import complex.sfx2.undo.CalcDocumentTest;
import com.sun.star.document.XUndoManager;
import com.sun.star.document.XUndoManagerListener;
+import com.sun.star.drawing.XControlShape;
+import com.sun.star.drawing.XDrawPage;
+import com.sun.star.drawing.XDrawPageSupplier;
+import com.sun.star.drawing.XShapes;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XSingleComponentFactory;
+import com.sun.star.lang.XTypeProvider;
+import com.sun.star.script.ScriptEventDescriptor;
+import com.sun.star.script.XEventAttacherManager;
+import com.sun.star.script.XLibraryContainer;
+import com.sun.star.task.XJob;
+import com.sun.star.uno.Type;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.util.InvalidStateException;
import com.sun.star.util.NotLockedException;
+import com.sun.star.view.XControlAccess;
import complex.sfx2.undo.DocumentTest;
import complex.sfx2.undo.DrawDocumentTest;
import complex.sfx2.undo.ImpressDocumentTest;
import complex.sfx2.undo.WriterDocumentTest;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
import java.util.Stack;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -60,6 +94,8 @@ import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import org.openoffice.test.OfficeConnection;
+import org.openoffice.test.tools.DocumentType;
+import org.openoffice.test.tools.SpreadsheetDocument;
/**
* Unit test for the UndoManager API
@@ -70,9 +106,17 @@ public class UndoManager
{
// -----------------------------------------------------------------------------------------------------------------
@Before
- public void beforeTest()
+ public void beforeTest() throws com.sun.star.uno.Exception
{
m_currentDocument = null;
+ m_undoListener = null;
+
+ // at our service factory, insert a new factory for our CallbackComponent
+ // this will allow the Basic code in our test documents to call back into this test case
+ // here, by just instantiating this service
+ final XSet globalFactory = UnoRuntime.queryInterface( XSet.class, getORB() );
+ m_callbackFactory = new CallbackComponentFactory();
+ globalFactory.insert( m_callbackFactory );
}
// -----------------------------------------------------------------------------------------------------------------
@@ -104,11 +148,92 @@ public class UndoManager
}
// -----------------------------------------------------------------------------------------------------------------
+ @Test
+ public void checkBrokenScripts() throws com.sun.star.uno.Exception, InterruptedException
+ {
+ System.out.println( "testing: broken scripts" );
+
+ m_currentDocument = OfficeDocument.blankDocument( getORB(), DocumentType.CALC );
+ m_undoListener = new UndoListener();
+ getUndoManager().addUndoManagerListener( m_undoListener );
+
+ impl_setupBrokenBasicScript();
+ final String scriptURI = "vnd.sun.star.script:default.callbacks.brokenScript?language=Basic&location=document";
+
+ // .............................................................................................................
+ // scenario 1: Pressing a button which is bound to execute the script
+ // (This is one of the many cases where SfxObjectShell::CallXScript is invoked)
+
+ // set up the button
+ final XPropertySet buttonModel = impl_setupButton();
+ buttonModel.setPropertyValue( "Label", "exec broken script" );
+ impl_assignStarBasicScript( buttonModel, "XActionListener", "actionPerformed",
+ "document:default.callbacks.brokenScript" );
+
+ // switch the doc's view to form alive mode (so the button will actually work)
+ m_currentDocument.getCurrentView().dispatch( ".uno:SwitchControlDesignMode" );
+
+ // click the button
+ m_callbackCalled = false;
+ impl_clickButton( buttonModel );
+ // the macro is executed asynchronously by the button, so wait at most 2 seconds for the callback to be
+ // triggered
+ impl_waitFor( m_callbackCondition, 2000 );
+ // check the callback has actually been called
+ assertTrue( "clicking the test button did not work as expected - basic script not called", m_callbackCalled );
+
+ // again, since the script is executed asynchronously, we might arrive here while its execution
+ // is not completely finished. Give OOo another (at most) 2 seconds to finish it.
+ m_undoListener.waitForAllContextsClosed( 20000 );
+ // assure that the Undo Context Depth of the doc is still "0": The Basic script entered such a
+ // context, and didn't close it (thus it is broken), but the application framework should have
+ // auto-closed the context after the macro finished.
+ assertEquals( "undo context was not auto-closed as expected", 0, m_undoListener.getCurrentUndoContextDepth() );
+
+ // .............................................................................................................
+ // scenario 2: dispatching the script URL. Technically, this is equivalent to configuring the
+ // script into a menu or toolbar, and selecting the respective menu/toolbar item
+ m_callbackCalled = false;
+ m_currentDocument.getCurrentView().dispatch( scriptURI );
+ assertTrue( "dispatching the Script URL did not work as expected - basic script not called", m_callbackCalled );
+ // same as above: The script didn't close the context, but the OOo framework should have
+ assertEquals( "undo context was not auto-closed as expected", 0, m_undoListener.getCurrentUndoContextDepth() );
+
+ // .............................................................................................................
+ // scenario 3: assigning the script to some document event, and triggering this event
+ final XEventsSupplier eventSupplier = UnoRuntime.queryInterface( XEventsSupplier.class, m_currentDocument.getDocument() );
+ final XNameReplace events = UnoRuntime.queryInterface( XNameReplace.class, eventSupplier.getEvents() );
+ final NamedValue[] scriptDescriptor = new NamedValue[] {
+ new NamedValue( "EventType", "Script" ),
+ new NamedValue( "Script", scriptURI )
+ };
+ events.replaceByName( "OnViewCreated", scriptDescriptor );
+
+ m_callbackCalled = false;
+ m_currentDocument.getCurrentView().dispatch( ".uno:NewWindow" );
+ assertTrue( "triggering an event did not work as expected - basic script not called", m_callbackCalled );
+ // same as above: The script didn't close the context, but the OOo framework should have
+ assertEquals( "undo context was not auto-closed as expected", 0, m_undoListener.getCurrentUndoContextDepth() );
+
+ // .............................................................................................................
+ // scenario 4: let the script enter an Undo context, but not close it, as usual.
+ // Additionally, let the script close the document - the OOo framework code which cares for
+ // auto-closing of Undo contexts should survive this, ideally ...
+ m_closeAfterCallback = true;
+ m_callbackCalled = false;
+ m_currentDocument.getCurrentView().dispatch( scriptURI );
+ assertTrue( m_callbackCalled );
+ assertTrue( "The Basic script should have closed the document.", m_undoListener.isDisposed() );
+ m_currentDocument = null;
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
@After
public void afterTest()
{
if ( m_currentDocument != null )
m_currentDocument.close();
+ m_callbackFactory.dispose();
}
// -----------------------------------------------------------------------------------------------------------------
@@ -116,51 +241,195 @@ public class UndoManager
* returns the undo manager belonging to a given document
* @return
*/
- private XUndoManager getUndoManager( final OfficeDocument i_document )
+ private XUndoManager getUndoManager()
{
- XUndoManagerSupplier suppUndo = UnoRuntime.queryInterface( XUndoManagerSupplier.class, i_document.getDocument() );
+ XUndoManagerSupplier suppUndo = UnoRuntime.queryInterface( XUndoManagerSupplier.class, m_currentDocument.getDocument() );
return suppUndo.getUndoManager();
}
// -----------------------------------------------------------------------------------------------------------------
+ private void impl_waitFor( final Object i_condition, final int i_milliSeconds ) throws InterruptedException
+ {
+ synchronized( i_condition )
+ {
+ i_condition.wait( i_milliSeconds );
+ }
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ private void impl_setupBrokenBasicScript()
+ {
+ try
+ {
+ final XEmbeddedScripts embeddedScripts = UnoRuntime.queryInterface( XEmbeddedScripts.class, m_currentDocument.getDocument() );
+ final XLibraryContainer basicLibs = embeddedScripts.getBasicLibraries();
+ final XNameContainer basicLib = basicLibs.createLibrary( "default" );
+
+ final String brokenScriptCode =
+ "Option Explicit\n" +
+ "\n" +
+ "Sub brokenScript\n" +
+ " Dim callback as Object\n" +
+ " ThisComponent.UndoManager.enterUndoContext( \"" + getCallbackUndoContextTitle() + "\"\n" +
+ "\n" +
+ " callback = createUnoService( \"" + getCallbackComponentServiceName() + "\" )\n" +
+ " Dim emptyArgs() as new com.sun.star.beans.NamedValue\n" +
+ " Dim result as String\n" +
+ " result = callback.execute( emptyArgs() )\n" +
+ " If result = \"close\" Then\n" +
+ " ThisComponent.close( TRUE )\n" +
+ " End If\n" +
+ "End Sub\n" +
+ "\n";
+
+ basicLib.insertByName( "callbacks", brokenScriptCode );
+ }
+ catch( com.sun.star.uno.Exception e )
+ {
+ fail( "caught an exception while setting up the script: " + e.toString() );
+ }
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ private XPropertySet impl_setupButton() throws com.sun.star.uno.Exception
+ {
+ // let the document create a shape
+ final XMultiServiceFactory docAsFactory = UnoRuntime.queryInterface( XMultiServiceFactory.class,
+ m_currentDocument.getDocument() );
+ final XControlShape xShape = UnoRuntime.queryInterface( XControlShape.class,
+ docAsFactory.createInstance( "com.sun.star.drawing.ControlShape" ) );
+
+ // position and size of the shape
+ xShape.setSize( new Size( 28 * 100, 10 * 100 ) );
+ xShape.setPosition( new Point( 10 * 100, 10 * 100 ) );
+
+ // create the form component (the model of a form control)
+ final String sQualifiedComponentName = "com.sun.star.form.component.CommandButton";
+ final XControlModel controlModel = UnoRuntime.queryInterface( XControlModel.class,
+ getORB().createInstance( sQualifiedComponentName ) );
+
+ // knitt both
+ xShape.setControl( controlModel );
+
+ // add the shape to the shapes collection of the document
+ SpreadsheetDocument spreadsheetDoc = (SpreadsheetDocument)m_currentDocument;
+ final XDrawPageSupplier suppDrawPage = UnoRuntime.queryInterface( XDrawPageSupplier.class,
+ spreadsheetDoc.getSheet( 0 ) );
+ final XDrawPage insertIntoPage = suppDrawPage.getDrawPage();
+
+ final XShapes sheetShapes = UnoRuntime.queryInterface( XShapes.class, insertIntoPage );
+ sheetShapes.add( xShape );
+
+ return UnoRuntime.queryInterface( XPropertySet.class, controlModel );
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ private void impl_assignStarBasicScript( final XPropertySet i_controlModel, final String i_interfaceName,
+ final String i_interfaceMethod, final String i_scriptCode )
+ {
+ try
+ {
+ final XChild modelAsChild = UnoRuntime.queryInterface( XChild.class, i_controlModel );
+ final XIndexContainer parentForm = UnoRuntime.queryInterface( XIndexContainer.class, modelAsChild.getParent() );
+
+ final XEventAttacherManager manager = UnoRuntime.queryInterface( XEventAttacherManager.class, parentForm );
+
+ int containerPosition = -1;
+ for ( int i = 0; i < parentForm.getCount(); ++i )
+ {
+ final XPropertySet child = UnoRuntime.queryInterface( XPropertySet.class, parentForm.getByIndex( i ) );
+ if ( UnoRuntime.areSame( child, i_controlModel ) )
+ {
+ containerPosition = i;
+ break;
+ }
+ }
+ assertFalse( "could not find the given control model within its parent", containerPosition == -1 );
+ manager.registerScriptEvent( containerPosition, new ScriptEventDescriptor(
+ i_interfaceName,
+ i_interfaceMethod,
+ "",
+ "StarBasic",
+ i_scriptCode
+ ) );
+ }
+ catch( com.sun.star.uno.Exception e )
+ {
+ fail( "caught an exception while assigning the script event to the button: " + e.toString() );
+ }
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ private void impl_clickButton( final XPropertySet i_buttonModel ) throws NoSuchElementException, IndexOutOfBoundsException
+ {
+ final XControlAccess controlAccess = UnoRuntime.queryInterface( XControlAccess.class,
+ m_currentDocument.getCurrentView().getController() );
+ final XControl control = controlAccess.getControl( UnoRuntime.queryInterface( XControlModel.class, i_buttonModel ) );
+ final XAccessible accessible = UnoRuntime.queryInterface( XAccessible.class, control );
+ final XAccessibleAction controlActions = UnoRuntime.queryInterface( XAccessibleAction.class, accessible.getAccessibleContext() );
+ for ( int i=0; i<controlActions.getAccessibleActionCount(); ++i )
+ {
+ if ( controlActions.getAccessibleActionDescription(i).equals( "click" ) )
+ {
+ controlActions.doAccessibleAction(i);
+ return;
+ }
+ }
+ fail( "did not find the accessible action named 'click'" );
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
private static class UndoListener implements XUndoManagerListener
{
public void undoActionAdded( UndoManagerEvent i_event )
{
+ assertFalse( "|undoActionAdded| called after document was disposed", m_isDisposed );
+
++m_undoActionsAdded;
m_mostRecentlyAddedAction = i_event.UndoActionTitle;
}
public void actionUndone( UndoManagerEvent i_event )
{
+ assertFalse( "|actionUndone| called after document was disposed", m_isDisposed );
+
++m_undoCount;
m_mostRecentlyUndone = i_event.UndoActionTitle;
}
public void actionRedone( UndoManagerEvent i_event )
{
+ assertFalse( "|actionRedone| called after document was disposed", m_isDisposed );
+
++m_redoCount;
- m_mostRecentlyRedone = i_event.UndoActionTitle;
}
public void allActionsCleared( EventObject eo )
{
+ assertFalse( "|allActionsCleared| called after document was disposed", m_isDisposed );
+
m_wasCleared = true;
}
public void redoActionsCleared( EventObject eo )
{
+ assertFalse( "|redoActionsCleared| called after document was disposed", m_isDisposed );
+
m_redoWasCleared = true;
}
public void resetAll( EventObject i_event )
{
+ assertFalse( "|resetAll| called after document was disposed", m_isDisposed );
+
m_managerWasReset = true;
m_activeUndoContexts.clear();
}
public void enteredContext( UndoManagerEvent i_event )
{
+ assertFalse( "|enteredContext| called after document was disposed", m_isDisposed );
+
m_activeUndoContexts.push( i_event.UndoActionTitle );
assertEquals( "different opinions on the context nesting level (after entering)",
m_activeUndoContexts.size(), i_event.UndoContextDepth );
@@ -168,6 +437,8 @@ public class UndoManager
public void enteredHiddenContext( UndoManagerEvent i_event )
{
+ assertFalse( "|enteredHiddenContext| called after document was disposed", m_isDisposed );
+
m_activeUndoContexts.push( i_event.UndoActionTitle );
assertEquals( "different opinions on the context nesting level (after entering hidden)",
m_activeUndoContexts.size(), i_event.UndoContextDepth );
@@ -175,26 +446,35 @@ public class UndoManager
public void leftContext( UndoManagerEvent i_event )
{
+ assertFalse( "|leftContext| called after document was disposed", m_isDisposed );
+
assertEquals( "nested undo context descriptions do not match", m_activeUndoContexts.pop(), i_event.UndoActionTitle );
assertEquals( "different opinions on the context nesting level (after leaving)",
m_activeUndoContexts.size(), i_event.UndoContextDepth );
m_leftContext = true;
+ impl_notifyContextDepth();
}
public void leftHiddenContext( UndoManagerEvent i_event )
{
+ assertFalse( "|leftHiddenContext| called after document was disposed", m_isDisposed );
+
m_activeUndoContexts.pop();
assertEquals( "different opinions on the context nesting level (after leaving)",
m_activeUndoContexts.size(), i_event.UndoContextDepth );
m_leftHiddenContext = true;
+ impl_notifyContextDepth();
}
public void cancelledContext( UndoManagerEvent i_event )
{
+ assertFalse( "|cancelledContext| called after document was disposed", m_isDisposed );
+
m_activeUndoContexts.pop();
assertEquals( "different opinions on the context nesting level (after cancelling)",
m_activeUndoContexts.size(), i_event.UndoContextDepth );
m_cancelledContext = true;
+ impl_notifyContextDepth();
}
public void disposing( EventObject i_event )
@@ -202,27 +482,47 @@ public class UndoManager
m_isDisposed = true;
}
- int getUndoActionsAdded() { return m_undoActionsAdded; }
- int getUndoActionCount() { return m_undoCount; }
- int getRedoActionCount() { return m_redoCount; }
- String getCurrentUndoContextTitle() { return m_activeUndoContexts.peek(); }
- String getMostRecentlyAddedActionTitle() { return m_mostRecentlyAddedAction; };
- String getMostRecentlyUndoneTitle() { return m_mostRecentlyUndone; }
- String getMostRecentlyRedoneTitle() { return m_mostRecentlyRedone; }
- int getUndoContextDepth() { return m_activeUndoContexts.size(); }
- boolean isDisposed() { return m_isDisposed; }
- boolean contextLeft() { return m_leftContext; }
- boolean hiddenContextLeft() { return m_leftHiddenContext; }
- boolean contextCancelled() { return m_cancelledContext; }
- boolean stackWasCleared() { return m_wasCleared; }
- boolean redoStackWasCleared() { return m_redoWasCleared; }
- boolean managerWasReset() { return m_managerWasReset; }
+ public void waitForAllContextsClosed( final int i_milliSeconds ) throws InterruptedException
+ {
+ synchronized ( m_allContextsClosedCondition )
+ {
+ if ( m_activeUndoContexts.empty() )
+ return;
+ m_allContextsClosedCondition.wait( i_milliSeconds );
+ }
+ }
+
+ private void impl_notifyContextDepth()
+ {
+ synchronized ( m_allContextsClosedCondition )
+ {
+ if ( m_activeUndoContexts.empty() )
+ {
+ m_allContextsClosedCondition.notifyAll();
+ }
+ }
+ }
+
+ private int getUndoActionsAdded() { return m_undoActionsAdded; }
+ private int getUndoActionCount() { return m_undoCount; }
+ private int getRedoActionCount() { return m_redoCount; }
+ private String getCurrentUndoContextTitle() { return m_activeUndoContexts.peek(); }
+ private String getMostRecentlyAddedActionTitle() { return m_mostRecentlyAddedAction; };
+ private String getMostRecentlyUndoneTitle() { return m_mostRecentlyUndone; }
+ private int getCurrentUndoContextDepth() { return m_activeUndoContexts.size(); }
+ private boolean isDisposed() { return m_isDisposed; }
+ private boolean wasContextLeft() { return m_leftContext; }
+ private boolean wasHiddenContextLeft() { return m_leftHiddenContext; }
+ private boolean hasContextBeenCancelled() { return m_cancelledContext; }
+ private boolean wereStacksCleared() { return m_wasCleared; }
+ private boolean wasRedoStackCleared() { return m_redoWasCleared; }
+ private boolean wasManagerReset() { return m_managerWasReset; }
void reset()
{
m_undoActionsAdded = m_undoCount = m_redoCount = 0;
m_activeUndoContexts.clear();
- m_mostRecentlyAddedAction = m_mostRecentlyUndone = m_mostRecentlyRedone = null;
+ m_mostRecentlyAddedAction = m_mostRecentlyUndone = null;
// m_isDisposed is not cleared, intentionally
m_leftContext = m_leftHiddenContext = m_cancelledContext = m_wasCleared = m_redoWasCleared = m_managerWasReset = false;
}
@@ -241,7 +541,7 @@ public class UndoManager
m_activeUndoContexts = new Stack<String>();
private String m_mostRecentlyAddedAction = null;
private String m_mostRecentlyUndone = null;
- private String m_mostRecentlyRedone = null;
+ private final Object m_allContextsClosedCondition = new Object();
};
// -----------------------------------------------------------------------------------------------------------------
@@ -271,50 +571,49 @@ public class UndoManager
return;
}
- final XUndoManager undoManager = getUndoManager( test.getDocument() );
+ final XUndoManager undoManager = getUndoManager();
undoManager.clear();
assertFalse( "clearing the Undo manager should result in the impossibility to undo anything", undoManager.isUndoPossible() );
assertFalse( "clearing the Undo manager should result in the impossibility to redo anything", undoManager.isRedoPossible() );
- final UndoListener listener = new UndoListener();
- undoManager.addUndoManagerListener( listener );
+ m_undoListener = new UndoListener();
+ undoManager.addUndoManagerListener( m_undoListener );
- impl_testSingleModification( test, undoManager, listener );
- impl_testMultipleModifications( test, undoManager, listener );
- impl_testCustomUndoActions( test, undoManager, listener );
- impl_testLocking( test, undoManager, listener );
- impl_testNestedContexts( undoManager, listener );
- impl_testErrorHandling( test, undoManager, listener );
- impl_testContextHandling( undoManager, listener );
- impl_testStackHandling( undoManager, listener );
- impl_testClearance( undoManager, listener );
- impl_testHiddenContexts( undoManager, listener );
+ impl_testSingleModification( test, undoManager );
+ impl_testMultipleModifications( test, undoManager );
+ impl_testCustomUndoActions( test, undoManager );
+ impl_testLocking( test, undoManager );
+ impl_testNestedContexts( undoManager );
+ impl_testErrorHandling( test, undoManager );
+ impl_testContextHandling( undoManager );
+ impl_testStackHandling( undoManager );
+ impl_testClearance( undoManager );
+ impl_testHiddenContexts( undoManager );
// close the document, ensure the Undo manager listener gets notified
m_currentDocument.close();
- assertTrue( "document is closed, but the UndoManagerListener has not been notified of the disposal", listener.isDisposed() );
- m_currentDocument = null;
+ assertTrue( "document is closed, but the UndoManagerListener has not been notified of the disposal", m_undoListener.isDisposed() );
}
// -----------------------------------------------------------------------------------------------------------------
- private void impl_testSingleModification( final DocumentTest i_test, final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ private void impl_testSingleModification( final DocumentTest i_test, final XUndoManager i_undoManager ) throws com.sun.star.uno.Exception
{
i_test.doSingleModification();
i_test.verifySingleModificationDocumentState();
// undo the modification, ensure the listener got the proper notifications
- assertEquals( "We did not yet do a undo!", 0, i_listener.getUndoActionCount() );
+ assertEquals( "We did not yet do a undo!", 0, m_undoListener.getUndoActionCount() );
i_undoManager.undo();
assertEquals( "A simple undo does not result in the proper Undo count.",
- 1, i_listener.getUndoActionCount() );
+ 1, m_undoListener.getUndoActionCount() );
// verify the document is in its initial state, again
i_test.verifyInitialDocumentState();
// redo the modification, ensure the listener got the proper notifications
- assertEquals( "did not yet do a redo!", 0, i_listener.getRedoActionCount() );
+ assertEquals( "did not yet do a redo!", 0, m_undoListener.getRedoActionCount() );
i_undoManager.redo();
- assertEquals( "did a redo, but got no notification of it!", 1, i_listener.getRedoActionCount() );
+ assertEquals( "did a redo, but got no notification of it!", 1, m_undoListener.getRedoActionCount() );
// ensure the document is in the proper state, again
i_test.verifySingleModificationDocumentState();
@@ -322,42 +621,42 @@ public class UndoManager
// expected
i_test.getDocument().getCurrentView().dispatch( ".uno:Undo" );
i_test.verifyInitialDocumentState();
- assertEquals( "UI-Undo does not notify the listener", 2, i_listener.getUndoActionCount() );
+ assertEquals( "UI-Undo does not notify the listener", 2, m_undoListener.getUndoActionCount() );
}
// -----------------------------------------------------------------------------------------------------------------
- private void impl_testMultipleModifications( final DocumentTest i_test, final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ private void impl_testMultipleModifications( final DocumentTest i_test, final XUndoManager i_undoManager ) throws com.sun.star.uno.Exception
{
- i_listener.reset();
- assertEquals( "unexpected initial undo context depth", 0, i_listener.getUndoContextDepth() );
+ m_undoListener.reset();
+ assertEquals( "unexpected initial undo context depth", 0, m_undoListener.getCurrentUndoContextDepth() );
i_undoManager.enterUndoContext( "Batch Changes" );
assertEquals( "unexpected undo context depth after entering a context",
- 1, i_listener.getUndoContextDepth() );
+ 1, m_undoListener.getCurrentUndoContextDepth() );
assertEquals( "entering an Undo context has not been notified properly",
- "Batch Changes", i_listener.getCurrentUndoContextTitle() );
+ "Batch Changes", m_undoListener.getCurrentUndoContextTitle() );
final int modifications = i_test.doMultipleModifications();
assertEquals( "unexpected number of undo actions while doing batch changes to the document",
- modifications, i_listener.getUndoActionsAdded() );
+ modifications, m_undoListener.getUndoActionsAdded() );
assertEquals( "seems the document operations touched the undo context depth",
- 1, i_listener.getUndoContextDepth() );
+ 1, m_undoListener.getCurrentUndoContextDepth() );
i_undoManager.leaveUndoContext();
assertEquals( "unexpected undo context depth after leaving the last context",
- 0, i_listener.getUndoContextDepth() );
+ 0, m_undoListener.getCurrentUndoContextDepth() );
assertEquals( "no Undo done, yet - still the listener has been notified of an Undo action",
- 0, i_listener.getUndoActionCount() );
+ 0, m_undoListener.getUndoActionCount() );
i_undoManager.undo();
- assertEquals( "Just did an undo - the listener should have been notified", 1, i_listener.getUndoActionCount() );
+ assertEquals( "Just did an undo - the listener should have been notified", 1, m_undoListener.getUndoActionCount() );
i_test.verifyInitialDocumentState();
}
// -----------------------------------------------------------------------------------------------------------------
- private void impl_testCustomUndoActions( final DocumentTest i_test, final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ private void impl_testCustomUndoActions( final DocumentTest i_test, final XUndoManager i_undoManager ) throws com.sun.star.uno.Exception
{
i_undoManager.clear();
- i_listener.reset();
+ m_undoListener.reset();
assertFalse( "undo stack not empty after clearing the undo manager", i_undoManager.isUndoPossible() );
assertFalse( "redo stack not empty after clearing the undo manager", i_undoManager.isRedoPossible() );
assertArrayEquals( ">0 descriptions for an empty undo stack?",
@@ -368,17 +667,17 @@ public class UndoManager
// add two actions, one directly, one within a context
final CustomUndoAction action1 = new CustomUndoAction( "UndoAction1" );
i_undoManager.addUndoAction( action1 );
- assertEquals( "Adding an undo action not observed by the listener", 1, i_listener.getUndoActionsAdded() );
+ assertEquals( "Adding an undo action not observed by the listener", 1, m_undoListener.getUndoActionsAdded() );
assertEquals( "Adding an undo action did not notify the proper title",
- action1.getTitle(), i_listener.getMostRecentlyAddedActionTitle() );
+ action1.getTitle(), m_undoListener.getMostRecentlyAddedActionTitle() );
final String contextTitle = "Undo Context";
i_undoManager.enterUndoContext( contextTitle );
final CustomUndoAction action2 = new CustomUndoAction( "UndoAction2" );
i_undoManager.addUndoAction( action2 );
assertEquals( "Adding an undo action not observed by the listener",
- 2, i_listener.getUndoActionsAdded() );
+ 2, m_undoListener.getUndoActionsAdded() );
assertEquals( "Adding an undo action did not notify the proper title",
- action2.getTitle(), i_listener.getMostRecentlyAddedActionTitle() );
+ action2.getTitle(), m_undoListener.getMostRecentlyAddedActionTitle() );
i_undoManager.leaveUndoContext();
// see if the manager has proper descriptions
@@ -390,7 +689,7 @@ public class UndoManager
// undo one action
i_undoManager.undo();
assertEquals( "improper action title notified during programmatic Undo",
- contextTitle, i_listener.getMostRecentlyUndoneTitle() );
+ contextTitle, m_undoListener.getMostRecentlyUndoneTitle() );
assertTrue( "nested custom undo action has not been undone as expected", action2.undoCalled() );
assertFalse( "nested custom undo action has not been undone as expected", action1.undoCalled() );
assertArrayEquals( "unexpected Redo descriptions after undoing a nested custom action",
@@ -400,7 +699,7 @@ public class UndoManager
// undo the second action, via UI dispatches
i_test.getDocument().getCurrentView().dispatch( ".uno:Undo" );
- assertEquals( "improper action title notified during UI Undo", action1.getTitle(), i_listener.getMostRecentlyUndoneTitle() );
+ assertEquals( "improper action title notified during UI Undo", action1.getTitle(), m_undoListener.getMostRecentlyUndoneTitle() );
assertTrue( "nested custom undo action has not been undone as expected", action1.undoCalled() );
assertArrayEquals( "unexpected Redo descriptions after undoing the second custom action",
new String[]{action1.getTitle(), contextTitle}, i_undoManager.getAllRedoActionTitles() );
@@ -413,10 +712,10 @@ public class UndoManager
}
// -----------------------------------------------------------------------------------------------------------------
- private void impl_testLocking( final DocumentTest i_test, final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ private void impl_testLocking( final DocumentTest i_test, final XUndoManager i_undoManager ) throws com.sun.star.uno.Exception
{
i_undoManager.reset();
- i_listener.reset();
+ m_undoListener.reset();
// implicit Undo actions, triggered by changes to the document
assertFalse( "unexpected initial locking state", i_undoManager.isLocked() );
@@ -424,10 +723,10 @@ public class UndoManager
assertTrue( "just locked the manager, why does it lie?", i_undoManager.isLocked() );
i_test.doSingleModification();
assertEquals( "when the Undo manager is locked, no implicit additions should happen",
- 0, i_listener.getUndoActionsAdded() );
+ 0, m_undoListener.getUndoActionsAdded() );
i_undoManager.unlock();
assertEquals( "unlock is not expected to add collected actions - they should be discarded",
- 0, i_listener.getUndoActionsAdded() );
+ 0, m_undoListener.getUndoActionsAdded() );
assertFalse( "just unlocked the manager, why does it lie?", i_undoManager.isLocked() );
// explicit Undo actions
@@ -435,13 +734,13 @@ public class UndoManager
i_undoManager.addUndoAction( new CustomUndoAction() );
i_undoManager.unlock();
assertEquals( "explicit Undo actions are expected to be ignored when the manager is locked",
- 0, i_listener.getUndoActionsAdded() );
+ 0, m_undoListener.getUndoActionsAdded() );
// Undo contexts while being locked
i_undoManager.lock();
i_undoManager.enterUndoContext( "Dummy Context" );
i_undoManager.enterHiddenUndoContext();
- assertEquals( "entering Undo contexts should be ignored when the manager is locked", 0, i_listener.getUndoContextDepth() );
+ assertEquals( "entering Undo contexts should be ignored when the manager is locked", 0, m_undoListener.getCurrentUndoContextDepth() );
i_undoManager.leaveUndoContext();
i_undoManager.leaveUndoContext();
i_undoManager.unlock();
@@ -454,12 +753,12 @@ public class UndoManager
}
// -----------------------------------------------------------------------------------------------------------------
- private void impl_testContextHandling( final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ private void impl_testContextHandling( final XUndoManager i_undoManager ) throws com.sun.star.uno.Exception
{
// .............................................................................................................
// part I: non-empty contexts
i_undoManager.reset();
- i_listener.reset();
+ m_undoListener.reset();
// put one action on the undo and one on the redo stack, as precondition for the following tests
XUndoAction undoAction1 = new CustomUndoAction( "Undo Action 1" );
@@ -474,7 +773,7 @@ public class UndoManager
// enter a context, add a single action
i_undoManager.enterUndoContext( "Undo Context" );
- assertEquals( "unexpected undo context depth after entering a context", 1, i_listener.getUndoContextDepth() );
+ assertEquals( "unexpected undo context depth after entering a context", 1, m_undoListener.getCurrentUndoContextDepth() );
XUndoAction undoAction3 = new CustomUndoAction( "Undo Action 3" );
i_undoManager.addUndoAction( undoAction3 );
@@ -492,31 +791,31 @@ public class UndoManager
// leave the context, check the listener has been notified properly, and the notified context depth is correct
i_undoManager.leaveUndoContext();
- assertTrue( i_listener.contextLeft() );
- assertFalse( i_listener.hiddenContextLeft() );
- assertFalse( i_listener.contextCancelled() );
- assertEquals( "unexpected undo context depth leaving a non-empty context", 0, i_listener.getUndoContextDepth() );
+ assertTrue( m_undoListener.wasContextLeft() );
+ assertFalse( m_undoListener.wasHiddenContextLeft() );
+ assertFalse( m_undoListener.hasContextBeenCancelled() );
+ assertEquals( "unexpected undo context depth leaving a non-empty context", 0, m_undoListener.getCurrentUndoContextDepth() );
// .............................................................................................................
// part II: empty contexts
i_undoManager.reset();
- i_listener.reset();
+ m_undoListener.reset();
// enter a context, leave it immediately without adding an action to it
i_undoManager.enterUndoContext( "Undo Context" );
i_undoManager.leaveUndoContext();
- assertFalse( i_listener.contextLeft() );
- assertFalse( i_listener.hiddenContextLeft() );
- assertTrue( i_listener.contextCancelled() );
+ assertFalse( m_undoListener.wasContextLeft() );
+ assertFalse( m_undoListener.wasHiddenContextLeft() );
+ assertTrue( m_undoListener.hasContextBeenCancelled() );
assertFalse( "leaving an empty context should silently remove it, and not contribute to the stack",
i_undoManager.isUndoPossible() );
}
// -----------------------------------------------------------------------------------------------------------------
- private void impl_testNestedContexts( final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ private void impl_testNestedContexts( final XUndoManager i_undoManager ) throws com.sun.star.uno.Exception
{
i_undoManager.reset();
- i_listener.reset();
+ m_undoListener.reset();
i_undoManager.enterUndoContext( "context 1" );
i_undoManager.enterUndoContext( "context 1.1" );
final CustomUndoAction action1 = new CustomUndoAction( "action 1.1.1" );
@@ -533,7 +832,7 @@ public class UndoManager
i_undoManager.addUndoAction( action4 );
i_undoManager.undo();
- assertEquals( "undoing a single action notifies a wrong title", action4.getTitle(), i_listener.getMostRecentlyUndoneTitle() );
+ assertEquals( "undoing a single action notifies a wrong title", action4.getTitle(), m_undoListener.getMostRecentlyUndoneTitle() );
assertTrue( "custom Undo not called", action4.undoCalled() );
assertFalse( "too many custom Undos called", action1.undoCalled() || action2.undoCalled() || action3.undoCalled() );
i_undoManager.undo();
@@ -541,10 +840,10 @@ public class UndoManager
}
// -----------------------------------------------------------------------------------------------------------------
- private void impl_testErrorHandling( final DocumentTest i_test, final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ private void impl_testErrorHandling( final DocumentTest i_test, final XUndoManager i_undoManager ) throws com.sun.star.uno.Exception
{
i_undoManager.reset();
- i_listener.reset();
+ m_undoListener.reset();
// try retrieving the comments for the current Undo/Redo - this should fail
boolean caughtExpected = false;
@@ -655,10 +954,10 @@ public class UndoManager
}
// -----------------------------------------------------------------------------------------------------------------
- private void impl_testStackHandling( final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ private void impl_testStackHandling( final XUndoManager i_undoManager ) throws com.sun.star.uno.Exception
{
i_undoManager.reset();
- i_listener.reset();
+ m_undoListener.reset();
assertFalse( i_undoManager.isUndoPossible() );
assertFalse( i_undoManager.isRedoPossible() );
@@ -681,33 +980,33 @@ public class UndoManager
}
// -----------------------------------------------------------------------------------------------------------------
- private void impl_testClearance( final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ private void impl_testClearance( final XUndoManager i_undoManager ) throws com.sun.star.uno.Exception
{
i_undoManager.reset();
- i_listener.reset();
+ m_undoListener.reset();
// add an action, clear the stack, verify the listener has been called
i_undoManager.addUndoAction( new CustomUndoAction() );
- assertFalse( "clearance listener unexpectedly called", i_listener.stackWasCleared() );
- assertFalse( "redo-clearance listener unexpectedly called", i_listener.redoStackWasCleared() );
+ assertFalse( "clearance listener unexpectedly called", m_undoListener.wereStacksCleared() );
+ assertFalse( "redo-clearance listener unexpectedly called", m_undoListener.wasRedoStackCleared() );
i_undoManager.clear();
- assertTrue( "clearance listener not called as expected", i_listener.stackWasCleared() );
- assertFalse( "redo-clearance listener unexpectedly called (2)", i_listener.redoStackWasCleared() );
+ assertTrue( "clearance listener not called as expected", m_undoListener.wereStacksCleared() );
+ assertFalse( "redo-clearance listener unexpectedly called (2)", m_undoListener.wasRedoStackCleared() );
// ensure the listener is also called if the stack is actually empty at the moment of the call
- i_listener.reset();
+ m_undoListener.reset();
assertFalse( i_undoManager.isUndoPossible() );
i_undoManager.clear();
- assertTrue( "clearance listener is also expected to be called if the stack was empty before", i_listener.stackWasCleared() );
+ assertTrue( "clearance listener is also expected to be called if the stack was empty before", m_undoListener.wereStacksCleared() );
// ensure the proper listeners are called for clearRedo
- i_listener.reset();
+ m_undoListener.reset();
i_undoManager.clearRedo();
- assertFalse( i_listener.stackWasCleared() );
- assertTrue( i_listener.redoStackWasCleared() );
+ assertFalse( m_undoListener.wereStacksCleared() );
+ assertTrue( m_undoListener.wasRedoStackCleared() );
// ensure the redo listener is also called upon implicit redo stack clearance
- i_listener.reset();
+ m_undoListener.reset();
i_undoManager.addUndoAction( new CustomUndoAction() );
i_undoManager.addUndoAction( new CustomUndoAction() );
i_undoManager.undo();
@@ -715,10 +1014,10 @@ public class UndoManager
assertTrue( i_undoManager.isRedoPossible() );
i_undoManager.addUndoAction( new CustomUndoAction() );
assertFalse( i_undoManager.isRedoPossible() );
- assertTrue( "implicit clearance of the Redo stack does not notify listeners", i_listener.redoStackWasCleared() );
+ assertTrue( "implicit clearance of the Redo stack does not notify listeners", m_undoListener.wasRedoStackCleared() );
// test resetting the manager
- i_listener.reset();
+ m_undoListener.reset();
i_undoManager.addUndoAction( new CustomUndoAction() );
i_undoManager.addUndoAction( new CustomUndoAction() );
i_undoManager.undo();
@@ -727,26 +1026,26 @@ public class UndoManager
i_undoManager.reset();
assertFalse( i_undoManager.isUndoPossible() );
assertFalse( i_undoManager.isRedoPossible() );
- assertTrue( "|reset| does not properly notify", i_listener.managerWasReset() );
+ assertTrue( "|reset| does not properly notify", m_undoListener.wasManagerReset() );
// resetting the manager, with open undo contexts
- i_listener.reset();
+ m_undoListener.reset();
i_undoManager.addUndoAction( new CustomUndoAction() );
i_undoManager.enterUndoContext( "Undo Context" );
i_undoManager.addUndoAction( new CustomUndoAction() );
i_undoManager.enterHiddenUndoContext();
i_undoManager.reset();
- assertTrue( "|reset| while contexts are open does not properly notify", i_listener.managerWasReset() );
+ assertTrue( "|reset| while contexts are open does not properly notify", m_undoListener.wasManagerReset() );
// verify the manager really has the proper context depth now
i_undoManager.enterUndoContext( "Undo Context" );
- assertEquals( "seems that |reset| did not really close the open contexts", 1, i_listener.getUndoContextDepth() );
+ assertEquals( "seems that |reset| did not really close the open contexts", 1, m_undoListener.getCurrentUndoContextDepth() );
}
// -----------------------------------------------------------------------------------------------------------------
- private void impl_testHiddenContexts( final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ private void impl_testHiddenContexts( final XUndoManager i_undoManager ) throws com.sun.star.uno.Exception
{
i_undoManager.reset();
- i_listener.reset();
+ m_undoListener.reset();
assertFalse( "precondition for testing hidden undo contexts not met", i_undoManager.isUndoPossible() );
// entering a hidden context should be rejected if the stack is empty
@@ -764,10 +1063,10 @@ public class UndoManager
final CustomUndoAction hiddenUndoAction = new CustomUndoAction( "hidden context action" );
i_undoManager.addUndoAction( hiddenUndoAction );
i_undoManager.leaveUndoContext();
- assertFalse( "leaving a hidden should not call |leftUndocontext|", i_listener.contextLeft() );
- assertTrue( "leaving a hidden does not call |leftHiddenUndocontext|", i_listener.hiddenContextLeft() );
- assertFalse( "leaving a non-empty hidden context claims to have cancelled it", i_listener.contextCancelled() );
- assertEquals( "leaving a hidden context is not properly notified", 0, i_listener.getUndoContextDepth() );
+ assertFalse( "leaving a hidden should not call |leftUndocontext|", m_undoListener.wasContextLeft() );
+ assertTrue( "leaving a hidden does not call |leftHiddenUndocontext|", m_undoListener.wasHiddenContextLeft() );
+ assertFalse( "leaving a non-empty hidden context claims to have cancelled it", m_undoListener.hasContextBeenCancelled() );
+ assertEquals( "leaving a hidden context is not properly notified", 0, m_undoListener.getCurrentUndoContextDepth() );
assertArrayEquals( "unexpected Undo stack after leaving a hidden context",
new String[] { undoAction1.getTitle(), undoAction0.getTitle() },
i_undoManager.getAllUndoActionTitles() );
@@ -783,15 +1082,15 @@ public class UndoManager
undoAction0.undoCalled() );
// leaving an empty hidden context should call the proper notification method
- i_listener.reset();
+ m_undoListener.reset();
i_undoManager.enterHiddenUndoContext();
i_undoManager.leaveUndoContext();
- assertFalse( i_listener.contextLeft() );
- assertFalse( i_listener.hiddenContextLeft() );
- assertTrue( i_listener.contextCancelled() );
+ assertFalse( m_undoListener.wasContextLeft() );
+ assertFalse( m_undoListener.wasHiddenContextLeft() );
+ assertTrue( m_undoListener.hasContextBeenCancelled() );
// nesting hidden and normal contexts
- i_listener.reset();
+ m_undoListener.reset();
i_undoManager.reset();
final CustomUndoAction action0 = new CustomUndoAction( "action 0" );
i_undoManager.addUndoAction( action0 );
@@ -810,11 +1109,11 @@ public class UndoManager
final CustomUndoAction action3 = new CustomUndoAction( "action 3" );
i_undoManager.addUndoAction( action3 );
i_undoManager.enterHiddenUndoContext();
- assertEquals( "mixed hidden/normal context do are not properly notified", 4, i_listener.getUndoContextDepth() );
+ assertEquals( "mixed hidden/normal context do are not properly notified", 4, m_undoListener.getCurrentUndoContextDepth() );
i_undoManager.leaveUndoContext();
- assertTrue( "the left context was empty - why wasn't 'cancelled' notified?", i_listener.contextCancelled() );
- assertFalse( i_listener.contextLeft() );
- assertFalse( i_listener.hiddenContextLeft() );
+ assertTrue( "the left context was empty - why wasn't 'cancelled' notified?", m_undoListener.hasContextBeenCancelled() );
+ assertFalse( m_undoListener.wasContextLeft() );
+ assertFalse( m_undoListener.wasHiddenContextLeft() );
i_undoManager.leaveUndoContext();
i_undoManager.leaveUndoContext();
i_undoManager.leaveUndoContext();
@@ -948,6 +1247,118 @@ public class UndoManager
private final short m_failWhich;
}
- private static final OfficeConnection m_connection = new OfficeConnection();
- private OfficeDocument m_currentDocument;
+ // -----------------------------------------------------------------------------------------------------------------
+ private static String getCallbackUndoContextTitle()
+ {
+ return "Some Unfinished Undo Context";
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ private static String getCallbackComponentServiceName()
+ {
+ return "org.openoffice.complex.sfx2.Callback";
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ /**
+ * a factory for a callback component which, at OOo runtime, is inserted into OOo's "component repository"
+ */
+ private class CallbackComponentFactory implements XSingleComponentFactory, XServiceInfo, XComponent
+ {
+ public Object createInstanceWithContext( XComponentContext i_context ) throws com.sun.star.uno.Exception
+ {
+ return new CallbackComponent();
+ }
+
+ public Object createInstanceWithArgumentsAndContext( Object[] i_arguments, XComponentContext i_context ) throws com.sun.star.uno.Exception
+ {
+ return createInstanceWithContext( i_context );
+ }
+
+ public String getImplementationName()
+ {
+ return "org.openoffice.complex.sfx2.CallbackComponent";
+ }
+
+ public boolean supportsService( String i_serviceName )
+ {
+ return i_serviceName.equals( getCallbackComponentServiceName() );
+ }
+
+ public String[] getSupportedServiceNames()
+ {
+ return new String[] { getCallbackComponentServiceName() };
+ }
+
+ public void dispose()
+ {
+ final EventObject event = new EventObject( this );
+
+ final ArrayList eventListenersCopy = (ArrayList)m_eventListeners.clone();
+ final Iterator iter = eventListenersCopy.iterator();
+ while ( iter.hasNext() )
+ {
+ ((XEventListener)iter.next()).disposing( event );
+ }
+ }
+
+ public void addEventListener( XEventListener i_listener )
+ {
+ if ( i_listener != null )
+ m_eventListeners.add( i_listener );
+ }
+
+ public void removeEventListener( XEventListener i_listener )
+ {
+ m_eventListeners.remove( i_listener );
+ }
+
+ private final ArrayList m_eventListeners = new ArrayList();
+ };
+
+ // -----------------------------------------------------------------------------------------------------------------
+ private class CallbackComponent implements XJob, XTypeProvider
+ {
+ CallbackComponent()
+ {
+ }
+
+ public Object execute( NamedValue[] i_parameters ) throws com.sun.star.lang.IllegalArgumentException, com.sun.star.uno.Exception
+ {
+ // this method is called from within the Basic script which is to check whether the OOo framework
+ // properly cleans up unfinished Undo contexts. It is called immediately after the context has been
+ // entered, so verify the expected Undo manager state.
+ assertEquals( getCallbackUndoContextTitle(), m_undoListener.getCurrentUndoContextTitle() );
+ assertEquals( 1, m_undoListener.getCurrentUndoContextDepth() );
+
+ synchronized( m_callbackCondition )
+ {
+ m_callbackCalled = true;
+ m_callbackCondition.notifyAll();
+ }
+ return m_closeAfterCallback ? "close" : "";
+ }
+
+ public Type[] getTypes()
+ {
+ final Class interfaces[] = getClass().getInterfaces();
+ Type types[] = new Type[ interfaces.length ];
+ for ( int i = 0; i < interfaces.length; ++i )
+ types[i] = new Type(interfaces[i]);
+ return types;
+ }
+
+ public byte[] getImplementationId()
+ {
+ return getClass().toString().getBytes();
+ }
+ }
+
+ private static final OfficeConnection m_connection = new OfficeConnection();
+ private OfficeDocument m_currentDocument;
+ private UndoListener m_undoListener;
+ private CallbackComponentFactory m_callbackFactory = null;
+ private boolean m_callbackCalled = false;
+ private boolean m_closeAfterCallback = false;
+ private final Object m_callbackCondition = new Object();
}