1f7cf3d52SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3f7cf3d52SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4f7cf3d52SAndrew Rist * or more contributor license agreements. See the NOTICE file 5f7cf3d52SAndrew Rist * distributed with this work for additional information 6f7cf3d52SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7f7cf3d52SAndrew Rist * to you under the Apache License, Version 2.0 (the 8f7cf3d52SAndrew Rist * "License"); you may not use this file except in compliance 9f7cf3d52SAndrew Rist * with the License. You may obtain a copy of the License at 10f7cf3d52SAndrew Rist * 11f7cf3d52SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12f7cf3d52SAndrew Rist * 13f7cf3d52SAndrew Rist * Unless required by applicable law or agreed to in writing, 14f7cf3d52SAndrew Rist * software distributed under the License is distributed on an 15f7cf3d52SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16f7cf3d52SAndrew Rist * KIND, either express or implied. See the License for the 17f7cf3d52SAndrew Rist * specific language governing permissions and limitations 18f7cf3d52SAndrew Rist * under the License. 19f7cf3d52SAndrew Rist * 20f7cf3d52SAndrew Rist *************************************************************/ 21f7cf3d52SAndrew Rist 22f7cf3d52SAndrew Rist 23cdf0e10cSrcweir package complex.dbaccess; 24cdf0e10cSrcweir 25cdf0e10cSrcweir import com.sun.star.lang.NotInitializedException; 26cdf0e10cSrcweir import com.sun.star.frame.DoubleInitializationException; 27cdf0e10cSrcweir import com.sun.star.awt.XTopWindow; 28cdf0e10cSrcweir import com.sun.star.beans.PropertyState; 29cdf0e10cSrcweir import com.sun.star.document.DocumentEvent; 30cdf0e10cSrcweir import com.sun.star.lang.XEventListener; 31cdf0e10cSrcweir import com.sun.star.lang.XMultiServiceFactory; 32cdf0e10cSrcweir import com.sun.star.script.XStorageBasedLibraryContainer; 33cdf0e10cSrcweir import com.sun.star.task.XInteractionRequest; 34cdf0e10cSrcweir 35cdf0e10cSrcweir import com.sun.star.uno.Type; 36cdf0e10cSrcweir import com.sun.star.uno.UnoRuntime; 37cdf0e10cSrcweir import com.sun.star.frame.XStorable; 38cdf0e10cSrcweir import com.sun.star.beans.PropertyValue; 39cdf0e10cSrcweir import com.sun.star.beans.XPropertySet; 40cdf0e10cSrcweir import com.sun.star.container.XNameContainer; 41cdf0e10cSrcweir import com.sun.star.container.XSet; 42cdf0e10cSrcweir import com.sun.star.document.XDocumentEventBroadcaster; 43cdf0e10cSrcweir import com.sun.star.document.XDocumentEventListener; 44cdf0e10cSrcweir import com.sun.star.document.XEmbeddedScripts; 45cdf0e10cSrcweir import com.sun.star.document.XEventsSupplier; 46cdf0e10cSrcweir import com.sun.star.lang.XComponent; 47cdf0e10cSrcweir import com.sun.star.frame.XComponentLoader; 48cdf0e10cSrcweir import com.sun.star.frame.XDispatch; 49cdf0e10cSrcweir import com.sun.star.frame.XDispatchProvider; 50cdf0e10cSrcweir import com.sun.star.frame.XFrame; 51cdf0e10cSrcweir import com.sun.star.frame.XLoadable; 52cdf0e10cSrcweir import com.sun.star.frame.XModel; 53cdf0e10cSrcweir import com.sun.star.frame.XModel2; 54cdf0e10cSrcweir import com.sun.star.frame.XTitle; 55cdf0e10cSrcweir import com.sun.star.lang.EventObject; 56cdf0e10cSrcweir import com.sun.star.lang.XServiceInfo; 57cdf0e10cSrcweir import com.sun.star.lang.XSingleComponentFactory; 58cdf0e10cSrcweir import com.sun.star.lang.XTypeProvider; 59cdf0e10cSrcweir import com.sun.star.script.provider.XScriptProviderSupplier; 60cdf0e10cSrcweir import com.sun.star.sdb.XDocumentDataSource; 61cdf0e10cSrcweir 62cdf0e10cSrcweir import com.sun.star.sdb.XFormDocumentsSupplier; 63cdf0e10cSrcweir import com.sun.star.sdb.XOfficeDatabaseDocument; 64cdf0e10cSrcweir import com.sun.star.sdb.XReportDocumentsSupplier; 65cdf0e10cSrcweir import com.sun.star.task.DocumentMacroConfirmationRequest; 66cdf0e10cSrcweir import com.sun.star.task.XInteractionApprove; 67cdf0e10cSrcweir import com.sun.star.task.XInteractionContinuation; 68cdf0e10cSrcweir import com.sun.star.task.XInteractionHandler; 69cdf0e10cSrcweir import com.sun.star.uno.XComponentContext; 70cdf0e10cSrcweir import com.sun.star.util.CloseVetoException; 71cdf0e10cSrcweir import com.sun.star.util.URL; 72cdf0e10cSrcweir import com.sun.star.util.XChangesBatch; 73cdf0e10cSrcweir import com.sun.star.util.XCloseable; 74cdf0e10cSrcweir import com.sun.star.util.XModifiable; 75cdf0e10cSrcweir import com.sun.star.util.XURLTransformer; 76cdf0e10cSrcweir import java.io.IOException; 77cdf0e10cSrcweir import java.util.Iterator; 78cdf0e10cSrcweir import java.util.ArrayList; 79cdf0e10cSrcweir import java.util.logging.Level; 80cdf0e10cSrcweir import java.util.logging.Logger; 81cdf0e10cSrcweir 82cdf0e10cSrcweir // ---------- junit imports ----------------- 83cdf0e10cSrcweir import org.junit.After; 84cdf0e10cSrcweir import org.junit.Before; 85cdf0e10cSrcweir import org.junit.Test; 86cdf0e10cSrcweir import static org.junit.Assert.*; 87cdf0e10cSrcweir // ------------------------------------------ 88cdf0e10cSrcweir 89cdf0e10cSrcweir public class DatabaseDocument extends TestCase implements com.sun.star.document.XDocumentEventListener 90cdf0e10cSrcweir { 91cdf0e10cSrcweir 92cdf0e10cSrcweir private static final String _BLANK = "_blank"; 93cdf0e10cSrcweir private XComponent m_callbackFactory = null; 94cdf0e10cSrcweir private final ArrayList m_documentEvents = new ArrayList(); 95cdf0e10cSrcweir private final ArrayList m_globalEvents = new ArrayList(); 96cdf0e10cSrcweir // for those states, see testDocumentEvents 97cdf0e10cSrcweir private static short STATE_NOT_STARTED = 0; 98cdf0e10cSrcweir private static short STATE_LOADING_DOC = 1; 99cdf0e10cSrcweir private static short STATE_MACRO_EXEC_APPROVED = 2; 100cdf0e10cSrcweir private static short STATE_ON_LOAD_RECEIVED = 3; 101cdf0e10cSrcweir private short m_loadDocState = STATE_NOT_STARTED; 102cdf0e10cSrcweir 103cdf0e10cSrcweir // ======================================================================================================== 104cdf0e10cSrcweir /** a helper class which can be used by the Basic scripts in our test documents 105cdf0e10cSrcweir * to notify us of events in this document 106cdf0e10cSrcweir */ 107cdf0e10cSrcweir private class CallbackComponent implements XDocumentEventListener, XTypeProvider 108cdf0e10cSrcweir { 109cdf0e10cSrcweir documentEventOccured(DocumentEvent _event)110cdf0e10cSrcweir public void documentEventOccured(DocumentEvent _event) 111cdf0e10cSrcweir { 112cdf0e10cSrcweir onDocumentEvent(_event); 113cdf0e10cSrcweir } 114cdf0e10cSrcweir disposing(com.sun.star.lang.EventObject _Event)115cdf0e10cSrcweir public void disposing(com.sun.star.lang.EventObject _Event) 116cdf0e10cSrcweir { 117cdf0e10cSrcweir // not interested in 118cdf0e10cSrcweir } 119cdf0e10cSrcweir getTypes()120cdf0e10cSrcweir public Type[] getTypes() 121cdf0e10cSrcweir { 122cdf0e10cSrcweir final Class interfaces[] = getClass().getInterfaces(); 123cdf0e10cSrcweir Type types[] = new Type[interfaces.length]; 124cdf0e10cSrcweir for (int i = 0; i < interfaces.length; ++i) 125cdf0e10cSrcweir { 126cdf0e10cSrcweir types[i] = new Type(interfaces[i]); 127cdf0e10cSrcweir } 128cdf0e10cSrcweir return types; 129cdf0e10cSrcweir } 130cdf0e10cSrcweir getImplementationId()131cdf0e10cSrcweir public byte[] getImplementationId() 132cdf0e10cSrcweir { 133cdf0e10cSrcweir return getClass().toString().getBytes(); 134cdf0e10cSrcweir } 135cdf0e10cSrcweir }; 136cdf0e10cSrcweir 137cdf0e10cSrcweir // ======================================================================================================== getCallbackComponentServiceName()138cdf0e10cSrcweir private static String getCallbackComponentServiceName() 139cdf0e10cSrcweir { 140cdf0e10cSrcweir return "org.openoffice.complex.dbaccess.EventCallback"; 141cdf0e10cSrcweir } 142cdf0e10cSrcweir 143cdf0e10cSrcweir // ======================================================================================================== 144cdf0e10cSrcweir /** a factory for a CallbackComponent 145cdf0e10cSrcweir */ 146cdf0e10cSrcweir private class CallbackComponentFactory implements XSingleComponentFactory, XServiceInfo, XComponent 147cdf0e10cSrcweir { 148cdf0e10cSrcweir 149cdf0e10cSrcweir private final ArrayList m_eventListeners = new ArrayList(); 150cdf0e10cSrcweir createInstanceWithContext(XComponentContext _context)151cdf0e10cSrcweir public Object createInstanceWithContext(XComponentContext _context) throws com.sun.star.uno.Exception 152cdf0e10cSrcweir { 153cdf0e10cSrcweir return new CallbackComponent(); 154cdf0e10cSrcweir } 155cdf0e10cSrcweir createInstanceWithArgumentsAndContext(Object[] arg0, XComponentContext _context)156cdf0e10cSrcweir public Object createInstanceWithArgumentsAndContext(Object[] arg0, XComponentContext _context) throws com.sun.star.uno.Exception 157cdf0e10cSrcweir { 158cdf0e10cSrcweir return createInstanceWithContext(_context); 159cdf0e10cSrcweir } 160cdf0e10cSrcweir getImplementationName()161cdf0e10cSrcweir public String getImplementationName() 162cdf0e10cSrcweir { 163cdf0e10cSrcweir return "org.openoffice.complex.dbaccess.CallbackComponent"; 164cdf0e10cSrcweir } 165cdf0e10cSrcweir supportsService(String _service)166cdf0e10cSrcweir public boolean supportsService(String _service) 167cdf0e10cSrcweir { 168cdf0e10cSrcweir return _service.equals(getCallbackComponentServiceName()); 169cdf0e10cSrcweir } 170cdf0e10cSrcweir getSupportedServiceNames()171cdf0e10cSrcweir public String[] getSupportedServiceNames() 172cdf0e10cSrcweir { 173cdf0e10cSrcweir return new String[] 174cdf0e10cSrcweir { 175cdf0e10cSrcweir getCallbackComponentServiceName() 176cdf0e10cSrcweir }; 177cdf0e10cSrcweir } 178cdf0e10cSrcweir dispose()179cdf0e10cSrcweir public void dispose() 180cdf0e10cSrcweir { 181cdf0e10cSrcweir final EventObject event = new EventObject(this); 182cdf0e10cSrcweir 183cdf0e10cSrcweir final ArrayList eventListenersCopy = (ArrayList) m_eventListeners.clone(); 184cdf0e10cSrcweir final Iterator iter = eventListenersCopy.iterator(); 185cdf0e10cSrcweir while (iter.hasNext()) 186cdf0e10cSrcweir { 187cdf0e10cSrcweir ((XEventListener) iter.next()).disposing(event); 188cdf0e10cSrcweir } 189cdf0e10cSrcweir } 190cdf0e10cSrcweir addEventListener(XEventListener _listener)191cdf0e10cSrcweir public void addEventListener(XEventListener _listener) 192cdf0e10cSrcweir { 193cdf0e10cSrcweir if (_listener != null) 194cdf0e10cSrcweir { 195cdf0e10cSrcweir m_eventListeners.add(_listener); 196cdf0e10cSrcweir } 197cdf0e10cSrcweir } 198cdf0e10cSrcweir removeEventListener(XEventListener _listener)199cdf0e10cSrcweir public void removeEventListener(XEventListener _listener) 200cdf0e10cSrcweir { 201cdf0e10cSrcweir m_eventListeners.remove(_listener); 202cdf0e10cSrcweir } 203cdf0e10cSrcweir }; 204cdf0e10cSrcweir 205cdf0e10cSrcweir // ======================================================================================================== 206cdf0e10cSrcweir private class MacroExecutionApprove implements XInteractionHandler 207cdf0e10cSrcweir { 208cdf0e10cSrcweir 209cdf0e10cSrcweir private XInteractionHandler m_defaultHandler = null; 210cdf0e10cSrcweir MacroExecutionApprove(XMultiServiceFactory _factory)211cdf0e10cSrcweir MacroExecutionApprove(XMultiServiceFactory _factory) 212cdf0e10cSrcweir { 213cdf0e10cSrcweir try 214cdf0e10cSrcweir { 215cdf0e10cSrcweir m_defaultHandler = UnoRuntime.queryInterface(XInteractionHandler.class, _factory.createInstance("com.sun.star.task.InteractionHandler")); 216cdf0e10cSrcweir } 217cdf0e10cSrcweir catch (Exception ex) 218cdf0e10cSrcweir { 219cdf0e10cSrcweir Logger.getLogger(DatabaseDocument.class.getName()).log(Level.SEVERE, null, ex); 220cdf0e10cSrcweir } 221cdf0e10cSrcweir } 222cdf0e10cSrcweir handle(XInteractionRequest _request)223cdf0e10cSrcweir public void handle(XInteractionRequest _request) 224cdf0e10cSrcweir { 225cdf0e10cSrcweir final Object request = _request.getRequest(); 226cdf0e10cSrcweir if (!(request instanceof DocumentMacroConfirmationRequest) && (m_defaultHandler != null)) 227cdf0e10cSrcweir { 228cdf0e10cSrcweir m_defaultHandler.handle(_request); 229cdf0e10cSrcweir return; 230cdf0e10cSrcweir } 231cdf0e10cSrcweir 232cdf0e10cSrcweir assertEquals("interaction handleer called in wrong state", STATE_LOADING_DOC, m_loadDocState); 233cdf0e10cSrcweir 234cdf0e10cSrcweir // auto-approve 235cdf0e10cSrcweir final XInteractionContinuation continuations[] = _request.getContinuations(); 236cdf0e10cSrcweir for (int i = 0; i < continuations.length; ++i) 237cdf0e10cSrcweir { 238cdf0e10cSrcweir final XInteractionApprove approve = UnoRuntime.queryInterface(XInteractionApprove.class, continuations[i]); 239cdf0e10cSrcweir if (approve != null) 240cdf0e10cSrcweir { 241cdf0e10cSrcweir approve.select(); 242cdf0e10cSrcweir m_loadDocState = STATE_MACRO_EXEC_APPROVED; 243cdf0e10cSrcweir break; 244cdf0e10cSrcweir } 245cdf0e10cSrcweir } 246cdf0e10cSrcweir } 247cdf0e10cSrcweir }; 248cdf0e10cSrcweir 249cdf0e10cSrcweir // ======================================================================================================== 250cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- 251cdf0e10cSrcweir @Before before()252cdf0e10cSrcweir public void before() throws java.lang.Exception 253cdf0e10cSrcweir { 254cdf0e10cSrcweir super.before(); 255cdf0e10cSrcweir 256cdf0e10cSrcweir try 257cdf0e10cSrcweir { 258cdf0e10cSrcweir // at our service factory, insert a new factory for our CallbackComponent 259cdf0e10cSrcweir // this will allow the Basic code in our test documents to call back into this test case 260cdf0e10cSrcweir // here, by just instantiating this service 261cdf0e10cSrcweir final XSet globalFactory = UnoRuntime.queryInterface(XSet.class, getMSF()); 262cdf0e10cSrcweir m_callbackFactory = new CallbackComponentFactory(); 263cdf0e10cSrcweir globalFactory.insert(m_callbackFactory); 264cdf0e10cSrcweir 265cdf0e10cSrcweir // register ourself as listener at the global event broadcaster 266cdf0e10cSrcweir final XDocumentEventBroadcaster broadcaster = UnoRuntime.queryInterface(XDocumentEventBroadcaster.class, getMSF().createInstance("com.sun.star.frame.GlobalEventBroadcaster")); 267cdf0e10cSrcweir broadcaster.addDocumentEventListener(this); 268cdf0e10cSrcweir } 269cdf0e10cSrcweir catch (Exception e) 270cdf0e10cSrcweir { 271cdf0e10cSrcweir System.out.println("could not create the test case, error message:\n" + e.getMessage()); 272cdf0e10cSrcweir e.printStackTrace(System.err); 273cdf0e10cSrcweir fail("failed to create the test case"); 274cdf0e10cSrcweir } 275cdf0e10cSrcweir } 276cdf0e10cSrcweir 277cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- 278cdf0e10cSrcweir @After after()279cdf0e10cSrcweir public void after() throws java.lang.Exception 280cdf0e10cSrcweir { 281cdf0e10cSrcweir try 282cdf0e10cSrcweir { 283cdf0e10cSrcweir // dispose our callback factory. This will automatically remove it from our service 284cdf0e10cSrcweir // factory 285cdf0e10cSrcweir m_callbackFactory.dispose(); 286cdf0e10cSrcweir 287cdf0e10cSrcweir // revoke ourself as listener at the global event broadcaster 288cdf0e10cSrcweir final XDocumentEventBroadcaster broadcaster = UnoRuntime.queryInterface(XDocumentEventBroadcaster.class, getMSF().createInstance("com.sun.star.frame.GlobalEventBroadcaster")); 289cdf0e10cSrcweir broadcaster.removeDocumentEventListener(this); 290cdf0e10cSrcweir } 291cdf0e10cSrcweir catch (Exception e) 292cdf0e10cSrcweir { 293cdf0e10cSrcweir System.out.println("could not create the test case, error message:\n" + e.getMessage()); 294cdf0e10cSrcweir e.printStackTrace(System.err); 295cdf0e10cSrcweir fail("failed to close the test case"); 296cdf0e10cSrcweir } 297cdf0e10cSrcweir 298cdf0e10cSrcweir super.after(); 299cdf0e10cSrcweir } 300cdf0e10cSrcweir 301cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- 302cdf0e10cSrcweir private static class UnoMethodDescriptor 303cdf0e10cSrcweir { 304cdf0e10cSrcweir 305cdf0e10cSrcweir public Class unoInterfaceClass = null; 306cdf0e10cSrcweir public String methodName = null; 307cdf0e10cSrcweir UnoMethodDescriptor(Class _class, String _method)308cdf0e10cSrcweir UnoMethodDescriptor(Class _class, String _method) 309cdf0e10cSrcweir { 310cdf0e10cSrcweir unoInterfaceClass = _class; 311cdf0e10cSrcweir methodName = _method; 312cdf0e10cSrcweir } 313cdf0e10cSrcweir } 314cdf0e10cSrcweir 315cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_checkDocumentInitState(Object _document, boolean _isInitialized)316cdf0e10cSrcweir private void impl_checkDocumentInitState(Object _document, boolean _isInitialized) 317cdf0e10cSrcweir { 318cdf0e10cSrcweir // things you cannot do with an uninitialized document: 319cdf0e10cSrcweir final UnoMethodDescriptor[] unsupportedMethods = new UnoMethodDescriptor[] 320cdf0e10cSrcweir { 321cdf0e10cSrcweir new UnoMethodDescriptor(XStorable.class, "store"), 322cdf0e10cSrcweir new UnoMethodDescriptor(XFormDocumentsSupplier.class, "getFormDocuments"), 323cdf0e10cSrcweir new UnoMethodDescriptor(XReportDocumentsSupplier.class, "getReportDocuments"), 324cdf0e10cSrcweir new UnoMethodDescriptor(XScriptProviderSupplier.class, "getScriptProvider"), 325cdf0e10cSrcweir new UnoMethodDescriptor(XEventsSupplier.class, "getEvents"), 326cdf0e10cSrcweir new UnoMethodDescriptor(XTitle.class, "getTitle"), 327cdf0e10cSrcweir new UnoMethodDescriptor(XModel2.class, "getControllers") 328cdf0e10cSrcweir // (there's much more than this, but we cannot list all methods here, can we ...) 329cdf0e10cSrcweir }; 330cdf0e10cSrcweir 331cdf0e10cSrcweir for (int i = 0; i < unsupportedMethods.length; ++i) 332cdf0e10cSrcweir { 333cdf0e10cSrcweir assureException( _document, unsupportedMethods[i].unoInterfaceClass, 334cdf0e10cSrcweir unsupportedMethods[i].methodName, new Object[]{}, _isInitialized ? null : NotInitializedException.class ); 335cdf0e10cSrcweir } 336cdf0e10cSrcweir } 337cdf0e10cSrcweir 338cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_createDocument()339cdf0e10cSrcweir private XModel impl_createDocument() throws Exception 340cdf0e10cSrcweir { 341cdf0e10cSrcweir final XModel databaseDoc = UnoRuntime.queryInterface(XModel.class, getMSF().createInstance("com.sun.star.sdb.OfficeDatabaseDocument")); 342cdf0e10cSrcweir 343cdf0e10cSrcweir // should not be initialized here - we did neither initNew nor load nor storeAsURL it 344cdf0e10cSrcweir impl_checkDocumentInitState(databaseDoc, false); 345cdf0e10cSrcweir 346cdf0e10cSrcweir return databaseDoc; 347cdf0e10cSrcweir } 348cdf0e10cSrcweir 349cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_closeDocument(XModel _databaseDoc)350cdf0e10cSrcweir private void impl_closeDocument(XModel _databaseDoc) throws CloseVetoException, IOException, Exception 351cdf0e10cSrcweir { 352cdf0e10cSrcweir final XCloseable closeDoc = UnoRuntime.queryInterface(XCloseable.class, _databaseDoc); 353cdf0e10cSrcweir closeDoc.close(true); 354cdf0e10cSrcweir } 355cdf0e10cSrcweir 356cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_createEmptyEmbeddedHSQLDocument()357cdf0e10cSrcweir private XModel impl_createEmptyEmbeddedHSQLDocument() throws Exception, IOException 358cdf0e10cSrcweir { 359cdf0e10cSrcweir final XModel databaseDoc = UnoRuntime.queryInterface(XModel.class, getMSF().createInstance("com.sun.star.sdb.OfficeDatabaseDocument")); 360cdf0e10cSrcweir final XStorable storeDoc = UnoRuntime.queryInterface(XStorable.class, databaseDoc); 361cdf0e10cSrcweir 362cdf0e10cSrcweir // verify the document rejects API calls which require it to be initialized 363cdf0e10cSrcweir impl_checkDocumentInitState(databaseDoc, false); 364cdf0e10cSrcweir 365cdf0e10cSrcweir // though the document is not initialized, you can ask for the location, the URL, and the args 366cdf0e10cSrcweir final String location = storeDoc.getLocation(); 367cdf0e10cSrcweir final String url = databaseDoc.getURL(); 368cdf0e10cSrcweir final PropertyValue[] args = databaseDoc.getArgs(); 369cdf0e10cSrcweir // they should be all empty at this time 370cdf0e10cSrcweir assertEquals("location is expected to be empty here", "", location); 371cdf0e10cSrcweir assertEquals("URL is expected to be empty here", "", url); 372cdf0e10cSrcweir assertEquals("Args are expected to be empty here", 0, args.length); 373cdf0e10cSrcweir 374cdf0e10cSrcweir // and, you should be able to set properties at the data source 375cdf0e10cSrcweir final XOfficeDatabaseDocument dataSourceAccess = UnoRuntime.queryInterface(XOfficeDatabaseDocument.class, databaseDoc); 376cdf0e10cSrcweir final XPropertySet dsProperties = UnoRuntime.queryInterface(XPropertySet.class, dataSourceAccess.getDataSource()); 377cdf0e10cSrcweir dsProperties.setPropertyValue("URL", "sdbc:embedded:hsqldb"); 378cdf0e10cSrcweir 379cdf0e10cSrcweir final String documentURL = createTempFileURL(); 380cdf0e10cSrcweir storeDoc.storeAsURL(documentURL, new PropertyValue[0]); 381cdf0e10cSrcweir 382cdf0e10cSrcweir // now that the document is stored, ... 383cdf0e10cSrcweir // ... its URL should be correct 384cdf0e10cSrcweir assertEquals("wrong URL after storing the document", documentURL, databaseDoc.getURL()); 385cdf0e10cSrcweir // ... it should be initialized 386cdf0e10cSrcweir impl_checkDocumentInitState(databaseDoc, true); 387cdf0e10cSrcweir 388cdf0e10cSrcweir return databaseDoc; 389cdf0e10cSrcweir } 390cdf0e10cSrcweir 391cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- 392cdf0e10cSrcweir @Test testLoadable()393cdf0e10cSrcweir public void testLoadable() throws Exception, IOException 394cdf0e10cSrcweir { 395cdf0e10cSrcweir XModel databaseDoc = impl_createEmptyEmbeddedHSQLDocument(); 396cdf0e10cSrcweir String documentURL = databaseDoc.getURL(); 397cdf0e10cSrcweir 398cdf0e10cSrcweir // there's three methods how you can initialize a database document: 399cdf0e10cSrcweir 400cdf0e10cSrcweir // .................................................................... 401cdf0e10cSrcweir // 1. XStorable::storeAsURL 402cdf0e10cSrcweir // (this is for compatibility reasons, to not break existing code) 403cdf0e10cSrcweir // this test is already made in impl_createEmptyEmbeddedHSQLDocument 404cdf0e10cSrcweir 405cdf0e10cSrcweir // .................................................................... 406cdf0e10cSrcweir // 2. XLoadable::load 407cdf0e10cSrcweir databaseDoc = UnoRuntime.queryInterface(XModel.class, getMSF().createInstance("com.sun.star.sdb.OfficeDatabaseDocument")); 408cdf0e10cSrcweir documentURL = copyToTempFile(documentURL); 409cdf0e10cSrcweir // load the doc, and verify it's initialized then, and has the proper URL 410cdf0e10cSrcweir XLoadable loadDoc = UnoRuntime.queryInterface(XLoadable.class, databaseDoc); 411cdf0e10cSrcweir loadDoc.load(new PropertyValue[] 412cdf0e10cSrcweir { 413cdf0e10cSrcweir new PropertyValue("URL", 0, documentURL, PropertyState.DIRECT_VALUE) 414cdf0e10cSrcweir }); 415cdf0e10cSrcweir databaseDoc.attachResource(documentURL, new PropertyValue[0]); 416cdf0e10cSrcweir 417cdf0e10cSrcweir assertEquals("wrong URL after loading the document", documentURL, databaseDoc.getURL()); 418cdf0e10cSrcweir impl_checkDocumentInitState(databaseDoc, true); 419cdf0e10cSrcweir 420cdf0e10cSrcweir // and while we are here ... initilizing the same document again should not be possible 421cdf0e10cSrcweir assureException( databaseDoc, XLoadable.class, "initNew", new Object[0], 422cdf0e10cSrcweir DoubleInitializationException.class ); 423cdf0e10cSrcweir assureException( databaseDoc, XLoadable.class, "load", new Object[] { new PropertyValue[0] }, 424cdf0e10cSrcweir DoubleInitializationException.class ); 425cdf0e10cSrcweir 426cdf0e10cSrcweir // .................................................................... 427cdf0e10cSrcweir // 3. XLoadable::initNew 428cdf0e10cSrcweir impl_closeDocument(databaseDoc); 429cdf0e10cSrcweir databaseDoc = impl_createDocument(); 430cdf0e10cSrcweir loadDoc = UnoRuntime.queryInterface(XLoadable.class, databaseDoc); 431cdf0e10cSrcweir loadDoc.initNew(); 432cdf0e10cSrcweir assertEquals("wrong URL after initializing the document", "", databaseDoc.getURL()); 433cdf0e10cSrcweir impl_checkDocumentInitState(databaseDoc, true); 434cdf0e10cSrcweir 435cdf0e10cSrcweir // same as above - initializing the document a second time must fail 436cdf0e10cSrcweir assureException( databaseDoc, XLoadable.class, "initNew", new Object[0], 437cdf0e10cSrcweir DoubleInitializationException.class ); 438cdf0e10cSrcweir assureException( databaseDoc, XLoadable.class, "load", new Object[] { new PropertyValue[0] }, 439cdf0e10cSrcweir DoubleInitializationException.class ); 440cdf0e10cSrcweir } 441cdf0e10cSrcweir 442cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_getMarkerLoadArgs()443cdf0e10cSrcweir private PropertyValue[] impl_getMarkerLoadArgs() 444cdf0e10cSrcweir { 445cdf0e10cSrcweir return new PropertyValue[] 446cdf0e10cSrcweir { 447cdf0e10cSrcweir new PropertyValue( "PickListEntry", 0, false, PropertyState.DIRECT_VALUE ), 448cdf0e10cSrcweir new PropertyValue( "TestCase_Marker", 0, "Yes", PropertyState.DIRECT_VALUE ) 449cdf0e10cSrcweir }; 450cdf0e10cSrcweir } 451cdf0e10cSrcweir 452cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_hasMarker( final PropertyValue[] _args )453cdf0e10cSrcweir private boolean impl_hasMarker( final PropertyValue[] _args ) 454cdf0e10cSrcweir { 455cdf0e10cSrcweir for ( int i=0; i<_args.length; ++i ) 456cdf0e10cSrcweir { 457cdf0e10cSrcweir if ( _args[i].Name.equals( "TestCase_Marker" ) && _args[i].Value.equals( "Yes" ) ) 458cdf0e10cSrcweir { 459cdf0e10cSrcweir return true; 460cdf0e10cSrcweir } 461cdf0e10cSrcweir } 462cdf0e10cSrcweir return false; 463cdf0e10cSrcweir } 464cdf0e10cSrcweir 465cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_getDefaultLoadArgs()466cdf0e10cSrcweir private PropertyValue[] impl_getDefaultLoadArgs() 467cdf0e10cSrcweir { 468cdf0e10cSrcweir return new PropertyValue[] 469cdf0e10cSrcweir { 470cdf0e10cSrcweir new PropertyValue("PickListEntry", 0, false, PropertyState.DIRECT_VALUE) 471cdf0e10cSrcweir }; 472cdf0e10cSrcweir } 473cdf0e10cSrcweir 474cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_getMacroExecLoadArgs()475cdf0e10cSrcweir private PropertyValue[] impl_getMacroExecLoadArgs() 476cdf0e10cSrcweir { 477cdf0e10cSrcweir return new PropertyValue[] 478cdf0e10cSrcweir { 479cdf0e10cSrcweir new PropertyValue("PickListEntry", 0, false, PropertyState.DIRECT_VALUE), 480cdf0e10cSrcweir new PropertyValue("MacroExecutionMode", 0, com.sun.star.document.MacroExecMode.USE_CONFIG, PropertyState.DIRECT_VALUE), 481cdf0e10cSrcweir new PropertyValue("InteractionHandler", 0, new MacroExecutionApprove(getMSF()), PropertyState.DIRECT_VALUE) 482cdf0e10cSrcweir }; 483cdf0e10cSrcweir } 484cdf0e10cSrcweir 485cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_setMacroSecurityLevel(int _level)486cdf0e10cSrcweir private int impl_setMacroSecurityLevel(int _level) throws Exception 487cdf0e10cSrcweir { 488cdf0e10cSrcweir final XMultiServiceFactory configProvider = UnoRuntime.queryInterface(XMultiServiceFactory.class, getMSF().createInstance("com.sun.star.configuration.ConfigurationProvider")); 489cdf0e10cSrcweir 490cdf0e10cSrcweir final PropertyValue[] args = new PropertyValue[] 491cdf0e10cSrcweir { 492cdf0e10cSrcweir new PropertyValue("nodepath", 0, "/org.openoffice.Office.Common/Security/Scripting", PropertyState.DIRECT_VALUE) 493cdf0e10cSrcweir }; 494cdf0e10cSrcweir 495cdf0e10cSrcweir final XPropertySet securitySettings = UnoRuntime.queryInterface(XPropertySet.class, configProvider.createInstanceWithArguments("com.sun.star.configuration.ConfigurationUpdateAccess", args)); 496cdf0e10cSrcweir final int oldValue = ((Integer) securitySettings.getPropertyValue("MacroSecurityLevel")).intValue(); 497cdf0e10cSrcweir securitySettings.setPropertyValue("MacroSecurityLevel", Integer.valueOf(_level)); 498cdf0e10cSrcweir 499cdf0e10cSrcweir final XChangesBatch committer = UnoRuntime.queryInterface(XChangesBatch.class, securitySettings); 500cdf0e10cSrcweir committer.commitChanges(); 501cdf0e10cSrcweir 502cdf0e10cSrcweir return oldValue; 503cdf0e10cSrcweir } 504cdf0e10cSrcweir 505cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_loadDocument( final String _documentURL, final PropertyValue[] _loadArgs )506cdf0e10cSrcweir private XModel impl_loadDocument( final String _documentURL, final PropertyValue[] _loadArgs ) throws Exception 507cdf0e10cSrcweir { 508cdf0e10cSrcweir final XComponentLoader loader = UnoRuntime.queryInterface(XComponentLoader.class, getMSF().createInstance("com.sun.star.frame.Desktop")); 509cdf0e10cSrcweir return UnoRuntime.queryInterface(XModel.class, loader.loadComponentFromURL(_documentURL, _BLANK, 0, _loadArgs)); 510cdf0e10cSrcweir } 511cdf0e10cSrcweir 512cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_storeDocument( final XModel _document )513cdf0e10cSrcweir private void impl_storeDocument( final XModel _document ) throws Exception, IOException 514cdf0e10cSrcweir { 515cdf0e10cSrcweir // store the document 516cdf0e10cSrcweir final String documentURL = FileHelper.getOOoCompatibleFileURL( _document.getURL() ); 517cdf0e10cSrcweir final XStorable storeDoc = UnoRuntime.queryInterface(XStorable.class, _document); 518cdf0e10cSrcweir storeDoc.store(); 519cdf0e10cSrcweir 520cdf0e10cSrcweir } 521cdf0e10cSrcweir 522cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_createDocWithMacro( final String _libName, final String _moduleName, final String _code )523cdf0e10cSrcweir private XModel impl_createDocWithMacro( final String _libName, final String _moduleName, final String _code ) throws Exception, IOException 524cdf0e10cSrcweir { 525cdf0e10cSrcweir // create an empty document 526cdf0e10cSrcweir XModel databaseDoc = impl_createEmptyEmbeddedHSQLDocument(); 527cdf0e10cSrcweir 528cdf0e10cSrcweir // create Basic library/module therein 529cdf0e10cSrcweir final XEmbeddedScripts embeddedScripts = UnoRuntime.queryInterface(XEmbeddedScripts.class, databaseDoc); 530cdf0e10cSrcweir final XStorageBasedLibraryContainer basicLibs = embeddedScripts.getBasicLibraries(); 531cdf0e10cSrcweir final XNameContainer newLib = basicLibs.createLibrary( _libName ); 532cdf0e10cSrcweir newLib.insertByName( _moduleName, _code ); 533cdf0e10cSrcweir 534cdf0e10cSrcweir return databaseDoc; 535cdf0e10cSrcweir } 536cdf0e10cSrcweir 537cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- 538cdf0e10cSrcweir /** tests various aspects of database document "revenants" 539cdf0e10cSrcweir * 540cdf0e10cSrcweir * Well, I do not really have a good term for this ... The point is, database documents are in real 541cdf0e10cSrcweir * only *one* aspect of a more complex thing. The second aspect is a data source. Both, in some sense, 542cdf0e10cSrcweir * just represent different views on the same thing. For a given database, there's at each time at most 543cdf0e10cSrcweir * one data source, and at most one database document. Both have a independent life time, and are 544cdf0e10cSrcweir * created when needed. 545cdf0e10cSrcweir * In particular, a document can be closed (this is what happens when the last UI window displaying 546cdf0e10cSrcweir * this document is closed), and then dies. Now when the other "view", the data source, still exists, 547*fb0b81f5Smseidel * the underlying document data is not discarded, but kept alive (else the data source would die 548cdf0e10cSrcweir * just because the document dies, which is not desired). If the document is loaded, again, then 549cdf0e10cSrcweir * it is re-created, using the data of its previous "incarnation". 550cdf0e10cSrcweir * 551cdf0e10cSrcweir * This method here tests some of those aspects of a document which should survive the death of one 552cdf0e10cSrcweir * instance and re-creation as a revenant. 553cdf0e10cSrcweir */ 554cdf0e10cSrcweir @Test testDocumentRevenants()555cdf0e10cSrcweir public void testDocumentRevenants() throws Exception, IOException 556cdf0e10cSrcweir { 557cdf0e10cSrcweir // create an empty document 558cdf0e10cSrcweir XModel databaseDoc = impl_createDocWithMacro( "Lib", "Module", 559cdf0e10cSrcweir "Sub Hello\n" + 560cdf0e10cSrcweir " MsgBox \"Hello\"\n" + 561cdf0e10cSrcweir "End Sub\n" 562cdf0e10cSrcweir ); 563cdf0e10cSrcweir impl_storeDocument( databaseDoc ); 564cdf0e10cSrcweir final String documentURL = databaseDoc.getURL(); 565cdf0e10cSrcweir 566cdf0e10cSrcweir // at this stage, the marker should not yet be present in the doc's args, else some of the below 567cdf0e10cSrcweir // tests become meaningless 568cdf0e10cSrcweir assertTrue( "A newly created doc should not have the test case marker", !impl_hasMarker( databaseDoc.getArgs() ) ); 569cdf0e10cSrcweir 570cdf0e10cSrcweir // obtain the DataSource associated with the document. Keeping this alive 571cdf0e10cSrcweir // ensures that the "impl data" of the document is kept alive, too, so when closing 572cdf0e10cSrcweir // and re-opening it, this "impl data" must be re-used. 573cdf0e10cSrcweir XDocumentDataSource dataSource = UnoRuntime.queryInterface(XDocumentDataSource.class, (UnoRuntime.queryInterface(XOfficeDatabaseDocument.class, databaseDoc)).getDataSource()); 574cdf0e10cSrcweir 575cdf0e10cSrcweir // close and reload the doc 576cdf0e10cSrcweir impl_closeDocument(databaseDoc); 577cdf0e10cSrcweir databaseDoc = impl_loadDocument( documentURL, impl_getMarkerLoadArgs() ); 578cdf0e10cSrcweir // since we just put the marker into the load-call, it should be present at the doc 579cdf0e10cSrcweir assertTrue( "The test case marker got lost.", impl_hasMarker( databaseDoc.getArgs() ) ); 580cdf0e10cSrcweir 581cdf0e10cSrcweir // The basic library should have survived 582cdf0e10cSrcweir final XEmbeddedScripts embeddedScripts = UnoRuntime.queryInterface(XEmbeddedScripts.class, databaseDoc); 583cdf0e10cSrcweir final XStorageBasedLibraryContainer basicLibs = embeddedScripts.getBasicLibraries(); 584cdf0e10cSrcweir assertTrue( "Baisc lib did not survive reloading a closed document", basicLibs.hasByName( "Lib" ) ); 585cdf0e10cSrcweir final XNameContainer lib = UnoRuntime.queryInterface(XNameContainer.class, basicLibs.getByName("Lib")); 586cdf0e10cSrcweir assertTrue( "Basic module did not survive reloading a closed document", lib.hasByName( "Module" ) ); 587cdf0e10cSrcweir 588cdf0e10cSrcweir // now closing the doc, and obtaining it from the data source, should preserve the marker we put into the load 589cdf0e10cSrcweir // args 590cdf0e10cSrcweir impl_closeDocument( databaseDoc ); 591cdf0e10cSrcweir databaseDoc = UnoRuntime.queryInterface(XModel.class, dataSource.getDatabaseDocument()); 592cdf0e10cSrcweir assertTrue( "The test case marker did not survive re-retrieval of the doc from the data source.", 593cdf0e10cSrcweir impl_hasMarker( databaseDoc.getArgs() ) ); 594cdf0e10cSrcweir 595cdf0e10cSrcweir // on the other hand, closing and regurlarly re-loading the doc *without* the marker should indeed 596cdf0e10cSrcweir // lose it 597cdf0e10cSrcweir impl_closeDocument( databaseDoc ); 598cdf0e10cSrcweir databaseDoc = impl_loadDocument( documentURL, impl_getDefaultLoadArgs() ); 599cdf0e10cSrcweir assertTrue( "Reloading the document kept the old args, instead of the newly supplied ones.", 600cdf0e10cSrcweir !impl_hasMarker( databaseDoc.getArgs() ) ); 601cdf0e10cSrcweir 602cdf0e10cSrcweir // clean up 603cdf0e10cSrcweir impl_closeDocument( databaseDoc ); 604cdf0e10cSrcweir } 605cdf0e10cSrcweir 606cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- 607cdf0e10cSrcweir @Test testDocumentEvents()608cdf0e10cSrcweir public void testDocumentEvents() throws Exception, IOException 609cdf0e10cSrcweir { 610cdf0e10cSrcweir // create an empty document 611cdf0e10cSrcweir final String libName = "EventHandlers"; 612cdf0e10cSrcweir final String moduleName = "all"; 613cdf0e10cSrcweir final String eventHandlerCode = 614cdf0e10cSrcweir "Option Explicit\n" + 615cdf0e10cSrcweir "\n" + 616cdf0e10cSrcweir "Sub OnLoad\n" + 617cdf0e10cSrcweir " Dim oCallback as Object\n" + 618cdf0e10cSrcweir " oCallback = createUnoService( \"" + getCallbackComponentServiceName() + "\" )\n" + 619cdf0e10cSrcweir "\n" + 620cdf0e10cSrcweir " ' as long as the Document is not passed to the Basic callbacks, we need to create\n" + 621cdf0e10cSrcweir " ' one ourself\n" + 622cdf0e10cSrcweir " Dim oEvent as new com.sun.star.document.DocumentEvent\n" + 623cdf0e10cSrcweir " oEvent.EventName = \"OnLoad\"\n" + 624cdf0e10cSrcweir " oEvent.Source = ThisComponent\n" + 625cdf0e10cSrcweir "\n" + 626cdf0e10cSrcweir " oCallback.documentEventOccured( oEvent )\n" + 627cdf0e10cSrcweir "End Sub\n"; 628cdf0e10cSrcweir XModel databaseDoc = impl_createDocWithMacro( libName, moduleName, eventHandlerCode ); 629cdf0e10cSrcweir final String documentURL = databaseDoc.getURL(); 630cdf0e10cSrcweir 631cdf0e10cSrcweir // bind the macro to the OnLoad event 632cdf0e10cSrcweir final String macroURI = "vnd.sun.star.script:" + libName + "." + moduleName + ".OnLoad?language=Basic&location=document"; 633cdf0e10cSrcweir final XEventsSupplier eventsSupplier = UnoRuntime.queryInterface(XEventsSupplier.class, databaseDoc); 634cdf0e10cSrcweir eventsSupplier.getEvents().replaceByName("OnLoad", new PropertyValue[] 635cdf0e10cSrcweir { 636cdf0e10cSrcweir new PropertyValue("EventType", 0, "Script", PropertyState.DIRECT_VALUE), 637cdf0e10cSrcweir new PropertyValue("Script", 0, macroURI, PropertyState.DIRECT_VALUE) 638cdf0e10cSrcweir }); 639cdf0e10cSrcweir 640cdf0e10cSrcweir // store the document, and close it 641cdf0e10cSrcweir impl_storeDocument( databaseDoc ); 642cdf0e10cSrcweir impl_closeDocument( databaseDoc ); 643cdf0e10cSrcweir 644cdf0e10cSrcweir // ensure the macro security configuration is "ask the user for document macro execution" 645cdf0e10cSrcweir final int oldSecurityLevel = impl_setMacroSecurityLevel(1); 646cdf0e10cSrcweir 647cdf0e10cSrcweir // load it, again 648cdf0e10cSrcweir m_loadDocState = STATE_LOADING_DOC; 649cdf0e10cSrcweir // expected order of states is: 650cdf0e10cSrcweir // STATE_LOADING_DOC - initialized here 651cdf0e10cSrcweir // STATE_MACRO_EXEC_APPROVED - done in our interaction handler, which auto-approves the execution of macros 652cdf0e10cSrcweir // STATE_ON_LOAD_RECEIVED - done in our callback for the document events 653cdf0e10cSrcweir // 654cdf0e10cSrcweir // In particular, it is important that the interaction handler (which plays the role of the user confirmation 655cdf0e10cSrcweir // here) is called before the OnLoad notification is received - since the latter happens from within 656cdf0e10cSrcweir // a Basic macro which is bound to the OnLoad event of the document. 657cdf0e10cSrcweir 658cdf0e10cSrcweir final String context = "OnLoad"; 659cdf0e10cSrcweir impl_startObservingEvents(context); 660cdf0e10cSrcweir databaseDoc = impl_loadDocument( documentURL, impl_getMacroExecLoadArgs() ); 661cdf0e10cSrcweir impl_stopObservingEvents(m_documentEvents, new String[] 662cdf0e10cSrcweir { 663cdf0e10cSrcweir "OnLoad" 664cdf0e10cSrcweir }, context); 665cdf0e10cSrcweir 666cdf0e10cSrcweir assertEquals("our provided interaction handler was not called", STATE_ON_LOAD_RECEIVED, m_loadDocState); 667cdf0e10cSrcweir 668cdf0e10cSrcweir // restore macro security level 669cdf0e10cSrcweir impl_setMacroSecurityLevel(oldSecurityLevel); 670cdf0e10cSrcweir 671cdf0e10cSrcweir // close the document 672cdf0e10cSrcweir impl_closeDocument(databaseDoc); 673cdf0e10cSrcweir } 674cdf0e10cSrcweir 675cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- 676cdf0e10cSrcweir @Test testGlobalEvents()677cdf0e10cSrcweir public void testGlobalEvents() throws Exception, IOException 678cdf0e10cSrcweir { 679cdf0e10cSrcweir XModel databaseDoc = impl_createEmptyEmbeddedHSQLDocument(); 680cdf0e10cSrcweir final XStorable storeDoc = UnoRuntime.queryInterface(XStorable.class, databaseDoc); 681cdf0e10cSrcweir 682cdf0e10cSrcweir String context, newURL; 683cdf0e10cSrcweir 684cdf0e10cSrcweir // XStorable.store 685cdf0e10cSrcweir final String oldURL = databaseDoc.getURL(); 686cdf0e10cSrcweir context = "store"; 687cdf0e10cSrcweir impl_startObservingEvents(context); 688cdf0e10cSrcweir storeDoc.store(); 689cdf0e10cSrcweir assertEquals("store is not expected to change the document URL", databaseDoc.getURL(), oldURL); 690cdf0e10cSrcweir impl_stopObservingEvents(m_globalEvents, new String[] 691cdf0e10cSrcweir { 692cdf0e10cSrcweir "OnSave", "OnSaveDone" 693cdf0e10cSrcweir }, context); 694cdf0e10cSrcweir 695cdf0e10cSrcweir // XStorable.storeToURL 696cdf0e10cSrcweir context = "storeToURL"; 697cdf0e10cSrcweir impl_startObservingEvents(context); 698cdf0e10cSrcweir storeDoc.storeToURL(createTempFileURL(), new PropertyValue[0]); 699cdf0e10cSrcweir assertEquals("storetoURL is not expected to change the document URL", databaseDoc.getURL(), oldURL); 700cdf0e10cSrcweir impl_stopObservingEvents(m_globalEvents, new String[] 701cdf0e10cSrcweir { 702cdf0e10cSrcweir "OnSaveTo", "OnSaveToDone" 703cdf0e10cSrcweir }, context); 704cdf0e10cSrcweir 705cdf0e10cSrcweir // XStorable.storeAsURL 706cdf0e10cSrcweir newURL = createTempFileURL(); 707cdf0e10cSrcweir context = "storeAsURL"; 708cdf0e10cSrcweir impl_startObservingEvents(context); 709cdf0e10cSrcweir storeDoc.storeAsURL(newURL, new PropertyValue[0]); 710cdf0e10cSrcweir assertEquals("storeAsURL is expected to change the document URL", databaseDoc.getURL(), newURL); 711cdf0e10cSrcweir impl_stopObservingEvents(m_globalEvents, new String[] 712cdf0e10cSrcweir { 713cdf0e10cSrcweir "OnSaveAs", "OnSaveAsDone" 714cdf0e10cSrcweir }, context); 715cdf0e10cSrcweir 716cdf0e10cSrcweir // XModifiable.setModified 717cdf0e10cSrcweir final XModifiable modifyDoc = UnoRuntime.queryInterface(XModifiable.class, databaseDoc); 718cdf0e10cSrcweir context = "setModified"; 719cdf0e10cSrcweir impl_startObservingEvents(context); 720cdf0e10cSrcweir modifyDoc.setModified(true); 721cdf0e10cSrcweir assertEquals("setModified didn't work", modifyDoc.isModified(), true); 722cdf0e10cSrcweir impl_stopObservingEvents(m_globalEvents, new String[] 723cdf0e10cSrcweir { 724cdf0e10cSrcweir "OnModifyChanged" 725cdf0e10cSrcweir }, context); 726cdf0e10cSrcweir 727cdf0e10cSrcweir // XStorable.store, with implicit reset of the "Modified" flag 728cdf0e10cSrcweir context = "store (2)"; 729cdf0e10cSrcweir impl_startObservingEvents(context); 730cdf0e10cSrcweir storeDoc.store(); 731cdf0e10cSrcweir assertEquals("'store' should implicitly reset the modified flag", modifyDoc.isModified(), false); 732cdf0e10cSrcweir impl_stopObservingEvents(m_globalEvents, new String[] 733cdf0e10cSrcweir { 734cdf0e10cSrcweir "OnSave", "OnSaveDone", "OnModifyChanged" 735cdf0e10cSrcweir }, context); 736cdf0e10cSrcweir 737cdf0e10cSrcweir // XComponentLoader.loadComponentFromURL 738cdf0e10cSrcweir newURL = copyToTempFile(databaseDoc.getURL()); 739cdf0e10cSrcweir final XComponentLoader loader = UnoRuntime.queryInterface(XComponentLoader.class, getMSF().createInstance("com.sun.star.frame.Desktop")); 740cdf0e10cSrcweir context = "loadComponentFromURL"; 741cdf0e10cSrcweir impl_startObservingEvents(context); 742cdf0e10cSrcweir databaseDoc = UnoRuntime.queryInterface(XModel.class, loader.loadComponentFromURL(newURL, _BLANK, 0, impl_getDefaultLoadArgs())); 743cdf0e10cSrcweir impl_stopObservingEvents(m_globalEvents, 744cdf0e10cSrcweir new String[] 745cdf0e10cSrcweir { 746cdf0e10cSrcweir "OnLoadFinished", "OnViewCreated", "OnFocus", "OnLoad" 747cdf0e10cSrcweir }, context); 748cdf0e10cSrcweir 749cdf0e10cSrcweir // closing a document by API 750cdf0e10cSrcweir final XCloseable closeDoc = UnoRuntime.queryInterface(XCloseable.class, databaseDoc); 751cdf0e10cSrcweir context = "close (API)"; 752cdf0e10cSrcweir impl_startObservingEvents(context); 753cdf0e10cSrcweir closeDoc.close(true); 754cdf0e10cSrcweir impl_stopObservingEvents(m_globalEvents, 755cdf0e10cSrcweir new String[] 756cdf0e10cSrcweir { 757cdf0e10cSrcweir "OnPrepareUnload", "OnViewClosed", "OnUnload" 758cdf0e10cSrcweir }, context); 759cdf0e10cSrcweir 760cdf0e10cSrcweir // closing a document via UI 761cdf0e10cSrcweir context = "close (UI)"; 762cdf0e10cSrcweir impl_startObservingEvents("prepare for '" + context + "'"); 763cdf0e10cSrcweir databaseDoc = UnoRuntime.queryInterface(XModel.class, loader.loadComponentFromURL(newURL, _BLANK, 0, impl_getDefaultLoadArgs())); 764cdf0e10cSrcweir impl_waitForEvent(m_globalEvents, "OnLoad", 5000); 765cdf0e10cSrcweir // wait for all events to arrive - OnLoad should be the last one 766cdf0e10cSrcweir 767cdf0e10cSrcweir final XDispatchProvider dispatchProvider = UnoRuntime.queryInterface(XDispatchProvider.class, databaseDoc.getCurrentController().getFrame()); 768cdf0e10cSrcweir final URL url = impl_getURL(".uno:CloseDoc"); 769cdf0e10cSrcweir final XDispatch dispatcher = dispatchProvider.queryDispatch(url, "", 0); 770cdf0e10cSrcweir impl_startObservingEvents(context); 771cdf0e10cSrcweir dispatcher.dispatch(url, new PropertyValue[0]); 772cdf0e10cSrcweir impl_stopObservingEvents(m_globalEvents, 773cdf0e10cSrcweir new String[] 774cdf0e10cSrcweir { 775cdf0e10cSrcweir "OnPrepareViewClosing", "OnViewClosed", "OnPrepareUnload", "OnUnload" 776cdf0e10cSrcweir }, context); 777cdf0e10cSrcweir 778cdf0e10cSrcweir // creating a new document 779cdf0e10cSrcweir databaseDoc = impl_createDocument(); 780cdf0e10cSrcweir final XLoadable loadDoc = UnoRuntime.queryInterface(XLoadable.class, databaseDoc); 781cdf0e10cSrcweir context = "initNew"; 782cdf0e10cSrcweir impl_startObservingEvents(context); 783cdf0e10cSrcweir loadDoc.initNew(); 784cdf0e10cSrcweir impl_stopObservingEvents(m_globalEvents, new String[] 785cdf0e10cSrcweir { 786cdf0e10cSrcweir "OnCreate" 787cdf0e10cSrcweir }, context); 788cdf0e10cSrcweir 789cdf0e10cSrcweir impl_startObservingEvents(context + " (cleanup)"); 790cdf0e10cSrcweir impl_closeDocument(databaseDoc); 791cdf0e10cSrcweir impl_waitForEvent(m_globalEvents, "OnUnload", 5000); 792cdf0e10cSrcweir 793cdf0e10cSrcweir // focus changes 794cdf0e10cSrcweir context = "activation"; 795cdf0e10cSrcweir // for this, load a database document ... 796cdf0e10cSrcweir impl_startObservingEvents("prepare for '" + context + "'"); 797cdf0e10cSrcweir databaseDoc = UnoRuntime.queryInterface(XModel.class, loader.loadComponentFromURL(newURL, _BLANK, 0, impl_getDefaultLoadArgs())); 798cdf0e10cSrcweir final int previousOnLoadEventPos = impl_waitForEvent(m_globalEvents, "OnLoad", 5000); 799cdf0e10cSrcweir // ... and another document ... 800cdf0e10cSrcweir final String otherURL = copyToTempFile(databaseDoc.getURL()); 801cdf0e10cSrcweir final XModel otherDoc = UnoRuntime.queryInterface(XModel.class, loader.loadComponentFromURL(otherURL, _BLANK, 0, impl_getDefaultLoadArgs())); 802cdf0e10cSrcweir impl_raise(otherDoc); 803cdf0e10cSrcweir impl_waitForEvent(m_globalEvents, "OnLoad", 5000, previousOnLoadEventPos + 1); 804cdf0e10cSrcweir 805cdf0e10cSrcweir // ... and switch between the two 806cdf0e10cSrcweir impl_startObservingEvents(context); 807cdf0e10cSrcweir impl_raise(databaseDoc); 808cdf0e10cSrcweir impl_stopObservingEvents(m_globalEvents, new String[] 809cdf0e10cSrcweir { 810cdf0e10cSrcweir "OnUnfocus", "OnFocus" 811cdf0e10cSrcweir }, context); 812cdf0e10cSrcweir 813cdf0e10cSrcweir // cleanup 814cdf0e10cSrcweir impl_startObservingEvents("cleanup after '" + context + "'"); 815cdf0e10cSrcweir impl_closeDocument(databaseDoc); 816cdf0e10cSrcweir impl_closeDocument(otherDoc); 817cdf0e10cSrcweir } 818cdf0e10cSrcweir 819cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_getURL(String _completeURL)820cdf0e10cSrcweir private URL impl_getURL(String _completeURL) throws Exception 821cdf0e10cSrcweir { 822cdf0e10cSrcweir final URL[] url = 823cdf0e10cSrcweir { 824cdf0e10cSrcweir new URL() 825cdf0e10cSrcweir }; 826cdf0e10cSrcweir url[0].Complete = _completeURL; 827cdf0e10cSrcweir final XURLTransformer urlTransformer = UnoRuntime.queryInterface(XURLTransformer.class, getMSF().createInstance("com.sun.star.util.URLTransformer")); 828cdf0e10cSrcweir urlTransformer.parseStrict(url); 829cdf0e10cSrcweir return url[0]; 830cdf0e10cSrcweir } 831cdf0e10cSrcweir 832cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_raise(XModel _document)833cdf0e10cSrcweir private void impl_raise(XModel _document) 834cdf0e10cSrcweir { 835cdf0e10cSrcweir final XFrame frame = _document.getCurrentController().getFrame(); 836cdf0e10cSrcweir final XTopWindow topWindow = UnoRuntime.queryInterface(XTopWindow.class, frame.getContainerWindow()); 837cdf0e10cSrcweir topWindow.toFront(); 838cdf0e10cSrcweir } 839cdf0e10cSrcweir 840cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_startObservingEvents(String _context)841cdf0e10cSrcweir private void impl_startObservingEvents(String _context) 842cdf0e10cSrcweir { 843cdf0e10cSrcweir System.out.println(" " + _context + " {"); 844cdf0e10cSrcweir synchronized (m_documentEvents) 845cdf0e10cSrcweir { 846cdf0e10cSrcweir m_documentEvents.clear(); 847cdf0e10cSrcweir } 848cdf0e10cSrcweir synchronized (m_globalEvents) 849cdf0e10cSrcweir { 850cdf0e10cSrcweir m_globalEvents.clear(); 851cdf0e10cSrcweir } 852cdf0e10cSrcweir } 853cdf0e10cSrcweir 854cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_stopObservingEvents(ArrayList _actualEvents, String[] _expectedEvents, String _context)855cdf0e10cSrcweir private void impl_stopObservingEvents(ArrayList _actualEvents, String[] _expectedEvents, String _context) 856cdf0e10cSrcweir { 857cdf0e10cSrcweir try 858cdf0e10cSrcweir { 859cdf0e10cSrcweir synchronized (_actualEvents) 860cdf0e10cSrcweir { 861cdf0e10cSrcweir int actualEventCount = _actualEvents.size(); 862cdf0e10cSrcweir while (actualEventCount < _expectedEvents.length) 863cdf0e10cSrcweir { 864cdf0e10cSrcweir // well, it's possible not all events already arrived, yet - finally, some of them 865cdf0e10cSrcweir // are notified asynchronously 866cdf0e10cSrcweir // So, wait a few seconds. 867cdf0e10cSrcweir try 868cdf0e10cSrcweir { 869cdf0e10cSrcweir _actualEvents.wait(20000); 870cdf0e10cSrcweir } 871cdf0e10cSrcweir catch (InterruptedException ex) 872cdf0e10cSrcweir { 873cdf0e10cSrcweir } 874cdf0e10cSrcweir 875cdf0e10cSrcweir if (actualEventCount == _actualEvents.size()) 876cdf0e10cSrcweir // the above wait was left because of the timeout, *not* because an event 877cdf0e10cSrcweir // arrived. Okay, we won't wait any longer, this is a failure. 878cdf0e10cSrcweir { 879cdf0e10cSrcweir break; 880cdf0e10cSrcweir } 881cdf0e10cSrcweir actualEventCount = _actualEvents.size(); 882cdf0e10cSrcweir } 883cdf0e10cSrcweir 884cdf0e10cSrcweir assertEquals("wrong event count for '" + _context + "'", 885cdf0e10cSrcweir _expectedEvents.length, _actualEvents.size()); 886cdf0e10cSrcweir 887cdf0e10cSrcweir for (int i = 0; i < _expectedEvents.length; ++i) 888cdf0e10cSrcweir { 88907a3d7f1SPedro Giffuni assertEquals("wrong event at position " + (i + 1) + " for '" + _context + "'", 890cdf0e10cSrcweir _expectedEvents[i], _actualEvents.get(i)); 891cdf0e10cSrcweir } 892cdf0e10cSrcweir } 893cdf0e10cSrcweir } 894cdf0e10cSrcweir finally 895cdf0e10cSrcweir { 896cdf0e10cSrcweir System.out.println(" }"); 897cdf0e10cSrcweir } 898cdf0e10cSrcweir } 899cdf0e10cSrcweir 900cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_waitForEvent(ArrayList _eventQueue, String _expectedEvent, int _maxMilliseconds)901cdf0e10cSrcweir int impl_waitForEvent(ArrayList _eventQueue, String _expectedEvent, int _maxMilliseconds) 902cdf0e10cSrcweir { 903cdf0e10cSrcweir return impl_waitForEvent(_eventQueue, _expectedEvent, _maxMilliseconds, 0); 904cdf0e10cSrcweir } 905cdf0e10cSrcweir 906cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- impl_waitForEvent(ArrayList _eventQueue, String _expectedEvent, int _maxMilliseconds, int _firstQueueElementToCheck)907cdf0e10cSrcweir int impl_waitForEvent(ArrayList _eventQueue, String _expectedEvent, int _maxMilliseconds, int _firstQueueElementToCheck) 908cdf0e10cSrcweir { 909cdf0e10cSrcweir synchronized (_eventQueue) 910cdf0e10cSrcweir { 911cdf0e10cSrcweir int waitedMilliseconds = 0; 912cdf0e10cSrcweir 913cdf0e10cSrcweir while (waitedMilliseconds < _maxMilliseconds) 914cdf0e10cSrcweir { 915cdf0e10cSrcweir for (int i = _firstQueueElementToCheck; i < _eventQueue.size(); ++i) 916cdf0e10cSrcweir { 917cdf0e10cSrcweir if (_expectedEvent.equals(_eventQueue.get(i))) 918cdf0e10cSrcweir // found the event in the queue 919cdf0e10cSrcweir { 920cdf0e10cSrcweir return i; 921cdf0e10cSrcweir } 922cdf0e10cSrcweir } 923cdf0e10cSrcweir 924cdf0e10cSrcweir // wait a little, perhaps the event will still arrive 925cdf0e10cSrcweir try 926cdf0e10cSrcweir { 927cdf0e10cSrcweir _eventQueue.wait(500); 928cdf0e10cSrcweir waitedMilliseconds += 500; 929cdf0e10cSrcweir } 930cdf0e10cSrcweir catch (InterruptedException e) 931cdf0e10cSrcweir { 932cdf0e10cSrcweir } 933cdf0e10cSrcweir } 934cdf0e10cSrcweir } 935cdf0e10cSrcweir 936cdf0e10cSrcweir fail("expected event '" + _expectedEvent + "' did not arrive after " + _maxMilliseconds + " milliseconds"); 937cdf0e10cSrcweir return -1; 938cdf0e10cSrcweir } 939cdf0e10cSrcweir 940cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- onDocumentEvent(DocumentEvent _Event)941cdf0e10cSrcweir void onDocumentEvent(DocumentEvent _Event) 942cdf0e10cSrcweir { 943cdf0e10cSrcweir if ("OnTitleChanged".equals(_Event.EventName)) 944cdf0e10cSrcweir // OnTitleChanged events are notified too often. This is known, and accepted. 945cdf0e10cSrcweir // (the deeper reason is that it's diffult to determine, in the DatabaseDocument implementatin, 946cdf0e10cSrcweir // when the title actually changed. In particular, when we do a saveAsURL, and then ask for a 947cdf0e10cSrcweir // title *before* the TitleHelper got the document's OnSaveAsDone event, then the wrong (old) 948cdf0e10cSrcweir // title is obtained. 949cdf0e10cSrcweir { 950cdf0e10cSrcweir return; 951cdf0e10cSrcweir } 952cdf0e10cSrcweir 953cdf0e10cSrcweir if ((_Event.EventName.equals("OnLoad")) && (m_loadDocState != STATE_NOT_STARTED)) 954cdf0e10cSrcweir { 955cdf0e10cSrcweir assertEquals("OnLoad event must come *after* invocation of the interaction handler / user!", 956cdf0e10cSrcweir m_loadDocState, STATE_MACRO_EXEC_APPROVED); 957cdf0e10cSrcweir m_loadDocState = STATE_ON_LOAD_RECEIVED; 958cdf0e10cSrcweir } 959cdf0e10cSrcweir 960cdf0e10cSrcweir synchronized (m_documentEvents) 961cdf0e10cSrcweir { 962cdf0e10cSrcweir m_documentEvents.add(_Event.EventName); 963cdf0e10cSrcweir m_documentEvents.notifyAll(); 964cdf0e10cSrcweir } 965cdf0e10cSrcweir 966cdf0e10cSrcweir System.out.println(" document event: " + _Event.EventName); 967cdf0e10cSrcweir } 968cdf0e10cSrcweir 969cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- documentEventOccured(DocumentEvent _Event)970cdf0e10cSrcweir public void documentEventOccured(DocumentEvent _Event) 971cdf0e10cSrcweir { 972cdf0e10cSrcweir if ("OnTitleChanged".equals(_Event.EventName)) 973cdf0e10cSrcweir // ignore. See onDocumentEvent for a justification 974cdf0e10cSrcweir { 975cdf0e10cSrcweir return; 976cdf0e10cSrcweir } 977cdf0e10cSrcweir 978cdf0e10cSrcweir synchronized (m_globalEvents) 979cdf0e10cSrcweir { 980cdf0e10cSrcweir m_globalEvents.add(_Event.EventName); 981cdf0e10cSrcweir m_globalEvents.notifyAll(); 982cdf0e10cSrcweir } 983cdf0e10cSrcweir 984cdf0e10cSrcweir System.out.println(" global event: " + _Event.EventName); 985cdf0e10cSrcweir } 986cdf0e10cSrcweir 987cdf0e10cSrcweir // -------------------------------------------------------------------------------------------------------- disposing(EventObject _Event)988cdf0e10cSrcweir public void disposing(EventObject _Event) 989cdf0e10cSrcweir { 990cdf0e10cSrcweir // not interested in 991cdf0e10cSrcweir } 992cdf0e10cSrcweir } 993