summaryrefslogtreecommitdiffstats
path: root/framework/qa
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /framework/qa
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'framework/qa')
-rw-r--r--framework/qa/complex/ModuleManager/CheckXModuleManager.java330
-rw-r--r--framework/qa/complex/XTitle/CheckXTitle.java325
-rw-r--r--framework/qa/complex/accelerators/AcceleratorsConfigurationTest.java789
-rw-r--r--framework/qa/complex/accelerators/KeyMapping.java143
-rw-r--r--framework/qa/complex/api_internal/CheckAPI.java180
-rw-r--r--framework/qa/complex/api_internal/api.lst263
-rw-r--r--framework/qa/complex/api_internal/tests.sce2
-rw-r--r--framework/qa/complex/api_internal/worksforme.sce54
-rw-r--r--framework/qa/complex/broken_document/LoadDocument.java108
-rw-r--r--framework/qa/complex/broken_document/TestDocument.java33
-rw-r--r--framework/qa/complex/broken_document/test_documents/dbf.dbf.emf1
-rw-r--r--framework/qa/complex/contextMenuInterceptor/CheckContextMenuInterceptor.java304
-rw-r--r--framework/qa/complex/contextMenuInterceptor/ContextMenuInterceptor.java132
-rw-r--r--framework/qa/complex/contextMenuInterceptor/space-metal.jpgbin0 -> 4313 bytes
-rw-r--r--framework/qa/complex/desktop/DesktopTerminate.java144
-rw-r--r--framework/qa/complex/dispatches/Interceptor.java338
-rw-r--r--framework/qa/complex/dispatches/checkdispatchapi.java401
-rw-r--r--framework/qa/complex/disposing/GetServiceWhileDisposingOffice.java82
-rw-r--r--framework/qa/complex/framework/autosave/AutoSave.java451
-rw-r--r--framework/qa/complex/framework/autosave/ConfigHelper.java94
-rw-r--r--framework/qa/complex/framework/autosave/Protocol.java890
-rw-r--r--framework/qa/complex/framework/recovery/CrashThread.java72
-rw-r--r--framework/qa/complex/framework/recovery/KlickButtonThread.java46
-rw-r--r--framework/qa/complex/framework/recovery/RecoveryTest.java611
-rw-r--r--framework/qa/complex/framework/recovery/RecoveryTools.java301
-rw-r--r--framework/qa/complex/imageManager/CheckImageManager.java201
-rw-r--r--framework/qa/complex/imageManager/_XComponent.java167
-rw-r--r--framework/qa/complex/imageManager/_XImageManager.java105
-rw-r--r--framework/qa/complex/imageManager/_XInitialization.java78
-rw-r--r--framework/qa/complex/imageManager/_XTypeProvider.java89
-rw-r--r--framework/qa/complex/imageManager/_XUIConfiguration.java66
-rw-r--r--framework/qa/complex/imageManager/_XUIConfigurationPersistence.java84
-rw-r--r--framework/qa/complex/loadAllDocuments/CheckXComponentLoader.java526
-rw-r--r--framework/qa/complex/loadAllDocuments/CheckXComponentLoader.props1
-rw-r--r--framework/qa/complex/loadAllDocuments/InteractionHandler.java122
-rw-r--r--framework/qa/complex/loadAllDocuments/StatusIndicator.java145
-rw-r--r--framework/qa/complex/loadAllDocuments/testdocuments/Calc_6.sxcbin0 -> 9547 bytes
-rw-r--r--framework/qa/complex/loadAllDocuments/testdocuments/Writer6.sxwbin0 -> 5754 bytes
-rw-r--r--framework/qa/complex/loadAllDocuments/testdocuments/draw1.sxdbin0 -> 11821 bytes
-rw-r--r--framework/qa/complex/loadAllDocuments/testdocuments/imp1.sxibin0 -> 35135 bytes
-rw-r--r--framework/qa/complex/loadAllDocuments/testdocuments/password_check.sxwbin0 -> 5128 bytes
-rw-r--r--framework/qa/complex/loadAllDocuments/testdocuments/pic.gifbin0 -> 1433 bytes
-rw-r--r--framework/qa/complex/loadAllDocuments/testdocuments/pic.jpgbin0 -> 2651 bytes
-rw-r--r--framework/qa/complex/path_settings/PathSettingsTest.java721
-rw-r--r--framework/qa/complex/path_substitution/PathSubstitutionTest.java294
-rw-r--r--framework/qa/cppunit/data/double-loading.odtbin0 -> 13729 bytes
-rw-r--r--framework/qa/cppunit/data/empty.fodp2
-rw-r--r--framework/qa/cppunit/dispatchtest.cxx219
-rw-r--r--framework/qa/cppunit/loadenv.cxx86
-rw-r--r--framework/qa/cppunit/services.cxx157
-rw-r--r--framework/qa/unoapi/framework.sce51
-rw-r--r--framework/qa/unoapi/knownissues.xcl77
-rw-r--r--framework/qa/unoapi/testdocuments/Calc_Link.sxcbin0 -> 5410 bytes
-rw-r--r--framework/qa/unoapi/testdocuments/Writer_link.sxwbin0 -> 5188 bytes
-rw-r--r--framework/qa/unoapi/testdocuments/XTypeDetection.sxwbin0 -> 4995 bytes
-rw-r--r--framework/qa/unoapi/testdocuments/delete.cfgbin0 -> 2799 bytes
56 files changed, 9285 insertions, 0 deletions
diff --git a/framework/qa/complex/ModuleManager/CheckXModuleManager.java b/framework/qa/complex/ModuleManager/CheckXModuleManager.java
new file mode 100644
index 000000000..1015d00c2
--- /dev/null
+++ b/framework/qa/complex/ModuleManager/CheckXModuleManager.java
@@ -0,0 +1,330 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.ModuleManager;
+
+import com.sun.star.beans.*;
+import com.sun.star.frame.*;
+import com.sun.star.lang.*;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.*;
+import com.sun.star.container.*;
+
+
+
+// ---------- junit imports -----------------
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+import static org.junit.Assert.*;
+
+
+
+/** @short todo document me
+ */
+public class CheckXModuleManager
+{
+
+ // some const
+
+
+ // member
+
+ /** points to the global uno service manager. */
+ private XMultiServiceFactory m_xSmgr = null;
+
+ /** the module manager for testing. */
+ private XModuleManager m_xMM = null;
+
+ /** a special frame used to load documents there. */
+ private XComponentLoader m_xLoader = null;
+
+
+ // test environment
+
+
+ /** @short Create the environment for following tests.
+
+ @descr Use either a component loader from desktop or
+ from frame
+ */
+ @Before public void before()
+ throws java.lang.Exception
+ {
+ // get uno service manager from global test environment
+ m_xSmgr = getMSF();
+
+ // create module manager
+ m_xMM = UnoRuntime.queryInterface(XModuleManager.class, m_xSmgr.createInstance("com.sun.star.frame.ModuleManager"));
+
+ // create desktop instance to create a special frame to load documents there.
+ XFrame xDesktop = UnoRuntime.queryInterface(XFrame.class, m_xSmgr.createInstance("com.sun.star.frame.Desktop"));
+
+ m_xLoader = UnoRuntime.queryInterface(XComponentLoader.class, xDesktop.findFrame("_blank", 0));
+ }
+
+
+ /** @short close the environment.
+ */
+ @After public void after()
+ throws java.lang.Exception
+ {
+ XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, m_xLoader);
+ xClose.close(false);
+
+ m_xLoader = null;
+ m_xMM = null;
+ m_xSmgr = null;
+ }
+
+
+ /** @todo document me
+ */
+ @Test public void checkModuleIdentification()
+ throws java.lang.Exception
+ {
+ impl_identifyModulesBasedOnDocs("com.sun.star.text.TextDocument" );
+ impl_identifyModulesBasedOnDocs("com.sun.star.text.WebDocument" );
+ impl_identifyModulesBasedOnDocs("com.sun.star.text.GlobalDocument" );
+ impl_identifyModulesBasedOnDocs("com.sun.star.formula.FormulaProperties" );
+ impl_identifyModulesBasedOnDocs("com.sun.star.sheet.SpreadsheetDocument" );
+ impl_identifyModulesBasedOnDocs("com.sun.star.drawing.DrawingDocument" );
+ impl_identifyModulesBasedOnDocs("com.sun.star.presentation.PresentationDocument");
+ impl_identifyModulesBasedOnDocs("com.sun.star.sdb.OfficeDatabaseDocument" );
+ // TODO: fails
+ // impl_identifyModulesBasedOnDocs("com.sun.star.chart.ChartDocument" );
+ }
+
+
+ /** @todo document me
+ */
+ @Test public void checkModuleConfigurationReadable()
+ throws java.lang.Exception
+ {
+ }
+
+
+ /** @todo document me
+ */
+ @Test public void checkModuleConfigurationWriteable()
+ throws java.lang.Exception
+ {
+ // modules supporting real documents
+ impl_checkReadOnlyPropsOfModule("com.sun.star.text.TextDocument" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.text.WebDocument" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.text.GlobalDocument" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.formula.FormulaProperties" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.sheet.SpreadsheetDocument" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.drawing.DrawingDocument" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.presentation.PresentationDocument");
+ impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.OfficeDatabaseDocument" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.chart.ChartDocument" );
+
+ // other modules
+ impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.FormDesign" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.TextReportDesign" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.RelationDesign" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.QueryDesign" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.TableDesign" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.sdb.DataSourceBrowser");
+ impl_checkReadOnlyPropsOfModule("com.sun.star.frame.Bibliography" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.script.BasicIDE" );
+ impl_checkReadOnlyPropsOfModule("com.sun.star.frame.StartModule" );
+ }
+
+
+ /** @todo document me
+ */
+ @Test public void checkModuleConfigurationQueries()
+ throws java.lang.Exception
+ {
+ impl_searchModulesByDocumentService("com.sun.star.text.TextDocument" );
+ impl_searchModulesByDocumentService("com.sun.star.text.WebDocument" );
+ impl_searchModulesByDocumentService("com.sun.star.text.GlobalDocument" );
+ impl_searchModulesByDocumentService("com.sun.star.formula.FormulaProperties" );
+ impl_searchModulesByDocumentService("com.sun.star.sheet.SpreadsheetDocument" );
+ impl_searchModulesByDocumentService("com.sun.star.drawing.DrawingDocument" );
+ impl_searchModulesByDocumentService("com.sun.star.presentation.PresentationDocument");
+ impl_searchModulesByDocumentService("com.sun.star.sdb.OfficeDatabaseDocument" );
+ impl_searchModulesByDocumentService("com.sun.star.chart.ChartDocument" );
+ }
+
+
+ /** @todo document me
+ */
+ private void impl_searchModulesByDocumentService(String sDocumentService)
+ throws java.lang.Exception
+ {
+ System.out.println("search modules matching document service '"+sDocumentService+"' ...");
+
+ NamedValue[] lProps = new NamedValue[1];
+ lProps[0] = new NamedValue();
+ lProps[0].Name = "ooSetupFactoryDocumentService";
+ lProps[0].Value = sDocumentService;
+
+ XContainerQuery xMM = UnoRuntime.queryInterface(XContainerQuery.class, m_xMM);
+ XEnumeration xResult = xMM.createSubSetEnumerationByProperties(lProps);
+ while(xResult.hasMoreElements())
+ {
+ PropertyValue[] lModuleProps = (PropertyValue[])AnyConverter.toArray(xResult.nextElement());
+ int c = lModuleProps.length;
+ int i = 0;
+ String sFoundModule = "";
+ String sFoundDocService = "";
+ for (i=0; i<c; ++i)
+ {
+ if (lModuleProps[i].Name.equals("ooSetupFactoryModuleIdentifier"))
+ {
+ sFoundModule = AnyConverter.toString(lModuleProps[i].Value);
+ }
+ if (lModuleProps[i].Name.equals("ooSetupFactoryDocumentService"))
+ {
+ sFoundDocService = AnyConverter.toString(lModuleProps[i].Value);
+ }
+ }
+
+ if (sFoundModule.length() < 1)
+ {
+ fail("Miss module identifier in result set. Returned data are incomplete.");
+ }
+
+ if ( ! sFoundDocService.equals(sDocumentService))
+ {
+ fail("Query returned wrong module '" + sFoundModule + "' with DocumentService='" + sFoundDocService + "'.");
+ }
+
+ System.out.println("Found module '"+sFoundModule+"'.");
+ }
+ }
+
+
+ /** @todo document me
+ */
+ private void impl_identifyModulesBasedOnDocs(String sModule)
+ throws java.lang.Exception
+ {
+ System.out.println("check identification of module '"+sModule+"' ...");
+
+ XNameAccess xMM = UnoRuntime.queryInterface(XNameAccess.class, m_xMM);
+ PropertyValue[] lModuleProps = (PropertyValue[])AnyConverter.toArray(xMM.getByName(sModule));
+ int c = lModuleProps.length;
+ int i = 0;
+ String sFactoryURL = "";
+
+ for (i=0; i<c; ++i)
+ {
+ if (lModuleProps[i].Name.equals("ooSetupFactoryEmptyDocumentURL"))
+ {
+ sFactoryURL = AnyConverter.toString(lModuleProps[i].Value);
+ break;
+ }
+ }
+
+ PropertyValue[] lArgs = new PropertyValue[1];
+ lArgs[0] = new PropertyValue();
+ lArgs[0].Name = "Hidden";
+ lArgs[0].Value = Boolean.TRUE;
+
+ XComponent xModel = m_xLoader.loadComponentFromURL(sFactoryURL, "_self", 0, lArgs);
+ XFrame xFrame = UnoRuntime.queryInterface(XFrame.class, m_xLoader);
+ XController xController = xFrame.getController();
+
+ String sModuleFrame = m_xMM.identify(xFrame );
+ String sModuleController = m_xMM.identify(xController);
+ String sModuleModel = m_xMM.identify(xModel );
+
+ if ( ! sModuleFrame.equals(sModule))
+ {
+ fail("Identification of module '" + sModule + "' failed if frame was used as entry point.");
+ }
+ if ( ! sModuleController.equals(sModule))
+ {
+ fail("Identification of module '" + sModule + "' failed if controller was used as entry point.");
+ }
+ if ( ! sModuleModel.equals(sModule))
+ {
+ fail("Identification of module '" + sModule + "' failed if model was used as entry point.");
+ }
+ }
+
+
+ /** @todo document me
+ */
+ private void impl_checkReadOnlyPropsOfModule(String sModule)
+ throws java.lang.Exception
+ {
+ XNameReplace xWrite = UnoRuntime.queryInterface(XNameReplace.class, m_xMM);
+
+ impl_checkReadOnlyPropOfModule(xWrite, sModule, "ooSetupFactoryDocumentService" , "test");
+ impl_checkReadOnlyPropOfModule(xWrite, sModule, "ooSetupFactoryActualFilter" , "test");
+ impl_checkReadOnlyPropOfModule(xWrite, sModule, "ooSetupFactoryActualTemplateFilter", "test");
+ impl_checkReadOnlyPropOfModule(xWrite, sModule, "ooSetupFactoryEmptyDocumentURL" , "test");
+ }
+
+
+ /** @todo document me
+ */
+ private void impl_checkReadOnlyPropOfModule(XNameReplace xMM ,
+ String sModule ,
+ String sPropName ,
+ Object aPropValue )
+ throws java.lang.Exception
+ {
+ PropertyValue[] lChanges = new PropertyValue[1];
+ lChanges[0] = new PropertyValue();
+ lChanges[0].Name = sPropName;
+ lChanges[0].Value = aPropValue;
+
+ // Note: Exception is expected !
+ System.out.println("check readonly state of module '"+sModule+"' for property '"+sPropName+"' ...");
+ try
+ {
+ xMM.replaceByName(sModule, lChanges);
+ fail("Was able to write READONLY property '"+sPropName+"' of module '"+sModule+"' configuration.");
+ }
+ catch(Throwable ex)
+ {}
+ }
+
+
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass public static void setUpConnection() throws Exception {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+
+ private static final OfficeConnection connection = new OfficeConnection();
+
+}
diff --git a/framework/qa/complex/XTitle/CheckXTitle.java b/framework/qa/complex/XTitle/CheckXTitle.java
new file mode 100644
index 000000000..e20697eba
--- /dev/null
+++ b/framework/qa/complex/XTitle/CheckXTitle.java
@@ -0,0 +1,325 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.XTitle;
+
+import static org.junit.Assert.*;
+import util.utils;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.frame.Desktop;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.frame.XFrame2;
+import com.sun.star.frame.XModel;
+import com.sun.star.frame.XTitle;
+import com.sun.star.frame.XController;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.URLTransformer;
+import com.sun.star.util.XURLTransformer;
+import com.sun.star.util.URL;
+import com.sun.star.frame.XDispatchProvider;
+import com.sun.star.frame.XDispatch;
+
+/** @short Check the interface XTitle
+
+ @descr These tests check in various cases the correctness of
+ the title in the ui window.
+*/
+
+public class CheckXTitle
+{
+
+ // some const
+ private static final String DOCUMENT_TITLE = "documentTitle";
+ private static final String UNO_URL_FOR_PRINT_PREVIEW = ".uno:PrintPreview";
+ private static final String UNO_URL_FOR_CLOSING_PRINT_PREVIEW = ".uno:ClosePreview";
+ private static final String UNO_URL_FOR_CLOSING_DOC = ".uno:CloseWin";
+
+ // members
+
+ /** will be set to xDesktop OR xFrame. */
+ private XComponentLoader m_xLoader = null;
+
+ /** provides uno service manager */
+ private XMultiServiceFactory m_xMSF = null;
+
+ /** used for parsing uno query URLs */
+ private XURLTransformer m_xParser = null;
+
+ // test environment
+ /** @short Create the environment for following tests.
+
+ @descr Use either a component loader from desktop or
+ from frame
+ */
+ @Before public void before() throws Exception
+ {
+ // get uno service manager from global test environment
+ /* points to the global uno service manager. */
+ m_xMSF = getMSF();
+
+ // define default loader
+ m_xLoader = Desktop.create(connection.getComponentContext());
+
+ // get URL parser
+ m_xParser = URLTransformer.create(connection.getComponentContext());
+ }
+
+ /** @short close the environment.
+ */
+ @After public void after() throws Exception
+ {
+ m_xLoader = null;
+ m_xParser = null;
+ m_xMSF = null;
+ }
+
+ private URL parseURL(String unoURL)
+ {
+ URL[] aParseURL = new URL[] { new URL() };
+ aParseURL[0].Complete = unoURL;
+ m_xParser.parseStrict(aParseURL);
+ return aParseURL[0];
+ }
+
+ private void waitUntilDispatcherAvailable(XModel xModel, String unoURL)
+ throws InterruptedException
+ {
+ utils.waitForEventIdle(m_xMSF);
+
+ // On Windows, some events such as focus changes are handled
+ // asynchronously using PostMessage (Windows message queue)
+ // so the previous UI transition may still not have completed yet
+ // even though we called waitForEventIdle.
+ //
+ // Loop a few times until the desired dispatcher is available, which
+ // is a better indication that the UI transition has completed.
+
+ XDispatchProvider xDisProv;
+ XDispatch xDispatcher = null;
+ URL parsed_url = parseURL(unoURL);
+
+ for (int ntries = 1; ntries < 5; ++ntries) {
+ xDisProv = UnoRuntime.queryInterface(
+ XDispatchProvider.class, xModel.getCurrentController() );
+ xDispatcher = xDisProv.queryDispatch(parsed_url, "", 0);
+ if (xDispatcher != null)
+ break;
+ Thread.sleep(250);
+ }
+ assertNotNull("Can not obtain dispatcher for query: " + unoURL, xDispatcher);
+ }
+
+
+ // prepare a uno URL query and dispatch it
+ private void prepareQueryAndDispatch(XDispatchProvider xDisProv, String unoURL)
+ {
+ XDispatch xDispatcher = null;
+ URL parsed_url = parseURL(unoURL);
+
+ xDispatcher = xDisProv.queryDispatch(parsed_url, "", 0);
+ assertNotNull("Can not obtain dispatcher for query: " + unoURL, xDispatcher);
+ xDispatcher.dispatch(parsed_url, null);
+ }
+
+ /** @short checks the numbers displayed in the title
+
+ @descr cycles through default view and print preview
+ and asserts that the title doesn't change.
+
+ disabled until the waitUntilDispatcherAvailable can be replaced
+ */
+ @Test
+ public void checkTitleNumbers() throws Exception
+ {
+ PropertyValue[] lArgs = new PropertyValue[1];
+
+ lArgs[0] = new PropertyValue();
+ lArgs[0].Name = "Hidden";
+ lArgs[0].Value = Boolean.FALSE;
+
+ // load doc
+ XComponent xDoc=null;
+ xDoc = m_xLoader.loadComponentFromURL("private:factory/swriter", "_blank", 0, lArgs);
+ assertNotNull("Could not load temporary document", xDoc);
+
+ XModel xModel = UnoRuntime.queryInterface( XModel.class, xDoc );
+ XController xController = UnoRuntime.queryInterface( XController.class, xModel.getCurrentController() );
+ XTitle xTitle = UnoRuntime.queryInterface( XTitle.class, xModel.getCurrentController().getFrame() );
+ XDispatchProvider xDisProv = null;
+
+ // get window title with ui in default mode
+ String defaultTitle = xTitle.getTitle();
+
+ xDisProv = UnoRuntime.queryInterface( XDispatchProvider.class, xModel.getCurrentController() );
+ prepareQueryAndDispatch( xDisProv, UNO_URL_FOR_PRINT_PREVIEW );
+ waitUntilDispatcherAvailable( xModel, UNO_URL_FOR_CLOSING_PRINT_PREVIEW );
+
+ // get window title with ui in print preview mode
+ String printPreviewTitle = xTitle.getTitle();
+ assertEquals("Title mismatch between default view window title and print preview window title",
+ defaultTitle, printPreviewTitle);
+
+ xDisProv = UnoRuntime.queryInterface( XDispatchProvider.class, xModel.getCurrentController() );
+ prepareQueryAndDispatch( xDisProv, UNO_URL_FOR_CLOSING_PRINT_PREVIEW );
+ waitUntilDispatcherAvailable( xModel, UNO_URL_FOR_CLOSING_DOC );
+
+ //get window title with ui back in default mode
+ String printPreviewClosedTitle = xTitle.getTitle();
+ assertEquals("Title mismatch between default view window title and title after switching from print preview to default view window" ,defaultTitle, printPreviewClosedTitle);
+
+ xDisProv = UnoRuntime.queryInterface( XDispatchProvider.class, xModel.getCurrentController() );
+ prepareQueryAndDispatch( xDisProv, UNO_URL_FOR_CLOSING_DOC );
+
+ xDoc = null;
+ xDisProv = null;
+ }
+
+ /** checks the if SuggestedSaveAsName is displayed in the title */
+ @Test
+ public void checkTitleSuggestedFileName() throws Exception
+ {
+ PropertyValue[] lArgs = new PropertyValue[2];
+
+ lArgs[0] = new PropertyValue();
+ lArgs[0].Name = "Hidden";
+ lArgs[0].Value = Boolean.FALSE;
+ lArgs[1] = new PropertyValue();
+ lArgs[1].Name = "SuggestedSaveAsName";
+ lArgs[1].Value = "suggestme.odt";
+
+ // load doc
+ XComponent xDoc = m_xLoader.loadComponentFromURL("private:factory/swriter", "_blank", 0, lArgs);
+ assertNotNull("Could not load temporary document", xDoc);
+
+ XModel xModel = UnoRuntime.queryInterface( XModel.class, xDoc );
+ XTitle xTitle = UnoRuntime.queryInterface( XTitle.class, xModel.getCurrentController().getFrame() );
+
+ String title = xTitle.getTitle();
+ assertTrue(title.startsWith("suggestme.odt"));
+
+ XDispatchProvider xDisProv = UnoRuntime.queryInterface( XDispatchProvider.class, xModel.getCurrentController() );
+ prepareQueryAndDispatch( xDisProv, UNO_URL_FOR_CLOSING_DOC );
+ }
+
+ /** @short sets frame title and checks for infinite recursion
+
+ @descr sets frame title. then cycles through default and
+ print preview. then closes the window and checks
+ for infinite recursion.
+
+ disabled until the waitUntilDispatcherAvailable can be replaced
+ */
+ @Test
+ public void setTitleAndCheck() throws Exception
+ {
+ PropertyValue[] lArgs = new PropertyValue[1];
+
+ lArgs[0] = new PropertyValue();
+ lArgs[0].Name = "Hidden";
+ lArgs[0].Value = Boolean.FALSE;
+
+ // load doc
+ XComponent xDoc = null;
+ xDoc = m_xLoader.loadComponentFromURL("private:factory/swriter", "_blank", 0, lArgs);
+ assertNotNull("Could not create office document", xDoc);
+ XModel xModel = UnoRuntime.queryInterface( XModel.class, xDoc );
+ XFrame2 xFrame = UnoRuntime.queryInterface( XFrame2.class, xModel.getCurrentController().getFrame() );
+ XDispatchProvider xDisProv = null;
+ // set doc title
+ xFrame.setTitle(DOCUMENT_TITLE);
+
+ // switch to print preview mode
+ xDisProv = UnoRuntime.queryInterface( XDispatchProvider.class, xModel.getCurrentController() );
+ prepareQueryAndDispatch( xDisProv, UNO_URL_FOR_PRINT_PREVIEW );
+ waitUntilDispatcherAvailable( xModel, UNO_URL_FOR_CLOSING_PRINT_PREVIEW );
+
+ // switch back to default mode
+ xDisProv = UnoRuntime.queryInterface( XDispatchProvider.class, xModel.getCurrentController() );
+ prepareQueryAndDispatch( xDisProv, UNO_URL_FOR_CLOSING_PRINT_PREVIEW );
+ waitUntilDispatcherAvailable( xModel, UNO_URL_FOR_CLOSING_DOC );
+
+ // close document
+ xDisProv = UnoRuntime.queryInterface( XDispatchProvider.class, xModel.getCurrentController() );
+ try{
+ prepareQueryAndDispatch( xDisProv, UNO_URL_FOR_CLOSING_DOC );
+ } catch( Exception e ) {
+ fail(e.toString());
+ }
+
+ xDoc = null;
+ xDisProv = null;
+ }
+
+ /** @short checks creation of new empty document with readonly set to true
+
+ @descr creation of a new document with readonly property set
+ to true. this should not fail even if as such it can
+ be seen as a slightly silly thing to do. But existing
+ 3rd-party code depends on it to work.
+ */
+ @Test public void checkLoadingWithReadOnly()
+ {
+ PropertyValue[] lArgs = new PropertyValue[2];
+
+ lArgs[0] = new PropertyValue();
+ lArgs[0].Name = "Hidden";
+ lArgs[0].Value = Boolean.FALSE;
+ lArgs[1] = new PropertyValue();
+ lArgs[1].Name = "ReadOnly";
+ lArgs[1].Value = Boolean.TRUE;
+
+ // load doc
+ XComponent xDoc = null;
+ try{
+ xDoc = m_xLoader.loadComponentFromURL("private:factory/swriter", "_default", 0, lArgs);
+ } catch (Exception e) {
+ }
+ assertNotNull("Creating a new document read with ReadOnly property true should work (even if slightly silly)", xDoc);
+ }
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass
+ public static void setUpConnection() throws Exception
+ {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass
+ public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+ private static final OfficeConnection connection = new OfficeConnection();
+}
diff --git a/framework/qa/complex/accelerators/AcceleratorsConfigurationTest.java b/framework/qa/complex/accelerators/AcceleratorsConfigurationTest.java
new file mode 100644
index 000000000..d8d1c0677
--- /dev/null
+++ b/framework/qa/complex/accelerators/AcceleratorsConfigurationTest.java
@@ -0,0 +1,789 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.accelerators;
+
+import com.sun.star.awt.KeyEvent;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.configuration.theDefaultProvider;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.embed.XStorage;
+import com.sun.star.embed.XTransactedObject;
+import com.sun.star.lang.XInitialization;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.ui.XAcceleratorConfiguration;
+import com.sun.star.ui.XUIConfigurationManager;
+import com.sun.star.ui.XUIConfigurationPersistence;
+import com.sun.star.ui.XUIConfigurationStorage;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.XChangesBatch;
+
+// ---------- junit imports -----------------
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.FileHelper;
+import org.openoffice.test.OfficeConnection;
+import static org.junit.Assert.*;
+
+
+
+/** @short todo document me
+ */
+public class AcceleratorsConfigurationTest
+{
+
+ /** points to the global uno service manager. */
+ private XMultiServiceFactory m_xSmgr = null;
+ /** the accelerator configuration for testing. */
+ private XAcceleratorConfiguration m_xGlobalAccelCfg = null;
+ private XAcceleratorConfiguration m_xModuleAccelCfg = null;
+ private XAcceleratorConfiguration m_xDocumentAccelCfg = null;
+ /** XCS/XCU based accelerator configuration. */
+ private XNameAccess m_xPrimaryKeys = null;
+ private XNameAccess m_xSecondaryKeys = null;
+
+
+ // test environment
+
+ /** @short Create the environment for following tests.
+ */
+ @Before
+ public void before()
+ throws java.lang.Exception
+ {
+ // get uno service manager from global test environment
+ m_xSmgr = getMSF();
+
+ m_xGlobalAccelCfg = UnoRuntime.queryInterface(XAcceleratorConfiguration.class, m_xSmgr.createInstance("com.sun.star.ui.GlobalAcceleratorConfiguration"));
+ m_xModuleAccelCfg = UnoRuntime.queryInterface(XAcceleratorConfiguration.class, m_xSmgr.createInstance("com.sun.star.ui.ModuleAcceleratorConfiguration"));
+ m_xDocumentAccelCfg = UnoRuntime.queryInterface(XAcceleratorConfiguration.class, m_xSmgr.createInstance("com.sun.star.ui.DocumentAcceleratorConfiguration"));
+
+ String sConfigPath = "org.openoffice.Office.Accelerators";
+ boolean bReadOnly = false;
+ XNameAccess xConfig2 = openConfig(sConfigPath, bReadOnly);
+ if (xConfig2 != null)
+ {
+ m_xPrimaryKeys = UnoRuntime.queryInterface(XNameAccess.class, xConfig2.getByName("PrimaryKeys"));
+ m_xSecondaryKeys = UnoRuntime.queryInterface(XNameAccess.class, xConfig2.getByName("SecondaryKeys"));
+ }
+ }
+
+
+ /** @short close the environment.
+ */
+ @After
+ public void after()
+ throws java.lang.Exception
+ {
+ m_xGlobalAccelCfg = null;
+ m_xModuleAccelCfg = null;
+ m_xDocumentAccelCfg = null;
+ m_xSmgr = null;
+ }
+
+
+ /** @todo document me.
+ */
+ @Test
+ public void checkGlobalAccelCfg()
+ throws java.lang.Exception
+ {
+ System.out.println("\n---- check Global accelerator configuration: ----");
+
+ String[] sKeys;
+ XNameAccess xPrimaryAccess = UnoRuntime.queryInterface(XNameAccess.class, m_xPrimaryKeys.getByName("Global"));
+ XNameAccess xSecondaryAccess = UnoRuntime.queryInterface(XNameAccess.class, m_xSecondaryKeys.getByName("Global"));
+
+ sKeys = new String[]
+ {
+ "A_MOD1"
+ };
+ impl_checkGetKeyCommands(m_xGlobalAccelCfg, xPrimaryAccess, sKeys);
+
+ sKeys = new String[]
+ {
+ "PASTE", "X_SHIFT"
+ };
+ String[] sCommands = new String[]
+ {
+ ".uno:test", ".uno:test"
+ };
+ impl_checkSetKeyCommands(m_xGlobalAccelCfg, xPrimaryAccess, xSecondaryAccess, sKeys, sCommands);
+
+ sKeys = new String[]
+ {
+ "C_MOD1", "CUT"
+ };
+ impl_checkRemoveKeyCommands(m_xGlobalAccelCfg, xPrimaryAccess, xSecondaryAccess, sKeys);
+
+ String[] sCommandList = new String[]
+ {
+ ".uno:Paste", ".uno:CloseWin"
+ };
+ impl_checkGetPreferredKeyEventsForCommandList(m_xGlobalAccelCfg, xPrimaryAccess, sCommandList);
+ }
+
+
+ /** @todo document me.
+ */
+ @Test
+ public void checkModuleAccelCfg()
+ throws java.lang.Exception
+ {
+ String[] sModules = new String[]
+ {
+ "com.sun.star.frame.StartModule",
+ "com.sun.star.drawing.DrawingDocument",
+ "com.sun.star.presentation.PresentationDocument",
+ "com.sun.star.sheet.SpreadsheetDocument",
+ "com.sun.star.text.TextDocument",
+ // add other modules here
+ };
+
+ for (int i = 0; i < sModules.length; ++i)
+ {
+ System.out.println("\n---- check accelerator configuration depending module: " + sModules[i] + " ----");
+
+ PropertyValue[] aProp = new PropertyValue[2];
+ aProp[0] = new PropertyValue();
+ aProp[0].Name = "ModuleIdentifier";
+ aProp[0].Value = sModules[i];
+ aProp[1] = new PropertyValue();
+ aProp[1].Name = "Locale";
+ aProp[1].Value = "en-US";
+
+ XInitialization xInit = UnoRuntime.queryInterface(XInitialization.class, m_xModuleAccelCfg);
+ xInit.initialize(aProp); // to fill cache
+
+ XNameAccess xPrimaryModules = UnoRuntime.queryInterface(XNameAccess.class, m_xPrimaryKeys.getByName("Modules"));
+ XNameAccess xSecondaryModules = UnoRuntime.queryInterface(XNameAccess.class, m_xSecondaryKeys.getByName("Modules"));
+
+ String[] sKeys;
+ XNameAccess xPrimaryAccess = UnoRuntime.queryInterface(XNameAccess.class, xPrimaryModules.getByName(sModules[i]));
+ XNameAccess xSecondaryAccess = UnoRuntime.queryInterface(XNameAccess.class, xSecondaryModules.getByName(sModules[i]));
+
+
+ if (sModules[i].equals("com.sun.star.presentation.PresentationDocument"))
+ {
+ sKeys = new String[]
+ {
+ "A_SHIFT_MOD1_MOD2"
+ };
+ }
+ else if (sModules[i].equals("com.sun.star.sheet.SpreadsheetDocument"))
+ {
+ sKeys = new String[]
+ {
+ "B_MOD1"
+ };
+ }
+ else if (sModules[i].equals("com.sun.star.text.TextDocument"))
+ {
+ sKeys = new String[]
+ {
+ "F11_MOD1"
+ };
+ }
+ else
+ {
+ sKeys = new String[]
+ {
+ "A_MOD1"
+ };
+ }
+ impl_checkGetKeyCommands(m_xModuleAccelCfg, xPrimaryAccess, sKeys);
+
+
+ String[] sCommands;
+ if (sModules[i].equals("com.sun.star.presentation.PresentationDocument"))
+ {
+ sKeys = new String[]
+ {
+ "A_SHIFT_MOD1_MOD2"
+ };
+ sCommands = new String[]
+ {
+ ".uno:test"
+ };
+ }
+ else if (sModules[i].equals("com.sun.star.sheet.SpreadsheetDocument"))
+ {
+ sKeys = new String[]
+ {
+ "B_MOD1"
+ };
+ sCommands = new String[]
+ {
+ ".uno:test"
+ };
+ }
+ else if (sModules[i].equals("com.sun.star.text.TextDocument"))
+ {
+ sKeys = new String[]
+ {
+ "F11_MOD1"
+ };
+ sCommands = new String[]
+ {
+ ".uno:test"
+ };
+ }
+ else
+ {
+ sKeys = new String[]
+ {
+ "PASTE"
+ };
+ sCommands = new String[]
+ {
+ ".uno:test"
+ };
+ }
+ impl_checkSetKeyCommands(m_xModuleAccelCfg, xPrimaryAccess, xSecondaryAccess, sKeys, sCommands);
+
+
+ if (sModules[i].equals("com.sun.star.presentation.PresentationDocument"))
+ {
+ sKeys = new String[]
+ {
+ "A_SHIFT_MOD1_MOD2"
+ };
+ }
+ else if (sModules[i].equals("com.sun.star.sheet.SpreadsheetDocument"))
+ {
+ sKeys = new String[]
+ {
+ "F5_SHIFT_MOD1"
+ };
+ }
+ else if (sModules[i].equals("com.sun.star.text.TextDocument"))
+ {
+ sKeys = new String[]
+ {
+ "BACKSPACE_MOD2"
+ };
+ }
+ else
+ {
+ sKeys = new String[]
+ {
+ "C_MOD1"
+ };
+ }
+ impl_checkRemoveKeyCommands(m_xModuleAccelCfg, xPrimaryAccess, xSecondaryAccess, sKeys);
+
+
+ String[] sCommandList;
+ if (sModules[i].equals("com.sun.star.presentation.PresentationDocument"))
+ {
+ sCommandList = new String[]
+ {
+ ".uno:Presentation"
+ };
+ }
+ else if (sModules[i].equals("com.sun.star.sheet.SpreadsheetDocument"))
+ {
+ sCommandList = new String[]
+ {
+ ".uno:InsertCell"
+ };
+ }
+ else if (sModules[i].equals("com.sun.star.text.TextDocument"))
+ {
+ sCommandList = new String[]
+ {
+ ".uno:SelectionModeBlock"
+ };
+ }
+ else
+ {
+ sCommandList = new String[]
+ {
+ ".uno:Cut"
+ };
+ }
+ impl_checkGetPreferredKeyEventsForCommandList(m_xModuleAccelCfg, xPrimaryAccess, sCommandList);
+ }
+ }
+
+
+ /** @todo document me.
+ */
+ @Test
+ public void checkDocumentAccelCfg()
+ throws java.lang.Exception
+ {
+ System.out.println("\n---- check Document accelerator configuration: ----");
+
+ String sDocCfgName;
+
+ String tempDirURL = util.utils.getOfficeTemp/*Dir*/(getMSF());
+ sDocCfgName = FileHelper.appendPath(tempDirURL, "test.cfg");
+ SaveDocumentAcceleratorConfiguration(sDocCfgName);
+
+ LoadDocumentAcceleratorConfiguration(sDocCfgName);
+ }
+
+
+ /** @todo document me.
+ */
+ private void impl_checkGetKeyCommands(XAcceleratorConfiguration xAccelCfg, XNameAccess xAccess, String[] sKeys)
+ throws java.lang.Exception
+ {
+ System.out.println("check getKeyCommands...");
+
+ for (int i = 0; i < sKeys.length; ++i)
+ {
+ if (xAccess.hasByName(sKeys[i]) && getCommandFromConfiguration(xAccess, sKeys[i]).length() > 0)
+ {
+ System.out.println("** get command by " + sKeys[i] + " **");
+
+ String sCmdFromCache = ""; // get a value using XAcceleratorConfiguration API
+ String sCmdFromConfiguration = ""; // get a value using configuration API
+
+ // GET shortcuts/commands using XAcceleratorConfiguration API
+ sCmdFromCache = xAccelCfg.getCommandByKeyEvent(convertShortcut2AWTKey(sKeys[i]));
+ System.out.println(sKeys[i] + "-->" + sCmdFromCache + ", by XAcceleratorConfiguration API");
+
+ // GET shortcuts/commands using configuration API
+ sCmdFromConfiguration = getCommandFromConfiguration(xAccess, sKeys[i]);
+ System.out.println(sKeys[i] + "-->" + sCmdFromConfiguration + ", by configuration API");
+
+ assertTrue("values are different by XAcceleratorConfiguration API and configuration API!", sCmdFromCache.equals(sCmdFromConfiguration));
+
+ String sLocale = "es";
+ setOfficeLocale(sLocale);
+ sCmdFromConfiguration = getCommandFromConfiguration(xAccess, sKeys[i]);
+ System.out.println(sKeys[i] + "-->" + sCmdFromConfiguration + ", by configuration API" + " for locale:" + getOfficeLocale());
+
+ sLocale = "en-US";
+ setOfficeLocale(sLocale); //reset to default locale
+ }
+ else
+ {
+ System.out.println(sKeys[i] + " doesn't exist!");
+ }
+ }
+ }
+
+
+ /** @todo document me.
+ */
+ private void impl_checkSetKeyCommands(XAcceleratorConfiguration xAccelCfg, XNameAccess xPrimaryAccess, XNameAccess xSecondaryAccess, String[] sKeys, String[] sCommands)
+ throws java.lang.Exception
+ {
+ System.out.println("check setKeyCommands...");
+
+ for (int i = 0; i < sKeys.length; ++i)
+ {
+ if (!xPrimaryAccess.hasByName(sKeys[i]) && !xSecondaryAccess.hasByName(sKeys[i]))
+ {
+ xAccelCfg.setKeyEvent(convertShortcut2AWTKey(sKeys[i]), sCommands[i]);
+ xAccelCfg.store();
+ if (xPrimaryAccess.hasByName(sKeys[i]))
+ {
+ System.out.println("add " + sKeys[i] + " successfully!");
+ }
+ else
+ {
+ System.out.println("add " + sKeys[i] + " failed!");
+ }
+ }
+ else if (xPrimaryAccess.hasByName(sKeys[i]))
+ {
+ String sOriginalCommand = getCommandFromConfiguration(xPrimaryAccess, sKeys[i]);
+ if (!sCommands[i].equals(sOriginalCommand))
+ {
+ xAccelCfg.setKeyEvent(convertShortcut2AWTKey(sKeys[i]), sCommands[i]);
+ xAccelCfg.store();
+
+ String sChangedCommand = getCommandFromConfiguration(xPrimaryAccess, sKeys[i]);
+ if (sCommands[i].equals(sChangedCommand))
+ {
+ System.out.println("change " + sKeys[i] + " successfully!");
+ }
+ else
+ {
+ System.out.println("change " + sKeys[i] + " failed!");
+ }
+ }
+ else
+ {
+ System.out.println(sKeys[i] + " already exist!");
+ }
+ }
+ else if (xSecondaryAccess.hasByName(sKeys[i]))
+ {
+ String sOriginalCommand = getCommandFromConfiguration(xSecondaryAccess, sKeys[i]);
+ if (!sCommands[i].equals(sOriginalCommand))
+ {
+ xAccelCfg.setKeyEvent(convertShortcut2AWTKey(sKeys[i]), sCommands[i]);
+ xAccelCfg.store();
+
+ String sChangedCommand = getCommandFromConfiguration(xPrimaryAccess, sKeys[i]);
+ if (sCommands[i].equals(sChangedCommand))
+ {
+ System.out.println("change " + sKeys[i] + " successfully!");
+ }
+ else
+ {
+ System.out.println("change " + sKeys[i] + " failed!");
+ }
+ }
+ else
+ {
+ System.out.println(sKeys[i] + " already exist!");
+ }
+ }
+ }
+ }
+
+
+ /** @todo document me.
+ */
+ private void impl_checkRemoveKeyCommands(XAcceleratorConfiguration xAccelCfg, XNameAccess xPrimaryAccess, XNameAccess xSecondaryAccess, String[] sKeys)
+ throws java.lang.Exception
+ {
+ System.out.println("check removeKeyCommands...");
+
+ for (int i = 0; i < sKeys.length; i++)
+ {
+ if (!xPrimaryAccess.hasByName(sKeys[i]) && !xSecondaryAccess.hasByName(sKeys[i]))
+ {
+ System.out.println(sKeys[i] + " doesn't exist!");
+ }
+ else if (xPrimaryAccess.hasByName(sKeys[i]))
+ {
+ xAccelCfg.removeKeyEvent(convertShortcut2AWTKey(sKeys[i]));
+ xAccelCfg.store();
+ if (!xPrimaryAccess.hasByName(sKeys[i]))
+ {
+ System.out.println("Remove " + sKeys[i] + " successfully!");
+ }
+ else
+ {
+ System.out.println("Remove " + sKeys[i] + " failed!");
+ }
+ }
+ else if (xSecondaryAccess.hasByName(sKeys[i]))
+ {
+ xAccelCfg.removeKeyEvent(convertShortcut2AWTKey(sKeys[i]));
+ xAccelCfg.store();
+ if (!xSecondaryAccess.hasByName(sKeys[i]))
+ {
+ System.out.println("Remove " + sKeys[i] + " successfully!");
+ }
+ else
+ {
+ System.out.println("Remove " + sKeys[i] + " failed!");
+ }
+ }
+ }
+ }
+
+
+ /** @todo document me.
+ */
+ private void impl_checkGetPreferredKeyEventsForCommandList(XAcceleratorConfiguration xAccelCfg, XNameAccess xPrimaryAccess, String[] sCommandList)
+ throws java.lang.Exception
+ {
+ System.out.println("check getPreferredKeyEventsForCommandList...");
+
+ Object[] oKeyEvents = xAccelCfg.getPreferredKeyEventsForCommandList(sCommandList);
+ for (int i = 0; i < oKeyEvents.length; i++)
+ {
+ System.out.println("get preferred key for command " + sCommandList[i] + ":");
+
+ KeyEvent aKeyEvent = (KeyEvent) AnyConverter.toObject(KeyEvent.class, oKeyEvents[i]);
+ String sKeyEvent = convertAWTKey2Shortcut(aKeyEvent);
+ System.out.println(sKeyEvent);
+
+ String sCmdFromConfiguration = getCommandFromConfiguration(xPrimaryAccess, sKeyEvent);
+ System.out.println(sCmdFromConfiguration);
+ if (sCommandList[i].equals(sCmdFromConfiguration))
+ {
+ System.out.println("get preferred key correctly!");
+ }
+ else
+ {
+ System.out.println("get preferred key failed!");
+ }
+ }
+ }
+
+
+ /** @todo document me.
+ */
+ private String getCommandFromConfiguration(XNameAccess xAccess, String sKey)
+ throws java.lang.Exception
+ {
+ String sCommand = "";
+
+ if (xAccess.hasByName(sKey))
+ {
+ XNameAccess xKey = UnoRuntime.queryInterface(XNameAccess.class, xAccess.getByName(sKey));
+ XNameAccess xCommand = UnoRuntime.queryInterface(XNameAccess.class, xKey.getByName("Command"));
+
+ String sLocale = getOfficeLocale();
+ if (xCommand.hasByName(sLocale))
+ {
+ sCommand = UnoRuntime.queryInterface(String.class, xCommand.getByName(sLocale));
+ }
+ }
+
+ return sCommand;
+ }
+
+
+ /** @todo document me.
+ */
+ private void LoadDocumentAcceleratorConfiguration(String sDocCfgName)
+ throws java.lang.Exception
+ {
+ XSingleServiceFactory xStorageFactory = UnoRuntime.queryInterface(XSingleServiceFactory.class, m_xSmgr.createInstance("com.sun.star.embed.StorageFactory"));
+
+ Object aArgs[] = new Object[2];
+ aArgs[0] = sDocCfgName;
+ aArgs[1] = Integer.valueOf(com.sun.star.embed.ElementModes.READ);
+ XStorage xRootStorage = UnoRuntime.queryInterface(XStorage.class, xStorageFactory.createInstanceWithArguments(aArgs));
+
+ XStorage xUIConfig = xRootStorage.openStorageElement("Configurations2", com.sun.star.embed.ElementModes.READ);
+
+ PropertyValue aProp = new PropertyValue();
+ aProp.Name = "DocumentRoot";
+ aProp.Value = xUIConfig;
+ Object[] lArgs = new Object[1];
+ lArgs[0] = aProp;
+
+ XInitialization xInit = UnoRuntime.queryInterface(XInitialization.class, m_xDocumentAccelCfg);
+ xInit.initialize(lArgs);
+
+ // TODO: throws css::container::NoSuchElementException
+ try
+ {
+ String test = m_xDocumentAccelCfg.getCommandByKeyEvent(convertShortcut2AWTKey("F2"));
+ System.out.println(test);
+ }
+ catch(com.sun.star.container.NoSuchElementException e)
+ {
+ System.out.println("NoSuchElementException caught: " + e.getMessage());
+ }
+ }
+
+
+ /** @todo document me.
+ */
+ private void SaveDocumentAcceleratorConfiguration(String sDocCfgName)
+ throws java.lang.Exception
+ {
+ XSingleServiceFactory xStorageFactory = UnoRuntime.queryInterface(XSingleServiceFactory.class, m_xSmgr.createInstance("com.sun.star.embed.StorageFactory"));
+
+ Object aArgs[] = new Object[2];
+ aArgs[0] = sDocCfgName;
+ aArgs[1] = Integer.valueOf(com.sun.star.embed.ElementModes.WRITE);
+ XStorage xRootStorage = UnoRuntime.queryInterface(XStorage.class, xStorageFactory.createInstanceWithArguments(aArgs));
+
+ XStorage xUIConfig = xRootStorage.openStorageElement("Configurations2", com.sun.star.embed.ElementModes.WRITE);
+
+ XUIConfigurationManager xCfgMgr = UnoRuntime.queryInterface(XUIConfigurationManager.class, m_xSmgr.createInstance("com.sun.star.ui.UIConfigurationManager"));
+
+ XUIConfigurationStorage xUICfgStore = UnoRuntime.queryInterface(XUIConfigurationStorage.class, xCfgMgr);
+ xUICfgStore.setStorage(xUIConfig);
+
+ XPropertySet xUIConfigProps = UnoRuntime.queryInterface(XPropertySet.class, xUIConfig);
+ xUIConfigProps.setPropertyValue("MediaType", "application/vnd.sun.xml.ui.configuration");
+
+ if (xCfgMgr != null)
+ {
+ XAcceleratorConfiguration xTargetAccMgr = UnoRuntime.queryInterface(XAcceleratorConfiguration.class, xCfgMgr.getShortCutManager());
+ XUIConfigurationPersistence xCommit1 = UnoRuntime.queryInterface(XUIConfigurationPersistence.class, xTargetAccMgr);
+ XUIConfigurationPersistence xCommit2 = UnoRuntime.queryInterface(XUIConfigurationPersistence.class, xCfgMgr);
+ xCommit1.store();
+ xCommit2.store();
+
+ XTransactedObject xCommit3 = UnoRuntime.queryInterface(XTransactedObject.class, xRootStorage);
+ xCommit3.commit();
+ }
+ }
+
+
+ /** @todo document me.
+ */
+ private com.sun.star.awt.KeyEvent convertShortcut2AWTKey(String sShortcut)
+ throws java.lang.Exception
+ {
+ com.sun.star.awt.KeyEvent aKeyEvent = new com.sun.star.awt.KeyEvent();
+ KeyMapping aKeyMapping = new KeyMapping();
+ String[] sShortcutSplits = sShortcut.split("_");
+
+ aKeyEvent.KeyCode = aKeyMapping.mapIdentifier2Code(sShortcutSplits[0]);
+ for (int i = 1; i < sShortcutSplits.length; i++)
+ {
+ if (sShortcutSplits[i].equals("SHIFT"))
+ {
+ aKeyEvent.Modifiers |= com.sun.star.awt.KeyModifier.SHIFT;
+ }
+ else if (sShortcutSplits[i].equals("MOD1"))
+ {
+ aKeyEvent.Modifiers |= com.sun.star.awt.KeyModifier.MOD1;
+ }
+ else if (sShortcutSplits[i].equals("MOD2"))
+ {
+ aKeyEvent.Modifiers |= com.sun.star.awt.KeyModifier.MOD2;
+ }
+ }
+
+ return aKeyEvent;
+ }
+
+
+ /** @todo document me.
+ */
+ private String convertAWTKey2Shortcut(com.sun.star.awt.KeyEvent aKeyEvent)
+ throws java.lang.Exception
+ {
+ String sShortcut;
+
+ KeyMapping aKeyMapping = new KeyMapping();
+ sShortcut = aKeyMapping.mapCode2Identifier(aKeyEvent.KeyCode);
+
+ if ((aKeyEvent.Modifiers & com.sun.star.awt.KeyModifier.SHIFT) == com.sun.star.awt.KeyModifier.SHIFT)
+ {
+ sShortcut += "_SHIFT";
+ }
+ if ((aKeyEvent.Modifiers & com.sun.star.awt.KeyModifier.MOD1) == com.sun.star.awt.KeyModifier.MOD1)
+ {
+ sShortcut += "_MOD1";
+ }
+ if ((aKeyEvent.Modifiers & com.sun.star.awt.KeyModifier.MOD2) == com.sun.star.awt.KeyModifier.MOD2)
+ {
+ sShortcut += "_MOD2";
+ }
+
+ return sShortcut;
+ }
+
+
+ /** @todo document me.
+ */
+ private String getOfficeLocale()
+ throws java.lang.Exception
+ {
+ String sLocale = "";
+
+ String sConfigPath = "org.openoffice.Setup";
+ boolean bReadOnly = true;
+ XNameAccess xRootConfig = openConfig(sConfigPath, bReadOnly);
+
+ if (xRootConfig != null)
+ {
+ XNameAccess xLocale = UnoRuntime.queryInterface(XNameAccess.class, xRootConfig.getByName("L10N"));
+ XPropertySet xSet = UnoRuntime.queryInterface(XPropertySet.class, xLocale);
+ sLocale = (String) xSet.getPropertyValue("ooLocale");
+ }
+
+ return sLocale;
+ }
+
+
+ /** @todo document me.
+ */
+ private void setOfficeLocale(String sLocale)
+ throws java.lang.Exception
+ {
+ String sConfigPath = "org.openoffice.Setup";
+ boolean bReadOnly = false;
+ XNameAccess xRootConfig = openConfig(sConfigPath, bReadOnly);
+
+ if (xRootConfig != null)
+ {
+ XNameAccess xLocale = UnoRuntime.queryInterface(XNameAccess.class, xRootConfig.getByName("L10N"));
+ XPropertySet xSet = UnoRuntime.queryInterface(XPropertySet.class, xLocale);
+ xSet.setPropertyValue("ooLocale", sLocale);
+ XChangesBatch xBatch = UnoRuntime.queryInterface(XChangesBatch.class, xRootConfig);
+ xBatch.commitChanges();
+ }
+ }
+
+
+ /** @todo document me.
+ */
+ private XNameAccess openConfig(
+ String sConfigPath,
+ boolean bReadOnly)
+ throws java.lang.Exception
+ {
+ XMultiServiceFactory xConfigRoot = theDefaultProvider.get(
+ connection.getComponentContext());
+
+ PropertyValue[] lParams = new PropertyValue[2];
+ lParams[0] = new PropertyValue();
+ lParams[0].Name = "nodepath";
+ lParams[0].Value = sConfigPath;
+
+ lParams[1] = new PropertyValue();
+ lParams[1].Name = "locale";
+ lParams[1].Value = "*";
+
+ Object aConfig;
+ if (bReadOnly)
+ {
+ aConfig = xConfigRoot.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", lParams);
+ }
+ else
+ {
+ aConfig = xConfigRoot.createInstanceWithArguments("com.sun.star.configuration.ConfigurationUpdateAccess", lParams);
+ }
+
+ XNameAccess xConfig = UnoRuntime.queryInterface(XNameAccess.class, aConfig);
+
+ if (xConfig == null)
+ {
+ throw new com.sun.star.uno.Exception("Could not open configuration \"" + sConfigPath + "\"");
+ }
+
+ return xConfig;
+ }
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass
+ public static void setUpConnection() throws Exception
+ {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass
+ public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+ private static final OfficeConnection connection = new OfficeConnection();
+}
diff --git a/framework/qa/complex/accelerators/KeyMapping.java b/framework/qa/complex/accelerators/KeyMapping.java
new file mode 100644
index 000000000..fd3637ba2
--- /dev/null
+++ b/framework/qa/complex/accelerators/KeyMapping.java
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.accelerators;
+
+import java.util.HashMap;
+
+class KeyIdentifierInfo
+{
+ protected String sIdentifier;
+ protected Short nCode;
+
+ KeyIdentifierInfo(String sID, Short nC)
+ {
+ sIdentifier = sID;
+ nCode = nC;
+ }
+}
+
+class IdentifierHashMap extends HashMap<String,Short>
+{
+}
+
+class CodeHashMap extends HashMap<Short,String>
+{
+}
+
+public class KeyMapping
+{
+ private final IdentifierHashMap aIdentifierHashMap;
+ private final CodeHashMap aCodeHashMap;
+
+ public KeyMapping()
+ {
+ KeyIdentifierInfo[] aInfoMap = {
+ new KeyIdentifierInfo("0", Short.valueOf(com.sun.star.awt.Key.NUM0)),
+ new KeyIdentifierInfo("1", Short.valueOf(com.sun.star.awt.Key.NUM1)),
+ new KeyIdentifierInfo("2", Short.valueOf(com.sun.star.awt.Key.NUM2)),
+ new KeyIdentifierInfo("3", Short.valueOf(com.sun.star.awt.Key.NUM3)),
+ new KeyIdentifierInfo("4", Short.valueOf(com.sun.star.awt.Key.NUM4)),
+ new KeyIdentifierInfo("5", Short.valueOf(com.sun.star.awt.Key.NUM5)),
+ new KeyIdentifierInfo("6", Short.valueOf(com.sun.star.awt.Key.NUM6)),
+ new KeyIdentifierInfo("7", Short.valueOf(com.sun.star.awt.Key.NUM7)),
+ new KeyIdentifierInfo("8", Short.valueOf(com.sun.star.awt.Key.NUM8)),
+ new KeyIdentifierInfo("9", Short.valueOf(com.sun.star.awt.Key.NUM9)),
+ new KeyIdentifierInfo("A", Short.valueOf(com.sun.star.awt.Key.A)),
+ new KeyIdentifierInfo("B", Short.valueOf(com.sun.star.awt.Key.B)),
+ new KeyIdentifierInfo("C", Short.valueOf(com.sun.star.awt.Key.C)),
+ new KeyIdentifierInfo("D", Short.valueOf(com.sun.star.awt.Key.D)),
+ new KeyIdentifierInfo("E", Short.valueOf(com.sun.star.awt.Key.E)),
+ new KeyIdentifierInfo("F", Short.valueOf(com.sun.star.awt.Key.F)),
+ new KeyIdentifierInfo("G", Short.valueOf(com.sun.star.awt.Key.G)),
+ new KeyIdentifierInfo("H", Short.valueOf(com.sun.star.awt.Key.H)),
+ new KeyIdentifierInfo("I", Short.valueOf(com.sun.star.awt.Key.I)),
+ new KeyIdentifierInfo("J", Short.valueOf(com.sun.star.awt.Key.J)),
+ new KeyIdentifierInfo("K", Short.valueOf(com.sun.star.awt.Key.K)),
+ new KeyIdentifierInfo("L", Short.valueOf(com.sun.star.awt.Key.L)),
+ new KeyIdentifierInfo("M", Short.valueOf(com.sun.star.awt.Key.M)),
+ new KeyIdentifierInfo("N", Short.valueOf(com.sun.star.awt.Key.N)),
+ new KeyIdentifierInfo("O", Short.valueOf(com.sun.star.awt.Key.O)),
+ new KeyIdentifierInfo("P", Short.valueOf(com.sun.star.awt.Key.P)),
+ new KeyIdentifierInfo("Q", Short.valueOf(com.sun.star.awt.Key.Q)),
+ new KeyIdentifierInfo("R", Short.valueOf(com.sun.star.awt.Key.R)),
+ new KeyIdentifierInfo("S", Short.valueOf(com.sun.star.awt.Key.S)),
+ new KeyIdentifierInfo("T", Short.valueOf(com.sun.star.awt.Key.T)),
+ new KeyIdentifierInfo("U", Short.valueOf(com.sun.star.awt.Key.U)),
+ new KeyIdentifierInfo("V", Short.valueOf(com.sun.star.awt.Key.V)),
+ new KeyIdentifierInfo("W", Short.valueOf(com.sun.star.awt.Key.W)),
+ new KeyIdentifierInfo("X", Short.valueOf(com.sun.star.awt.Key.X)),
+ new KeyIdentifierInfo("Y", Short.valueOf(com.sun.star.awt.Key.Y)),
+ new KeyIdentifierInfo("Z", Short.valueOf(com.sun.star.awt.Key.Z)),
+ new KeyIdentifierInfo("F1", Short.valueOf(com.sun.star.awt.Key.F1)),
+ new KeyIdentifierInfo("F2", Short.valueOf(com.sun.star.awt.Key.F2)),
+ new KeyIdentifierInfo("F3", Short.valueOf(com.sun.star.awt.Key.F3)),
+ new KeyIdentifierInfo("F4", Short.valueOf(com.sun.star.awt.Key.F4)),
+ new KeyIdentifierInfo("F5", Short.valueOf(com.sun.star.awt.Key.F5)),
+ new KeyIdentifierInfo("F6", Short.valueOf(com.sun.star.awt.Key.F6)),
+ new KeyIdentifierInfo("F7", Short.valueOf(com.sun.star.awt.Key.F7)),
+ new KeyIdentifierInfo("F8", Short.valueOf(com.sun.star.awt.Key.F8)),
+ new KeyIdentifierInfo("F9", Short.valueOf(com.sun.star.awt.Key.F9)),
+ new KeyIdentifierInfo("F10", Short.valueOf(com.sun.star.awt.Key.F10)),
+ new KeyIdentifierInfo("F11", Short.valueOf(com.sun.star.awt.Key.F11)),
+ new KeyIdentifierInfo("F12", Short.valueOf(com.sun.star.awt.Key.F12)),
+ new KeyIdentifierInfo("DOWN", Short.valueOf(com.sun.star.awt.Key.DOWN)),
+ new KeyIdentifierInfo("UP", Short.valueOf(com.sun.star.awt.Key.UP)),
+ new KeyIdentifierInfo("LEFT", Short.valueOf(com.sun.star.awt.Key.LEFT)),
+ new KeyIdentifierInfo("RIGHT", Short.valueOf(com.sun.star.awt.Key.RIGHT)),
+ new KeyIdentifierInfo("HOME", Short.valueOf(com.sun.star.awt.Key.HOME)),
+ new KeyIdentifierInfo("END", Short.valueOf(com.sun.star.awt.Key.END)),
+ new KeyIdentifierInfo("PAGEUP", Short.valueOf(com.sun.star.awt.Key.PAGEUP)),
+ new KeyIdentifierInfo("PAGEDOWN", Short.valueOf(com.sun.star.awt.Key.PAGEDOWN)),
+ new KeyIdentifierInfo("RETURN", Short.valueOf(com.sun.star.awt.Key.RETURN)),
+ new KeyIdentifierInfo("ESCAPE", Short.valueOf(com.sun.star.awt.Key.ESCAPE)),
+ new KeyIdentifierInfo("TAB", Short.valueOf(com.sun.star.awt.Key.TAB)),
+ new KeyIdentifierInfo("BACKSPACE", Short.valueOf(com.sun.star.awt.Key.BACKSPACE)),
+ new KeyIdentifierInfo("SPACE", Short.valueOf(com.sun.star.awt.Key.SPACE)),
+ new KeyIdentifierInfo("INSERT", Short.valueOf(com.sun.star.awt.Key.INSERT)),
+ new KeyIdentifierInfo("DELETE", Short.valueOf(com.sun.star.awt.Key.DELETE)),
+ new KeyIdentifierInfo("ADD", Short.valueOf(com.sun.star.awt.Key.ADD)),
+ new KeyIdentifierInfo("SUBTRACT", Short.valueOf(com.sun.star.awt.Key.SUBTRACT)),
+ new KeyIdentifierInfo("MULTIPLY", Short.valueOf(com.sun.star.awt.Key.MULTIPLY)),
+ new KeyIdentifierInfo("DIVIDE", Short.valueOf(com.sun.star.awt.Key.DIVIDE)),
+ new KeyIdentifierInfo("CUT", Short.valueOf(com.sun.star.awt.Key.CUT)),
+ new KeyIdentifierInfo("COPY", Short.valueOf(com.sun.star.awt.Key.COPY)),
+ new KeyIdentifierInfo("PASTE", Short.valueOf(com.sun.star.awt.Key.PASTE)),
+ new KeyIdentifierInfo("UNDO", Short.valueOf(com.sun.star.awt.Key.UNDO)),
+ new KeyIdentifierInfo("REPEAT", Short.valueOf(com.sun.star.awt.Key.REPEAT))
+ };
+
+ aIdentifierHashMap = new IdentifierHashMap();
+ aCodeHashMap = new CodeHashMap();
+ for (int i = 0; i<aInfoMap.length; i++)
+ {
+ aIdentifierHashMap.put(aInfoMap[i].sIdentifier, aInfoMap[i].nCode);
+ aCodeHashMap.put(aInfoMap[i].nCode, aInfoMap[i].sIdentifier);
+ }
+ }
+
+ public short mapIdentifier2Code(String sIdentifier)
+ {
+ return aIdentifierHashMap.get(sIdentifier).shortValue();
+ }
+
+ public String mapCode2Identifier(short nCode)
+ {
+ return aCodeHashMap.get(Short.valueOf(nCode));
+ }
+}
diff --git a/framework/qa/complex/api_internal/CheckAPI.java b/framework/qa/complex/api_internal/CheckAPI.java
new file mode 100644
index 000000000..cd17f4a69
--- /dev/null
+++ b/framework/qa/complex/api_internal/CheckAPI.java
@@ -0,0 +1,180 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.api_internal;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import helper.OfficeProvider;
+import helper.ProcessHandler;
+
+import java.io.UnsupportedEncodingException;
+import java.util.StringTokenizer;
+import lib.TestParameters;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+
+import com.sun.star.beans.NamedValue;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.task.XJob;
+import com.sun.star.uno.UnoRuntime;
+
+/**
+ * This test executes the API tests internally in LibreOffice. Prerequisite is
+ * that an OOoRunner.jar is registered inside of LibreOffice. Adjust the joblist
+ * inside of the CheckAPI.props to determine which tests will be executed.
+ */
+public class CheckAPI {
+
+ /**
+ * The test parameters
+ */
+ private TestParameters param = null;
+
+ /**
+ *
+ */
+ @Before public void before()
+ {
+ param = new TestParameters();
+ }
+ /**
+ * Execute the API tests inside of the Office. If the Office crashes, it
+ * will be restarted and the job will continue after the one that caused the crash.
+ */
+ @Test public void checkAPI() {
+ System.out.println("Start with test");
+ // if test is idle for 5 minutes, assume that it hangs and kill it.
+ XMultiServiceFactory xMSF = getMSF();
+ Object oObj = null;
+ try {
+ oObj = xMSF.createInstance("org.openoffice.RunnerService");
+ }
+ catch(com.sun.star.uno.Exception e) {
+ fail("Could not create Instance of 'org.openoffice.RunnerService'");
+ }
+ assertNotNull("Cannot create 'org.openoffice.RunnerService'", oObj);
+
+ // get the parameters for the internal test
+ final NamedValue[] internalParams = new NamedValue[3];
+ internalParams[0] = new NamedValue();
+ internalParams[0].Name = "-OutProducer";
+ internalParams[0].Value = "stats.SimpleFileOutProducer";
+ internalParams[1] = new NamedValue();
+ internalParams[1].Name = "-OutputPath";
+ internalParams[1].Value = "/dev/null";
+
+ // do we have test jobs?
+ final PropertyValue[] props = new PropertyValue[1];
+ props[0] = new PropertyValue();
+ props[0].Value = "sw.SwXTextTable";
+
+ System.out.println("Props length: "+ props.length);
+ for (int i=0; i<props.length; i++) {
+ XJob xJob = UnoRuntime.queryInterface(XJob.class, oObj);
+ internalParams[2] = new NamedValue();
+ internalParams[2].Name = "-o";
+ internalParams[2].Value = props[i].Value;
+ System.out.println("Executing: " + (String)props[i].Value);
+
+ String erg = null;
+
+ try {
+ erg = (String)xJob.execute(internalParams);
+ }
+ catch(Throwable t) {
+ // restart and go on with test!!
+ t.printStackTrace();
+ fail("Test run '" + (String)props[i].Value +"' could not be executed: Office crashed and is killed!");
+ xMSF = null;
+ ProcessHandler handler = (ProcessHandler)param.get("AppProvider");
+ handler.kill();
+ util.utils.pause(10000);
+ OfficeProvider op = new OfficeProvider();
+ try {
+ xMSF = (XMultiServiceFactory)op.getManager(param);
+ param.put("ServiceFactory",xMSF);
+
+ oObj = xMSF.createInstance("org.openoffice.RunnerService");
+ }
+ catch(com.sun.star.uno.Exception e) {
+ fail("Could not create Instance of 'org.openoffice.RunnerService'");
+ }
+ catch (UnsupportedEncodingException e) {
+ fail("Could not get Manager'");
+ }
+ }
+ System.out.println(erg);
+ String processedErg = parseResult(erg);
+ assertTrue("Run '" + (String)props[i].Value + "' has result '" + processedErg + "'", processedErg == null);
+ }
+ }
+
+ private String parseResult(String erg) {
+ String lineFeed = System.getProperty("line.separator");
+ String processedErg = null;
+ if (erg != null) {
+ StringTokenizer token = new StringTokenizer(erg, lineFeed);
+ String previousLine = null;
+ while ( token.hasMoreTokens() ) {
+ String line = token.nextToken();
+ // got a failure!
+ if ( line.indexOf("FAILED") != -1 ) {
+ processedErg = (processedErg == null)?"":processedErg + ";";
+ processedErg += previousLine + ":" + line;
+ }
+ if ( line.startsWith("Execute:") ) {
+ previousLine = line;
+ }
+ else {
+ previousLine += " " + line;
+ }
+ }
+ }
+ return processedErg;
+ }
+
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass public static void setUpConnection() throws Exception {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+
+ private static final OfficeConnection connection = new OfficeConnection();
+
+}
+
+
diff --git a/framework/qa/complex/api_internal/api.lst b/framework/qa/complex/api_internal/api.lst
new file mode 100644
index 000000000..096e10dc8
--- /dev/null
+++ b/framework/qa/complex/api_internal/api.lst
@@ -0,0 +1,263 @@
+job1=cached.CachedContentResultSetFactory
+job2=cached.CachedContentResultSetStubFactory
+job3=cached.CachedDynamicResultSetFactory
+job4=cached.CachedDynamicResultSetStubFactory
+job5=cmdmail.SimpleCommandMail
+job6=corereflection.uno.CoreReflection
+job7=dbaccess.DBContentLoader
+job8=dbaccess.OCommandDefinition
+job9=dbaccess.ODatabaseContext
+job10=dbaccess.ODatabaseSource
+job11=dbaccess.ODatasourceAdministrationDialog
+job12=dbaccess.OInteractionHandler
+job13=dbaccess.OQueryDesign
+job14=dbaccess.OSQLMessageDialog
+job15=dbaccess.SbaXGridControl
+job16=fileacc.SimpleFileAccess
+job17=fop.FolderPicker
+job18=forms.OButtonControl
+job19=forms.OCheckBoxControl
+job20=forms.OCheckBoxModel
+job21=forms.OComboBoxControl
+job22=forms.OComboBoxModel
+job23=forms.OCurrencyControl
+job24=forms.OCurrencyModel
+job25=forms.ODateControl
+job26=forms.ODateModel
+job27=forms.OEditControl
+job28=forms.OFileControlModel
+job29=forms.OFixedTextModel
+job30=forms.OFormattedControl
+job31=forms.OFormattedFieldWrapper
+job32=forms.OGroupBoxControl
+job33=forms.OGroupBoxModel
+job34=forms.OHiddenModel
+job35=forms.OImageButtonControl
+job36=forms.OImageButtonModel
+job37=forms.OImageControlControl
+job38=forms.OImageControlModel
+job39=forms.OListBoxControl
+job40=forms.OListBoxModel
+job41=forms.ONumericControl
+job42=forms.ONumericModel
+job43=forms.OPatternControl
+job44=forms.OPatternModel
+job45=forms.ORadioButtonControl
+job46=forms.ORadioButtonModel
+job47=forms.OTimeControl
+job48=forms.OTimeModel
+job49=fwk.MailToDispatcher
+job50=fwk.ServiceHandler
+job51=fwl.PathSettings
+job52=i18n.ChapterCollator
+job53=i18n.Collator
+job54=i18n.LocaleData
+job55=i18n.NumberFormatCodeMapper
+job56=i18n.TextSearch
+job57=implreg.uno.ImplementationRegistration
+job58=introspection.uno.Introspection
+job59=invocadapt.uno.InvocationAdapterFactory
+job60=invocation.uno.Invocation
+job61=javavm.uno.JavaVirtualMachine
+job62=lng.LinguProps
+job63=mcnttype.MimeContentTypeFactory
+job64=namingservice.uno.NamingService
+job65=nestedreg.uno.NestedRegistry
+job66=proxyfac.uno.ProxyFactory
+job68=regtypeprov.uno.RegistryTypeDescriptionProvider
+job69=remotebridge.uno.various
+job70=sc.AccessibleEditableTextPara_HeaderFooter
+job71=sc.ScAccessibleCell
+job72=sc.ScAccessiblePageHeader
+job73=sc.ScAccessiblePreviewTable
+job74=sc.ScAccessibleSpreadsheet
+job78=sc.ScAutoFormatFieldObj
+job88=sc.ScDatabaseRangeObj
+job126=sc.ScSheetLinkObj
+job132=sc.ScStyleObj
+job140=sc.XMLContentExporter
+job141=sc.XMLContentImporter
+job142=sc.XMLImporter
+job143=sc.XMLMetaExporter
+job144=sc.XMLMetaImporter
+job145=sc.XMLSettingsExporter
+job146=sc.XMLSettingsImporter
+job147=sc.XMLStylesExporter
+job148=sc.XMLStylesImporter
+job149=sd.AccessibleDrawDocumentView
+job150=sd.AccessibleOutlineView
+job151=sd.AccessibleSlideView
+job152=sd.SdDocLinkTargets
+job153=sd.SdDrawPagesAccess
+job154=sd.SdLayer
+job155=sd.SdLayerManager
+job156=sd.SdMasterPagesAccess
+job157=sd.SdXCustomPresentation
+job158=sd.SdXPresentation
+job159=servicemgr.uno.OServiceManager
+job160=sfx.SfxMacroLoader
+job161=simplereg.uno.SimpleRegistry
+job162=sm.SmEditAccessible
+job163=sm.SmModel
+job164=sm.XMLExporter
+job165=sm.XMLMetaExporter
+job166=sm.XMLSettingsExporter
+job167=sm.XMLSettingsImporter
+job168=srtrs.SortedDynamicResultSetFactory
+job169=streams.uno.DataInputStream
+job170=streams.uno.DataOutputStream
+job171=streams.uno.MarkableInputStream
+job172=streams.uno.MarkableOutputStream
+job173=streams.uno.ObjectInputStream
+job174=streams.uno.ObjectOutputStream
+job175=streams.uno.Pipe
+job176=streams.uno.Pump
+job177=svtools.AccessibleBrowseBoxHeaderBar
+job178=svtools.AccessibleBrowseBoxHeaderCell
+job179=svtools.AccessibleBrowseBoxTable
+job180=svtools.AccessibleBrowseBoxTableCell
+job181=svtools.AccessibleTabBar
+job182=svtools.AccessibleTabBarPageList
+job183=svx.AccessibleControlShape
+job184=svx.AccessibleGraphicShape
+job185=svx.AccessiblePresentationGraphicShape
+job186=svx.AccessiblePresentationShape
+job187=svx.AccessibleShape
+job188=svx.SvxShapeCollection
+job189=svx.SvxUnoTextContent
+job190=svx.SvxUnoTextContentEnum
+job191=svx.SvxUnoTextField
+job192=svx.SvxUnoTextRangeEnumeration
+job193=sw.SwAccessibleDocumentPageView
+job194=sw.SwAccessibleDocumentView
+job195=sw.SwAccessibleEndnoteView
+job196=sw.SwAccessibleFooterView
+job197=sw.SwAccessibleFootnoteView
+job198=sw.SwAccessibleHeaderView
+job199=sw.SwAccessibleParagraphView
+job200=sw.SwAccessibleTableCellView
+job201=sw.SwAccessibleTextFrameView
+job202=sw.SwAccessibleTextGraphicObject
+job203=sw.SwXBodyText
+job204=sw.SwXBookmark
+job205=sw.SwXBookmarks
+job206=sw.SwXCell
+job207=sw.SwXDocumentIndexes
+job208=sw.SwXDocumentIndexMark
+job209=sw.SwXEndnoteProperties
+job210=sw.SwXFieldEnumeration
+job211=sw.SwXFieldMaster
+job212=sw.SwXFootnote
+job213=sw.SwXFootnoteProperties
+job214=sw.SwXFootnotes
+job215=sw.SwXFootnoteText
+job216=sw.SwXFrames
+job217=sw.SwXHeadFootText
+job218=sw.SwXLineNumberingProperties
+job219=sw.SwXModule
+job220=sw.SwXParagraphEnumeration
+job221=sw.SwXPrintSettings
+job222=sw.SwXPropertySet
+job223=sw.SwXPropertySetInfo
+job224=sw.SwXReferenceMark
+job225=sw.SwXReferenceMarks
+job226=sw.SwXStyle
+job227=sw.SwXStyleFamilies
+job228=sw.SwXStyleFamily
+job229=sw.SwXTableCellText
+job230=sw.SwXTableRows
+job231=sw.SwXTextColumns
+job232=sw.SwXTextDefaults
+job233=sw.SwXTextEmbeddedObjects
+job234=sw.SwXTextField
+job235=sw.SwXTextFieldMasters
+job236=sw.SwXTextFieldTypes
+job237=sw.SwXTextFrameText
+job238=sw.SwXTextGraphicObjects
+job239=sw.SwXTextPortionEnumeration
+job240=sw.SwXTextRanges
+job241=sw.SwXTextSearch
+job242=sw.SwXTextSection
+job243=sw.SwXTextSections
+job244=sw.SwXTextTableRow
+job245=sw.SwXTextTables
+job246=sw.SwXViewSettings
+job247=sw.XMLContentExporter
+job248=sw.XMLExporter
+job249=sw.XMLImporter
+job250=sw.XMLMetaExporter
+job251=sw.XMLSettingsExporter
+job252=sw.XMLSettingsImporter
+job253=sw.XMLStylesExporter
+job254=sysdtrans.SystemClipboard
+job255=syssh.SystemShellExecute
+job256=text.DefaultNumberingProvider
+job257=toolkit.AccessibleComboBox
+job258=toolkit.AccessibleList
+job259=toolkit.AccessibleListBox
+job260=toolkit.AccessibleMenuSeparator
+job261=toolkit.AccessibleStatusBar
+job262=toolkit.AccessibleTabControl
+job263=toolkit.AccessibleWindow
+job264=toolkit.TabControllerModel
+job265=toolkit.UnoControlCheckBox
+job266=toolkit.UnoControlCheckBoxModel
+job267=toolkit.UnoControlComboBox
+job268=toolkit.UnoControlComboBoxModel
+job269=toolkit.UnoControlContainerModel
+job270=toolkit.UnoControlCurrencyField
+job271=toolkit.UnoControlCurrencyFieldModel
+job272=toolkit.UnoControlDateField
+job273=toolkit.UnoControlDateFieldModel
+job274=toolkit.UnoControlEdit
+job275=toolkit.UnoControlEditModel
+job276=toolkit.UnoControlFileControlModel
+job277=toolkit.UnoControlFixedText
+job278=toolkit.UnoControlFixedTextModel
+job279=toolkit.UnoControlFormattedField
+job280=toolkit.UnoControlFormattedFieldModel
+job281=toolkit.UnoControlGroupBox
+job282=toolkit.UnoControlGroupBoxModel
+job283=toolkit.UnoControlImageControl
+job284=toolkit.UnoControlImageControlModel
+job285=toolkit.UnoControlListBox
+job286=toolkit.UnoControlListBoxModel
+job287=toolkit.UnoControlNumericFieldModel
+job288=toolkit.UnoControlPatternField
+job289=toolkit.UnoControlPatternFieldModel
+job290=toolkit.UnoControlProgressBarModel
+job291=toolkit.UnoControlRadioButton
+job292=toolkit.UnoControlRadioButtonModel
+job293=toolkit.UnoControlScrollBarModel
+job294=toolkit.UnoControlTimeField
+job295=toolkit.UnoControlTimeFieldModel
+job296=typeconverter.uno.TypeConverter
+job297=typemgr.uno.TypeDescriptionManager
+job298=ucb.UcbContentProviderProxyFactory
+job299=ucb.UcbPropertiesManager
+job300=ucb.UcbStore
+job301=ucb.UniversalContentBroker
+job302=ucpchelp.CHelpContentProvider
+job303=ucpdav.WebDAVContentProvider
+job304=ucpfile.FileProvider
+job305=ucpftp.FTPContentProvider
+job306=ucphier.HierarchyContentProvider
+job307=ucphier.HierarchyDataSource
+job308=ucppkg.PackageContentProvider
+job309=uui.UUIInteractionHandler
+job310=xmloff.Draw.XMLContentExporter
+job311=xmloff.Draw.XMLExporter
+job312=xmloff.Draw.XMLMetaExporter
+job313=xmloff.Draw.XMLSettingsExporter
+job314=xmloff.Draw.XMLSettingsImporter
+job315=xmloff.Draw.XMLStylesExporter
+job316=xmloff.Impress.XMLContentExporter
+job317=xmloff.Impress.XMLExporter
+job318=xmloff.Impress.XMLMetaExporter
+job319=xmloff.Impress.XMLSettingsExporter
+job320=xmloff.Impress.XMLSettingsImporter
+job321=xmloff.Impress.XMLStylesExporter
+job322=cfgmgr2.AdministrationProvider
+job323=cfgmgr2.ConfigurationProvider
+job324=cfgmgr2.ConfigurationProviderWrapper
+job325=cfgmgr2.OConfigurationRegistry
diff --git a/framework/qa/complex/api_internal/tests.sce b/framework/qa/complex/api_internal/tests.sce
new file mode 100644
index 000000000..adc5db8fb
--- /dev/null
+++ b/framework/qa/complex/api_internal/tests.sce
@@ -0,0 +1,2 @@
+job1=cfgmgr2.AdministrationProvider
+job3=sw.SwXBodyText
diff --git a/framework/qa/complex/api_internal/worksforme.sce b/framework/qa/complex/api_internal/worksforme.sce
new file mode 100644
index 000000000..e764cbd93
--- /dev/null
+++ b/framework/qa/complex/api_internal/worksforme.sce
@@ -0,0 +1,54 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+job=cmdmail.SimpleCommandMail
+job=fileacc.SimpleFileAccess
+job=sc.ScCellFieldObj
+job=sc.XMLImporter
+job=sc.XMLMetaExporter
+job=sd.SdDocLinkTargets
+job=sd.SdDrawPage
+job=sd.SdMasterPagesAccess
+job=sd.SdXCustomPresentation
+job=sd.SdXPresentation
+job=servicemgr.uno.OServiceManager
+job=sfx.SfxMacroLoader
+job=simplereg.uno.SimpleRegistry
+job=sm.XMLSettingsExporter
+job=sm.XMLSettingsImporter
+job=srtrs.SortedDynamicResultSetFactory
+job=svx.SvxShapeCollection
+job=svx.SvxUnoTextRangeEnumeration
+job=sw.SwXBodyText
+job=sw.XMLExporter
+job=sw.XMLImporter
+job=sw.XMLMetaExporter
+job=sw.XMLSettingsExporter
+job=sw.XMLSettingsImporter
+job=sw.XMLStylesExporter
+job=sysdtrans.SystemClipboard
+job=syssh.SystemShellExecute
+job=text.DefaultNumberingProvider
+job=toolkit.TabControllerModel
+job=toolkit.UnoControlCheckBox
+job=toolkit.UnoControlTimeField
+job=toolkit.UnoControlTimeFieldModel
+job=typeconverter.uno.TypeConverter
+job=typemgr.uno.TypeDescriptionManager
+job=ucb.UcbContentProviderProxyFactory
+job=ucb.UcbPropertiesManager
+job=ucb.UcbStore
diff --git a/framework/qa/complex/broken_document/LoadDocument.java b/framework/qa/complex/broken_document/LoadDocument.java
new file mode 100644
index 000000000..c8c8da3b0
--- /dev/null
+++ b/framework/qa/complex/broken_document/LoadDocument.java
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.broken_document;
+
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.frame.XFrame;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+import static org.junit.Assert.*;
+
+
+/**
+ * Check, if message boxes appear when the Office is in "headless" mode. Tests
+ * bug i15809. This test uses the broken document dbf.dbf.emf.
+ */
+public class LoadDocument {
+
+
+ /**
+ * Start Office with "--headless" parameter, then
+ * load the broken document "dbf.dbf.emf", that brings a message box up in
+ * the ui, see if the headless mode of SOffice changes.
+ */
+ @Test public void checkHeadlessState()
+ {
+ XMultiServiceFactory xMSF = getMSF();
+ XFrame xDesktop = null;
+
+ try {
+ xDesktop = UnoRuntime.queryInterface(XFrame.class, xMSF.createInstance("com.sun.star.frame.Desktop"));
+ }
+ catch(com.sun.star.uno.Exception e) {
+ fail("Could not create a desktop instance.");
+ }
+
+ XComponentLoader xDesktopLoader = UnoRuntime.queryInterface(XComponentLoader.class, xDesktop);
+ System.out.println("xDesktopLoader is null: " + (xDesktopLoader == null));
+ PropertyValue[] val = new PropertyValue[0];
+
+ String fileUrl = complex.broken_document.TestDocument.getUrl("dbf.dbf.emf");
+ System.out.println("File Url: " + fileUrl);
+
+ try {
+ xDesktopLoader.loadComponentFromURL(fileUrl, "_blank", 0, val);
+ }
+ catch(com.sun.star.io.IOException e) {
+ fail("Could not load document");
+ }
+ catch(com.sun.star.lang.IllegalArgumentException e) {
+ fail("Could not load document");
+ }
+
+ // try again: headless mode defect now?
+ try {
+ xDesktopLoader.loadComponentFromURL(fileUrl, "_blank", 0, val);
+ }
+ catch(com.sun.star.io.IOException e) {
+ fail("Could not load document");
+ }
+ catch(com.sun.star.lang.IllegalArgumentException e) {
+ fail("Could not load document");
+ }
+
+ }
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass public static void setUpConnection() throws Exception {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+
+ private static final OfficeConnection connection = new OfficeConnection();
+
+}
diff --git a/framework/qa/complex/broken_document/TestDocument.java b/framework/qa/complex/broken_document/TestDocument.java
new file mode 100644
index 000000000..c9712c8e8
--- /dev/null
+++ b/framework/qa/complex/broken_document/TestDocument.java
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.broken_document;
+
+import java.io.File;
+import org.openoffice.test.OfficeFileUrl;
+import org.openoffice.test.Argument;
+
+final class TestDocument
+{
+ public static String getUrl(String name)
+ {
+ return OfficeFileUrl.getAbsolute(new File(Argument.get("tdoc"), name));
+ }
+
+ private TestDocument() {}
+}
diff --git a/framework/qa/complex/broken_document/test_documents/dbf.dbf.emf b/framework/qa/complex/broken_document/test_documents/dbf.dbf.emf
new file mode 100644
index 000000000..11e45e9df
--- /dev/null
+++ b/framework/qa/complex/broken_document/test_documents/dbf.dbf.emf
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/framework/qa/complex/contextMenuInterceptor/CheckContextMenuInterceptor.java b/framework/qa/complex/contextMenuInterceptor/CheckContextMenuInterceptor.java
new file mode 100644
index 000000000..e1f59fdf7
--- /dev/null
+++ b/framework/qa/complex/contextMenuInterceptor/CheckContextMenuInterceptor.java
@@ -0,0 +1,304 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.contextMenuInterceptor;
+
+import com.sun.star.accessibility.AccessibleRole;
+import com.sun.star.accessibility.XAccessible;
+import com.sun.star.accessibility.XAccessibleComponent;
+import com.sun.star.accessibility.XAccessibleContext;
+import com.sun.star.awt.Point;
+import com.sun.star.awt.Rectangle;
+import com.sun.star.awt.XBitmap;
+import com.sun.star.awt.XExtendedToolkit;
+import com.sun.star.awt.XWindow;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.drawing.XShape;
+import com.sun.star.frame.XFrame;
+import com.sun.star.frame.XModel;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.ui.XContextMenuInterception;
+import com.sun.star.ui.XContextMenuInterceptor;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XInterface;
+import com.sun.star.util.XCloseable;
+import java.awt.Robot;
+import java.awt.event.InputEvent;
+import java.io.File;
+import util.AccessibilityTools;
+import util.DesktopTools;
+import util.DrawTools;
+import util.SOfficeFactory;
+import org.openoffice.test.OfficeFileUrl;
+
+// ---------- junit imports -----------------
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+import static org.junit.Assert.*;
+
+
+/**
+ *
+ */
+public class CheckContextMenuInterceptor
+{
+
+ XMultiServiceFactory xMSF = null;
+ XFrame xFrame = null;
+ Point point = null;
+ XWindow xWindow = null;
+ com.sun.star.lang.XComponent xDrawDoc;
+
+ @Before
+ public void before()
+ {
+ xMSF = getMSF();
+ }
+
+ @After
+ public void after() throws Exception
+ {
+ System.out.println("release the popup menu");
+ try
+ {
+ Robot rob = new Robot();
+ int x = point.X;
+ int y = point.Y;
+ rob.mouseMove(x, y);
+ rob.mousePress(InputEvent.BUTTON1_MASK);
+ rob.mouseRelease(InputEvent.BUTTON1_MASK);
+ }
+ catch (java.awt.AWTException e)
+ {
+ System.out.println("couldn't press mouse button");
+ }
+
+ XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xFrame);
+
+ xClose.close(true);
+
+ xFrame = null;
+ }
+
+ @Test
+ public void checkContextMenuInterceptor() throws Exception
+ {
+ System.out.println(" **** Context Menu Interceptor *** ");
+
+ // initialize the test document
+ xDrawDoc = DrawTools.createDrawDoc(xMSF);
+
+ SOfficeFactory SOF = SOfficeFactory.getFactory(xMSF);
+ XShape oShape = SOF.createShape(xDrawDoc, 5000, 5000, 1500, 1000, "GraphicObject");
+ DrawTools.getShapes(DrawTools.getDrawPage(xDrawDoc, 0)).add(oShape);
+
+ com.sun.star.frame.XModel xModel =
+ UnoRuntime.queryInterface(com.sun.star.frame.XModel.class, xDrawDoc);
+
+ // get the frame for later usage
+ xFrame = xModel.getCurrentController().getFrame();
+
+ // ensure that the document content is optimal visible
+ DesktopTools.zoomToEntirePage(xMSF, xDrawDoc);
+
+ XBitmap xBitmap = null;
+
+ // adding graphic as ObjRelation for GraphicObjectShape
+ XPropertySet oShapeProps = UnoRuntime.queryInterface(XPropertySet.class, oShape);
+ System.out.println("Inserting a shape into the document");
+
+ try
+ {
+ String sFile = OfficeFileUrl.getAbsolute(new File("space-metal.jpg"));
+ oShapeProps.setPropertyValue("GraphicURL", sFile);
+ Object oProp = oShapeProps.getPropertyValue("GraphicObjectFillBitmap");
+ xBitmap = (XBitmap) AnyConverter.toObject(new Type(XBitmap.class), oProp);
+ }
+ catch (com.sun.star.lang.WrappedTargetException e)
+ {
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e)
+ {
+ }
+ catch (com.sun.star.beans.PropertyVetoException e)
+ {
+ }
+ catch (com.sun.star.beans.UnknownPropertyException e)
+ {
+ }
+
+ // reuse the frame
+ com.sun.star.frame.XController xController = xFrame.getController();
+ XContextMenuInterception xContextMenuInterception = null;
+ XContextMenuInterceptor xContextMenuInterceptor = null;
+
+ if (xController != null)
+ {
+ System.out.println("Creating context menu interceptor");
+
+ // add our context menu interceptor
+ xContextMenuInterception =
+ UnoRuntime.queryInterface(XContextMenuInterception.class, xController);
+
+ if (xContextMenuInterception != null)
+ {
+ ContextMenuInterceptor aContextMenuInterceptor = new ContextMenuInterceptor(xBitmap);
+ xContextMenuInterceptor =
+ UnoRuntime.queryInterface(XContextMenuInterceptor.class, aContextMenuInterceptor);
+
+ System.out.println("Register context menu interceptor");
+ xContextMenuInterception.registerContextMenuInterceptor(xContextMenuInterceptor);
+ }
+ }
+
+ openContextMenu(UnoRuntime.queryInterface(XModel.class, xDrawDoc));
+
+ checkHelpEntry();
+
+ // remove our context menu interceptor
+ if (xContextMenuInterception != null
+ && xContextMenuInterceptor != null)
+ {
+ System.out.println("Release context menu interceptor");
+ xContextMenuInterception.releaseContextMenuInterceptor(
+ xContextMenuInterceptor);
+ }
+ }
+
+ private void checkHelpEntry() throws Exception
+ {
+ XInterface toolkit = null;
+
+ System.out.println("get accessibility...");
+ try
+ {
+ toolkit = (XInterface) xMSF.createInstance("com.sun.star.awt.Toolkit");
+ }
+ catch (com.sun.star.uno.Exception e)
+ {
+ System.out.println("could not get Toolkit " + e.toString());
+ }
+ XExtendedToolkit tk = UnoRuntime.queryInterface(XExtendedToolkit.class, toolkit);
+
+ XAccessible xRoot = null;
+
+ try
+ {
+ xWindow = UnoRuntime.queryInterface(XWindow.class, tk.getTopWindow(0));
+
+ xRoot = AccessibilityTools.getAccessibleObject(xWindow);
+ }
+ catch (com.sun.star.lang.IndexOutOfBoundsException e)
+ {
+ System.out.println("Couldn't get Window");
+ }
+
+ XAccessibleContext oPopMenu = AccessibilityTools.getAccessibleObjectForRole(xRoot, AccessibleRole.POPUP_MENU);
+
+ System.out.println("ImplementationName: " + util.utils.getImplName(oPopMenu));
+
+ XAccessible xHelp = null;
+ System.out.println("Try to get first entry of context menu...");
+ xHelp = oPopMenu.getAccessibleChild(0);
+ if (xHelp == null)
+ {
+ fail("first entry of context menu is NULL");
+ }
+
+ XAccessibleContext xHelpCont = xHelp.getAccessibleContext();
+ if (xHelpCont == null)
+ {
+ fail("No able to retrieve accessible context from first entry of context menu");
+ }
+
+ String aAccessibleName = xHelpCont.getAccessibleName();
+ if (!aAccessibleName.equals("Help"))
+ {
+ System.out.println("Accessible name found = " + aAccessibleName);
+ fail("First entry of context menu is not from context menu interceptor");
+ }
+
+ System.out.println("try to get first children of Help context...");
+ xHelpCont.getAccessibleChild(0);
+ }
+
+ private void openContextMenu(XModel aModel)
+ {
+
+ System.out.println("try to open context menu...");
+
+ xWindow = AccessibilityTools.getCurrentWindow(aModel);
+
+ XAccessible xRoot = AccessibilityTools.getAccessibleObject(xWindow);
+
+ XInterface oObj = AccessibilityTools.getAccessibleObjectForRole(xRoot, AccessibleRole.PANEL);
+
+ XAccessibleComponent window = UnoRuntime.queryInterface(XAccessibleComponent.class, oObj);
+
+ point = window.getLocationOnScreen();
+ Rectangle rect = window.getBounds();
+
+ System.out.println("click mouse button...");
+ try
+ {
+ Robot rob = new Robot();
+ int x = point.X + (rect.Width / 2);
+ int y = point.Y + (rect.Height / 2);
+ rob.mouseMove(x, y);
+ System.out.println("Press Button");
+ rob.mousePress(InputEvent.BUTTON3_MASK);
+ System.out.println("Release Button");
+ rob.mouseRelease(InputEvent.BUTTON3_MASK);
+ System.out.println("done");
+ }
+ catch (java.awt.AWTException e)
+ {
+ System.out.println("couldn't press mouse button");
+ }
+
+ util.utils.waitForEventIdle(getMSF());
+ }
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass
+ public static void setUpConnection() throws Exception
+ {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass
+ public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+ private static final OfficeConnection connection = new OfficeConnection();
+}
diff --git a/framework/qa/complex/contextMenuInterceptor/ContextMenuInterceptor.java b/framework/qa/complex/contextMenuInterceptor/ContextMenuInterceptor.java
new file mode 100644
index 000000000..7496b58e0
--- /dev/null
+++ b/framework/qa/complex/contextMenuInterceptor/ContextMenuInterceptor.java
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.contextMenuInterceptor;
+
+import com.sun.star.ui.*;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.uno.UnoRuntime;
+
+public class ContextMenuInterceptor implements XContextMenuInterceptor
+{
+
+ private final com.sun.star.awt.XBitmap myBitmap;
+
+ public ContextMenuInterceptor(com.sun.star.awt.XBitmap aBitmap)
+ {
+ myBitmap = aBitmap;
+ }
+
+ public ContextMenuInterceptorAction notifyContextMenuExecute(
+ com.sun.star.ui.ContextMenuExecuteEvent aEvent) throws RuntimeException
+ {
+ try
+ {
+ // Retrieve context menu container and query for service factory to
+ // create sub menus, menu entries and separators
+ com.sun.star.container.XIndexContainer xContextMenu = aEvent.ActionTriggerContainer;
+ com.sun.star.lang.XMultiServiceFactory xMenuElementFactory =
+ UnoRuntime.queryInterface(com.sun.star.lang.XMultiServiceFactory.class, xContextMenu);
+
+ if (xMenuElementFactory != null)
+ {
+
+ // create root menu entry for sub menu and sub menu
+ com.sun.star.beans.XPropertySet xRootMenuEntry =
+ UnoRuntime.queryInterface(com.sun.star.beans.XPropertySet.class, xMenuElementFactory.createInstance("com.sun.star.ui.ActionTrigger"));
+
+ // create a line separator for our new help sub menu
+ com.sun.star.beans.XPropertySet xSeparator =
+ UnoRuntime.queryInterface(com.sun.star.beans.XPropertySet.class, xMenuElementFactory.createInstance("com.sun.star.ui.ActionTriggerSeparator"));
+ Short aSeparatorType = Short.valueOf(ActionTriggerSeparatorType.LINE);
+ xSeparator.setPropertyValue("SeparatorType", aSeparatorType);
+
+ // query sub menu for index container to get access
+ com.sun.star.container.XIndexContainer xSubMenuContainer =
+ UnoRuntime.queryInterface(com.sun.star.container.XIndexContainer.class, xMenuElementFactory.createInstance("com.sun.star.ui.ActionTriggerContainer"));
+
+ // initialize root menu entry "Help"
+ xRootMenuEntry.setPropertyValue("Text", "Help");
+ xRootMenuEntry.setPropertyValue("CommandURL", "slot:5410");
+ xRootMenuEntry.setPropertyValue("HelpURL", "5410");
+ xRootMenuEntry.setPropertyValue("SubContainer", xSubMenuContainer);
+ xRootMenuEntry.setPropertyValue("Image", myBitmap);
+
+ // create menu entries for the new sub menu
+ // initialize help/content menu entry
+ // entry "Content"
+ XPropertySet xMenuEntry = UnoRuntime.queryInterface(XPropertySet.class, xMenuElementFactory.createInstance("com.sun.star.ui.ActionTrigger"));
+ xMenuEntry.setPropertyValue("Text", "Content");
+ xMenuEntry.setPropertyValue("CommandURL", "slot:5401");
+ xMenuEntry.setPropertyValue("HelpURL", "5401");
+
+ // insert menu entry to sub menu
+ xSubMenuContainer.insertByIndex(0, xMenuEntry);
+
+ // initialize help/help on help
+ // entry "Help on Help"
+ xMenuEntry = UnoRuntime.queryInterface(com.sun.star.beans.XPropertySet.class, xMenuElementFactory.createInstance("com.sun.star.ui.ActionTrigger"));
+ xMenuEntry.setPropertyValue("Text", "Help on Help");
+ xMenuEntry.setPropertyValue("CommandURL", "slot:5400");
+ xMenuEntry.setPropertyValue("HelpURL", "5400");
+
+ // insert menu entry to sub menu
+ xSubMenuContainer.insertByIndex(1, xMenuEntry);
+ // initialize help/tips
+ // entry "Tips"
+ xMenuEntry = UnoRuntime.queryInterface(com.sun.star.beans.XPropertySet.class, xMenuElementFactory.createInstance("com.sun.star.ui.ActionTrigger"));
+ xMenuEntry.setPropertyValue("Text", "Tips");
+ xMenuEntry.setPropertyValue("CommandURL", "slot:5404");
+ xMenuEntry.setPropertyValue("HelpURL", "5404");
+
+ // insert menu entry to sub menu
+ xSubMenuContainer.insertByIndex(2, xMenuEntry);
+
+ // add separator into the given context menu
+ xContextMenu.insertByIndex(0, xSeparator);
+
+ // add new sub menu into the given context menu
+ xContextMenu.insertByIndex(0, xRootMenuEntry);
+
+ // The controller should execute the modified context menu and stop notifying other
+ // interceptors.
+ return com.sun.star.ui.ContextMenuInterceptorAction.EXECUTE_MODIFIED;
+ }
+ }
+ catch (com.sun.star.beans.UnknownPropertyException ex)
+ {
+ // do something useful
+ // we used an unknown property
+ }
+ catch (com.sun.star.lang.IndexOutOfBoundsException ex)
+ {
+ // do something useful
+ // we used an invalid index for accessing a container
+ }
+ catch (com.sun.star.uno.Exception ex)
+ {
+ // something strange has happened!
+ }
+ catch (java.lang.Throwable ex)
+ {
+ // catch java exceptions do something useful
+ }
+
+ return com.sun.star.ui.ContextMenuInterceptorAction.IGNORED;
+ }
+}
diff --git a/framework/qa/complex/contextMenuInterceptor/space-metal.jpg b/framework/qa/complex/contextMenuInterceptor/space-metal.jpg
new file mode 100644
index 000000000..d23344389
--- /dev/null
+++ b/framework/qa/complex/contextMenuInterceptor/space-metal.jpg
Binary files differ
diff --git a/framework/qa/complex/desktop/DesktopTerminate.java b/framework/qa/complex/desktop/DesktopTerminate.java
new file mode 100644
index 000000000..5a60a5ed5
--- /dev/null
+++ b/framework/qa/complex/desktop/DesktopTerminate.java
@@ -0,0 +1,144 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.desktop;
+
+
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.frame.XDesktop;
+import com.sun.star.uno.UnoRuntime;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+import static org.junit.Assert.*;
+
+
+/**
+ * Parameters:
+ * <ul>
+ * <li>NoOffice=yes - StarOffice is not started initially.</li>
+ * </ul>
+ */
+public class DesktopTerminate
+{
+
+ private XMultiServiceFactory xMSF;
+ private static final int iOfficeCloseTime = 1000;
+
+ /**
+ * Test if all available document types change the
+ * persistent Window Attributes
+ *
+ * The test follows basically these steps:
+ * - Create a configuration reader and a componentloader
+ * - Look for all document types in the configuration
+ * - Do for every doc type
+ * - start office
+ * - read configuration attribute settings
+ * - create a new document
+ * - resize the document and close it
+ * - close office
+ * - start office
+ * - read configuration attribute settings
+ * - create another new document
+ * - compare old settings with new ones: should be different
+ * - compare the document size with the resized document: should be equal
+ * - close office
+ * - Test finished
+ */
+ @Test public void checkPersistentWindowState()
+ {
+ try
+ {
+
+ System.out.println("Connect the first time.");
+
+ if (!connect())
+ {
+ return;
+ }
+
+ if (!disconnect())
+ {
+ return;
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private boolean connect()
+ {
+ try
+ {
+ xMSF = getMSF();
+ util.utils.pause(10000);
+ }
+ catch (java.lang.Exception e)
+ {
+ System.out.println(e.getClass().getName());
+ System.out.println("Message: " + e.getMessage());
+ fail("Cannot connect the Office.");
+ return false;
+ }
+ return true;
+ }
+
+ private boolean disconnect()
+ {
+ try
+ {
+ XDesktop desk = null;
+ desk = UnoRuntime.queryInterface(XDesktop.class, xMSF.createInstance("com.sun.star.frame.Desktop"));
+ desk.terminate();
+ System.out.println("Waiting " + iOfficeCloseTime + " milliseconds for the Office to close down");
+ util.utils.pause(iOfficeCloseTime);
+ xMSF = null;
+ }
+ catch (java.lang.Exception e)
+ {
+ e.printStackTrace();
+ fail("Cannot dispose the Office.");
+ return false;
+ }
+ return true;
+ }
+
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass public static void setUpConnection() throws Exception {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass public static void tearDownConnection()
+ {
+ System.out.println("tearDownConnection()");
+ // don't do a tearDown here, desktop is already terminated.
+ }
+
+ private static final OfficeConnection connection = new OfficeConnection();
+
+}
diff --git a/framework/qa/complex/dispatches/Interceptor.java b/framework/qa/complex/dispatches/Interceptor.java
new file mode 100644
index 000000000..ecbac4421
--- /dev/null
+++ b/framework/qa/complex/dispatches/Interceptor.java
@@ -0,0 +1,338 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.dispatches;
+
+// __________ Imports __________
+
+// structs, const, ...
+import com.sun.star.beans.PropertyValue;
+
+// exceptions
+import com.sun.star.frame.DispatchDescriptor;
+import com.sun.star.frame.XDispatch;
+import com.sun.star.frame.XDispatchProvider;
+import com.sun.star.frame.XDispatchProviderInterceptor;
+import com.sun.star.frame.XInterceptorInfo;
+import com.sun.star.frame.XStatusListener;
+
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.awt.XDataTransferProviderAccess;
+
+// helper
+import com.sun.star.util.URL;
+import com.sun.star.uno.UnoRuntime;
+
+// __________ Implementation __________
+
+/**
+ * implements a configurable interceptor for dispatch events.
+ */
+public class Interceptor implements XDispatch,
+ XDispatchProviderInterceptor,
+ XInterceptorInfo
+{
+ /** contains the list of interception URL schema's (wildcards are allowed there!)
+ supported by this interceptor. It can be set from outside.
+ If no external URLs are set, the default "*" is used instead.
+ That would have the same effect as if this implementation would not support the
+ interface XInterceptorInfo !
+ */
+ private String[] m_lURLs4InterceptionInfo = null;
+
+
+
+ /** These URL's will be blocked by this interceptor.
+ Can be set from outside. Every queryDispatch() for these
+ set of URL's will be answered with an empty dispatch object!
+ If no external URLs are set the default "*" is used instead.
+ So every incoming URL will be blocked .-)
+ */
+ private String[] m_lURLs4Blocking = null;
+
+
+
+ /** Every dispatch interceptor knows it's master and slave interceptor
+ of the dispatch chain. These values must be stupid handled .-)
+ They have to be set and reset in case the right interface methods are called.
+ Nothing more. It's not allowed to dispose() it.
+ The slave can be used inside queryDispatch() to forward requests,
+ which are not handled by this interceptor instance.
+ */
+ private XDispatchProvider m_xSlave = null;
+ private XDispatchProvider m_xMaster = null;
+
+
+
+ /** counts calls of setSlave...().
+ So the outside API test can use this value to know if this interceptor
+ was really added to the interceptor chain of OOo.
+ */
+ private int m_nRegistrationCount = 0;
+
+
+
+ /** indicates if this interceptor object is currently part of the interceptor
+ chain of OOo. Only true if a valid slave or master dispatch is set on this
+ instance.
+ */
+ private boolean m_bIsRegistered = false;
+
+ /** points to the global uno service manager. */
+ private XMultiServiceFactory m_xMSF = null;
+
+ public Interceptor(XMultiServiceFactory xMSF)
+ {
+ m_xMSF = xMSF;
+ }
+
+
+ /** XInterceptorInfo */
+ public synchronized String[] getInterceptedURLs()
+ {
+ return impl_getURLs4InterceptionInfo();
+ }
+
+
+
+ /** XDispatchProviderInterceptor */
+ public synchronized XDispatchProvider getSlaveDispatchProvider()
+ {
+ System.out.println("Interceptor.getSlaveDispatchProvider() called");
+ return m_xSlave;
+ }
+
+
+
+ /** XDispatchProviderInterceptor */
+ public synchronized XDispatchProvider getMasterDispatchProvider()
+ {
+ System.out.println("Interceptor.getMasterDispatchProvider() called");
+ return m_xMaster;
+ }
+
+
+
+ /** XDispatchProviderInterceptor */
+ public synchronized void setSlaveDispatchProvider(XDispatchProvider xSlave)
+ {
+ System.out.println("Interceptor.setSlaveDispatchProvider("+xSlave+") called");
+
+ if (xSlave != null)
+ {
+ ++m_nRegistrationCount;
+ m_bIsRegistered = true;
+ }
+ else
+ {
+ m_bIsRegistered = false;
+ }
+
+ m_xSlave = xSlave;
+ }
+
+ /** XDispatchProviderInterceptor */
+ public synchronized void setMasterDispatchProvider(XDispatchProvider xMaster)
+ {
+ System.out.println("Interceptor.setMasterDispatchProvider("+xMaster+") called");
+ m_xMaster = xMaster;
+ }
+
+ private XDataTransferProviderAccess m_xToolkit = null;
+
+ /** A beautiful method whose only purpose is to take and release a
+ * solar mutex. If this hangs - you can see a beautiful deadlock
+ * when you attach your debugger to the main process.
+ */
+ private void checkNoSolarMutexHeld()
+ {
+ try
+ {
+ if (m_xToolkit == null)
+ m_xToolkit = UnoRuntime.queryInterface(
+ XDataTransferProviderAccess.class,
+ m_xMSF.createInstance("com.sun.star.awt.Toolkit"));
+
+ // A Method notable only for taking the solar mutex.
+ System.out.println("Check solarmutex not held - if so deadlock");
+ m_xToolkit.getDragSource( null );
+ System.out.println("Solarmutex not held.");
+ } catch (java.lang.Throwable ex) {
+ System.out.println("Failed to create and invoke toolkit method " + ex.toString());
+ }
+ }
+
+ /** XDispatchProvider
+ */
+ public synchronized XDispatch queryDispatch(URL aURL,
+ String sTargetFrameName,
+ int nSearchFlags)
+ {
+ System.out.println("Interceptor.queryDispatch('"+aURL.Complete+"', '"+sTargetFrameName+"', "+nSearchFlags+") called");
+
+ checkNoSolarMutexHeld();
+
+ if (impl_isBlockedURL(aURL.Complete))
+ {
+ System.out.println("Interceptor.queryDispatch(): URL blocked => returns NULL");
+ return null;
+ }
+
+ if (m_xSlave != null)
+ {
+ System.out.println("Interceptor.queryDispatch(): ask slave ...");
+ return m_xSlave.queryDispatch(aURL, sTargetFrameName, nSearchFlags);
+ }
+
+ System.out.println("Interceptor.queryDispatch(): no idea => returns this");
+ return this;
+ }
+
+
+
+ /** XDispatchProvider
+ */
+ public XDispatch[] queryDispatches(DispatchDescriptor[] lRequests)
+ {
+ int i = 0;
+ int c = lRequests.length;
+
+ XDispatch[] lResults = new XDispatch[c];
+ for (i=0; i<c; ++i)
+ {
+ lResults[i] = queryDispatch(lRequests[i].FeatureURL ,
+ lRequests[i].FrameName ,
+ lRequests[i].SearchFlags);
+ }
+
+ return lResults;
+ }
+
+
+
+ /** XDispatch
+ */
+ public synchronized void dispatch(URL aURL ,
+ PropertyValue[] lArguments)
+ {
+ System.out.println("Interceptor.dispatch('"+aURL.Complete+"') called");
+ }
+
+
+
+ /** XDispatch
+ */
+ public synchronized void addStatusListener(XStatusListener xListener,
+ com.sun.star.util.URL aURL )
+ {
+ System.out.println("Interceptor.addStatusListener(..., '"+aURL.Complete+"') called");
+ }
+
+
+
+ /** XDispatch
+ */
+ public synchronized void removeStatusListener(XStatusListener xListener,
+ com.sun.star.util.URL aURL )
+ {
+ System.out.println("Interceptor.removeStatusListener(..., '"+aURL.Complete+"') called");
+ }
+
+
+
+ public synchronized int getRegistrationCount()
+ {
+ return m_nRegistrationCount;
+ }
+
+
+
+ public synchronized boolean isRegistered()
+ {
+ return m_bIsRegistered;
+ }
+
+
+ /** set a new list of URL's, which should be blocked by this interceptor.
+ (that's why it's necessary to call this impl-method before the interceptor
+ is used at the OOo API!)
+ */
+ public synchronized void setURLs4URLs4Blocking(String[] lURLs)
+ {
+ m_lURLs4Blocking = lURLs;
+ }
+
+
+
+ /** must be used internal to access the member m_lURLs4InterceptionInfo
+ - threadsafe
+ - and to make sure it's initialized on demand
+ */
+ private synchronized String[] impl_getURLs4InterceptionInfo()
+ {
+ if (m_lURLs4InterceptionInfo == null)
+ {
+ m_lURLs4InterceptionInfo = new String[] { "*" };
+ }
+
+ return m_lURLs4InterceptionInfo;
+ }
+
+
+
+ /** must be used internal to access the member m_lURLs4Blocking
+ - threadsafe
+ - and to make sure it's initialized on demand
+ */
+ private synchronized String[] impl_getURLs4Blocking()
+ {
+ if (m_lURLs4Blocking == null)
+ {
+ m_lURLs4Blocking = new String[] { "*" };
+ }
+
+ return m_lURLs4Blocking;
+ }
+
+
+ private boolean impl_isBlockedURL(String sURL)
+ {
+ String[] lBlockedURLs = impl_getURLs4Blocking();
+ int i = 0;
+ int c = lBlockedURLs.length;
+
+ for (i=0; i<c; ++i)
+ {
+ if (impl_match(sURL, lBlockedURLs[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+
+ private boolean impl_match(String sVal1, String sVal2)
+ {
+ // TODO implement wildcard match
+ return sVal1.equals(sVal2);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/qa/complex/dispatches/checkdispatchapi.java b/framework/qa/complex/dispatches/checkdispatchapi.java
new file mode 100644
index 000000000..851b467da
--- /dev/null
+++ b/framework/qa/complex/dispatches/checkdispatchapi.java
@@ -0,0 +1,401 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.dispatches;
+
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.frame.DispatchInformation;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.frame.XDispatchInformationProvider;
+import com.sun.star.frame.XDispatchProviderInterception;
+import com.sun.star.frame.XDispatchProviderInterceptor;
+import com.sun.star.frame.XFrame;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.XCloseable;
+import com.sun.star.awt.XReschedule;
+import com.sun.star.awt.XToolkitExperimental;
+import java.util.HashMap;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+import static org.junit.Assert.*;
+
+/** @short Check the interface XDispatchInformationProvider
+
+@descr Because there exists more than one implementation of a dispatch
+object, we have to test all these implementations ...
+ */
+public class checkdispatchapi
+{
+ // member
+ /** points to the global uno service manager. */
+ private XMultiServiceFactory m_xMSF = null;
+
+// private connectivity.tools.HsqlDatabase db;
+
+ /** can be used to create new test frames. */
+ private XFrame m_xDesktop = null;
+ /** provides XDispatchInformationProvider interface. */
+ private XFrame m_xFrame = null;
+
+
+ // test environment
+
+ /** @short Create the environment for following tests.
+
+ @descr create an empty test frame, where we can load
+ different components inside.
+ */
+ @Before public void before() throws Exception
+ {
+ // get uno service manager from global test environment
+ m_xMSF = getMSF();
+
+// db = new connectivity.tools.HsqlDatabase(m_xMSF);
+
+ // create desktop
+ m_xDesktop = UnoRuntime.queryInterface(XFrame.class, m_xMSF.createInstance("com.sun.star.frame.Desktop"));
+
+ m_xFrame = impl_createNewFrame();
+ }
+
+ /** @short close the environment.
+ */
+ @After public void after() throws Exception
+ {
+// db.close();
+ impl_closeFrame(m_xFrame);
+ m_xFrame = null;
+ }
+
+ @Test public void checkDispatchInfoOfWriter() throws Exception
+ {
+ impl_checkDispatchInfoOfXXX("private:factory/swriter");
+ }
+
+ @Test public void checkDispatchInfoOfCalc() throws Exception
+ {
+ impl_checkDispatchInfoOfXXX("private:factory/scalc");
+ }
+
+ @Test public void checkDispatchInfoOfDraw() throws Exception
+ {
+ impl_checkDispatchInfoOfXXX("private:factory/sdraw");
+ }
+
+ @Test public void checkDispatchInfoOfImpress() throws Exception
+ {
+ impl_checkDispatchInfoOfXXX("private:factory/simpress");
+ }
+
+ @Test public void checkDispatchInfoOfChart() throws Exception
+ {
+ impl_checkDispatchInfoOfXXX("private:factory/schart");
+ }
+
+ @Test public void checkDispatchInfoOfMath() throws Exception
+ {
+ impl_checkDispatchInfoOfXXX("private:factory/smath");
+ }
+
+ @Test public void checkDispatchInfoOfDataBase() throws Exception
+ {
+// impl_checkDispatchInfoOfXXX("private:factory/sdatabase");
+ }
+
+ @Test public void checkDispatchInfoOfBibliography() throws Exception
+ {
+// impl_checkDispatchInfoOfXXX(".component:Bibliography/View1");
+ }
+
+ @Test public void checkDispatchInfoOfQueryDesign()
+ {
+// callDatabaseDispatch(".component:DB/QueryDesign");
+ }
+
+ @Test public void checkDispatchInfoOfTableDesign() throws Exception
+ {
+// callDatabaseDispatch(".component:DB/TableDesign");
+ }
+
+ @Test public void checkDispatchInfoOfFormGridView() throws Exception
+ {
+// impl_checkDispatchInfoOfXXX(".component:DB/FormGridView");
+ }
+
+ @Test public void checkDispatchInfoOfDataSourceBrowser() throws Exception
+ {
+// impl_checkDispatchInfoOfXXX(".component:DB/DataSourceBrowser");
+ }
+
+ @Test public void checkDispatchInfoOfRelationDesign()
+ {
+// callDatabaseDispatch(".component:DB/RelationDesign");
+ }
+
+ private void callDatabaseDispatch(String url)
+ {
+/* disabled along with all db related tests for now.
+
+ try
+ {
+ final PropertyValue args = new PropertyValue();
+ args.Name = "ActiveConnection";
+ args.Value = db.defaultConnection();
+
+ XFrame xFrame = impl_createNewFrame();
+
+ impl_loadIntoFrame(xFrame, url, new PropertyValue[]
+ {
+ args
+ });
+ impl_checkDispatchInfo(xFrame);
+ impl_closeFrame(xFrame);
+ }
+ catch (java.lang.Exception e)
+ {
+ } */
+ }
+
+ @Test public void checkDispatchInfoOfBasic() throws Exception
+ {
+ Object aComponent = impl_createUNOComponent("com.sun.star.script.BasicIDE");
+ impl_checkDispatchInfo(aComponent);
+ }
+
+ @Test public void checkDispatchInfoOfStartModule() throws Exception
+ {
+ Object aComponent = impl_createUNOComponent("com.sun.star.frame.StartModule");
+ impl_checkDispatchInfo(aComponent);
+ }
+
+ @Test public void checkInterceptorLifeTime() throws Exception
+ {
+ // Note: It's important for the following test, that aInterceptor will be hold alive by the uno reference
+ // xInterceptor. Otherwise we can't check some internal states of aInterceptor at the end of this method, because
+ // it was already killed .-)
+
+ Interceptor aInterceptor = new Interceptor(m_xMSF);
+ XDispatchProviderInterceptor xInterceptor = UnoRuntime.queryInterface(XDispatchProviderInterceptor.class, aInterceptor);
+
+ XFrame xFrame = impl_createNewFrame();
+ XDispatchProviderInterception xInterception = UnoRuntime.queryInterface(XDispatchProviderInterception.class, xFrame);
+
+ xInterception.registerDispatchProviderInterceptor(xInterceptor);
+ impl_closeFrame(xFrame);
+
+ int nRegCount = aInterceptor.getRegistrationCount();
+ boolean bIsRegistered = aInterceptor.isRegistered();
+
+ System.out.println("registration count = " + nRegCount);
+ System.out.println("is registered ? = " + bIsRegistered);
+
+ if (nRegCount < 1)
+ {
+ fail("Interceptor was never registered.");
+ }
+
+ if (bIsRegistered)
+ {
+ fail("Interceptor was not deregistered automatically on closing the corresponding frame.");
+ }
+
+ System.out.println("Destruction of interception chain works as designed .-)");
+ }
+
+ @Test public void checkInterception() throws Exception
+ {
+ String[] lDisabledURLs = new String[] { ".uno:Open" };
+
+ System.out.println("create and initialize interceptor ...");
+ Interceptor aInterceptor = new Interceptor(m_xMSF);
+ aInterceptor.setURLs4URLs4Blocking(lDisabledURLs);
+
+ XDispatchProviderInterceptor xInterceptor = UnoRuntime.queryInterface(XDispatchProviderInterceptor.class, aInterceptor);
+
+ System.out.println("create and initialize frame ...");
+ XFrame xFrame = impl_createNewFrame();
+
+ XDispatchProviderInterception xInterception = UnoRuntime.queryInterface(XDispatchProviderInterception.class, xFrame);
+ System.out.println("register interceptor ...");
+ xInterception.registerDispatchProviderInterceptor(xInterceptor);
+
+ impl_loadIntoFrame(xFrame, "private:factory/swriter", null);
+
+ // Framework dispatcher update is on a ~50ms wait.
+ Thread.sleep(100);
+
+ XReschedule m_xReschedule = UnoRuntime.queryInterface(
+ XReschedule.class, m_xMSF.createInstance("com.sun.star.awt.Toolkit"));
+ // queryDispatch for toolbars etc. happens asynchronously.
+ System.out.println("process deferred events ...");
+ m_xReschedule.reschedule();
+ XToolkitExperimental m_xIdles = UnoRuntime.queryInterface(
+ XToolkitExperimental.class, m_xReschedule);
+ m_xIdles.processEventsToIdle();
+
+ System.out.println("deregister interceptor ...");
+ xInterception.releaseDispatchProviderInterceptor(xInterceptor);
+ }
+
+ private void impl_checkDispatchInfoOfXXX(String sXXX) throws Exception
+ {
+ XFrame xFrame = impl_createNewFrame();
+ impl_loadIntoFrame(xFrame, sXXX, null);
+ impl_checkDispatchInfo(xFrame);
+ impl_closeFrame(xFrame);
+ }
+
+ /** @short load a URL into the current test frame.
+ */
+ private void impl_loadIntoFrame(XFrame xFrame, String sURL, PropertyValue args[]) throws Exception
+ {
+ XComponentLoader xLoader = UnoRuntime.queryInterface(XComponentLoader.class, xFrame);
+ if (xLoader == null)
+ {
+ fail("Frame does not provide required interface XComponentLoader.");
+ }
+
+ XComponent xDoc = xLoader.loadComponentFromURL(sURL, "_self", 0, args);
+
+ if (xDoc == null)
+ {
+ fail("Could not load \"" + sURL + "\".");
+ }
+ }
+
+ /** @short create a uno implementation directly.
+ */
+ private Object impl_createUNOComponent(String sName)
+ {
+ Object aComponent = null;
+ try
+ {
+ aComponent = m_xMSF.createInstance(sName);
+ }
+ catch (java.lang.Throwable ex)
+ {
+ aComponent = null;
+ }
+
+ if (aComponent == null)
+ {
+ fail("Could not create UNO component \"" + sName + "\".");
+ }
+ return aComponent;
+ }
+
+ /** @short check the interface XDispatchInformationProvider
+ at the specified component.
+ */
+ private void impl_checkDispatchInfo(Object aComponent) throws Exception
+ {
+ XDispatchInformationProvider xInfoProvider = UnoRuntime.queryInterface(XDispatchInformationProvider.class, aComponent);
+ if (xInfoProvider == null)
+ {
+ // Warning
+ System.out.println("Warning:\tComponent does not provide the [optional!] interface XDispatchInformationProvider.");
+ return;
+ }
+
+ short[] lGroups = xInfoProvider.getSupportedCommandGroups();
+ int c1 = lGroups.length;
+ int i1 = 0;
+ for (i1 = 0; i1 < c1; ++i1)
+ {
+ short nGroup = lGroups[i1];
+ DispatchInformation[] lInfos = xInfoProvider.getConfigurableDispatchInformation(nGroup);
+ int c2 = lInfos.length;
+ int i2 = 0;
+
+ // check for empty lists
+ // Warning
+ if (lInfos.length < 1)
+ {
+ System.out.println("Warning:\tCould not get any DispatchInformation for group [" + nGroup + "].");
+ }
+
+ // check for duplicates (and by the way, if the info item match the requested group)
+ HashMap<String, String> aCheckMap = new HashMap<String, String>(c2);
+ for (i2 = 0; i2 < c2; ++i2)
+ {
+ DispatchInformation aInfo = lInfos[i2];
+ if (aInfo.GroupId != nGroup)
+ {
+ // Error
+ fail("At least one DispatchInformation item does not match the requested group.\n\trequested group=[" + nGroup
+ + "] returned group=[" + aInfo.GroupId + "] command=\"" + aInfo.Command + "\""); // true => don't break this test
+ continue;
+ }
+
+ if (aCheckMap.containsKey(aInfo.Command))
+ {
+ // Error
+ fail("Found a duplicate item: group=[" + aInfo.GroupId + "] command=\"" + aInfo.Command + "\""); // true => don't break this test
+ continue;
+ }
+
+ aCheckMap.put(aInfo.Command, aInfo.Command);
+ System.out.println("\t[" + aInfo.GroupId + "] \"" + aInfo.Command + "\"");
+ }
+ }
+ }
+
+ private synchronized XFrame impl_createNewFrame()
+ {
+ XFrame xFrame = m_xDesktop.findFrame("_blank", 0);
+ xFrame.getContainerWindow().setVisible(true);
+ return xFrame;
+ }
+
+ private synchronized void impl_closeFrame(XFrame xFrame) throws Exception
+ {
+ XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xFrame);
+ xClose.close(false);
+ }
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass
+ public static void setUpConnection() throws Exception
+ {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass
+ public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+ private static final OfficeConnection connection = new OfficeConnection();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/qa/complex/disposing/GetServiceWhileDisposingOffice.java b/framework/qa/complex/disposing/GetServiceWhileDisposingOffice.java
new file mode 100644
index 000000000..fd7fffcb3
--- /dev/null
+++ b/framework/qa/complex/disposing/GetServiceWhileDisposingOffice.java
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.disposing;
+
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XDesktop;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+
+
+/**
+ * This test is for bug110698. The Office is closed and is continually connected
+ * while it closes. This did let the Office freeze. Now when the Office is
+ * closed, the connection is refused.
+ */
+public class GetServiceWhileDisposingOffice
+{
+
+ @Test public void checkServiceWhileDisposing() throws Exception
+ {
+ XMultiServiceFactory xMSF = getMSF();
+ XDesktop xDesktop = null;
+
+ xDesktop = UnoRuntime.queryInterface(XDesktop.class, xMSF.createInstance("com.sun.star.frame.Desktop"));
+ int step = 0;
+ try
+ {
+ System.out.println("Start the termination of the Office.");
+ xDesktop.terminate();
+ for (; step < 10000; step++)
+ {
+ xMSF.createInstance("com.sun.star.frame.Desktop");
+ }
+ }
+ catch (com.sun.star.lang.DisposedException e)
+ {
+ System.out.println("DisposedException in step: " + step);
+ }
+ }
+
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass
+ public static void setUpConnection() throws Exception
+ {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass
+ public static void tearDownConnection()
+ {
+ System.out.println("tearDownConnection()");
+ // Office is already terminated.
+ }
+ private static final OfficeConnection connection = new OfficeConnection();
+
+}
diff --git a/framework/qa/complex/framework/autosave/AutoSave.java b/framework/qa/complex/framework/autosave/AutoSave.java
new file mode 100644
index 000000000..c6e7549d0
--- /dev/null
+++ b/framework/qa/complex/framework/autosave/AutoSave.java
@@ -0,0 +1,451 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.framework.autosave;
+
+
+
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.frame.FeatureStateEvent;
+import com.sun.star.frame.XDispatch;
+import com.sun.star.frame.XDispatchProvider;
+import com.sun.star.frame.XModel;
+import com.sun.star.frame.XStatusListener;
+import com.sun.star.frame.theAutoRecovery;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sheet.FillDirection;
+import com.sun.star.sheet.XCellSeries;
+import com.sun.star.table.XCellRange;
+import com.sun.star.util.XCloseable;
+import com.sun.star.sheet.XSpreadsheet;
+import com.sun.star.sheet.XSpreadsheetDocument;
+import com.sun.star.sheet.XSpreadsheets;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XInterface;
+import com.sun.star.util.URL;
+import com.sun.star.util.XURLTransformer;
+import java.util.*;
+import util.utils;
+
+
+// ---------- junit imports -----------------
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+import util.SOfficeFactory;
+import static org.junit.Assert.*;
+
+
+
+/** @short Check some use cases of the AutoSave feature
+ */
+public class AutoSave
+{
+
+ private static class AutoSaveListener implements XStatusListener
+ {
+ private XDispatch m_xAutoSave;
+ private URL m_aRegistration;
+ private final Protocol m_aLog;
+
+ private AutoSaveListener(XMultiServiceFactory xSMGR ,
+ XDispatch xAutoSave,
+ Protocol aLog )
+ {
+ m_aLog = aLog;
+ m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "create listener for AutoSave notifications ...");
+
+ try
+ {
+ m_xAutoSave = xAutoSave;
+
+ XURLTransformer xParser = UnoRuntime.queryInterface(XURLTransformer.class, xSMGR.createInstance("com.sun.star.util.URLTransformer"));
+ URL[] aURL = new URL[1];
+ aURL[0] = new URL();
+ aURL[0].Complete = "vnd.sun.star.autorecovery:/doAutoSave";
+ xParser.parseStrict(aURL);
+ m_aRegistration = aURL[0];
+
+ m_xAutoSave.addStatusListener(this, m_aRegistration);
+ m_aLog.log(Protocol.TYPE_INFO, "successfully registered as AutoSave listener.");
+ }
+ catch(Throwable ex)
+ {
+ m_aLog.log(ex);
+ }
+
+ m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "");
+ }
+
+ private void disableListener()
+ {
+ m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "stop listening for AutoSave notifications ...");
+
+ XDispatch xAutoSave = null;
+ URL aRegURL = null;
+ synchronized (this)
+ {
+ xAutoSave = m_xAutoSave;
+ aRegURL = m_aRegistration;
+ }
+
+ try
+ {
+ if (
+ (xAutoSave != null) &&
+ (aRegURL != null)
+ )
+ xAutoSave.removeStatusListener(this, aRegURL);
+ }
+ catch(Throwable ex)
+ {
+ m_aLog.log(ex);
+ }
+
+ m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "");
+ }
+
+ public void statusChanged(FeatureStateEvent aEvent)
+ {
+ m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "statusChanged() called from AutoSave ...");
+
+ m_aLog.log("FeatureURL = \""+aEvent.FeatureURL.Complete+"\"" );
+ m_aLog.log("FeatureDescriptor = \""+aEvent.FeatureDescriptor+"\"" );
+ m_aLog.log("IsEnabled = \""+aEvent.IsEnabled+"\"" );
+ m_aLog.log("Requery = \""+aEvent.Requery+"\"" );
+ m_aLog.log("State:" );
+ m_aLog.log(aEvent.State );
+
+ m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "");
+ }
+
+ public void disposing(com.sun.star.lang.EventObject aEvent)
+ {
+ m_aLog.log(Protocol.TYPE_INFO, "disposing() called from AutoSave.");
+ synchronized(this)
+ {
+ m_xAutoSave = null;
+ m_aRegistration = null;
+ }
+ }
+ }
+
+
+ // some const
+
+
+ // member
+
+ private Protocol m_aLog;
+
+ /** points to the global uno service manager. */
+ private XMultiServiceFactory m_xSMGR = null;
+
+ private SOfficeFactory m_aSOF;
+
+ /** can be used to trigger/enable/disable the AutoSave feature. */
+ private XDispatch m_xAutoSave = null;
+
+ private XURLTransformer m_xURLParser = null;
+
+
+ // test environment
+
+
+ /** @short Create the environment for following tests.
+
+ @descr create an empty test frame, where we can load
+ different components inside.
+ */
+ @Before public void before()
+ {
+ m_aLog = new Protocol(Protocol.MODE_HTML | Protocol.MODE_STDOUT, Protocol.FILTER_NONE, utils.getUsersTempDir() + "/complex_log_ascii_01.html");
+
+ try
+ {
+ // get uno service manager from global test environment
+ m_xSMGR = getMSF();
+
+ // get another helper to e.g. create test documents
+ m_aSOF = SOfficeFactory.getFactory(m_xSMGR);
+
+ // create AutoSave instance
+ m_xAutoSave = theAutoRecovery.get(connection.getComponentContext());
+
+ // prepare AutoSave
+ // make sure it will be started every 1 min
+ ConfigHelper aConfig = new ConfigHelper(connection.getComponentContext(), "org.openoffice.Office.Recovery", false);
+ aConfig.writeRelativeKey("AutoSave", "Enabled" , Boolean.TRUE );
+ aConfig.writeRelativeKey("AutoSave", "TimeIntervall", Integer.valueOf(1)); // 1 min
+ aConfig.flush();
+ aConfig = null;
+
+ // is needed to parse dispatch commands
+ m_xURLParser = UnoRuntime.queryInterface(XURLTransformer.class, m_xSMGR.createInstance("com.sun.star.util.URLTransformer"));
+
+ }
+ catch(java.lang.Throwable ex)
+ {
+ m_aLog.log(ex);
+ fail("Couldn't create test environment");
+ }
+ }
+
+
+ /** @short close the environment.
+ */
+ @After public void after()
+ {
+ // ???
+ }
+
+
+ // create a calc document with content, which needs some time for saving
+ private XInterface createBigCalcDoc()
+ {
+ m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "createBigCalcDoc() started ...");
+ try
+ {
+ m_aLog.log("Create empty calc document for testing.");
+ XSpreadsheetDocument xSheetDoc = m_aSOF.createCalcDoc("_default");
+ m_aLog.log("Retrieve first sheet from calc document.");
+ XSpreadsheets xSheets = xSheetDoc.getSheets();
+ XSpreadsheet xSheet = (XSpreadsheet)AnyConverter.toObject(
+ new Type(XSpreadsheet.class),
+ xSheets.getByName(
+ xSheets.getElementNames()[0]));
+ m_aLog.log("Fill two cells with value and formula.");
+ xSheet.getCellByPosition(0, 0).setValue(1);
+ xSheet.getCellByPosition(0, 1).setFormula("=a1+1");
+ m_aLog.log("Retrieve big range.");
+ XCellRange xRange = xSheet.getCellRangeByName("A1:Z9999");
+ XCellSeries xSeries = UnoRuntime.queryInterface(XCellSeries.class, xRange);
+ m_aLog.log("Duplicate cells from top to bottom inside range.");
+ xSeries.fillAuto(FillDirection.TO_BOTTOM, 2);
+ m_aLog.log("Duplicate cells from left to right inside range.");
+ xSeries.fillAuto(FillDirection.TO_RIGHT , 1);
+
+ m_aLog.log(Protocol.TYPE_SCOPE_CLOSE | Protocol.TYPE_OK, "createBigCalcDoc() finished.");
+ return xSheetDoc;
+ }
+ catch(Throwable ex)
+ {
+ m_aLog.log(ex);
+ }
+
+ m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "createBigCalcDoc() finished.");
+ return null;
+ }
+
+
+ private void saveDoc(XInterface xDoc,
+ String sURL)
+ {
+ m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "saveDoc('"+sURL+"') started ...");
+ try
+ {
+ URL[] aURL = new URL[1];
+ aURL[0] = new URL();
+ aURL[0].Complete = ".uno:SaveAs";
+ m_xURLParser.parseStrict(aURL);
+
+ XModel xModel = UnoRuntime.queryInterface(XModel.class, xDoc);
+ XDispatchProvider xProvider = UnoRuntime.queryInterface(XDispatchProvider.class, xModel.getCurrentController());
+ XDispatch xDispatch = xProvider.queryDispatch(aURL[0], "_self", 0);
+
+ PropertyValue[] lArgs = new PropertyValue[3];
+ lArgs[0] = new PropertyValue();
+ lArgs[0].Name = "URL";
+ lArgs[0].Value = sURL;
+ lArgs[1] = new PropertyValue();
+ lArgs[1].Name = "Overwrite";
+ lArgs[1].Value = Boolean.TRUE;
+ lArgs[2] = new PropertyValue();
+ lArgs[2].Name = "StoreTo";
+ lArgs[2].Value = Boolean.TRUE;
+
+ xDispatch.dispatch(aURL[0], lArgs);
+
+ m_aLog.log(Protocol.TYPE_OK, "saveDoc('"+sURL+"') = OK.");
+ }
+ catch(Throwable ex)
+ {
+ m_aLog.log(ex);
+ }
+ m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "saveDoc('"+sURL+"') finished.");
+ }
+
+
+ private void closeDoc(XInterface xDoc)
+ {
+ m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "closeDoc() started ...");
+
+ try
+ {
+ Random aRandom = new Random();
+ int nRetry = 5;
+ while(nRetry>0)
+ {
+ try
+ {
+ XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xDoc);
+ if (xClose != null)
+ {
+ xClose.close(false);
+ m_aLog.log(Protocol.TYPE_OK, "closeDoc() = OK.");
+ nRetry = 0;
+ }
+ else
+ {
+ m_aLog.log(Protocol.TYPE_ERROR, "closeDoc() = ERROR. Doc doesn't provide needed interface!");
+ }
+ }
+ catch(com.sun.star.util.CloseVetoException exVeto)
+ {
+ m_aLog.log(Protocol.TYPE_WARNING , "got CloseVetoException on calling doc.close()." );
+ m_aLog.log(Protocol.TYPE_WARNING_INFO, "Please check the reason for that more in detail." );
+ m_aLog.log(Protocol.TYPE_WARNING_INFO, "A message like \"Can not close while saving.\" was intended and doesn't show an error!");
+ m_aLog.log(Protocol.TYPE_WARNING_INFO, exVeto.getMessage());
+ }
+
+ if (nRetry > 0)
+ {
+ --nRetry;
+ long nWait = aRandom.nextInt(30000); // 30 sec.
+ try
+ {
+ m_aLog.log(Protocol.TYPE_INFO, "sleep for "+nWait+" ms");
+ synchronized(this)
+ {
+ wait(nWait);
+ }
+ }
+ catch(Throwable ex)
+ {
+ m_aLog.log(Protocol.TYPE_WARNING , "got exception for wait() !?");
+ m_aLog.log(Protocol.TYPE_WARNING_INFO, ex.getMessage());
+ }
+ }
+ }
+ }
+ catch(Throwable ex)
+ {
+ m_aLog.log(ex);
+ }
+
+ m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "closeDoc() finished.");
+ }
+
+ private class DocThread extends Thread
+ {
+ DocThread()
+ {}
+
+ @Override
+ public void run()
+ {
+ impl_checkConcurrentAutoSaveToNormalUISave();
+ }
+ }
+
+
+ /** @short check concurrent save requests to the same document
+ * at the same time.
+ *
+ * @descr First we simulate an UI save by dispatching the right URL
+ * to the document and at the same time we try to trigger an AutoSave
+ * from another thread. So these operations should be started at the same time.
+ * It should not crash. The AutoSave request must be postponed.
+ */
+ @Test public void checkConcurrentAutoSaveToNormalUISave()
+ {
+ m_aLog.log(Protocol.TYPE_TESTMARK , "AutoSave");
+ m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "checkConcurrentAutoSaveToNormalUISave()");
+
+ AutoSaveListener xListener = new AutoSaveListener(m_xSMGR, m_xAutoSave, m_aLog);
+
+ try
+ {
+ DocThread aThread = new DocThread();
+ aThread.start();
+ aThread.join();
+ }
+ catch(Throwable ex)
+ {}
+
+ xListener.disableListener();
+
+ m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "checkConcurrentAutoSaveToNormalUISave()");
+ m_aLog.logStatistics();
+ }
+
+ public void impl_checkConcurrentAutoSaveToNormalUISave()
+ {
+ Random aRandom = new Random();
+
+ int i = 0;
+ int c = 5;
+ for (i=0; i<c; ++i)
+ {
+ XInterface xDoc = createBigCalcDoc();
+ try
+ {
+ long nWait = aRandom.nextInt(120000);
+ m_aLog.log(Protocol.TYPE_INFO, "sleep for "+nWait+" ms");
+ synchronized(this)
+ {
+ wait(nWait);
+ }
+ }
+ catch(Throwable ex)
+ {
+ m_aLog.log(Protocol.TYPE_WARNING , "got exception for wait() !?");
+ m_aLog.log(Protocol.TYPE_WARNING_INFO, ex.getMessage());
+ }
+ saveDoc(xDoc, utils.getOfficeTemp(m_xSMGR) + "/test_calc.ods");
+ closeDoc(xDoc);
+ }
+ }
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass
+ public static void setUpConnection() throws Exception
+ {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass
+ public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+ private static final OfficeConnection connection = new OfficeConnection();
+}
diff --git a/framework/qa/complex/framework/autosave/ConfigHelper.java b/framework/qa/complex/framework/autosave/ConfigHelper.java
new file mode 100644
index 000000000..3e7fc394f
--- /dev/null
+++ b/framework/qa/complex/framework/autosave/ConfigHelper.java
@@ -0,0 +1,94 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.framework.autosave;
+
+import com.sun.star.uno.*;
+import com.sun.star.lang.*;
+import com.sun.star.configuration.theDefaultProvider;
+import com.sun.star.container.*;
+import com.sun.star.beans.*;
+import com.sun.star.util.*;
+
+class ConfigHelper
+{
+ private final XHierarchicalNameAccess m_xConfig;
+
+
+ public ConfigHelper(XComponentContext context,
+ String sConfigPath ,
+ boolean bReadOnly )
+ throws com.sun.star.uno.Exception
+ {
+ XMultiServiceFactory xConfigRoot = theDefaultProvider.get(context);
+
+ PropertyValue[] lParams = new PropertyValue[1];
+ lParams[0] = new PropertyValue();
+ lParams[0].Name = "nodepath";
+ lParams[0].Value = sConfigPath;
+
+ Object aConfig;
+ if (bReadOnly)
+ {
+ aConfig = xConfigRoot.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", lParams);
+ }
+ else
+ {
+ aConfig = xConfigRoot.createInstanceWithArguments("com.sun.star.configuration.ConfigurationUpdateAccess", lParams);
+ }
+
+ m_xConfig = UnoRuntime.queryInterface(XHierarchicalNameAccess.class, aConfig);
+
+ if (m_xConfig == null)
+ {
+ throw new com.sun.star.uno.Exception("Could not open configuration \"" + sConfigPath + "\"");
+ }
+ }
+
+
+
+
+
+ public void writeRelativeKey(String sRelPath,
+ String sKey ,
+ Object aValue )
+ throws com.sun.star.container.NoSuchElementException
+ {
+ try
+ {
+ XPropertySet xPath = UnoRuntime.queryInterface(XPropertySet.class, m_xConfig.getByHierarchicalName(sRelPath));
+ xPath.setPropertyValue(sKey, aValue);
+ }
+ catch(com.sun.star.uno.Exception ex)
+ {
+ throw new com.sun.star.container.NoSuchElementException(ex);
+ }
+ }
+
+
+ public void flush()
+ {
+ try
+ {
+ XChangesBatch xBatch = UnoRuntime.queryInterface(XChangesBatch.class, m_xConfig);
+ xBatch.commitChanges();
+ }
+ catch(com.sun.star.uno.Exception ex)
+ {}
+ }
+}
diff --git a/framework/qa/complex/framework/autosave/Protocol.java b/framework/qa/complex/framework/autosave/Protocol.java
new file mode 100644
index 000000000..d5cc42b67
--- /dev/null
+++ b/framework/qa/complex/framework/autosave/Protocol.java
@@ -0,0 +1,890 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.framework.autosave;
+
+// __________ Imports __________
+
+// others
+import javax.swing.*;
+import java.io.*;
+import java.sql.*;
+
+// __________ Implementation __________
+
+/**
+ * Implements a log mechanism to create a protocol of all steps of e.g. an api test
+ * It provides the possibility to write the logged messages to a file and/or
+ * to stdout/stderr (if necessary at the same time!).
+ *
+ * TODO
+ * - implement filter, which e.g. suppress showing of INFO data
+ */
+public class Protocol extends JComponent
+{
+
+ /**
+ * Note: Following values can be combined - they are interpreted as flags.
+ *
+ * @const MODE_STDOUT messages are logged to stdout
+ * @const MODE_STDERR messages are logged to stderr
+ * @const MODE_ASCII messages are logged to an ascii file
+ * @const MODE_HTML messages are logged to a html file
+ *
+ * @const TYPE_SCOPE_OPEN open, mark or count a new scope for following log statements
+ * @const TYPE_SCOPE_CLOSE close, mark or count the current scope
+ * @const TYPE_TESTMARK it marks the beginning of a (sub)test, can be used for statistic purposes
+ * @const TYPE_OK this protocol line is marked as an OK message
+ * @const TYPE_ERROR this protocol line is marked as an error
+ * @const TYPE_WARNING this protocol line is marked as a warning
+ * @const TYPE_INFO this protocol line represent some debug data for analyzing
+ */
+ public static final int MODE_STDOUT = 1;
+ private static final int MODE_STDERR = 2;
+ private static final int MODE_ASCII = 4;
+ public static final int MODE_HTML = 8;
+
+ public static final int TYPE_OK = 1;
+ public static final int TYPE_ERROR = 2;
+ public static final int TYPE_WARNING = 4;
+ public static final int TYPE_INFO = 8;
+ public static final int TYPE_SCOPE_OPEN = 16;
+ public static final int TYPE_SCOPE_CLOSE = 32;
+ public static final int TYPE_TESTMARK = 64;
+ private static final int TYPE_ERROR_INFO = 128;
+ public static final int TYPE_WARNING_INFO = 256;
+ private static final int TYPE_STATISTIC = 512;
+ private static final int TYPE_LINK = 1024;
+
+ public static final int FILTER_NONE = 0;
+
+
+
+
+
+
+
+
+
+
+
+
+ /**
+ */
+ private static final int MARK_DIFF = 5;
+
+ private static final String BGCOLOR_LINECOL = "#95CC77";
+ private static final String FGCOLOR_LINECOL_NORMAL = "#ffffbd";
+ private static final String FGCOLOR_LINECOL_MARKED = "#000088";
+
+ private static final String BGCOLOR_STANDARD = "#ffffff";
+ private static final String FGCOLOR_STANDARD = "#000000";
+
+ private static final String BGCOLOR_SCOPE = "#eeeeee";
+ private static final String FGCOLOR_SCOPE = "#000000";
+
+ private static final String BGCOLOR_TIMESTAMP = "#e0e0e0";
+ private static final String FGCOLOR_TIMESTAMP = "#000000";
+
+ private static final String BGCOLOR_TESTMARK = "#0000ff";
+ private static final String FGCOLOR_TESTMARK = "#ffffff";
+
+ private static final String BGCOLOR_OK = "#88dd88";
+ private static final String FGCOLOR_OK = "#ffffff";
+
+ private static final String BGCOLOR_WARNING = "#ffff00";
+ private static final String FGCOLOR_WARNING = "#000000";
+
+ private static final String BGCOLOR_WARNING_INFO = "#ffffcc";
+ private static final String FGCOLOR_WARNING_INFO = "#000000";
+
+ private static final String BGCOLOR_ERROR = "#ff0000";
+ private static final String FGCOLOR_ERROR = "#ffff00";
+
+ private static final String BGCOLOR_ERROR_INFO = "#ffbbbb";
+ private static final String FGCOLOR_ERROR_INFO = "#000000";
+
+ private static final String BGCOLOR_INFO = "#eeeeee";
+ private static final String FGCOLOR_INFO = "#000000";
+
+ private static final String BGCOLOR_STATISTIC = "#0000ff";
+ private static final String FGCOLOR_STATISTIC = "#ffffff";
+
+ private static final String BGCOLOR_LINK = BGCOLOR_INFO;
+ private static final String FGCOLOR_LINK = FGCOLOR_INFO;
+
+
+ /**
+ * @member m_nMode the mode, in which this protocol object runs
+ * @member m_nFilter can be used to filter log messages by type
+ * @member m_sFileName we need it to open the log file on demand (if nMode require such log file)
+ * @member m_nLine used as line number for the protocol
+ * @member m_nScope used to format scopes
+ * @member m_nErrors count errors in protocol
+ * @member m_nWarnings count warnings in protocol
+ * @member m_nTestMarks count test marker in protocol
+ */
+ private final int m_nMode ;
+ private final int m_nFilter ;
+ private final String m_sFileName ;
+ private long m_nLine ;
+ private long m_nScope ;
+ private long m_nErrors ;
+ private long m_nWarnings ;
+ private long m_nTestMarks;
+ private Timestamp m_aStartTime;
+
+
+ /**
+ * special helper class to represent one line of a protocol.
+ * Such line can be specified as a special one (ERROR, WARNING ...).
+ * That makes it possible to analyze the whole protocol using tools.
+ */
+ private class ProtocolLine
+ {
+ /// the line number of this protocol line (size of the vector of all protocol lines cn be used to count such lines!)
+ private final long m_nLine;
+ /// deepness of the current scope
+ private final long m_nScope;
+ /// mark line as an error, warning, data entry ... (see const definitions before)
+ private final int m_nType;
+ /// of course, we have to know the logged message too :-)
+ private final String m_sMessage;
+ /// and it can be useful to know the current time, when this line was created
+ private final Timestamp m_aStamp;
+
+ /** ctor for fast initializing of such line */
+ private ProtocolLine( long nLine ,
+ long nScope ,
+ int nType ,
+ String sMessage )
+ {
+ m_aStamp = new Timestamp(System.currentTimeMillis());
+ m_nLine = nLine ;
+ m_nScope = nScope ;
+ m_nType = nType ;
+ m_sMessage = sMessage;
+ }
+
+ /** format this line as an ascii string for writing log files */
+ @Override
+ public synchronized String toString()
+ {
+ StringBuffer sLine = new StringBuffer(1000);
+
+ // insert line number
+ // Use right bound notation and format 6 digits!
+ sLine.append("[" );
+ if (m_nLine<10)
+ sLine.append(" ");
+ else
+ if (m_nLine<100)
+ sLine.append(" ");
+ else
+ if (m_nLine<1000)
+ sLine.append(" ");
+ else
+ if (m_nLine<10000)
+ sLine.append(" ");
+ else
+ if (m_nLine<100000)
+ sLine.append(" ");
+ sLine.append(m_nLine);
+ sLine.append("] " );
+
+ // add time stamp
+ // close with a "TAB" ... because some time stamps are not normalized to
+ // a well defined string length .-)
+ sLine.append(m_aStamp.toString()+" \t");
+
+ // add special line type
+ if ((m_nType & TYPE_OK) == TYPE_OK)
+ sLine.append(" OK ");
+ else
+ if ((m_nType & TYPE_ERROR) == TYPE_ERROR)
+ sLine.append(" ERROR ");
+ else
+ if ((m_nType & TYPE_ERROR_INFO) == TYPE_ERROR_INFO)
+ sLine.append(" ERROR INFO ");
+ else
+ if ((m_nType & TYPE_WARNING) == TYPE_WARNING)
+ sLine.append(" WARNING ");
+ else
+ if ((m_nType & TYPE_WARNING_INFO) == TYPE_WARNING_INFO)
+ sLine.append(" WARNING INFO ");
+ else
+ if ((m_nType & TYPE_INFO) == TYPE_INFO)
+ sLine.append(" INFO ");
+ else
+ if ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK)
+ sLine.append(" TEST ");
+ else
+ if ((m_nType & TYPE_LINK) == TYPE_LINK)
+ sLine.append(" LINK ");
+ else
+ if ((m_nType & TYPE_STATISTIC) == TYPE_STATISTIC)
+ sLine.append(" STATISTIC ");
+ else
+ if (
+ ((m_nType & TYPE_SCOPE_OPEN ) == TYPE_SCOPE_OPEN ) ||
+ ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE)
+ )
+ sLine.append(" SCOPE ");
+ else
+ sLine.append(" ");
+
+ // add scope information
+ for (int s=0; s<m_nScope; ++s)
+ sLine.append(" ");
+
+ if ((m_nType & TYPE_SCOPE_OPEN) == TYPE_SCOPE_OPEN)
+ sLine.append(" { ");
+ else
+ if ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE)
+ sLine.append(" } ");
+ else
+ sLine.append(" ");
+
+ // add message
+ sLine.append(m_sMessage);
+ sLine.append("\n" );
+
+ return sLine.toString();
+ }
+
+ /**
+ * format this line as a string for writing log files
+ * using the html format
+ */
+ private synchronized String toHTML()
+ {
+ StringBuffer sLine = new StringBuffer(1000);
+ sLine.append("<tr>");
+
+ // insert line number
+ if (m_nLine % MARK_DIFF == 0)
+ impl_generateColoredHTMLCell(sLine, Long.toString(m_nLine), BGCOLOR_LINECOL, FGCOLOR_LINECOL_MARKED, true);
+ else
+ impl_generateColoredHTMLCell(sLine, Long.toString(m_nLine), BGCOLOR_LINECOL, FGCOLOR_LINECOL_NORMAL, false);
+
+ // add time stamp
+ impl_generateColoredHTMLCell(sLine, m_aStamp.toString()+" ", BGCOLOR_TIMESTAMP, FGCOLOR_TIMESTAMP, false);
+
+ // add log type info
+ boolean bTypeCellFilled = false;
+ if ((m_nType & TYPE_ERROR_INFO) == TYPE_ERROR_INFO)
+ {
+ impl_generateColoredHTMLCell(sLine, "ERROR INFO", BGCOLOR_ERROR_INFO, FGCOLOR_ERROR_INFO, false);
+ bTypeCellFilled = true;
+ }
+ else
+ if ((m_nType & TYPE_ERROR) == TYPE_ERROR)
+ {
+ impl_generateColoredHTMLCell(sLine, "ERROR", BGCOLOR_ERROR, FGCOLOR_ERROR, true);
+ bTypeCellFilled = true;
+ }
+ else
+ if ((m_nType & TYPE_WARNING_INFO) == TYPE_WARNING_INFO)
+ {
+ impl_generateColoredHTMLCell(sLine, "WARNING INFO", BGCOLOR_WARNING_INFO, FGCOLOR_WARNING_INFO, false);
+ bTypeCellFilled = true;
+ }
+ else
+ if ((m_nType & TYPE_WARNING) == TYPE_WARNING)
+ {
+ impl_generateColoredHTMLCell(sLine, "WARNING", BGCOLOR_WARNING, FGCOLOR_WARNING, true);
+ bTypeCellFilled = true;
+ }
+ else
+ if ((m_nType & TYPE_OK) == TYPE_OK)
+ {
+ impl_generateColoredHTMLCell(sLine, "OK", BGCOLOR_OK, FGCOLOR_OK, true);
+ bTypeCellFilled = true;
+ }
+ else
+ if ((m_nType & TYPE_INFO) == TYPE_INFO)
+ {
+ impl_generateColoredHTMLCell(sLine, "INFO", BGCOLOR_INFO, FGCOLOR_INFO, false);
+ bTypeCellFilled = true;
+ }
+ else
+ if ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK)
+ {
+ impl_generateColoredHTMLCell(sLine, "TEST", BGCOLOR_TESTMARK, FGCOLOR_TESTMARK, true);
+ bTypeCellFilled = true;
+ }
+ else
+ if ((m_nType & TYPE_STATISTIC) == TYPE_STATISTIC)
+ {
+ impl_generateColoredHTMLCell(sLine, "STATISTIC", BGCOLOR_STATISTIC, FGCOLOR_STATISTIC, false);
+ bTypeCellFilled = true;
+ }
+ else
+ if ((m_nType & TYPE_LINK) == TYPE_LINK)
+ {
+ impl_generateColoredHTMLCell(sLine, "LINK", BGCOLOR_LINK, FGCOLOR_LINK, false);
+ bTypeCellFilled = true;
+ }
+ else
+ if (
+ ((m_nType & TYPE_SCOPE_OPEN ) == TYPE_SCOPE_OPEN ) ||
+ ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE)
+ )
+ {
+ impl_generateColoredHTMLCell(sLine, "SCOPE", BGCOLOR_SCOPE, FGCOLOR_SCOPE, false);
+ bTypeCellFilled = true;
+ }
+
+ // if no type information was added to the current column, we must
+ // write any content into this cell. Otherwise some browser
+ // shows a strange layout!
+ if (! bTypeCellFilled)
+ impl_generateColoredHTMLCell(sLine, " ", BGCOLOR_STANDARD, FGCOLOR_STANDARD, false);
+
+ // add scope information
+ sLine.append("<td>");
+ for (int s=0; s<m_nScope; ++s)
+ sLine.append("&nbsp;&nbsp;&nbsp;");
+ String sColor = "#000000";
+ if ((m_nScope % 2) == 0)
+ sColor = "#808080";
+ if ((m_nType & TYPE_SCOPE_OPEN) == TYPE_SCOPE_OPEN)
+ sLine.append("<font color=\""+sColor+"\">{ "+m_nScope+"</font>");
+ else
+ if ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE)
+ sLine.append("<font color=\""+sColor+"\">"+m_nScope+" }</font>");
+ sLine.append("</td>\n");
+
+ // add message
+ sLine.append("<td>" );
+ sLine.append(m_sMessage);
+ sLine.append("</td>\n" );
+
+ sLine.append("</tr>\n" );
+
+ return sLine.toString();
+ }
+
+ /** detect, if this line object represent an error */
+ public synchronized boolean isError()
+ {
+ return (
+ ((m_nType & TYPE_ERROR) == TYPE_ERROR) &&
+ ((m_nType & TYPE_INFO ) != TYPE_INFO )
+ );
+ }
+
+ /** detect, if this line object represent a warning */
+ public synchronized boolean isWarning()
+ {
+ return (
+ ((m_nType & TYPE_WARNING) == TYPE_WARNING) &&
+ ((m_nType & TYPE_INFO ) != TYPE_INFO )
+ );
+ }
+
+ /** detect, if this line object represent a marked position */
+ public synchronized boolean isTestMark()
+ {
+ return ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK);
+ }
+
+ /**
+ * create a colored table cell formatted as HTML.
+ *
+ * @param sCell
+ * an outside string buffer, which can be
+ * used to generate the
+ * needed HTML code there.
+ *
+ * @param sContent
+ * the text content of this cell.
+ *
+ * @param sBGColor
+ * a string, which represent the background color
+ * coded in HTML.
+ *
+ * @param sFGColor
+ * a string, which represent the foreground color
+ * coded in HTML.
+ *
+ * @param bBold
+ * enable/disable bold state for the text content.
+ */
+ private void impl_generateColoredHTMLCell(StringBuffer sCell ,
+ String sContent,
+ String sBGColor,
+ String sFGColor,
+ boolean bBold )
+ {
+ sCell.append("<td bgcolor=\""+sBGColor+"\">");
+ sCell.append("<font color=\""+sFGColor+"\">");
+ if (bBold)
+ sCell.append("<b>");
+ sCell.append(sContent);
+ if (bBold)
+ sCell.append("</b>");
+ sCell.append("</font></td>\n");
+ }
+ }
+
+
+ /**
+ * ctor
+ * It creates a new instance of this class and initializes it in the right mode.
+ *
+ * @param nMode
+ * specify how the log should be generated.
+ *
+ * @param nFilter
+ * can be used to filter log messages by its type.
+ *
+ * @param sFileName
+ * the name of the log file (if nMode requires a log file)
+ */
+ public Protocol(int nMode ,
+ int nFilter ,
+ String sFileName)
+ {
+ m_nMode = nMode;
+ m_nFilter = nFilter;
+ m_sFileName = sFileName;
+ m_nLine = 0;
+ m_nScope = 1;
+ m_nWarnings = 0;
+ m_nErrors = 0;
+ m_aStartTime = new Timestamp(System.currentTimeMillis());
+ }
+
+
+
+
+
+ /**
+ * log an unspecified message.
+ *
+ * Sometimes it's not necessary to set a special type for a message.
+ * The pure message seems to be enough. The type of such "pure messages"
+ * will be set to INFO.
+ *
+ * @param sMessage
+ * the pure message
+ *
+ * @see #log(int, String)
+ */
+ public synchronized void log( /*IN*/ String sMessage )
+ {
+ log(TYPE_INFO, sMessage);
+ }
+
+
+ /**
+ * log an exception.
+ *
+ * It uses all information available by this exception object
+ * to generate the log. So exceptions are printed out using a
+ * standard format.
+ *
+ * @param exThrowable
+ * the exception
+ */
+ public synchronized void log( /*IN*/ Throwable exThrowable )
+ {
+ log(TYPE_SCOPE_OPEN | TYPE_ERROR, "exception \""+exThrowable.getMessage()+"\"");
+
+ StackTraceElement[] lStack = exThrowable.getStackTrace();
+ for (int i=0; i<lStack.length; ++i)
+ log(TYPE_ERROR_INFO, lStack[i].toString());
+
+ log(TYPE_SCOPE_CLOSE | TYPE_ERROR_INFO, "");
+ }
+
+
+
+
+
+
+
+
+
+
+ public synchronized void log( /*IN*/ Object aAny )
+ {
+ StringBuffer sValue = new StringBuffer(1000);
+ impl_logAny(sValue, aAny);
+
+ log(TYPE_SCOPE_OPEN | TYPE_INFO, "any:" );
+ log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValue.toString());
+ }
+
+
+ /**
+ * log a message.
+ *
+ * It looks for the internal set mode and decide, how this message
+ * will be handled. Then it generates a special object which represent
+ * one protocol line, format it and print it out.
+ *
+ * @param nType
+ * mark a line as a special one or open/close scopes
+ *
+ * @param sMessage
+ * the message, which the outside code wish to be written into the log
+ */
+ public synchronized void log( /*IN*/ int nType ,
+ /*IN*/ String sMessage )
+ {
+ nType = (nType & ~m_nFilter);
+ if (nType == 0)
+ return;
+
+ ++m_nLine;
+
+ // it's necessary to open scopes before creating the protocol line
+ // to guarantee right tab handling for new scope value!
+ if ((nType & TYPE_SCOPE_OPEN) == TYPE_SCOPE_OPEN)
+ ++m_nScope;
+
+ // create the protocol line
+ ProtocolLine aLine = new ProtocolLine(m_nLine, m_nScope, nType, sMessage);
+ String sAsciiLog = aLine.toString();
+ String sHTMLLog = aLine.toHTML();
+
+ // it's necessary to close scope after creating the protocol line
+ // to guarantee right tab handling for old scope value!
+ if (
+ ( m_nScope > 0 ) &&
+ ((nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE)
+ )
+ {
+ --m_nScope;
+ }
+
+ // update statistic values
+ if (aLine.isTestMark())
+ ++m_nTestMarks;
+ if (aLine.isWarning())
+ ++m_nWarnings;
+ if (aLine.isError())
+ ++m_nErrors;
+
+ // no else - it's a bit field of possible reactions!
+ if ((m_nMode & MODE_STDOUT) == MODE_STDOUT)
+ System.out.print(sAsciiLog);
+ // no else - it's a bit field of possible reactions!
+ if ((m_nMode & MODE_STDERR) == MODE_STDERR)
+ System.err.print(sAsciiLog);
+ // no else - it's a bit field of possible reactions!
+ // But these both conditions must be handled together.
+ // Because we can't generate different types of log contents to the same log file.
+ // We prefer HTML if both types are set.
+ if (
+ ((m_nMode & MODE_HTML ) == MODE_HTML ) ||
+ ((m_nMode & MODE_ASCII) == MODE_ASCII)
+ )
+ {
+ boolean bAppend = (m_nLine>1);
+ String sContent;
+ if ((m_nMode & MODE_HTML) == MODE_HTML)
+ {
+ if (! bAppend)
+ sContent = impl_generateHTMLHeader()+sHTMLLog;
+ else
+ sContent = sHTMLLog;
+ }
+ else
+ {
+ if (! bAppend)
+ sContent = impl_generateAsciiHeader()+sAsciiLog;
+ else
+ sContent = sAsciiLog;
+ }
+
+ impl_writeToLogFile(m_sFileName, bAppend, sContent);
+ }
+ }
+
+
+
+
+
+ /**
+ * log the current statistic values
+ * We write it into our protocol buffer and
+ * reset it.
+ */
+ public synchronized void logStatistics()
+ {
+ Timestamp aEndTime = new Timestamp(System.currentTimeMillis());
+ Timestamp aDiff = new Timestamp(aEndTime.getTime()-m_aStartTime.getTime());
+
+ int nLogType = TYPE_STATISTIC;
+ if (m_nErrors > 0)
+ nLogType = TYPE_ERROR_INFO;
+ else
+ if (m_nWarnings > 0)
+ nLogType = TYPE_WARNING_INFO;
+
+ log(nLogType | TYPE_SCOPE_OPEN , "statistic:" );
+ log(nLogType , "tests = "+m_nTestMarks );
+ log(nLogType , "errors = "+m_nErrors );
+ log(nLogType , "warnings = "+m_nWarnings );
+ log(nLogType , "elapsed time = "+aDiff.toString());
+ log(nLogType | TYPE_SCOPE_CLOSE, "" );
+
+ resetStatistics();
+ }
+
+ private synchronized void resetStatistics()
+ {
+ m_nTestMarks = 0;
+ m_nWarnings = 0;
+ m_nErrors = 0;
+ m_aStartTime = new Timestamp(System.currentTimeMillis());
+ }
+
+
+ /**
+ * returns a generic html header for generating html log files
+ *
+ * It's used from the method finish() to generate a valid html formatted file.
+ * For that it's necessary to open some special html targets like e.g. <html>.
+ *
+ * @return A string, which includes the whole header.
+ *
+ * @see #finish()
+ * @see #impl_generateHTMLFooter()
+ */
+ private String impl_generateHTMLHeader()
+ {
+ return "<html>\n<head>\n<title>"+m_sFileName+"</title>\n</head>\n<body>\n<table>\n";
+ }
+
+ private String impl_generateAsciiHeader()
+ {
+ return "********************************************************************************\n";
+ }
+
+ /**
+ * helper to log different representations of a property(array)
+ *
+ * @param sOut
+ * used to generate the log output there.
+ *
+ * @param lProps
+ * represent the property(array) to be logged.
+ */
+ private void impl_logPropertyArray( /*OUT*/ StringBuffer sOut ,
+ /*IN */ com.sun.star.beans.PropertyValue[] lProps )
+ {
+ int i = 0;
+ int c = lProps.length;
+
+ for (i=0; i<c; ++i)
+ impl_logProperty(sOut, lProps[i]);
+ }
+
+ private void impl_logPropertyArray( /*OUT*/ StringBuffer sOut ,
+ /*IN */ com.sun.star.beans.NamedValue[] lProps )
+ {
+ int i = 0;
+ int c = lProps.length;
+
+ for (i=0; i<c; ++i)
+ impl_logProperty(sOut, lProps[i]);
+ }
+
+ private void impl_logProperty( /*OUT*/ StringBuffer sOut ,
+ /*IN*/ com.sun.star.beans.NamedValue aProp )
+ {
+ sOut.append("\""+aProp.Name+"\" = ");
+ impl_logAny(sOut, aProp.Value);
+ }
+
+ private void impl_logProperty( /*OUT*/ StringBuffer sOut ,
+ /*IN*/ com.sun.star.beans.PropertyValue aProp )
+ {
+ sOut.append("\""+aProp.Name+"\" = ");
+ impl_logAny(sOut, aProp.Value);
+ }
+
+
+ /**
+ * it tries to convert the given any into a suitable string notation .-)
+ */
+ private synchronized void impl_logAny( /*OUT*/ StringBuffer sOut ,
+ /*IN */ Object aAny )
+ {
+ try
+ {
+ if (com.sun.star.uno.AnyConverter.isVoid(aAny))
+ {
+ sOut.append("[void] {");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isChar(aAny))
+ {
+ sOut.append("[char] {");
+ sOut.append(com.sun.star.uno.AnyConverter.toChar(aAny));
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isBoolean(aAny))
+ {
+ sOut.append("[boolean] {");
+ if (com.sun.star.uno.AnyConverter.toBoolean(aAny))
+ sOut.append("TRUE");
+ else
+ sOut.append("FALSE");
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isByte(aAny))
+ {
+ sOut.append("[byte] {");
+ sOut.append(com.sun.star.uno.AnyConverter.toByte(aAny));
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isShort(aAny))
+ {
+ sOut.append("[short] {");
+ sOut.append(com.sun.star.uno.AnyConverter.toShort(aAny));
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isInt(aAny))
+ {
+ sOut.append("[int] {");
+ sOut.append(com.sun.star.uno.AnyConverter.toInt(aAny));
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isLong(aAny))
+ {
+ sOut.append("[long] {");
+ sOut.append(com.sun.star.uno.AnyConverter.toLong(aAny));
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isFloat(aAny))
+ {
+ sOut.append("[float] {");
+ sOut.append(com.sun.star.uno.AnyConverter.toFloat(aAny));
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isDouble(aAny))
+ {
+ sOut.append("[double] {");
+ sOut.append(com.sun.star.uno.AnyConverter.toDouble(aAny));
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isString(aAny))
+ {
+ sOut.append("[string] {");
+ sOut.append(com.sun.star.uno.AnyConverter.toString(aAny));
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isEnum(aAny))
+ {
+ sOut.append("[enum] {");
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isType(aAny))
+ {
+ sOut.append("[type] {");
+ sOut.append("}");
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isArray(aAny))
+ {
+ if (aAny instanceof String[])
+ {
+ sOut.append("[sequence< string >] {");
+ sOut.append("}");
+ }
+ else
+ if (aAny instanceof com.sun.star.beans.PropertyValue[])
+ {
+ sOut.append("[sequence< PropertyValue >] {");
+ com.sun.star.beans.PropertyValue[] lSubProps = (com.sun.star.beans.PropertyValue[])com.sun.star.uno.AnyConverter.toArray(aAny);
+ impl_logPropertyArray(sOut, lSubProps);
+ sOut.append("}");
+ }
+ else
+ if (aAny instanceof com.sun.star.beans.NamedValue[])
+ {
+ sOut.append("[sequence< NamedValue >] {");
+ com.sun.star.beans.NamedValue[] lSubProps = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(aAny);
+ impl_logPropertyArray(sOut, lSubProps);
+ sOut.append("}");
+ }
+ else
+ {
+ sOut.append("[unknown array] {-}");
+ }
+ }
+ else
+ if (com.sun.star.uno.AnyConverter.isObject(aAny))
+ {
+ sOut.append("[object] {");
+ // TODO
+ sOut.append("}");
+ }
+
+ if ((m_nMode & MODE_HTML) == MODE_HTML)
+ sOut.append("<br>");
+ else
+ sOut.append("\n");
+ }
+ catch(com.sun.star.lang.IllegalArgumentException exIll)
+ {
+ sOut.append("Got exception during property conversion.\n");
+ sOut.append(exIll.getMessage());
+ sOut.append("\n");
+ }
+ }
+
+
+ /**
+ * Writes the given content to the specified log file.
+ */
+ private void impl_writeToLogFile(String sFileName,
+ boolean bAppend ,
+ String sContent )
+ {
+ try
+ {
+ FileWriter aLogFile = new FileWriter(sFileName, bAppend);
+ aLogFile.write(sContent);
+ aLogFile.flush();
+ aLogFile.close();
+ aLogFile = null;
+ }
+ catch (java.io.IOException exIO)
+ {
+ System.err.println("Can't dump protocol into log file.");
+ System.err.println(exIO);
+ exIO.printStackTrace();
+ }
+ }
+}
diff --git a/framework/qa/complex/framework/recovery/CrashThread.java b/framework/qa/complex/framework/recovery/CrashThread.java
new file mode 100644
index 000000000..8a16f83c6
--- /dev/null
+++ b/framework/qa/complex/framework/recovery/CrashThread.java
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.framework.recovery;
+
+import com.sun.star.frame.XController;
+import com.sun.star.frame.XDispatch;
+import com.sun.star.frame.XDispatchProvider;
+import com.sun.star.frame.XModel;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.URL;
+import com.sun.star.util.XURLTransformer;
+
+/**
+ * Thread to crash the office. This thread dies after the office process
+ * is nopt longer available.
+ */
+public class CrashThread extends Thread {
+ private final XComponent xDoc;
+ private final XMultiServiceFactory msf;
+
+ public CrashThread(XComponent xDoc, XMultiServiceFactory msf) {
+ this.xDoc = xDoc;
+ this.msf = msf;
+ }
+
+ @Override
+ public void run() {
+ try{
+ XModel xModel = UnoRuntime.queryInterface(XModel.class, xDoc);
+
+ XController xController = xModel.getCurrentController();
+ XDispatchProvider xDispProv = UnoRuntime.queryInterface(
+ XDispatchProvider.class,
+ xController);
+ XURLTransformer xParser = UnoRuntime.queryInterface(
+ XURLTransformer.class,
+ msf.createInstance(
+ "com.sun.star.util.URLTransformer"));
+
+ // Because it's an in/out parameter we must use an array of URL objects.
+ URL[] aParseURL = new URL[1];
+ aParseURL[0] = new URL();
+ aParseURL[0].Complete = ".uno:Crash";
+ xParser.parseStrict(aParseURL);
+
+ URL aURL = aParseURL[0];
+ XDispatch xDispatcher = xDispProv.queryDispatch(aURL, "", 0);
+
+ if (xDispatcher != null) {
+ xDispatcher.dispatch(aURL, null);
+ }
+ } catch (Exception e){}
+ }
+}
diff --git a/framework/qa/complex/framework/recovery/KlickButtonThread.java b/framework/qa/complex/framework/recovery/KlickButtonThread.java
new file mode 100644
index 000000000..90ecf68c4
--- /dev/null
+++ b/framework/qa/complex/framework/recovery/KlickButtonThread.java
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.framework.recovery;
+
+import com.sun.star.awt.XWindow;
+import util.UITools;
+
+/**
+ * Thread to crash the office. This thread dies after the office process
+ * is no longer available.
+ */
+public class KlickButtonThread extends Thread {
+ private final XWindow xWindow;
+ private final String buttonName;
+
+ public KlickButtonThread(XWindow xWindow, String buttonName) {
+ this.xWindow = xWindow;
+ this.buttonName = buttonName;
+ }
+
+ @Override
+ public void run() {
+ try{
+ UITools oUITools = new UITools(xWindow);
+
+ oUITools.clickButton(buttonName);
+
+ } catch (Exception e){}
+ }
+}
diff --git a/framework/qa/complex/framework/recovery/RecoveryTest.java b/framework/qa/complex/framework/recovery/RecoveryTest.java
new file mode 100644
index 000000000..ede07b486
--- /dev/null
+++ b/framework/qa/complex/framework/recovery/RecoveryTest.java
@@ -0,0 +1,611 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.framework.recovery;
+
+import com.sun.star.accessibility.XAccessibleContext;
+import com.sun.star.awt.Rectangle;
+import com.sun.star.awt.Size;
+import com.sun.star.awt.XDialog;
+import com.sun.star.awt.XWindow;
+import com.sun.star.container.XEnumeration;
+import com.sun.star.frame.XModel;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.text.ControlCharacter;
+import com.sun.star.text.XText;
+import com.sun.star.text.XTextCursor;
+import com.sun.star.text.XTextDocument;
+import com.sun.star.uno.UnoRuntime;
+import complexlib.ComplexTestCase;
+import helper.OfficeProvider;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Random;
+import util.DesktopTools;
+import util.PropertyName;
+import util.SOfficeFactory;
+import util.UITools;
+import util.utils;
+
+public class RecoveryTest extends ComplexTestCase {
+
+ static XMultiServiceFactory xMSF;
+ static SOfficeFactory SOF;
+ static RecoveryTools rt;
+ /**
+ * If you divide the screen in four parts in the first of them the office
+ * windows should be placed. The range of the first quarter is stored in the variable.
+ */
+ static Point windowMaxPosition;
+ /**
+ * The office windows starts in the first quarter of the screen. In this variable
+ * the maximum size for the windows was stored so the windows can be placed
+ * visible on the screen.
+ */
+ static Size windowMaxSize;
+
+ /**
+ * All office windows will be placed by this test on randomized positions.
+ * This positions was stored in this Hashmap. The keys are the frame names
+ * and the values are com sun.star.awt.Rectangle.
+ * @see com.sun.star.awt.Rectangle
+ */
+ private final HashMap<String, Rectangle> windowsPosSize = new HashMap<String, Rectangle>();
+
+ /**
+ * A function to tell the framework, which test functions are available.
+ * @return All test methods.
+ *
+ * @todo: hidden documents
+ * @todo: running presentation
+ * @todo: modular dialogs like Hpyerlink-Dialog
+ * @todo: second view of a document
+ * @todo: remove recovery data before start test
+ * @todo: after a second start after the crash there should no documents recovered anymore
+ * @todo: enable remove of recovery files
+ */
+ @Override
+ public String[] getTestMethodNames() {
+ return new String[]{"testCrash"};
+ }
+
+ /** Create the environment for following tests.
+ * Use either a component loader from desktop or
+ * from frame
+ */
+ public void normalCrash(){
+ cleanRecoveryData();
+ startOffice();
+ generateDesktop();
+ makeCrash();
+ int expectedDocumentCount = windowsPosSize.size() + 1;
+ handleRecoveryDialogAfterCrash(expectedDocumentCount);
+ startOffice();
+ handleRecoveryDialog_QuickExit(expectedDocumentCount);
+ handleCrashReporterDialog(true);
+ checkDocumentCount(expectedDocumentCount);
+ }
+
+ public void testCrash(){
+ cleanRecoveryData();
+ restoreBackupRecoveryData();
+ startOffice();
+ int expectedDocumentCount = 3;
+ handleRecoveryDialog_QuickExitAndSave(expectedDocumentCount);
+ }
+
+ public void before() throws Exception {
+
+ String msg ="\n\n\tPATH TO OFFICE BINARY MISSING!\n";
+ msg +="\tPlease run your command with the following parameter:\n\n";
+ msg +="\t-AppExecutionCommand=OFFICEBINARY CONNECTIONSTRING\n\n";
+ msg +="Example Windows:\n";
+ msg +="-AppExecutionCommand=C:\\office\\soffice.exe --accept=socket,host=localhost,port=8101;urp;\n\n";
+ msg +="Example UNIX:\n";
+ msg +="-AppExecutionCommand=/office/soffice \"--accept=socket,host=localhost,port=8101;urp;\"\n\n";
+ msg+="NOTE: on UNIX be sure to have the connection string inside quotation mark!\n";
+
+ assure(msg, param.get("AppExecutionCommand") != null && ! param.get("AppExecutionCommand").equals(""));
+ System.out.println("HALLO" + param.get("AppExecutionCommand"));
+ msg = "\n\nONE PARAMETER IS MISSING!\n";
+ msg += "Please append to your command the following parameter:\n\n";
+ msg += "\t-NoOffice=true";
+ assure(msg, param.getBool("NoOffice"));
+
+
+ rt = new RecoveryTools(param ,log);
+
+ rt.removeParametersFromAppExecutionCommand();
+
+ log.println("start the office to test recovery feature...");
+
+ // make window ranges
+ makeWindowPositionRage();
+
+ }
+
+ private void startOffice(){
+ assure("Could not connect to office", connect());
+ log.setWatcher(param.get("Watcher"));
+ }
+
+
+ private void checkDocumentCount(int expectedDocumentCount){
+ XEnumeration allComp = DesktopTools.getAllComponents(xMSF);
+ int documentCount = 0;
+
+ try{
+ while (allComp.hasMoreElements()){
+ allComp.nextElement();
+ documentCount ++;
+ }
+ }
+ catch ( com.sun.star.container.NoSuchElementException e){}
+ catch ( com.sun.star.lang.WrappedTargetException e){}
+
+ String msg ="The amount of documents to recover is different from the expected amount:\n";
+ msg += "\texpected:\t" + expectedDocumentCount + "\n";
+ msg += "\tto recover:\t" + documentCount;
+
+ assure(msg, expectedDocumentCount == documentCount);
+ }
+
+ /**
+ * This function starts an office instance. It uses the AppExecutionCommand parameter.
+ * @return TRUE if office is connected otherwise FALSE
+ */
+ private boolean connect(){
+ try {
+
+ OfficeProvider oProvider = new OfficeProvider();
+ xMSF = (XMultiServiceFactory)oProvider.getManager(param);
+
+ SOF = SOfficeFactory.getFactory(xMSF);
+
+ }
+ catch (java.lang.Exception e) {
+ log.println(e.getClass().getName());
+ log.println("Message: " + e.getMessage());
+ failed("Cannot connect the Office.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * This function crashes the office
+ */
+ private void makeCrash(){
+ // get all documents
+ Object[] allDocs = DesktopTools.getAllOpenDocuments(xMSF);
+
+ // get one of them for dispatching
+ XComponent xDoc = (XComponent) allDocs[0];
+ log.println("make the crash in second thread");
+
+ CrashThread crash = new CrashThread(xDoc, xMSF);
+ crash.start();
+ util.utils.shortWait();
+ util.utils.shortWait();
+ }
+
+ /**
+ * This function uses accessibility to handle the dialog which appears while the
+ * office is crashed. It click the button "OK" to continue.
+ */
+ private void handleRecoveryDialogAfterCrash(int expectedDocumentCount){
+ try{
+
+ // if the office crashes, the recovery feature needs some time
+ // to save all docs. Therefore the recovery dialog could need some
+ // time to pop up.
+ log.println("waiting for recovery dialog...");
+
+ int counter = 0;
+ int maximum = param.getInt(PropertyName.THREAD_TIME_OUT) / utils.DEFAULT_SHORT_WAIT_MS;
+
+ XDialog oDialog = rt.getActiveDialog(xMSF);
+
+ while ( oDialog == null && (counter < maximum))
+ {
+ util.utils.shortWait();
+ oDialog = rt.getActiveDialog(xMSF);
+ counter ++;
+ }
+
+ assure("could not get Recovery Window",(oDialog != null));
+
+ XWindow xWindow = UnoRuntime.queryInterface(XWindow.class, oDialog);
+
+ UITools oUITools = new UITools(xWindow);
+
+ oUITools.printAccessibleTree((PrintWriter) log, param.getBool(PropertyName.DEBUG_IS_ACTIVE));
+
+ String[] documents = oUITools.getListBoxItems("The following files will be recovered");
+ log.println("there are " + documents.length + " documents to save");
+
+ String msg ="The amount of documents to recover is different from the expected amount:\n";
+ msg += "\texpected:\t" + expectedDocumentCount + "\n";
+ msg += "\tto recover:\t" + documents.length;
+
+ assure(msg, expectedDocumentCount == documents.length);
+
+ log.println("disable automatically launch of Office");
+ oUITools.setCheckBoxValue("Launch StarOffice automatically", Integer.valueOf(0));
+
+ log.println("start saving...");
+ oUITools.clickButton("OK");
+
+ rt.waitForClosedOffice();
+
+ } catch (Exception e){
+ e.printStackTrace();
+ failed("Could not handle crash-dialog: " + e.toString());
+ }
+ }
+
+ private void handleCrashReporterDialog(boolean cancel){
+ try{
+
+ log.println("try to get Crash Reporter Dialog...");
+
+ XDialog oDialog = rt.getActiveDialog(xMSF);
+ assure("could not get CrashReporter Dialog", oDialog != null);
+
+ XWindow xWindow = UnoRuntime.queryInterface(XWindow.class, oDialog);
+
+ log.println(oDialog.getTitle());
+
+ UITools oUITools = new UITools(xWindow);
+
+ if (cancel) {
+ log.println("clicking 'Cancel' button...");
+
+ rt.clickThreadButton(xWindow, "Cancel");
+ }
+ else {
+ log.println("clicking 'Next' button...");
+ oUITools.clickButton("Next>>");
+ }
+
+ } catch (Exception e){
+ failed("Could not handle CrashReporter Dialog: " + e.toString());
+ }
+ }
+
+ private void handleRecoveryDialog_QuickExit(int expectedDocumentCount){
+ log.println("handle Recovery Dialog at restart: quick exit");
+ handleRecoveryDialogAtRestart(expectedDocumentCount, false, true);
+ handleAreYouSureDialog(true);
+ handleSaveDocumentsDialog(false);
+
+ }
+ private void handleRecoveryDialog_QuickExitAndSave(int expectedDocumentCount){
+ log.println("handle Recovery Dialog at restart: quick exit");
+ handleRecoveryDialogAtRestart(expectedDocumentCount, false, true);
+ handleAreYouSureDialog(true);
+ handleSaveDocumentsDialog(true);
+ }
+ /**
+ * This function uses accessibility to handle the dialog which appears while the
+ * office is started after a crash. It waits until the "next>>" button is enabled
+ * and click it then to continue.
+ * @param expectedDocumentCount the amount of documents which must be displayed in the recovery dialog
+ * @param recover If the document should be recovered this variable must be true. If it is false
+ * the recovery process was stopped and the button cancel was clicked.
+ * @param cancel If the recovery is finished, this parameter decides to click the "Next" button
+ * or the click cancel. If the value is true, the cancel button was clicked.
+ */
+ private void handleRecoveryDialogAtRestart(int expectedDocumentCount, boolean recover, boolean cancel){
+ try{
+
+ log.println("try to get Recovery Dialog...");
+
+ XDialog oDialog = null;
+ oDialog = rt.getActiveDialogAfterStartup(xMSF);
+
+ assure("could not get Recovery Dialog at start of office", (oDialog != null), ContinueWithTest.YES);
+
+ XWindow xWindow = UnoRuntime.queryInterface(XWindow.class, oDialog);
+ log.println("got the following dialog: '" +oDialog.getTitle() + "'");
+
+ UITools oUITools = new UITools(xWindow);
+
+ String listBoxName = "Status of recovered documents";
+ String[] documents = oUITools.getListBoxItems(listBoxName);
+ log.println("there are " + documents.length + " documents to recover");
+ log.println("The following files will be recovered:");
+ for (int i=0;i<documents.length;i++){
+ log.println(documents[i]);
+ }
+
+ String msg ="The amount of documents to recover is different from the expected amount:\n";
+ msg += "\texpected:\t" + expectedDocumentCount + "\n";
+ msg += "\tto recover:\t" + documents.length;
+
+ assure(msg, expectedDocumentCount ==documents.length);
+
+ if (recover){
+
+ log.println("clicking 'Start Recovery' button...");
+ oUITools.clickButton("Start Recovery >");
+
+ util.utils.shortWait();
+
+ int counter = 0;
+ int maximum = param.getInt(PropertyName.THREAD_TIME_OUT) / utils.DEFAULT_SHORT_WAIT_MS;
+
+ XAccessibleContext oButton = null;
+ while ((oButton == null) && (counter < maximum)){
+ log.println("recovering...");
+
+ try{
+ oButton = oUITools.getButton("Next >");
+ } catch (NullPointerException e){
+ // no fault: The title "Start Recovery" switches to "Next"
+ // while all documents are recoverd
+ }
+ util.utils.shortWait();
+ counter++;
+ }
+
+ if (cancel) {
+ log.println("clicking 'Cancel' button...");
+
+ rt.clickThreadButton(xWindow, "Cancel");
+
+ }
+ else {
+ log.println("clicking 'Next' button...");
+ oUITools.clickButton("Next >");
+ }
+
+ util.utils.shortWait();
+
+ } else {
+ log.println("do not recover: clicking 'Cancel' button...");
+
+ rt.clickThreadButton(xWindow, "Cancel");
+ }
+
+ } catch (Exception e){
+ failed("Could not handle recovery-dialog at restart: " + e.toString());
+ }
+
+ }
+
+ /**
+ * This function uses accessibility to handle the dialog "Are you sure".
+ * It click "Yes" or "No", dependent on the value of the parameter <CODE>Yes</CODE>
+ * @param yes If value is <CODE>TRUE</CODE> the button "Yes" was clicked, otherwise the button
+ * "No".
+ */
+ private void handleAreYouSureDialog(boolean yes)
+ {
+ try{
+ if (yes){
+ rt.handleModalDialog(xMSF, "Yes");
+ } else{
+ rt.handleModalDialog(xMSF, "Cancel");
+ }
+ } catch (com.sun.star.accessibility.IllegalAccessibleComponentStateException e){
+ failed("Could not handle 'Are you sure' dialog.");
+ }
+ }
+
+ /**
+ * This function uses accessibility to handle the dialog "Are you sure".
+ * It click "Yes" or "No", depending on the value of the parameter <CODE>Yes</CODE>
+ * @param saveDocuments If value is <CODE>TRUE</CODE> the button "Yes" was clicked, otherwise the button
+ * "No".
+ */
+ private void handleSaveDocumentsDialog(boolean saveDocuments)
+ {
+ try{
+ if (!saveDocuments){
+ rt.handleModalDialog(xMSF, "Cancel");
+ } else{
+ XWindow oDialog = null;
+ oDialog = rt.getActiveWindow(xMSF);
+
+ assure("could not get 'Save Documents' Dialog: ", (oDialog != null), ContinueWithTest.YES);
+
+ UITools oUITools = new UITools(oDialog);
+
+ oUITools.printAccessibleTree((PrintWriter) log, param.getBool(PropertyName.DEBUG_IS_ACTIVE));
+
+ String listBoxName = "Documents";
+ String[] documents = null;
+ try{
+ documents = oUITools.getListBoxItems(listBoxName);
+ } catch (java.lang.Exception e){
+ failed("could not get the document names from the 'Save Documents' dialog", ContinueWithTest.YES);
+ }
+ log.println("there are " + documents.length + " documents to save");
+ log.println("The following documents will be saved:");
+ for (int i=0;i<documents.length;i++){
+ log.println(documents[i]);
+ }
+ String tempURL = utils.getOfficeTempDir(xMSF);
+
+ log.println("the destination for saving is: " + tempURL);
+ try{
+ oUITools.setTextEditFiledText("Save to", tempURL);
+ } catch (java.lang.Exception e){
+ failed("could not set target directory for saving documents at 'Save Documents' dialog", ContinueWithTest.YES);
+ }
+ try{
+ oUITools.clickButton("OK");
+ } catch (java.lang.Exception e){
+ failed("could not click 'OK' at 'Save Documents' dialog", ContinueWithTest.YES);
+ }
+ }
+ } catch (com.sun.star.accessibility.IllegalAccessibleComponentStateException e){
+ failed("Could not handle 'Are you sure' dialog.");
+ }
+ }
+
+ /**
+ * This function gets the current screen size and calculate the first
+ * quarter of it. This quarter was used to position to Office windows.
+ * Further this function calculates the maximum window size so the window
+ * is visible if it placed on extreme position.
+ */
+ private void makeWindowPositionRage(){
+ Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
+ Point pos = new Point();
+ Size size = new Size();
+
+ // get the max position of the first quarter of the screen
+ pos.x = screenDim.width / 2;
+ pos.y = screenDim.height / 2;
+ windowMaxPosition = pos;
+
+ // get the max size of the windows while they placed in windowMaxPosition
+ // range and not outside the visibility
+ size.Height = screenDim.height;
+ size.Width = screenDim.width;
+ windowMaxSize = size;
+ }
+
+ private void generateDesktop(){
+
+ // create some documents with content
+ makeWriterDoc("WriterDoc1", true);
+
+
+ makeWriterDoc("WriterDocEmpty", false);
+
+ log.println("Test object successfully created.");
+
+ }
+
+ private void positioningDocument(XModel model){
+
+ XWindow xWindow = model.getCurrentController().getFrame().getContainerWindow();
+ String frameName = model.getCurrentController().getFrame().getName();
+
+ // get randomized position and size
+ Rectangle posSize = makePosZize();
+
+ // save position and size
+ windowsPosSize.put(frameName, posSize);
+
+ xWindow.setPosSize(posSize.X, posSize.Y, posSize.Width, posSize.Height,
+ com.sun.star.awt.PosSize.POSSIZE);
+ Rectangle test = xWindow.getPosSize();
+ log.println("x: "+test.X+" y:"+test.Y+" width:"+test.Width+" height:"+test.Height);
+ }
+
+ private Rectangle makePosZize(){
+
+ Rectangle posSize = new Rectangle();
+ Random rand = new Random();
+
+ // Random integers that range from 0 to n
+ posSize.X = rand.nextInt(windowMaxPosition.x + 1);
+ posSize.Y = rand.nextInt(windowMaxPosition.y + 1);
+
+ int maxHeight = windowMaxSize.Height-posSize.X;
+ int maxWidth = windowMaxSize.Width-posSize.Y;
+ int height = rand.nextInt(maxHeight + 1);
+ int width = rand.nextInt((windowMaxSize.Width-posSize.Y) + 1);
+
+ // be sure that the new size his greater than the half of windowMaxSize
+ posSize.Height = (height < (maxHeight / 2)) ? height + (maxHeight / 2) : height;
+ posSize.Width = (width < (maxWidth / 2)) ? width + (maxWidth / 2) : width;
+
+ return posSize;
+ }
+
+ private void makeWriterDoc(String frameName, boolean withContent){
+ log.println("creating Writer document '" + frameName + "'");
+ XTextDocument xTextDoc = createNewWriterDoc(frameName);
+ if (withContent) fillWriterDocWithContent(xTextDoc);
+ positioningDocument(UnoRuntime.queryInterface(XModel.class,
+ xTextDoc));
+ }
+
+ private XTextDocument createNewWriterDoc(String frameName){
+ XTextDocument xTextDoc = null;
+ try {
+ xTextDoc = SOF.createTextDoc(frameName);
+ } catch (com.sun.star.uno.Exception e) {
+ log.println("Exception occurred while creating text document '"+frameName+"':");
+ failed("Couldn't create test environment");
+ }
+ return xTextDoc;
+ }
+
+ private void fillWriterDocWithContent(XTextDocument xTextDoc){
+ try{
+ log.println( "inserting some lines" );
+ XText oText = xTextDoc.getText();
+ XTextCursor oCursor = oText.createTextCursor();
+ for (int i=0; i<5; i++){
+ oText.insertString( oCursor,"Paragraph Number: " + i, false);
+ oText.insertString( oCursor,
+ " The quick brown fox jumps over the lazy Dog: SwXParagraph",
+ false);
+ oText.insertControlCharacter(
+ oCursor, ControlCharacter.PARAGRAPH_BREAK, false );
+ oText.insertString( oCursor,
+ "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG: SwXParagraph",
+ false);
+ oText.insertControlCharacter(oCursor,
+ ControlCharacter.PARAGRAPH_BREAK, false );
+ oText.insertControlCharacter(
+ oCursor, ControlCharacter.LINE_BREAK, false );
+ }
+ } catch ( com.sun.star.lang.IllegalArgumentException e ){
+ log.println("Exception occurred while filling text document with content.");
+ failed("Couldn't create test environment");
+ }
+ }
+
+ /**
+ * copies all files from the backup.recoveryTest folder into the backup folder
+ * and copies the Recovery.xcu.recoveryTest to recovery.xcu
+ */
+ private void restoreBackupRecoveryData()
+ {
+ log.println("restore backup recovery data...");
+ try{
+ rt.copyRecoveryData(false);
+ }catch (com.sun.star.io.IOException e){
+ failed("could not copy recovery data: " + e.toString());
+ }catch (java.io.IOException e){
+ failed("could not copy recovery data: " + e.toString());
+ }
+ }
+
+ private void cleanRecoveryData(){
+ try{
+ log.println("bootstrapping the office to get user path to remove old recovery data...");
+
+ rt.cleanRecoveryData();
+
+ } catch (com.sun.star.io.IOException e){
+ failed("could not clean recovery data: " + e.toString());
+ }
+ }
+}
diff --git a/framework/qa/complex/framework/recovery/RecoveryTools.java b/framework/qa/complex/framework/recovery/RecoveryTools.java
new file mode 100644
index 000000000..3a9451250
--- /dev/null
+++ b/framework/qa/complex/framework/recovery/RecoveryTools.java
@@ -0,0 +1,301 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.framework.recovery;
+
+import com.sun.star.awt.XDialog;
+import com.sun.star.awt.XExtendedToolkit;
+import com.sun.star.awt.XWindow;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XInterface;
+
+import helper.FileTools;
+import helper.UnoProvider;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.HashMap;
+
+import lib.TestParameters;
+import share.LogWriter;
+import util.PropertyName;
+import util.UITools;
+import util.utils;
+
+/**
+ * this class supports the <CODE>RecoverTest</CODE>. You will find here some helper
+ * functions.
+ */
+public class RecoveryTools {
+
+ private final TestParameters param;
+ private final LogWriter log;
+
+ /**
+ * Creates new OfficeWatcher
+ * @param param the test parameter
+ * @param log a log writer
+ */
+ public RecoveryTools(TestParameters param, LogWriter log) {
+ this.param = param;
+ this.log = log;
+
+ }
+
+ /**
+ * get the active dialog from the top of the desktop
+ * @return a <CODE>XDialog</CODE> interface of the dialog
+ */
+ public XDialog getActiveDialog( XMultiServiceFactory xMSF){
+ XWindow xWin = getActiveWindow(xMSF);
+ return UnoRuntime.queryInterface(XDialog.class, xWin);
+ }
+
+ public XWindow getActiveWindow( XMultiServiceFactory xMSF){
+ XInterface xToolKit = null;
+ try {
+ xToolKit = (XInterface) xMSF.createInstance("com.sun.star.awt.Toolkit") ;
+ } catch (com.sun.star.uno.Exception e) {
+ return null;
+ }
+
+ XExtendedToolkit tk = UnoRuntime.queryInterface(XExtendedToolkit.class, xToolKit);
+ Object atw = tk.getActiveTopWindow();
+ return UnoRuntime.queryInterface(XWindow.class, atw);
+ }
+
+ /**
+ * After a crash the office start with a recovery dialog. It could be that the office
+ * is connectable but not all services to get the dialog a loaded. This function
+ * tries to get the dialog until the <CODE>OfficeWatcher</CODE> kills the office.
+ * @return a <CODE>XDialog</CODE> interface of the dialog
+ */
+ public XDialog getActiveDialogAfterStartup(XMultiServiceFactory xMSF){
+ // while the office starts it takes some time to get the dialog.
+
+ // the dialog is accessible AFTER the office has recoverd all documents.
+ // This could consumes more time then the TimeOut allow.
+ int counter = 0;
+ int multi = 5;
+ int pause = utils.DEFAULT_SHORT_WAIT_MS * 10;
+ int timeOut = param.getInt(PropertyName.THREAD_TIME_OUT)*5;
+ int maximum = (timeOut / pause) * multi;
+
+ XDialog oDialog = getActiveDialog(xMSF);
+
+ while (oDialog == null && (counter < maximum)){
+ log.println("waiting until the office has recovered... remaining " + (timeOut * multi - pause * counter)/1000 + " seconds");
+ util.utils.pause(pause);
+ oDialog = getActiveDialog(xMSF);
+ counter ++;
+ }
+ return oDialog;
+ }
+
+ /**
+ * remove the content of the user backup folder and removes the Recovery.xcu. This
+ * was done from the Office via XSimpleFileAccess
+ * @throws com.sun.star.io.IOException the exception was thrown if something goes wrong.
+ */
+ public void cleanRecoveryData()
+ throws com.sun.star.io.IOException
+ {
+ try{
+ HashMap<String, String> recFiles = getRecoveryFiles();
+
+ String recoveryFolder = recFiles.get("recoveryFolder");
+ String recoveryXCU = recFiles.get("recoveryXCU");
+
+ log.println("try to remove content of '" + recoveryFolder + "'");
+
+ File rf = new File(recoveryFolder);
+
+ boolean success = FileTools.cleanDir(rf);
+ log.println("removed " + recoveryFolder + ": " + success);
+
+ log.println("try to remove '" + recoveryXCU + "'");
+
+ File xcu = new File(recoveryXCU);
+ if (xcu.isFile()){
+ success = xcu.delete();
+ log.println("removed " + recoveryXCU + " : " + success);
+ }
+
+ } catch (Exception e){
+ throw new com.sun.star.io.IOException("could not remove old recovery data", e);
+ }
+ }
+
+ private HashMap<String, String> getRecoveryFiles()
+ throws com.sun.star.io.IOException
+ {
+ try{
+ log.println("try to get UnoProvider...");
+ UnoProvider unoProv = new UnoProvider();
+ XMultiServiceFactory xMSF = (XMultiServiceFactory) unoProv.getManager(param);
+
+ String userPath = utils.expandMacro(xMSF, "${$ORIGIN/bootstraprc:UserInstallation}");
+ System.out.println("userPath:'" + userPath + "'");
+
+ if (userPath.equals(""))userPath = utils.expandMacro(xMSF, "${$ORIGIN/bootstrap.ini:UserInstallation}");
+ System.out.println("userPath:'" + userPath + "'");
+
+ if (userPath.equals("")) throw new com.sun.star.io.IOException("could not get user path at bootstraping");
+
+ String recoveryFolder = utils.getSystemURL(userPath + "/user/backup");
+
+ String recoveryXCU = utils.getSystemURL(userPath + "/user/registry/data/org/openoffice/Office/Recovery.xcu");
+
+ HashMap<String, String> recFiles = new HashMap<String, String>();
+
+ recFiles.put("recoveryFolder", recoveryFolder);
+ recFiles.put("recoveryXCU", recoveryXCU);
+ return recFiles;
+
+ } catch (Exception e){
+ throw new com.sun.star.io.IOException("could not get recovery folder", e);
+ }
+
+ }
+
+
+ /**
+ * This function waits until the office is closed. If the closing time reach
+ * the value of parameter <CODE>THREAD_TIME_OUT</CODE> the office was killed.
+ */
+ public void waitForClosedOffice(){
+ // check for the office process
+ helper.ProcessHandler ph = (helper.ProcessHandler) param.get("AppProvider");
+
+ int timeOut = param.getInt(PropertyName.THREAD_TIME_OUT)*5;
+ int pause = utils.DEFAULT_SHORT_WAIT_MS * 20;
+ int multi = 0;
+ while ((ph != null) && (ph.getExitCode()<0) && (pause*multi < timeOut)) {
+ log.println("waiting until the office is closed... remaining " + (timeOut - pause * multi)/1000 + " seconds");
+ util.utils.pause(pause);
+ multi ++;
+ }
+
+ // be sure that office is closed
+ if (ph != null) ph.kill();
+ }
+
+
+
+ /**
+ * The office must be started WITH restore functionality.
+ * Therefore the parameter '<CODE>--norestore</CODE>'
+ * was removed from the <CODE>AppExecutionCommand</CODE> parameter
+ */
+ public void removeParametersFromAppExecutionCommand(){
+
+ //remove some params to start office
+ String office = (String) param.get("AppExecutionCommand");
+ String[] params = {"--norestore"};
+
+ for (int i = 0; i < params.length; i++){
+ int index = office.indexOf(params[i]);
+ int length = params[i].length();
+ if (index != -1){
+ office = office.substring(0, index) + office.substring(index + length);
+ log.println("removed '" + params[i] + "' from AppExecutionCommand: " + office);
+ }
+ }
+ param.put("AppExecutionCommand", office);
+ log.println("connect: " + (String) param.get("AppExecutionCommand"));
+
+ }
+
+ /**
+ * This function uses accessibility to handle modal dialogs like the
+ * "Are you sure" dialog.
+ * It clicks the named button given in parameter <CODE>buttonName</CODE>
+ * @param buttonName the name of the button which should be clicked
+ */
+ public void handleModalDialog(XMultiServiceFactory xMSF, String buttonName)
+ throws com.sun.star.accessibility.IllegalAccessibleComponentStateException
+ {
+
+ log.println("try to get modal Dialog...");
+
+ util.utils.shortWait();
+
+ XWindow oDialog = getActiveWindow(xMSF);
+
+ if (oDialog == null) throw new com.sun.star.accessibility.IllegalAccessibleComponentStateException("could not get modal Dialog");
+
+
+ UITools oUITools = new UITools(oDialog);
+ oUITools.printAccessibleTree((PrintWriter) log, param.getBool(PropertyName.DEBUG_IS_ACTIVE));
+
+ try{
+ log.println("click ' " + buttonName + "' button..");
+ oUITools.clickButton(buttonName);
+ } catch ( java.lang.Exception e){
+ throw new com.sun.star.accessibility.IllegalAccessibleComponentStateException("Could not click '"+buttonName +"' at modal dialog", e);
+ }
+ util.utils.shortWait();
+ }
+
+ public void clickThreadButton(XWindow xWindow, String buttonName)
+ {
+ KlickButtonThread kbt = new KlickButtonThread(xWindow, buttonName);
+ kbt.start();
+ util.utils.pause(utils.DEFAULT_SHORT_WAIT_MS * 10);
+ }
+
+ public void copyRecoveryData(boolean backup)
+ throws com.sun.star.io.IOException, java.io.IOException
+ {
+ HashMap<String, String> recFiles = null;
+
+ try{
+ recFiles = getRecoveryFiles();
+ } catch ( com.sun.star.io.IOException e){
+ throw new com.sun.star.io.IOException("Could not get recovery files", e);
+ }
+
+ try{
+ String recoveryFolder = recFiles.get("recoveryFolder");
+ String recoveryXCU = recFiles.get("recoveryXCU");
+
+ File recFolder = new File(recoveryFolder);
+ File recFolderBackup = new File(recoveryFolder+".recoveryTest");
+
+ File recXCU = new File(recoveryXCU);
+ File recXCUBackup = new File(recoveryXCU + ".recoveryTest");
+
+ if (backup){
+ FileTools.copyDirectory(recFolder, recFolderBackup);
+ FileTools.copyFile(recXCU, recXCUBackup);
+ } else {
+ FileTools.copyDirectory(recFolderBackup, recFolder);
+ FileTools.copyFile(recXCUBackup, recXCU);
+
+ }
+ } catch (java.io.IOException e){
+ // the new constructor that takes a Throwable is only available in Java1.6
+ java.io.IOException newEx = new java.io.IOException("Could not copy recovery files");
+ newEx.initCause(e);
+ throw newEx;
+ }
+ }
+
+
+}
diff --git a/framework/qa/complex/imageManager/CheckImageManager.java b/framework/qa/complex/imageManager/CheckImageManager.java
new file mode 100644
index 000000000..a88a96d30
--- /dev/null
+++ b/framework/qa/complex/imageManager/CheckImageManager.java
@@ -0,0 +1,201 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.imageManager;
+
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XInitialization;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XTypeProvider;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.ui.XImageManager;
+import com.sun.star.ui.XModuleUIConfigurationManagerSupplier;
+import com.sun.star.ui.XUIConfiguration;
+import com.sun.star.ui.XUIConfigurationManager;
+import com.sun.star.ui.XUIConfigurationPersistence;
+
+
+// ---------- junit imports -----------------
+import lib.TestParameters;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+import static org.junit.Assert.*;
+
+
+/**
+ *
+ */
+public class CheckImageManager {
+ boolean checkUIConfigManager = false;
+ XMultiServiceFactory xMSF = null;
+ /**
+ * The test parameters
+ */
+ private TestParameters param = null;
+
+ @Before public void before()
+ {
+ xMSF = getMSF();
+ param = new TestParameters();
+ param.put("ServiceFactory", xMSF); // some qadevOOo functions need the ServiceFactory
+ }
+
+
+ @Test public void checkImageManagerFromModule()
+ {
+ System.out.println(" **** ImageManager from ModuleUIConfigurationManager *** ");
+ XUIConfigurationManager xManager = null;
+ try {
+ Object o = xMSF.createInstance(
+ "com.sun.star.ui.ModuleUIConfigurationManagerSupplier");
+ XModuleUIConfigurationManagerSupplier xMUICMS =
+ UnoRuntime.queryInterface(XModuleUIConfigurationManagerSupplier.class, o);
+ xManager = xMUICMS.getUIConfigurationManager(
+ "com.sun.star.text.TextDocument");
+ }
+ catch(com.sun.star.uno.Exception e) {
+ fail("Exception. " + e.getMessage());
+ }
+ XImageManager xImageManager = UnoRuntime.queryInterface(XImageManager.class, xManager.getImageManager());
+ performChecks(xImageManager, "ModuleUIConfig");
+ }
+
+ public void checkImageManager() {
+ System.out.println(" **** ImageManager from UIConfigurationManager *** ");
+ XUIConfigurationManager xManager = null;
+ try {
+ xManager = UnoRuntime.queryInterface(XUIConfigurationManager.class, xMSF.createInstance("com.sun.star.comp.framework.UIConfigurationManager"));
+ }
+ catch(com.sun.star.uno.Exception e) {
+ fail("Exception. " + e.getMessage());
+ }
+
+ XImageManager xImageManager = UnoRuntime.queryInterface(XImageManager.class, xManager.getImageManager());
+ performChecks(xImageManager, "UIConfig");
+ }
+
+ private void performChecks(XImageManager xImageManager, String testObjectName) {
+ util.dbg.printInterfaces(xImageManager);
+
+ OXUIConfigurationListenerImpl configListener = new OXUIConfigurationListenerImpl();
+ param.put("XUIConfiguration.XUIConfigurationListenerImpl", configListener);
+
+ XInitialization xInit = UnoRuntime.queryInterface(XInitialization.class, xImageManager);
+ _XInitialization _xInit = new _XInitialization(param, xInit);
+ assertTrue(testObjectName + "::XInitialization.initialize", _xInit._initialize());
+
+ // xImageManager is already there, just write a test ;-)
+ _XImageManager _xImage = new _XImageManager(xImageManager);
+ assertTrue(testObjectName + "::XImageManager.getAllImageNames", _xImage._getAllImageNames());
+ assertTrue(testObjectName + "::XImageManager.getImages", _xImage._getImages());
+ assertTrue(testObjectName + "::XImageManager.hasImage", _xImage._hasImage());
+ assertTrue(testObjectName + "::XImageManager.insertImages", _xImage._insertImages());
+ assertTrue(testObjectName + "::XImageManager.removeImages", _xImage._removeImages());
+ assertTrue(testObjectName + "::XImageManager.replaceImages", _xImage._replaceImages());
+ assertTrue(testObjectName + "::XImageManager.reset", _xImage._reset());
+
+ XTypeProvider xType = UnoRuntime.queryInterface(XTypeProvider.class, xImageManager);
+ _XTypeProvider _xType = new _XTypeProvider(xType);
+ assertTrue(testObjectName + "::XTypeProvider.getImplementationId", _xType._getImplementationId());
+ assertTrue(testObjectName + "::XTypeProvider.getTypes", _xType._getTypes());
+
+ XUIConfiguration xUIConfig = UnoRuntime.queryInterface(XUIConfiguration.class, xImageManager);
+ _XUIConfiguration _xUIConfig = new _XUIConfiguration(param, xUIConfig);
+ _xUIConfig.before();
+ assertTrue(testObjectName + "::XUIConfig.addConfigurationListener", _xUIConfig._addConfigurationListener());
+ assertTrue(testObjectName + "::XUIConfig.removeConfigurationListener", _xUIConfig._removeConfigurationListener());
+
+ XUIConfigurationPersistence xUIConfigPersistence = (XUIConfigurationPersistence)UnoRuntime.queryInterface(XUIConfiguration.class, xImageManager);
+ _XUIConfigurationPersistence _xUIConfigPersistence = new _XUIConfigurationPersistence(param, xUIConfigPersistence);
+ _xUIConfigPersistence.before();
+ assertTrue(testObjectName + "::XUIConfigPersistence.isModified", _xUIConfigPersistence._isModified());
+ assertTrue(testObjectName + "::XUIConfigPersistence.isReadOnly", _xUIConfigPersistence._isReadOnly());
+ assertTrue(testObjectName + "::XUIConfigPersistence.reload", _xUIConfigPersistence._reload());
+ assertTrue(testObjectName + "::XUIConfigPersistence.store", _xUIConfigPersistence._store());
+ assertTrue(testObjectName + "::XUIConfigPersistence.storeToStorage", _xUIConfigPersistence._storeToStorage());
+
+ XComponent xComp = UnoRuntime.queryInterface(XComponent.class, xImageManager);
+ _XComponent _xComp = new _XComponent(param, xComp);
+ _xComp.before();
+ assertTrue(testObjectName + "::XComponent.addEventListener", _xComp._addEventListener());
+ assertTrue(testObjectName + "::XComponent.removeEventListener", _xComp._removeEventListener());
+ assertTrue(testObjectName + "::XComponent.dispose", _xComp._dispose());
+ }
+
+
+ private static class OXUIConfigurationListenerImpl implements _XUIConfiguration.XUIConfigurationListenerImpl {
+ private boolean triggered = false;
+
+ public boolean actionWasTriggered() {
+ return triggered;
+ }
+
+ public void disposing(com.sun.star.lang.EventObject eventObject) {
+ triggered = true;
+ }
+
+ public void elementInserted(com.sun.star.ui.ConfigurationEvent configurationEvent) {
+ triggered = true;
+ }
+
+ public void elementRemoved(com.sun.star.ui.ConfigurationEvent configurationEvent) {
+ triggered = true;
+ }
+
+ public void elementReplaced(com.sun.star.ui.ConfigurationEvent configurationEvent) {
+ triggered = true;
+ }
+
+ public void fireEvent() {
+ // remove for real action:
+ triggered = !triggered;
+ }
+
+ public void reset() {
+ // remove comment for real function
+ //triggered = false;
+ }
+
+ }
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass
+ public static void setUpConnection() throws Exception
+ {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass
+ public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+ private static final OfficeConnection connection = new OfficeConnection();
+
+}
diff --git a/framework/qa/complex/imageManager/_XComponent.java b/framework/qa/complex/imageManager/_XComponent.java
new file mode 100644
index 000000000..0d0a997b7
--- /dev/null
+++ b/framework/qa/complex/imageManager/_XComponent.java
@@ -0,0 +1,167 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.imageManager;
+
+import com.sun.star.frame.XDesktop;
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XEventListener;
+import lib.TestParameters;
+
+/**
+* Testing <code>com.sun.star.lang.XComponent</code>
+* interface methods :
+* <ul>
+* <li><code> dispose()</code></li>
+* <li><code> addEventListener()</code></li>
+* <li><code> removeEventListener()</code></li>
+* </ul>
+* After this interface test object <b>must be recreated</b>. <p>
+* Multithreaded test ability <b>not implemented</b> yet.
+* @see com.sun.star.lang.XComponent
+*/
+public class _XComponent {
+
+ private XComponent oObj = null;
+ private XComponent altDispose = null;
+ private final TestParameters tEnv;
+ private boolean listenerDisposed[] = new boolean[2];
+ private String[] Loutput = new String[2];
+
+ /**
+ * Listener which added but not removed, and its method must be called
+ * on <code>dispose</code> call.
+ */
+ private class MyEventListener implements XEventListener {
+ private final int number;
+ private final String message;
+ private MyEventListener(int number, String message) {
+ this.message = message;
+ this.number = number;
+ }
+ public void disposing ( EventObject oEvent ) {
+ Loutput[number] = Thread.currentThread() + " is DISPOSING " + message + this;
+ listenerDisposed[number] = true;
+ }
+ }
+
+ private final XEventListener listener1 = new MyEventListener(0, "EV1");
+ private final XEventListener listener2 = new MyEventListener(1, "EV2");
+
+ public _XComponent(TestParameters tEnv, XComponent oObj) {
+ this.tEnv = tEnv;
+ this.oObj = oObj;
+ }
+
+ /**
+ * For the cfgmgr2.OSetElement tests: dispose the owner element.
+ */
+ public void before() {
+ // do not dispose this component, but parent instead
+ altDispose = (XComponent)tEnv.get("XComponent.DisposeThis");
+
+ }
+
+ /**
+ * Adds two listeners. <p>
+ * Has OK status if then the first listener will receive an event
+ * on <code>dispose</code> method call.
+ */
+ public boolean _addEventListener() {
+
+ listenerDisposed[0] = false;
+ listenerDisposed[1] = false;
+
+ oObj.addEventListener( listener1 );
+ oObj.addEventListener( listener2 );
+
+ return true;
+ } // finished _addEventListener()
+
+ /**
+ * Removes the second of two added listeners. <p>
+ * Method tests to be completed successfully :
+ * <ul>
+ * <li> <code>addEventListener</code> : method must add two listeners. </li>
+ * </ul> <p>
+ * Has OK status if no events will be sent to the second listener on
+ * <code>dispose</code> method call.
+ */
+ public boolean _removeEventListener() {
+ if (disposed)
+ {
+ System.out.println("Hint: already disposed.");
+ return false;
+ }
+ // the second listener should not be called
+ oObj.removeEventListener( listener2 );
+ System.out.println(Thread.currentThread() + " is removing EL " + listener2);
+ return true;
+ } // finished _removeEventListener()
+
+ private boolean disposed = false;
+
+ /**
+ * Disposes the object and then check appropriate listeners were
+ * called or not. <p>
+ * Method tests to be completed successfully :
+ * <ul>
+ * <li> <code>removeEventListener</code> : method must remove one of two
+ * listeners. </li>
+ * </ul> <p>
+ * Has OK status if liseter removed wasn't called and other listener
+ * was.
+ */
+ public boolean _dispose() {
+ disposed = false;
+
+ System.out.println( "begin dispose" + Thread.currentThread());
+ XDesktop oDesk = (XDesktop) tEnv.get("Desktop");
+ if (oDesk !=null) {
+ oDesk.terminate();
+ }
+ else {
+ if (altDispose == null)
+ {
+ oObj.dispose();
+ }
+ else
+ {
+ altDispose.dispose();
+ }
+ }
+
+ util.utils.shortWait();
+ if (Loutput[0]!=null){
+ System.out.println(Loutput[0]);
+ }
+ if (Loutput[1]!=null) {
+ System.out.println(Loutput[1]);
+ }
+ System.out.println( "end dispose" + Thread.currentThread());
+ disposed = true;
+
+ // check that dispose() works OK.
+ return listenerDisposed[0] && !listenerDisposed[1];
+
+ } // finished _dispose()
+
+} // finished class _XComponent
+
+
diff --git a/framework/qa/complex/imageManager/_XImageManager.java b/framework/qa/complex/imageManager/_XImageManager.java
new file mode 100644
index 000000000..c077bbf26
--- /dev/null
+++ b/framework/qa/complex/imageManager/_XImageManager.java
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.imageManager;
+
+import com.sun.star.graphic.XGraphic;
+import com.sun.star.ui.ImageType;
+import com.sun.star.ui.XImageManager;
+
+
+/**
+ *
+ */
+public class _XImageManager {
+
+
+ private String[]imageNames = null;
+ private XGraphic[] xGraphicArray = null;
+ private final XImageManager oObj;
+
+ public _XImageManager( XImageManager oObj) {
+ this.oObj = oObj;
+ }
+
+ public boolean _getAllImageNames() {
+ short s = ImageType.COLOR_NORMAL + ImageType.SIZE_DEFAULT;
+ imageNames = oObj.getAllImageNames(s);
+ for (int i=0; i<(imageNames.length>10?10:imageNames.length); i++)
+ {
+ System.out.println("###### Image: " + imageNames[i]);
+ }
+ return imageNames != null;
+ }
+
+ public boolean _getImages() {
+ short s = ImageType.COLOR_NORMAL + ImageType.SIZE_DEFAULT;
+ try {
+ xGraphicArray = oObj.getImages(s, imageNames);
+ }
+ catch(com.sun.star.lang.IllegalArgumentException e) {
+ }
+ return xGraphicArray != null;
+ }
+
+ public boolean _hasImage() {
+ boolean result = true;
+ short s = ImageType.COLOR_NORMAL + ImageType.SIZE_DEFAULT;
+ try { // check the first image names, 10 at max
+ for (int i=0; i<(imageNames.length>10?10:imageNames.length); i++)
+ {
+ result &= oObj.hasImage(s, imageNames[i]);
+ }
+ }
+ catch(com.sun.star.lang.IllegalArgumentException e) {
+ result = false;
+ }
+ return result;
+ }
+
+ public boolean _insertImages() {
+ try {
+ oObj.insertImages((short)imageNames.length, imageNames, xGraphicArray);
+ }
+ catch(com.sun.star.container.ElementExistException e) {
+ }
+ catch(com.sun.star.lang.IllegalArgumentException e) {
+ }
+ catch(com.sun.star.lang.IllegalAccessException e) {
+ }
+ return true;
+ }
+
+ public boolean _removeImages() {
+ try {
+ oObj.removeImages((short)(imageNames.length-1), imageNames);
+ }
+ catch(com.sun.star.lang.IllegalArgumentException e) {
+ }
+ catch(com.sun.star.lang.IllegalAccessException e) {
+ }
+ return true;
+ }
+
+ public boolean _replaceImages() {
+ return true;
+ }
+
+ public boolean _reset() {
+ return true;
+ }
+}
diff --git a/framework/qa/complex/imageManager/_XInitialization.java b/framework/qa/complex/imageManager/_XInitialization.java
new file mode 100644
index 000000000..07508ef3f
--- /dev/null
+++ b/framework/qa/complex/imageManager/_XInitialization.java
@@ -0,0 +1,78 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.imageManager;
+
+
+
+
+import com.sun.star.lang.XInitialization;
+import lib.TestParameters;
+
+/**
+* Testing <code>com.sun.star.lang.XInitialization</code>
+* interface methods. <p>
+* This test needs the following object relations :
+* <ul>
+* <li> <code>'XInitialization.args'</code> (of type <code>Object[]</code>):
+* (<b>Optional</b>) : argument for <code>initialize</code>
+* method. If omitted, zero length array is used. </li>
+* <ul> <p>
+* Test is multithread compliant. <p>
+* Till the present time there was no need to recreate environment
+* after this test completion.
+*/
+public class _XInitialization {
+
+
+ private final TestParameters tEnv;
+ private XInitialization oObj = null;
+
+ public _XInitialization(TestParameters tEnv, XInitialization oObj) {
+
+ this.tEnv = tEnv;
+ this.oObj = oObj;
+ }
+
+ /**
+ * Test calls the method with 0 length array and checks that
+ * no exceptions were thrown. <p>
+ * Has <b> OK </b> status if no exceptions were thrown. <p>
+ */
+ public boolean _initialize() {
+ boolean result = true ;
+
+ try {
+ Object[] args = (Object[]) tEnv.get("XInitialization.args");
+ if (args==null) {
+ oObj.initialize(new Object[0]);
+ } else {
+ oObj.initialize(args);
+ }
+
+ } catch (com.sun.star.uno.Exception e) {
+ System.out.println("Exception occurred while method calling.") ;
+ result = false ;
+ }
+
+ return result ;
+ } // finished _initialize()
+
+} // finished class _XInitialization
+
+
diff --git a/framework/qa/complex/imageManager/_XTypeProvider.java b/framework/qa/complex/imageManager/_XTypeProvider.java
new file mode 100644
index 000000000..318c056c8
--- /dev/null
+++ b/framework/qa/complex/imageManager/_XTypeProvider.java
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.imageManager;
+
+
+
+import com.sun.star.lang.XTypeProvider;
+import com.sun.star.uno.Type;
+
+/**
+* Testing <code>com.sun.star.lang.XTypeProvider</code>
+* interface methods :
+* <ul>
+* <li><code> getTypes()</code></li>
+* <li><code> getImplementationId()</code></li>
+* </ul> <p>
+* Test is <b> NOT </b> multithread compliant. <p>
+* @see com.sun.star.lang.XTypeProvider
+*/
+public class _XTypeProvider {
+
+
+
+ private XTypeProvider oObj = null;
+
+ public _XTypeProvider(XTypeProvider oObj) {
+ this.oObj = oObj;
+ }
+
+ /**
+ * Just calls the method.<p>
+ * Has <b>OK</b> status if no runtime exceptions occurred.
+ */
+ public boolean _getImplementationId() {
+ boolean result = true;
+ System.out.println("testing getImplementationId() ... ");
+
+ System.out.println("The ImplementationId is "+oObj.getImplementationId());
+ result = true;
+
+ return result;
+
+ } // end getImplementationId()
+
+
+ /**
+ * Calls the method and checks the return value.<p>
+ * Has <b>OK</b> status if one of the return value equals to the
+ * type <code>com.sun.star.lang.XTypeProvider</code>.
+ */
+ public boolean _getTypes() {
+ boolean result = false;
+ System.out.println("getting Types...");
+ Type[] types = oObj.getTypes();
+ for (int i=0;i<types.length;i++) {
+ int k = i+1;
+ System.out.println(k+". Type is "+types[i].toString());
+ if (types[i].toString().equals
+ ("Type[com.sun.star.lang.XTypeProvider]")) {
+ result = true;
+ }
+ }
+ if (!result) {
+ System.out.println("Component must provide Type "
+ +"<com.sun.star.lang.XTypeProvider>");
+ }
+
+ return result;
+
+ } // end getTypes()
+
+}
+
diff --git a/framework/qa/complex/imageManager/_XUIConfiguration.java b/framework/qa/complex/imageManager/_XUIConfiguration.java
new file mode 100644
index 000000000..f2e7be33d
--- /dev/null
+++ b/framework/qa/complex/imageManager/_XUIConfiguration.java
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.imageManager;
+
+
+import com.sun.star.ui.XUIConfiguration;
+import com.sun.star.ui.XUIConfigurationListener;
+import lib.TestParameters;
+
+
+
+public class _XUIConfiguration {
+
+
+ private final TestParameters tEnv;
+ private final XUIConfiguration oObj;
+ private XUIConfigurationListenerImpl xListener = null;
+
+ public interface XUIConfigurationListenerImpl
+ extends XUIConfigurationListener {
+ void reset();
+ void fireEvent();
+ boolean actionWasTriggered();
+ }
+
+
+ public _XUIConfiguration(TestParameters tEnv, XUIConfiguration oObj) {
+ this.tEnv = tEnv;
+ this.oObj = oObj;
+ }
+
+ public void before() {
+ xListener = (XUIConfigurationListenerImpl)tEnv.get(
+ "XUIConfiguration.XUIConfigurationListenerImpl");
+ }
+
+ public boolean _addConfigurationListener() {
+ oObj.addConfigurationListener(xListener);
+ xListener.fireEvent();
+ return xListener.actionWasTriggered();
+ }
+
+ public boolean _removeConfigurationListener() {
+ oObj.removeConfigurationListener(xListener);
+ xListener.reset();
+ xListener.fireEvent();
+ return !xListener.actionWasTriggered();
+ }
+
+}
diff --git a/framework/qa/complex/imageManager/_XUIConfigurationPersistence.java b/framework/qa/complex/imageManager/_XUIConfigurationPersistence.java
new file mode 100644
index 000000000..23735a179
--- /dev/null
+++ b/framework/qa/complex/imageManager/_XUIConfigurationPersistence.java
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+package complex.imageManager;
+
+import com.sun.star.embed.XStorage;
+import com.sun.star.ui.XUIConfigurationPersistence;
+import lib.TestParameters;
+
+
+
+public class _XUIConfigurationPersistence {
+
+
+ private final TestParameters tEnv;
+ private final XUIConfigurationPersistence oObj;
+ private XStorage xStore = null;
+
+ public _XUIConfigurationPersistence(TestParameters tEnv, XUIConfigurationPersistence oObj) {
+
+ this.tEnv = tEnv;
+ this.oObj = oObj;
+ }
+
+ public void before() {
+ xStore = (XStorage)tEnv.get("XUIConfigurationStorage.Storage");
+ }
+
+ public boolean _reload() {
+ try {
+ oObj.reload();
+ }
+ catch(com.sun.star.uno.Exception e) {
+
+ }
+ return true;
+ }
+
+ public boolean _store() {
+ try {
+ oObj.store();
+ }
+ catch(com.sun.star.uno.Exception e) {
+
+ }
+ return true;
+ }
+
+ public boolean _storeToStorage() {
+ boolean result = true;
+ try {
+ oObj.storeToStorage(xStore);
+ }
+ catch(com.sun.star.uno.Exception e) {
+ result = false;
+
+ }
+ return result;
+ }
+
+ public boolean _isModified() {
+ return !oObj.isModified();
+ }
+
+ public boolean _isReadOnly() {
+ return !oObj.isReadOnly();
+ }
+
+}
diff --git a/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.java b/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.java
new file mode 100644
index 000000000..451ba1292
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.java
@@ -0,0 +1,526 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+ package complex.loadAllDocuments;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import helper.URLHelper;
+
+import java.io.File;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+import org.openoffice.test.OfficeFileUrl;
+
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.frame.FrameSearchFlag;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.frame.XFrame;
+import com.sun.star.frame.XStorable;
+import com.sun.star.io.XInputStream;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.ucb.XSimpleFileAccess;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.XCloseable;
+
+
+/** @short Check the interface method XComponentLoader.loadComponentFromURL()
+
+ @descr A prerequisite for this test is a server which allows access to files
+ that will be loaded via three different access methods:
+ <ul>
+ <li>1. nfs (mounted directory / mapped network drive)</li>
+ <li>2. ftp</li>
+ <li>3. http</li>
+ </ul>
+ <p>
+ The test will look for a list of files from the <i>TestDocumentPath</i>
+ on and load these files from the mounted directory, via ftp and http.
+ The parameters for this have to be "ftp_access" and "http_access".
+ If they are not given, tests for ftp and http will fail.
+
+ @todo We need a further test for accessing UNC paths on windows!
+ */
+public class CheckXComponentLoader
+{
+
+ // some const
+
+ /** used to classify the result of a loadComponentFromURL() request. */
+ private static final int RESULT_VALID_DOC = 1;
+ private static final int RESULT_EMPTY_DOC = 2;
+ private static final int RESULT_ILLEGALARGUMENTEXCEPTION = 3;
+ private static final int RESULT_IOEXCEPTION = 4;
+ private static final int RESULT_RUNTIMEEXCEPTION = 5;
+ private static final int RESULT_EXCEPTION = 6;
+
+ /** used for testing password protected files. */
+ private static final String SUFFIX_PASSWORD_TEMPFILE = "password_";
+ private static final String PREFIX_PASSWORD_TEMPFILE = ".sxw";
+ private static final String DEFAULT_PASSWORD = "DefaultPasswordForComponentLoaderTest";
+
+
+ // member
+
+ /** provides XComponentLoader interface too. */
+ private XFrame m_xFrame = null;
+
+ /** will be set to xDesktop OR xFrame. */
+ private XComponentLoader m_xLoader = null;
+
+ /** can be used to open local files as stream. */
+ private XSimpleFileAccess m_xStreamProvider = null;
+
+ /** directory for creating temp. files. */
+ private String m_sTempPath = null;
+
+ /** directory for searching files to load */
+ private String m_sTestDocPath = null;
+
+ /** files of m_sTestDocPath to test. */
+ private static ArrayList<String> m_lTestFiles = null;
+
+
+ // test environment
+
+
+ /** @short Create the environment for following tests.
+
+ @descr Use either a component loader from desktop or
+ from frame
+ */
+ @Before public void before() throws Exception
+ {
+ // get uno service manager from global test environment
+ /* points to the global uno service manager. */
+ XMultiServiceFactory xMSF = getMSF();
+
+ // create stream provider
+ m_xStreamProvider = UnoRuntime.queryInterface(XSimpleFileAccess.class, xMSF.createInstance("com.sun.star.ucb.SimpleFileAccess"));
+
+ // create desktop instance
+ /* provides XComponentLoader interface. */
+ XFrame xDesktop = UnoRuntime.queryInterface(XFrame.class, xMSF.createInstance("com.sun.star.frame.Desktop"));
+
+ // create frame instance
+ m_xFrame = xDesktop.findFrame("testFrame_componentLoader",
+ FrameSearchFlag.TASKS | FrameSearchFlag.CREATE);
+ assertNotNull("Couldn't create test frame.", m_xFrame);
+
+ // define default loader for testing
+ // TODO think about using of bot loader instances!
+ m_xLoader = UnoRuntime.queryInterface(XComponentLoader.class, xDesktop);
+ assertNotNull("Desktop service doesn't support needed component loader interface.", m_xLoader);
+
+ // get temp path for this environment
+ final String tempDirURL = util.utils.getOfficeTemp/*Dir*/(getMSF());
+ m_sTempPath = graphical.FileHelper.getSystemPathFromFileURL(tempDirURL);
+ // m_sTempPath = "."+fs_sys;
+
+ // get all files from the given directory
+ // TODO URLHelper should ignore directories!
+ m_lTestFiles = new ArrayList<String>();
+ final String sTestDocURL = OfficeFileUrl.getAbsolute(new File("testdocuments"));
+ m_sTestDocPath = graphical.FileHelper.getSystemPathFromFileURL(sTestDocURL);
+ File aBaseDir = new File(m_sTestDocPath);
+ List<File> lDirContent = URLHelper.getSystemFilesFromDir(aBaseDir.getPath());
+ Iterator<File> lList = lDirContent.iterator();
+ int nBasePathLength = m_sTestDocPath.length();
+ while(lList.hasNext())
+ {
+ File aFile = lList.next();
+
+ // ignore broken links and directories at all
+ if (
+ (!aFile.exists()) ||
+ (!aFile.isFile())
+ )
+ {
+ continue;
+ }
+
+ String sCompletePath = aFile.getAbsolutePath();
+ String sSubPath = sCompletePath.substring(nBasePathLength);
+
+ m_lTestFiles.add(sSubPath);
+ }
+ }
+
+
+ /** @short close the environment.
+ */
+ @After public void after() throws Exception
+ {
+ XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, m_xFrame);
+ xClose.close(false);
+
+ m_xFrame = null;
+ m_xLoader = null;
+ }
+
+
+ /** @short Look for files in the given directory for loading.
+ */
+ @Test public void checkUsingOfMediaDescriptor()
+ {
+ InteractionHandler xHandler = new InteractionHandler();
+ StatusIndicator xIndicator = new StatusIndicator();
+
+ PropertyValue[] lProps = new PropertyValue[3];
+
+ lProps[0] = new PropertyValue();
+ lProps[0].Name = "Hidden";
+ lProps[0].Value = Boolean.TRUE;
+
+ lProps[1] = new PropertyValue();
+ lProps[1].Name = "InteractionHandler";
+ lProps[1].Value = xHandler;
+
+ lProps[2] = new PropertyValue();
+ lProps[2].Name = "StatusIndicator";
+ lProps[2].Value = xIndicator;
+
+ Iterator<String> aSnapshot = m_lTestFiles.iterator();
+ while (aSnapshot.hasNext())
+ {
+ File aSysFile = new File(m_sTestDocPath, aSnapshot.next());
+ String sURL = URLHelper.getFileURLFromSystemPath(aSysFile);
+
+ loadURL(m_xLoader, RESULT_VALID_DOC, sURL, "_blank", 0, lProps);
+ // It's not needed to reset this using states!
+ // It's done internally...
+ if (!xIndicator.wasUsed())
+ {
+ System.out.println("External progress was not used for loading.");
+ }
+ if (xHandler.wasUsed())
+ {
+ System.out.println("External interaction handler was not used for loading.");
+ }
+ }
+ }
+
+
+ /** TODO document me and move this method to a more global helper! */
+ private String impl_getTempFileName(String sTempPath,
+ String sSuffix ,
+ String sPrefix )
+ {
+ File aDir = new File(sTempPath);
+ aDir.mkdirs();
+
+ // TODO: create a temp file which not exist!
+ for (int i=0; i<999999; ++i)
+ {
+ File aTempFile = new File(aDir, sSuffix+i+sPrefix);
+ if (!aTempFile.exists())
+ {
+ return aTempFile.getAbsolutePath();
+ }
+ }
+
+ fail("Seems that all temp file names are currently in use!");
+ return null;
+ }
+
+
+ /** TODO document me and move this method to a more global helper! */
+ private void impl_createTempOfficeDocument(XComponentLoader xLoader ,
+ String sSourceURL,
+ String sTargetURL,
+ String sFilter ,
+ String sPassword ) throws Exception
+ {
+ PropertyValue[] lLoadProps = new PropertyValue[1];
+
+ lLoadProps[0] = new PropertyValue();
+ lLoadProps[0].Name = "Hidden";
+ lLoadProps[0].Value = Boolean.TRUE;
+
+ PropertyValue[] lSaveProps = new PropertyValue[3];
+
+ lSaveProps[0] = new PropertyValue();
+ lSaveProps[0].Name = "FilterName";
+ lSaveProps[0].Value = sFilter;
+
+ lSaveProps[1] = new PropertyValue();
+ lSaveProps[1].Name = "PassWord";
+ lSaveProps[1].Value = sPassword;
+
+ lSaveProps[2] = new PropertyValue();
+ lSaveProps[2].Name = "Overwrite";
+ lSaveProps[2].Value = Boolean.TRUE;
+
+ XComponent xDoc = null;
+ // load it
+ xDoc = xLoader.loadComponentFromURL(sSourceURL, "_blank", 0, lLoadProps);
+ assertNotNull("Could create office document, which should be saved as temp one.", xDoc);
+
+ // save it as temp file
+ XStorable xStore = UnoRuntime.queryInterface(XStorable.class, xDoc);
+ xStore.storeAsURL(sTargetURL, lSaveProps);
+
+ // Don't forget to close this file. Otherwise the temp file is locked!
+ XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xDoc);
+ xClose.close(false);
+ }
+
+
+ /** @short Check the password handling.
+
+ @descr The used password is the one given
+ as password for the ftp connection,
+ or - if none given a default one.
+ */
+ @Test public void checkLoadingWithPassword() throws Exception
+ {
+ String sTempFile = impl_getTempFileName(m_sTempPath, SUFFIX_PASSWORD_TEMPFILE, PREFIX_PASSWORD_TEMPFILE);
+ File aTestFile = new File(sTempFile);
+ String sTestURL = URLHelper.getFileURLFromSystemPath(aTestFile);
+
+ impl_createTempOfficeDocument(m_xLoader, "private:factory/swriter", sTestURL, "StarOffice XML (Writer)", DEFAULT_PASSWORD);
+
+ PropertyValue[] lArgs1 = new PropertyValue[2];
+
+ lArgs1[0] = new PropertyValue();
+ lArgs1[0].Name = "Hidden";
+ lArgs1[0].Value = Boolean.TRUE;
+
+ lArgs1[1] = new PropertyValue();
+ lArgs1[1].Name = "Password";
+ lArgs1[1].Value = DEFAULT_PASSWORD;
+
+ PropertyValue[] lArgs2 = new PropertyValue[1];
+
+ lArgs2[0] = new PropertyValue();
+ lArgs2[0].Name = "Hidden";
+ lArgs2[0].Value = Boolean.TRUE;
+
+ loadURL(m_xLoader, RESULT_VALID_DOC, sTestURL, "_blank", 0, lArgs1);
+// TODO: wrong? loadURL(m_xLoader, RESULT_EMPTY_DOC, sTestURL, "_blank", 0, lArgs2);
+ }
+
+ /**
+ * Check URL encoding. The first filename that matches "*.sxw"
+ * is used as source for several encodings.
+ */
+ @Test public void checkURLEncoding() throws Exception {
+ PropertyValue[] lProps = new PropertyValue[1];
+
+ lProps[0] = new PropertyValue();
+ lProps[0].Name = "Hidden";
+ lProps[0].Value = Boolean.TRUE;
+
+ // first get encoding of this system
+ InputStreamReader in = new InputStreamReader(System.in);
+ String sSystemEncoding = in.getEncoding();
+
+ System.out.println("This system's encoding: " + sSystemEncoding);
+
+ assertNotNull("Found an empty directory. There are no files for testing.", m_lTestFiles);
+
+
+ // get a file name as byte array
+ Iterator<String> aSnapshot = m_lTestFiles.iterator();
+ byte[] baURL = null;
+
+ while (aSnapshot.hasNext()) {
+ File aFile = new File(m_sTestDocPath, aSnapshot.next());
+ String sFile = URLHelper.getFileURLFromSystemPath(aFile);
+
+ // take the first sxw file as stream
+ if (sFile.endsWith(".sxw")) {
+ baURL = sFile.getBytes();
+
+ break;
+ }
+ }
+
+ assertNotNull("Found no file to load. Cannot test.", baURL);
+
+ //construct several different encoded strings
+ String[] sEncoding = new String[] {
+ "US-ASCII", "TRUE", // us ascii encoding
+ "ISO-8859-1", "TRUE", // iso encoding
+ "UTF-8", "TRUE", // 8 bit utf encoding
+ "UTF-16BE", "FALSE", // 16 bit big endian utf
+ "UTF-16LE", "FALSE", // 16 bit little endian utf
+ "UTF-16", "FALSE" // 16 bit, order specified by byte order mark
+
+ };
+
+ for (int i = 0; i < sEncoding.length; i = i + 2) {
+ String encURL = new String(baURL, sEncoding[i]);
+ System.out.println("ENC[" + sEncoding[i] + "]");
+
+ if (sEncoding[i + 1].equals("TRUE")) {
+ loadURL(m_xLoader, RESULT_VALID_DOC, encURL, "_blank", 0,
+ lProps);
+ } else {
+ //with cws_loadenv01 changed to IllegalArgumentException
+ loadURL(m_xLoader, RESULT_ILLEGALARGUMENTEXCEPTION, encURL, "_blank", 0,
+ lProps);
+ }
+ }
+ }
+
+ /** TODO document me
+ */
+ @Test public void checkStreamLoading() throws Exception
+ {
+ PropertyValue[] lProps = new PropertyValue[2];
+
+ lProps[0] = new PropertyValue();
+ lProps[0].Name = "Hidden";
+ lProps[0].Value = Boolean.TRUE;
+
+ lProps[1] = new PropertyValue();
+ lProps[1].Name = "InputStream";
+
+ Iterator<String> aSnapshot = m_lTestFiles.iterator();
+ while (aSnapshot.hasNext())
+ {
+ File aFile = new File(m_sTestDocPath, aSnapshot.next());
+ String sURL = URLHelper.getFileURLFromSystemPath(aFile);
+
+ XInputStream xStream = m_xStreamProvider.openFileRead(sURL);
+ lProps[1].Value = xStream;
+
+ // check different version of "private:stream" URL!
+ loadURL(m_xLoader, RESULT_VALID_DOC, "private:stream" , "_blank", 0, lProps);
+ }
+ }
+
+ /**
+ * Loads one URL with the given parameters using the method
+ * loadComponentFromURL(). Further it's possible to specify, which result is
+ * required and we check internally if it was reached. Logging of errors
+ * and success stories is done inside this method too. Of course we catch
+ * all possible exceptions and try to leave the office without any forgotten
+ * but opened documents.
+ */
+ private void loadURL(XComponentLoader xLoader, int nRequiredResult,
+ String sURL, String sTarget, int nFlags,
+ PropertyValue[] lProps) {
+ int nResult = RESULT_EMPTY_DOC;
+ XComponent xDoc = null;
+
+ try {
+ xDoc = xLoader.loadComponentFromURL(sURL, sTarget, nFlags,
+ lProps);
+
+ if (xDoc != null) {
+ nResult = RESULT_VALID_DOC;
+ } else {
+ nResult = RESULT_EMPTY_DOC;
+ }
+ } catch (com.sun.star.lang.IllegalArgumentException exArgument) {
+ nResult = RESULT_ILLEGALARGUMENTEXCEPTION;
+ } catch (com.sun.star.io.IOException exIO) {
+ nResult = RESULT_IOEXCEPTION;
+ } catch (com.sun.star.uno.RuntimeException exRuntime) {
+ nResult = RESULT_RUNTIMEEXCEPTION;
+ } catch (Exception e) {
+ nResult = RESULT_EXCEPTION;
+ }
+
+ try {
+ if (xDoc != null) {
+ xDoc.dispose();
+ xDoc = null;
+ }
+ } catch (com.sun.star.uno.RuntimeException exClosing) {
+ System.out.println("exception during disposing of a document found!" +
+ " Doesn't influence test - but should be checked.");
+ }
+
+ String sMessage = "URL[\"" + sURL + "\"]";
+
+ if (nResult == nRequiredResult) {
+ System.out.println(sMessage + " expected result [" +
+ convertResult2String(nResult) + "] ");
+ } else {
+ fail(sMessage + " unexpected result [" +
+ convertResult2String(nResult) + "] " +
+ "\nrequired was [" +
+ convertResult2String(nRequiredResult) + "]" +
+ "\nwe got [" + convertResult2String(nResult) + "]"
+ );
+ }
+ }
+
+ /**
+ * it match the int result value to a string, which can be used for logging
+ */
+ private static String convertResult2String(int nResult) {
+ switch (nResult) {
+ case RESULT_VALID_DOC:
+ return "VALID_DOC";
+
+ case RESULT_EMPTY_DOC:
+ return "EMPTY_DOC";
+
+ case RESULT_ILLEGALARGUMENTEXCEPTION:
+ return "ILLEGALARGUMENTEXCEPTION";
+
+ case RESULT_IOEXCEPTION:
+ return "IOEXCEPTION";
+
+ case RESULT_RUNTIMEEXCEPTION:
+ return "RUNTIMEEXCEPTION";
+
+ case RESULT_EXCEPTION:
+ return "ALLOTHEREXCEPTION";
+ }
+
+ return "unknown!";
+ }
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass
+ public static void setUpConnection() throws Exception
+ {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass
+ public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+ private static final OfficeConnection connection = new OfficeConnection();
+
+}
diff --git a/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.props b/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.props
new file mode 100644
index 000000000..92b56bef9
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/CheckXComponentLoader.props
@@ -0,0 +1 @@
+ThreadTimeOut=600000
diff --git a/framework/qa/complex/loadAllDocuments/InteractionHandler.java b/framework/qa/complex/loadAllDocuments/InteractionHandler.java
new file mode 100644
index 000000000..24cf6a151
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/InteractionHandler.java
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.loadAllDocuments;
+
+import com.sun.star.task.XInteractionHandler;
+import com.sun.star.uno.AnyConverter;
+
+
+/**
+ * Implements a simple interaction handler,
+ * which can abort all incoming interactions only ... but make it possible to
+ * log it. So it can be used for debug and test purposes.
+ */
+public class InteractionHandler implements XInteractionHandler
+{
+
+
+ /**
+ * @const RETRY_COUNT it defines the max count of
+ * retrying of an interaction
+ */
+ private static final int RETRY_COUNT = 3;
+
+
+
+ /**
+ * count using of RETRY continuations
+ */
+ private int m_nTry ;
+ /** true if the interaction handler was used */
+ private boolean m_bWasUsed ;
+
+
+ /**
+ * ctor
+ * It's initialize an object of this class with default values
+ * and set the protocol stack. So the outside code can check
+ * if this handler was used or not.
+ */
+ public InteractionHandler()
+ {
+ m_nTry = 0 ;
+ m_bWasUsed = false;
+ }
+
+ /**
+ * Called to start the interaction, because the outside code wish to solve
+ * a detected problem or to inform the user about something.
+ * We save the information here and can handle two well known continuations
+ * only.
+ * [abort and retry].
+ *
+ * @param xRequest
+ * describe the interaction
+ */
+ public void handle(com.sun.star.task.XInteractionRequest xRequest)
+ {
+ m_bWasUsed = true;
+
+ // analyze the possible continuations.
+ // We can abort all incoming interactions only.
+ // But additional we can try to continue it several times too.
+ // Of course after e.g. three loops we have to stop and abort it.
+ com.sun.star.task.XInteractionContinuation[] lContinuations = xRequest.getContinuations();
+
+ com.sun.star.task.XInteractionAbort xAbort = null;
+ com.sun.star.task.XInteractionRetry xRetry = null;
+ com.sun.star.uno.Type xAbortType = new com.sun.star.uno.Type(com.sun.star.task.XInteractionAbort.class);
+ com.sun.star.uno.Type xRetryType = new com.sun.star.uno.Type(com.sun.star.task.XInteractionRetry.class);
+
+ for (int i=0; i<lContinuations.length; ++i)
+ {
+ try
+ {
+ if (xAbort == null)
+ xAbort = (com.sun.star.task.XInteractionAbort)AnyConverter.toObject(xAbortType, lContinuations[i]);
+ if (xRetry == null)
+ xRetry = (com.sun.star.task.XInteractionRetry)AnyConverter.toObject(xRetryType, lContinuations[i]);
+ }
+ catch(com.sun.star.lang.IllegalArgumentException exArg) {}
+ }
+
+ // try it again, but only if it wasn't tried too much before.
+ if (xRetry != null)
+ {
+ synchronized(this)
+ {
+ if (m_nTry < RETRY_COUNT)
+ {
+ ++m_nTry;
+ xRetry.select();
+ return;
+ }
+ }
+ }
+
+ // otherwise we can abort this interaction only
+ if (xAbort != null)
+ {
+ xAbort.select();
+ }
+ }
+
+ public boolean wasUsed() {
+ return m_bWasUsed;
+ }
+}
diff --git a/framework/qa/complex/loadAllDocuments/StatusIndicator.java b/framework/qa/complex/loadAllDocuments/StatusIndicator.java
new file mode 100644
index 000000000..c1edbffd1
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/StatusIndicator.java
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.loadAllDocuments;
+
+// __________ Imports __________
+
+
+
+// __________ Implementation __________
+
+/**
+ * Implements a simple status indicator, which
+ * provide information about state of a load request.
+ * It can be used as an argument e.g. for loadComponentFromURL().
+ */
+public class StatusIndicator implements com.sun.star.task.XStatusIndicator
+{
+
+ private boolean m_bWasUsed ;
+
+
+
+ /**
+ * ctor
+ * It's initialize an object of this class with default values.
+ */
+ public StatusIndicator()
+ {
+ m_bWasUsed = false;
+ }
+
+
+
+ /**
+ * It starts the progress and set the initial text and range.
+ *
+ * @param sText
+ * the initial text for showing
+ *
+ * @param nRange
+ * the new range for following progress
+ */
+ public void start( /*IN*/String sText, /*IN*/int nRange )
+ {
+ synchronized(this)
+ {
+ m_bWasUsed = true;
+ }
+ impl_show();
+ }
+
+
+
+ /**
+ * Finish the progress and reset internal members.
+ */
+ public void end()
+ {
+ synchronized(this)
+ {
+ m_bWasUsed = true;
+ }
+ impl_show();
+ }
+
+
+
+ /**
+ * Set the new description text.
+ *
+ * @param sText
+ * the new text for showing
+ */
+ public void setText( /*IN*/String sText )
+ {
+ synchronized(this)
+ {
+ m_bWasUsed = true;
+ }
+ impl_show();
+ }
+
+
+
+ /**
+ * Set the new progress value.
+ *
+ * @param nValue
+ * the new progress value
+ * Must fit the range!
+ */
+ public void setValue( /*IN*/int nValue )
+ {
+ synchronized(this)
+ {
+ m_bWasUsed = true;
+ }
+ impl_show();
+ }
+
+
+
+ /**
+ * Reset text and progress value to her defaults.
+ */
+ public void reset()
+ {
+ synchronized(this)
+ {
+ m_bWasUsed = true;
+ }
+ impl_show();
+ }
+
+
+
+ /*
+ * Internal helper to show the status.
+ * Currently it's implement as normal text out on stdout.
+ * But of course other things are possible here too.
+ * e.g. a dialog
+ */
+ private void impl_show()
+ {
+ }
+
+ public boolean wasUsed() {
+ return m_bWasUsed;
+ }
+}
diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/Calc_6.sxc b/framework/qa/complex/loadAllDocuments/testdocuments/Calc_6.sxc
new file mode 100644
index 000000000..4b2b57208
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/testdocuments/Calc_6.sxc
Binary files differ
diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/Writer6.sxw b/framework/qa/complex/loadAllDocuments/testdocuments/Writer6.sxw
new file mode 100644
index 000000000..1b2c2cb2d
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/testdocuments/Writer6.sxw
Binary files differ
diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/draw1.sxd b/framework/qa/complex/loadAllDocuments/testdocuments/draw1.sxd
new file mode 100644
index 000000000..58c8772cb
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/testdocuments/draw1.sxd
Binary files differ
diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/imp1.sxi b/framework/qa/complex/loadAllDocuments/testdocuments/imp1.sxi
new file mode 100644
index 000000000..efcdf9b6a
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/testdocuments/imp1.sxi
Binary files differ
diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/password_check.sxw b/framework/qa/complex/loadAllDocuments/testdocuments/password_check.sxw
new file mode 100644
index 000000000..ec545b99e
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/testdocuments/password_check.sxw
Binary files differ
diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/pic.gif b/framework/qa/complex/loadAllDocuments/testdocuments/pic.gif
new file mode 100644
index 000000000..abbbc65f6
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/testdocuments/pic.gif
Binary files differ
diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/pic.jpg b/framework/qa/complex/loadAllDocuments/testdocuments/pic.jpg
new file mode 100644
index 000000000..6b4b744f8
--- /dev/null
+++ b/framework/qa/complex/loadAllDocuments/testdocuments/pic.jpg
Binary files differ
diff --git a/framework/qa/complex/path_settings/PathSettingsTest.java b/framework/qa/complex/path_settings/PathSettingsTest.java
new file mode 100644
index 000000000..236b6e466
--- /dev/null
+++ b/framework/qa/complex/path_settings/PathSettingsTest.java
@@ -0,0 +1,721 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.path_settings;
+
+import com.sun.star.beans.Property;
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XFastPropertySet;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.beans.XPropertiesChangeListener;
+import com.sun.star.beans.XPropertyChangeListener;
+import com.sun.star.beans.XVetoableChangeListener;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.util.thePathSettings;
+
+// ---------- junit imports -----------------
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+import static org.junit.Assert.*;
+
+
+public class PathSettingsTest
+{
+
+ // the test object: an instance of the tested service
+ private static Object aPathSettings = null;
+ // the properties of the service
+ private static Property[] xPropertyInfoOfPathSettings = null;
+ private static String[] aPathSettingNames = null;
+ private static String[] availablePropNames = new String[]
+ {
+ "Addin",
+ "AutoCorrect",
+ "AutoText",
+ "Backup",
+ "Basic",
+ "Bitmap",
+ "Config",
+ "Dictionary",
+ "Favorite",
+ "Filter",
+ "Fingerprint",
+ "Gallery",
+ "Graphic",
+ "Help",
+ "Linguistic",
+ "Module",
+ "Palette",
+ "Plugin",
+ "Storage",
+ "Temp",
+ "Template",
+ "UIConfig",
+ "UserConfig",
+ "Work",
+ };
+ // every path name from availablePropNames exist in this characteristics
+ // name
+ // name_internal
+ // name_user
+ // name_writable
+ private static String[] availablePropNameExtensions = new String[]
+ {
+ "",
+ "_internal",
+ "_user",
+ "_writable"
+ };
+ private static String[] aPathSettingValues = null;
+ ArrayList<Property> aListOfWorkingProperty;
+
+ /**
+ * Initialize before the tests start: this has to be done only once.
+ * This methods sets the 'aPathSettings' and 'xPropertyInfoOfPathSettings' variables.
+ */
+ @Before
+ public void before() throws Exception
+ {
+ try
+ {
+ aPathSettings = thePathSettings.get(connection.getComponentContext());
+ assertNotNull("Can't instantiate com.sun.star.util.thePathSettings.", aPathSettings);
+ util.dbg.getSuppServices(aPathSettings);
+ final XPropertySet xPropSet_of_PathSettings = UnoRuntime.queryInterface(XPropertySet.class, aPathSettings);
+
+ xPropertyInfoOfPathSettings = xPropSet_of_PathSettings.getPropertySetInfo().getProperties();
+ aPathSettingNames = new String[xPropertyInfoOfPathSettings.length];
+ aPathSettingValues = new String[xPropertyInfoOfPathSettings.length];
+
+ aListOfWorkingProperty = new ArrayList<Property>();
+
+ // get initial values and create new ones
+ for (int i = 0; i < xPropertyInfoOfPathSettings.length; i++)
+ {
+ final String sName = xPropertyInfoOfPathSettings[i].Name;
+ aPathSettingNames[i] = sName;
+ Object o = xPropSet_of_PathSettings.getPropertyValue(sName);
+
+ String sValue = convertToString(o);
+ aPathSettingValues[i] = sValue;
+ aListOfWorkingProperty.add(xPropertyInfoOfPathSettings[i]);
+ }
+ }
+ catch (com.sun.star.uno.Exception e)
+ {
+ System.out.println(e.getClass().getName());
+ System.out.println("Message: " + e.getMessage());
+ }
+ }
+
+ private String convertToString(Object o)
+ {
+ String sValue = "";
+ try
+ {
+ if (AnyConverter.isString(o))
+ {
+ sValue = AnyConverter.toString(o);
+ }
+ else if (AnyConverter.isArray(o))
+ {
+ Object oValueList = AnyConverter.toArray(o);
+ String[] aValueList = (String[]) oValueList;
+ String sValues = "";
+ for (int j = 0; j < aValueList.length; j++)
+ {
+ if (sValues.length() > 0)
+ {
+ sValues += ";";
+ }
+ sValues += aValueList[j];
+ }
+ sValue = sValues;
+ }
+ else
+ {
+ System.out.println("Can't convert Object to String");
+ }
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e)
+ {
+ /* ignore */
+ }
+ return sValue;
+ }
+
+ /**
+ * Simple existence test, if this fails, the Lists must update
+ */
+ @Test
+ public void checkInternalListConsistence()
+ {
+ // check if all Properties are in the internal test list
+ for (int i = 0; i < xPropertyInfoOfPathSettings.length; i++)
+ {
+ final String sName = xPropertyInfoOfPathSettings[i].Name;
+ boolean bOccur = checkIfNameExistsInList(sName, availablePropNames, availablePropNameExtensions);
+ assertTrue("TEST IS WRONG, Name:='" + sName + "' doesn't exist in internal Test list.", bOccur);
+ }
+
+ // check if all properties in the internal list also exist in real life
+ for (int i = 0; i < availablePropNames.length; i++)
+ {
+ final String aListName = availablePropNames[i];
+ for (int j = 0; j < availablePropNameExtensions.length; j++)
+ {
+ final String aSubListName = availablePropNameExtensions[j];
+ final String aName = aListName + aSubListName;
+ boolean bOccur = checkIfNameExistsInList(aName, aPathSettingNames, new String[]
+ {
+ ""
+ } /* list must not empty! */);
+ assertTrue("TEST IS WRONG, Name:='" + aName + "' from the internal test list do not occur in real life path settings.", bOccur);
+ }
+ }
+ }
+
+ /**
+ * Simple O(n^n) check if a given String (_sNameMustOccur) exist in the given list(+SubList) values.
+ * @param _sNameMustOccur
+ * @param _aList
+ * @param _aSubList
+ * @return true, if name occur
+ */
+ private boolean checkIfNameExistsInList(String _sNameMustOccur, String[] _aList, String[] _aSubList)
+ {
+ for (int i = 0; i < _aList.length; i++)
+ {
+ final String aListName = _aList[i];
+ for (int j = 0; j < _aSubList.length; j++)
+ {
+ final String aSubListName = _aSubList[j];
+ final String aName = aListName + aSubListName;
+ if (aName.equals(_sNameMustOccur))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Shows the path settings
+ */
+ @Test
+ public void showPathSettings() throws UnknownPropertyException, WrappedTargetException
+ {
+ System.out.println("\n---- All properties ----");
+ final XPropertySet xPropSet_of_PathSettings = UnoRuntime.queryInterface(XPropertySet.class, aPathSettings);
+
+ for (int i = 0; i < aListOfWorkingProperty.size(); i++)
+ {
+ final String sName = aListOfWorkingProperty.get(i).Name;
+ System.out.print(sName);
+ Object o = xPropSet_of_PathSettings.getPropertyValue(sName);
+
+ try
+ {
+ AnyConverter.toString(o);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e)
+ {
+ }
+ System.out.println();
+ }
+ System.out.println("---- Finish showing properties ----\n");
+ }
+
+ private boolean checkPaths(Object _o, Object _o2)
+ {
+ String sLeftPath = "";
+ String sRightPath = "";
+ if (AnyConverter.isArray(_o))
+ {
+ try
+ {
+ Object oValues = AnyConverter.toArray(_o);
+ sLeftPath = convertToString(oValues);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e)
+ {
+ }
+ }
+ else if (AnyConverter.isString(_o))
+ {
+ try
+ {
+ sLeftPath = AnyConverter.toString(_o);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e)
+ {
+ }
+ }
+
+ if (AnyConverter.isArray(_o2))
+ {
+ try
+ {
+ Object oValues = AnyConverter.toArray(_o2);
+ sRightPath = convertToString(oValues);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e)
+ {
+ }
+ }
+ else if (AnyConverter.isString(_o2))
+ {
+ try
+ {
+ sRightPath = AnyConverter.toString(_o2);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e)
+ {
+ }
+ }
+ return checkPaths(sLeftPath, sRightPath);
+ }
+
+ /**
+ * Check 2 given paths if the _aOtherPath exists in _aPath, _aPath could be a list separated by ';'
+ * @param _aPath
+ * @param _aOtherPath
+ * @return true, if _aOtherPath found
+ */
+ private boolean checkPaths(String _aPath, String _aOtherPath)
+ {
+ if (_aOtherPath.contains(";"))
+ {
+ StringTokenizer aToken = new StringTokenizer(_aOtherPath, ";");
+ int nCount = 0;
+ int nFound = 0;
+ while (aToken.hasMoreElements())
+ {
+ String sPath = (String)aToken.nextElement();
+ nCount ++;
+ if (checkPaths(_aPath, sPath))
+ {
+ nFound++;
+ }
+ }
+ if (nFound == nCount)
+ {
+ return true;
+ }
+ }
+ else if(_aPath.contains(";"))
+ {
+ StringTokenizer aToken = new StringTokenizer(_aPath, ";");
+ while (aToken.hasMoreElements())
+ {
+ String sToken = (String)aToken.nextElement();
+ if (sToken.equals(_aOtherPath))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ else if (_aPath.equals(_aOtherPath))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This tests the XFastPropertySet interface implementation.
+ */
+ @Test
+ public void checkXFastPropertySet()
+ {
+ System.out.println("---- Testing the XFastPropertySet interface ----");
+
+
+ // do for all properties
+ // xPropertyInfoOfPathSettings.length
+ for (int i = 0; i < aListOfWorkingProperty.size(); i++)
+ {
+ final Property property = aListOfWorkingProperty.get(i); // xPropertyInfoOfPathSettings[i];
+ String name = property.Name;
+ // get property name and initial value
+ System.out.println("Test property with name: " + name);
+ boolean bResult;
+ if (name.endsWith("_writable"))
+ {
+ bResult = checkStringProperty(property);
+ }
+ else if (name.endsWith("_user"))
+ {
+ bResult = checkStringListProperty(property);
+ }
+ else if (name.endsWith("_internal"))
+ {
+ bResult = checkStringListProperty(property);
+ }
+ else
+ {
+ // old path settings
+ bResult = checkStringProperty(property);
+ }
+ System.out.print(" Test of property " + name + " finished");
+ if (bResult)
+ {
+ System.out.println(" [ok]");
+ }
+ else
+ {
+ System.out.println(" [FAILED]");
+ }
+ System.out.println();
+ }
+ System.out.println("---- Test of XFastPropertySet finished ----\n");
+ }
+
+ private boolean checkStringListProperty(Property property)
+ {
+ // creating instances
+ boolean bResult = true;
+ XFastPropertySet xFPS = UnoRuntime.queryInterface(XFastPropertySet.class, aPathSettings);
+
+ String name = property.Name;
+ int handle = property.Handle;
+
+ Object oValue;
+ try
+ {
+ oValue = xFPS.getFastPropertyValue(handle);
+ }
+ catch (UnknownPropertyException ex)
+ {
+ return false;
+ }
+ catch (WrappedTargetException ex)
+ {
+ return false;
+ }
+
+ if (!AnyConverter.isArray(oValue))
+ {
+ System.out.println(" Internal error, type wrong. PathSetting property with name:" + name + " should be an array.");
+ return false;
+ }
+
+ String val;
+ try
+ {
+ Object oValues = AnyConverter.toArray(oValue);
+
+
+ final String[] aValues = (String[])oValues;
+
+ // aNewValues contains a deep copy of aValues
+ String[] aNewValues = new String[aValues.length];
+ System.arraycopy(aValues, 0, aNewValues, 0, aValues.length);
+ if (aValues.length > 0)
+ {
+ val = aValues[0];
+ }
+ else
+ {
+ val = null;
+ aNewValues = new String[1]; // create a String list
+ }
+ System.out.println(" Property has initial value: '" + val + "'");
+
+ // set to a new correct value
+ String newVal = changeToCorrectValue(val);
+ assertFalse("newVal must not equal val.", newVal.equals(val));
+
+ System.out.println(" Try to change to a correct value '" + newVal + "'");
+ aNewValues[0] = newVal;
+
+ try
+ {
+ try
+ {
+ xFPS.setFastPropertyValue(handle, aNewValues);
+ }
+ catch (com.sun.star.lang.WrappedTargetException e)
+ {
+ System.out.println(" FAIL: setFastPropertyValue(handle:=" + handle + ", name:='" + name + "')" + e.getMessage());
+ bResult = false;
+ }
+
+ // Property_internal can't change we will not arrive beyond this line
+
+ // check the change
+ Object oObj = xFPS.getFastPropertyValue(handle);
+ if (!checkPaths(oObj, aNewValues))
+ {
+ System.out.println(" FAIL: Did not change value on property " + name + ".");
+ bResult = false;
+ }
+
+ // set back to initial setting
+ System.out.println(" Try to check");
+ try
+ {
+ xFPS.setFastPropertyValue(handle, oValue);
+ }
+ catch (com.sun.star.beans.PropertyVetoException e)
+ {
+ // should not occur
+ System.out.println(" FAIL: PropertyVetoException caught: " + e.getMessage());
+ bResult = false;
+ }
+ }
+ catch (com.sun.star.beans.PropertyVetoException e)
+ {
+ if (!name.endsWith("_internal"))
+ {
+ // should not occur
+ System.out.println(" FAIL: PropertyVetoException caught: " + e.getMessage());
+ bResult = false;
+ }
+ else
+ {
+ System.out.println(" OK: PropertyVetoException caught: " + e.getMessage() + " it seems not allowed to change internal values.");
+ }
+ }
+
+ // check if changed
+ Object checkVal3 = xFPS.getFastPropertyValue(handle);
+ if (!checkPaths(checkVal3, oValues))
+ {
+ System.out.println(" FAIL: Can't change value back to original on property " + name);
+ bResult = false;
+ }
+ }
+ catch (com.sun.star.uno.Exception e)
+ {
+ System.out.println(" FAIL: getFastPropertyValue(handle:=" + handle + ", name:='" + name + "')" + e.getMessage());
+ bResult = false;
+ }
+ return bResult;
+ }
+
+ private boolean checkStringProperty(Property property)
+ {
+ boolean bResult = true;
+ XFastPropertySet xFPS = UnoRuntime.queryInterface(XFastPropertySet.class, aPathSettings);
+ String name = property.Name;
+ int handle = property.Handle;
+ Object oValue;
+ try
+ {
+ oValue = xFPS.getFastPropertyValue(handle);
+ }
+ catch (UnknownPropertyException ex)
+ {
+ return false;
+ }
+ catch (WrappedTargetException ex)
+ {
+ return false;
+ }
+
+
+ try
+ {
+ String val = "";
+ val = AnyConverter.toString(oValue);
+ System.out.println(" Property has initial value: '" + val + "'");
+
+ // set to a new correct value
+ String newVal = changeToCorrectValue(val);
+ System.out.println(" Try to change to a correct value '" + newVal + "'");
+ xFPS.setFastPropertyValue(handle, newVal);
+
+ // check the change
+ String checkVal = (String) xFPS.getFastPropertyValue(handle);
+ if (!checkPaths(checkVal, newVal))
+ {
+ System.out.println(" FAIL: Did not change value on property " + name + ".");
+ bResult = false;
+ }
+ /*
+ * Change the given String to an incorrect path URL.
+ */
+ newVal = "fileblablabla";
+ System.out.println(" Try to change to incorrect value '" + newVal + "'");
+ try
+ {
+ xFPS.setFastPropertyValue(handle, newVal);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e)
+ {
+ System.out.println(" Correctly thrown Exception caught.");
+ }
+
+ // check if changed
+ String checkVal2 = (String) xFPS.getFastPropertyValue(handle);
+ if (!checkPaths(checkVal2, checkVal))
+ {
+ System.out.println(" FAIL: Value did change on property " + name + " though it should not have.");
+ bResult = false;
+ }
+ else
+ {
+ System.out.println(" OK: Incorrect value was not set.");
+ }
+ // set back to initial setting
+ System.out.println(" Set back to initial value.");
+ try
+ {
+ xFPS.setFastPropertyValue(handle, val);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException e)
+ {
+ System.out.println(" IllegalArgumentException caught: " + e.getMessage());
+ bResult = false;
+ }
+ // check if changed
+ String checkVal3 = (String) xFPS.getFastPropertyValue(handle);
+ if (!checkVal3.equals(val))
+ {
+ if (!checkPaths(checkVal3, val))
+ {
+ System.out.println(" FAIL: Can't change value back to original on property " + name);
+ System.out.println(" Value is: " + checkVal3);
+
+ bResult = false;
+ }
+ else
+ {
+ System.out.println(" OK: the pathsettings contains the original path.");
+ System.out.println(" Value is: " + checkVal3);
+ System.out.println(" Value should be: " + val);
+ }
+ }
+ else
+ {
+ System.out.println(" OK: Change value back to original on property " + name);
+ }
+ }
+ catch (com.sun.star.uno.Exception e)
+ {
+ System.out.println(" FAIL: getFastPropertyValue(handle:=" + handle + ", name:='" + name + "')" + e.getMessage());
+ bResult = false;
+ }
+ return bResult;
+ }
+
+
+ // ____________________
+ /**
+ * This tests the XPropertySet interface implementation.
+ */
+
+ /**
+ * Change the given String to a correct path URL.
+ * @return The changed path URL.
+ */
+ private String changeToCorrectValue(String path)
+ {
+ // the simplest possibility
+ if (path == null || path.equals(""))
+ {
+ String sTempDir = System.getProperty("java.io.tmpdir");
+ sTempDir = util.utils.getFullURL(sTempDir);
+ return sTempDir; // "file:///tmp";
+ }
+ return graphical.FileHelper.appendPath(path, "tmp");
+ }
+
+ /**
+ * Listener implementation which sets a flag when
+ * listener was called.
+ */
+ public class MyChangeListener implements XPropertiesChangeListener,
+ XPropertyChangeListener,
+ XVetoableChangeListener
+ {
+
+ private boolean propChanged = false;
+ private boolean propertiesChanged = false;
+ private boolean vetoableChanged = false;
+
+ public void propertiesChange(
+ com.sun.star.beans.PropertyChangeEvent[] e)
+ {
+ propertiesChanged = true;
+ }
+
+ public void vetoableChange(com.sun.star.beans.PropertyChangeEvent pE)
+ throws com.sun.star.beans.PropertyVetoException
+ {
+ vetoableChanged = true;
+ }
+
+ public void propertyChange(com.sun.star.beans.PropertyChangeEvent pE)
+ {
+ propChanged = true;
+ }
+
+ public void disposing(com.sun.star.lang.EventObject eventObject)
+ {
+ }
+
+ public void resetListener()
+ {
+ propChanged = false;
+ propertiesChanged = false;
+ vetoableChanged = false;
+ }
+
+ public boolean changePropertyEventFired()
+ {
+ return propChanged;
+ }
+
+ public boolean changePropertiesEventFired()
+ {
+ return propertiesChanged;
+ }
+
+ public boolean vetoableChangeEventFired()
+ {
+ return vetoableChanged;
+ }
+ }
+
+ // setup and close connections
+ @BeforeClass
+ public static void setUpConnection() throws Exception
+ {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass
+ public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+ private static final OfficeConnection connection = new OfficeConnection();
+}
diff --git a/framework/qa/complex/path_substitution/PathSubstitutionTest.java b/framework/qa/complex/path_substitution/PathSubstitutionTest.java
new file mode 100644
index 000000000..96d59287c
--- /dev/null
+++ b/framework/qa/complex/path_substitution/PathSubstitutionTest.java
@@ -0,0 +1,294 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package complex.path_substitution;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openoffice.test.OfficeConnection;
+
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.XStringSubstitution;
+
+/**
+ *
+ */
+public class PathSubstitutionTest
+{
+
+ // all substitution variables
+ private VariableContainer substVars = null;
+
+ /**
+ * Create an array with all substitution variables
+ */
+ @Before public void initialize()
+ {
+ substVars = new VariableContainer();
+ substVars.add("$(prog)", true, true);
+ substVars.add("$(inst)", true, true);
+ substVars.add("$(user)", true, true);
+ substVars.add("$(work)", true, true);
+ substVars.add("$(home)", true, true);
+ substVars.add("$(temp)", true, true);
+ substVars.add("$(lang)", false, false);
+ substVars.add("$(username)", false, false);
+ substVars.add("$(langid)", false, false);
+ substVars.add("$(vlang)", false, false);
+ // path won't resubstitute
+ substVars.add("$(path)", true, false);
+ }
+
+ /**
+ * One actual test: as the method 'getTestMethodNames()' tells.
+ */
+ @Test public void checkXStringSubstitution()
+ {
+ XMultiServiceFactory xMSF = getMSF();
+ System.out.println("---- Testing the XStringSubstitution interface ----");
+ System.out.println("Create instance of test object.\n");
+ XStringSubstitution oObj = null;
+ try
+ {
+ Object x = xMSF.createInstance(
+ "com.sun.star.util.PathSubstitution");
+ oObj = UnoRuntime.queryInterface(XStringSubstitution.class, x);
+ if (oObj == null)
+ {
+ throw new com.sun.star.uno.Exception();
+ }
+ }
+ catch (com.sun.star.uno.Exception e)
+ {
+ System.out.println(e.getClass().getName());
+ System.out.println("Message: " + e.getMessage());
+ fail("Could not create an instance of the test object.");
+ return;
+ }
+
+ for (int i = 0; i < substVars.size(); i++)
+ {
+ String var = substVars.getVariable(i);
+ System.out.println("Testing var '" + var + "'");
+ try
+ {
+ String substVal = oObj.getSubstituteVariableValue(var);
+ System.out.println("\tvalue '" + substVal + "'");
+ substVars.putValue(i, substVal);
+
+ // simple check: let path in a string replace
+ String substString = var + "/additional/path";
+
+ System.out.println("Substitute '" + substString + "'");
+ String newValue = oObj.substituteVariables(substString, true);
+ System.out.println("Return value '" + newValue + "'");
+ // 2do: better check for correct substitution
+ assertTrue("Did not substitute '"
+ + substString + "' to '" + newValue
+ + "' correctly:", newValue.startsWith(substVal));
+
+ // simple check part two:
+ //make substitution backwards if possible
+ if (substVars.canReSubstitute(i))
+ {
+ substString = substVal + "/additional/path";
+
+ System.out.println("Substitute backwards '" + substString + "'");
+ newValue = oObj.reSubstituteVariables(substString);
+ System.out.println("Return value '" + newValue + "'");
+ // 2do: better check for correct substitution
+ assertTrue("Did not reSubstitute '"
+ + substString + "' to '" + newValue
+ + "' correctly:", checkResubstitute(newValue, var));
+ }
+
+ // simple check part three: look if replace
+ //in middle of text works
+ substString = "file:///starting/" + var + "/path";
+
+ String sCanSubstAllPos;
+ if (substVars.onlySubstituteAtBegin(i))
+ sCanSubstAllPos = "NO";
+ else
+ sCanSubstAllPos = "YES";
+ System.out.println("Variable can substitute within string: "+sCanSubstAllPos);
+ System.out.println("Substitute '" + substString + "'");
+ newValue = oObj.substituteVariables(substString, false);
+ System.out.println("Return value '" + newValue + "'");
+ boolean erg = true;
+ if (substVars.onlySubstituteAtBegin(i))
+ {
+ // in this case it should not have worked
+ erg = newValue.indexOf(substVal) == -1;
+ }
+ else
+ {
+ erg = newValue.indexOf(substVal) != -1;
+ }
+ assertTrue("Did not substitute '"
+ + substString + "' to '" + newValue
+ + "' correctly:", erg);
+
+ }
+ catch (com.sun.star.uno.Exception e)
+ {
+ System.out.println(e.getClass().getName());
+ System.out.println("Message: " + e.getMessage());
+ fail("Could not create an instance of the test object.");
+ return;
+ }
+ System.out.println("Finish testing '" + var + "'\n");
+ }
+
+ // check of greedy resubstitution
+ String prog = "$(prog)";
+ String inst = "$(inst)";
+ String instPth = substVars.getValue(inst);
+ String progPth = substVars.getValue(prog);
+
+ if (progPth.startsWith(instPth) && instPth.startsWith(progPth))
+ {
+ System.out.println("Greedy ReSubstitute");
+ String substString = progPth + "/additional/path";
+ String newVal = oObj.reSubstituteVariables(substString);
+ System.out.println("String '" + substString
+ + "' should be resubstituted with");
+ System.out.println("Variable '" + prog + "' instead of Variable '"
+ + inst + "'");
+ assertTrue("Did not reSubstitute '" + substString
+ + "' to '" + newVal + "' correctly:",
+ newVal.startsWith(prog));
+ }
+
+ System.out.println(
+ "---- Finish testing the XStringSubstitution interface ----");
+ }
+
+ /**
+ * test the resubstitution
+ * @return true, if resubstitution is correct.
+ */
+ private boolean checkResubstitute(String subst, String original)
+ {
+ // simple: subst starts with original
+ if (subst.startsWith(original))
+ {
+ return true;
+ }
+ else
+ { // hard: been resubstituted with a different variable.
+ for (int i = 0; i < substVars.size(); i++)
+ {
+ String var = substVars.getVariable(i);
+ if (subst.startsWith(var) && original.startsWith(original))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Class for containing the substitution variables with their
+ * values and some information.
+ */
+ private static class VariableContainer
+ {
+
+ public ArrayList<String> varName;
+ public ArrayList<String> varValue;
+ public ArrayList<Boolean> substAtBegin;
+ public ArrayList<Boolean> resubst;
+
+ public VariableContainer()
+ {
+ varName = new ArrayList<String>();
+ varValue = new ArrayList<String>();
+ substAtBegin = new ArrayList<Boolean>();
+ resubst = new ArrayList<Boolean>();
+ }
+
+ public void add(String var, boolean onlySubstAtBegin,
+ boolean canResubst)
+ {
+ varName.add(var);
+ this.substAtBegin.add(Boolean.valueOf(onlySubstAtBegin));
+ this.resubst.add(Boolean.valueOf(canResubst));
+ }
+
+ public void putValue(int i, String val)
+ {
+ varValue.add(i, val);
+ }
+
+ public int size()
+ {
+ return varName.size();
+ }
+
+ public String getVariable(int i)
+ {
+ return varName.get(i);
+ }
+
+ public String getValue(String var)
+ {
+ return varValue.get(varName.indexOf(var));
+ }
+
+ public boolean onlySubstituteAtBegin(int i)
+ {
+ return substAtBegin.get(i).booleanValue();
+ }
+
+ public boolean canReSubstitute(int i)
+ {
+ return resubst.get(i).booleanValue();
+ }
+ }
+
+ private XMultiServiceFactory getMSF()
+ {
+ return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager());
+ }
+
+ // setup and close connections
+ @BeforeClass
+ public static void setUpConnection() throws Exception
+ {
+ System.out.println("setUpConnection()");
+ connection.setUp();
+ }
+
+ @AfterClass
+ public static void tearDownConnection()
+ throws InterruptedException, com.sun.star.uno.Exception
+ {
+ System.out.println("tearDownConnection()");
+ connection.tearDown();
+ }
+ private static final OfficeConnection connection = new OfficeConnection();
+}
diff --git a/framework/qa/cppunit/data/double-loading.odt b/framework/qa/cppunit/data/double-loading.odt
new file mode 100644
index 000000000..ce990fc5c
--- /dev/null
+++ b/framework/qa/cppunit/data/double-loading.odt
Binary files differ
diff --git a/framework/qa/cppunit/data/empty.fodp b/framework/qa/cppunit/data/empty.fodp
new file mode 100644
index 000000000..3c2a4cf2c
--- /dev/null
+++ b/framework/qa/cppunit/data/empty.fodp
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.presentation"><office:body><office:presentation><draw:page/></office:presentation></office:body></office:document>
diff --git a/framework/qa/cppunit/dispatchtest.cxx b/framework/qa/cppunit/dispatchtest.cxx
new file mode 100644
index 000000000..16a4ecb51
--- /dev/null
+++ b/framework/qa/cppunit/dispatchtest.cxx
@@ -0,0 +1,219 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <cppuhelper/implbase.hxx>
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/DispatchHelper.hpp>
+#include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
+#include <com/sun/star/frame/XInterceptorInfo.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <rtl/ref.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Sample interception implementation that asserts getInterceptedURLs() and queryDispatch() is in sync.
+class MyInterceptor
+ : public cppu::WeakImplHelper<frame::XDispatchProviderInterceptor, frame::XInterceptorInfo>
+{
+ uno::Reference<frame::XDispatchProvider> m_xMaster;
+ uno::Reference<frame::XDispatchProvider> m_xSlave;
+ uno::Sequence<OUString> m_aDisabledCommands;
+ int m_nExpected;
+ int m_nUnexpected;
+
+public:
+ MyInterceptor();
+
+ /// Number of queryDispatch() calls that operate on a command advertised by getInterceptedURLs().
+ int getExpected();
+ /// Number of queryDispatch() calls that operate on a command not advertised by getInterceptedURLs().
+ int getUnexpected();
+
+ // frame::XInterceptorInfo
+ virtual uno::Sequence<OUString> SAL_CALL getInterceptedURLs() override;
+
+ // frame::XDispatchProviderInterceptor
+ virtual void SAL_CALL setMasterDispatchProvider(
+ const uno::Reference<frame::XDispatchProvider>& xNewSupplier) override;
+ virtual uno::Reference<frame::XDispatchProvider> SAL_CALL getMasterDispatchProvider() override;
+ virtual void SAL_CALL
+ setSlaveDispatchProvider(const uno::Reference<frame::XDispatchProvider>& xNewSupplier) override;
+ virtual uno::Reference<frame::XDispatchProvider> SAL_CALL getSlaveDispatchProvider() override;
+
+ // frame::XDispatchProvider
+ virtual uno::Sequence<uno::Reference<frame::XDispatch>> SAL_CALL
+ queryDispatches(const uno::Sequence<frame::DispatchDescriptor>& rRequests) override;
+ virtual uno::Reference<frame::XDispatch>
+ SAL_CALL queryDispatch(const util::URL& rURL, const OUString& rTargetFrameName,
+ sal_Int32 SearchFlags) override;
+};
+
+MyInterceptor::MyInterceptor()
+ : m_aDisabledCommands{ ".uno:Bold" }
+ , m_nExpected(0)
+ , m_nUnexpected(0)
+{
+}
+
+int MyInterceptor::getExpected()
+{
+ int nRet = m_nExpected;
+ m_nExpected = 0;
+ return nRet;
+}
+
+int MyInterceptor::getUnexpected()
+{
+ int nRet = m_nUnexpected;
+ m_nUnexpected = 0;
+ return nRet;
+}
+
+uno::Sequence<OUString> MyInterceptor::getInterceptedURLs() { return m_aDisabledCommands; }
+
+void MyInterceptor::setMasterDispatchProvider(
+ const uno::Reference<frame::XDispatchProvider>& xNewSupplier)
+{
+ m_xMaster = xNewSupplier;
+}
+
+uno::Reference<frame::XDispatchProvider> MyInterceptor::getMasterDispatchProvider()
+{
+ return m_xMaster;
+}
+
+void MyInterceptor::setSlaveDispatchProvider(
+ const uno::Reference<frame::XDispatchProvider>& xNewSupplier)
+{
+ m_xSlave = xNewSupplier;
+}
+
+uno::Reference<frame::XDispatchProvider> MyInterceptor::getSlaveDispatchProvider()
+{
+ return m_xSlave;
+}
+
+uno::Sequence<uno::Reference<frame::XDispatch>>
+MyInterceptor::queryDispatches(const uno::Sequence<frame::DispatchDescriptor>& rRequests)
+{
+ uno::Sequence<uno::Reference<frame::XDispatch>> aResult(rRequests.getLength());
+ auto aResultRange = asNonConstRange(aResult);
+
+ for (sal_Int32 i = 0; i < rRequests.getLength(); ++i)
+ {
+ aResultRange[i] = queryDispatch(rRequests[i].FeatureURL, rRequests[i].FrameName,
+ rRequests[i].SearchFlags);
+ }
+
+ return aResult;
+}
+
+uno::Reference<frame::XDispatch> MyInterceptor::queryDispatch(const util::URL& rURL,
+ const OUString& /*rTargetFrameName*/,
+ sal_Int32 /*SearchFlags*/)
+{
+ if (std::find(std::cbegin(m_aDisabledCommands), std::cend(m_aDisabledCommands), rURL.Complete)
+ != std::cend(m_aDisabledCommands))
+ ++m_nExpected;
+ else
+ ++m_nUnexpected;
+
+ return uno::Reference<frame::XDispatch>();
+}
+
+/// Tests how InterceptionHelper invokes a registered interceptor.
+class DispatchTest : public test::BootstrapFixture, public unotest::MacrosTest
+{
+protected:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ virtual void setUp() override;
+ virtual void tearDown() override;
+};
+
+void DispatchTest::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void DispatchTest::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+CPPUNIT_TEST_FIXTURE(DispatchTest, testInterception)
+{
+ mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument");
+ uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xModel.is());
+
+ uno::Reference<frame::XDispatchProviderInterception> xRegistration(
+ xModel->getCurrentController()->getFrame(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xRegistration.is());
+
+ rtl::Reference<MyInterceptor> pInterceptor(new MyInterceptor());
+ xRegistration->registerDispatchProviderInterceptor(pInterceptor);
+
+ dispatchCommand(mxComponent, ".uno:Bold", {});
+ CPPUNIT_ASSERT_EQUAL(1, pInterceptor->getExpected());
+ CPPUNIT_ASSERT_EQUAL(0, pInterceptor->getUnexpected());
+ dispatchCommand(mxComponent, ".uno:Italic", {});
+ CPPUNIT_ASSERT_EQUAL(1, pInterceptor->getExpected());
+ // This was 1: MyInterceptor::queryDispatch() was called for .uno:Italic.
+ CPPUNIT_ASSERT_EQUAL(0, pInterceptor->getUnexpected());
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/framework/qa/cppunit/data/";
+
+CPPUNIT_TEST_FIXTURE(DispatchTest, testSfxOfficeDispatchDispose)
+{
+ // this test doesn't work with a new document because of aURL.Main check in SfxBaseController::dispatch()
+ mxComponent = loadFromDesktop(m_directories.getURLFromSrc(DATA_DIRECTORY) + "empty.fodp",
+ "com.sun.star.presentation.PresentationDocument");
+ uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xModel.is());
+ uno::Reference<frame::XController> xController(xModel->getCurrentController());
+ CPPUNIT_ASSERT(xController.is());
+ uno::Reference<frame::XDispatchProvider> xFrame(xController->getFrame(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xFrame.is());
+
+ uno::Reference<util::XURLTransformer> xParser(util::URLTransformer::create(mxComponentContext));
+ util::URL url;
+ url.Complete = xModel->getURL() + "#dummy";
+ xParser->parseStrict(url);
+
+ uno::Reference<frame::XDispatch> xDisp(xFrame->queryDispatch(url, "", 0));
+ CPPUNIT_ASSERT(xDisp.is());
+
+ mxComponent->dispose();
+
+ util::URL urlSlot;
+ urlSlot.Complete = "slot:5598";
+ xParser->parseStrict(urlSlot);
+ // crashed with UAF
+ xDisp->dispatch(urlSlot, {});
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/qa/cppunit/loadenv.cxx b/framework/qa/cppunit/loadenv.cxx
new file mode 100644
index 000000000..4842645bb
--- /dev/null
+++ b/framework/qa/cppunit/loadenv.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <vcl/scheduler.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Covers framework/source/loadenv/ fixes.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+public:
+ void setUp() override;
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/framework/qa/cppunit/data/";
+
+class DocumentOpener
+{
+public:
+ DECL_STATIC_LINK(DocumentOpener, OpenDocument, void*, void);
+};
+
+IMPL_STATIC_LINK(DocumentOpener, OpenDocument, void*, pArg, void)
+{
+ CPPUNIT_ASSERT(pArg);
+ auto pURL = static_cast<OUString*>(pArg);
+ uno::Reference<uno::XComponentContext> xComponentContext
+ = comphelper::getProcessComponentContext();
+ uno::Reference<frame::XDesktop2> xDesktop = frame::Desktop::create(xComponentContext);
+ xDesktop->loadComponentFromURL(*pURL, "_default", 0, {});
+ delete pURL;
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testDoubleLoading)
+{
+ // Try to load the same document twice. This is similar to trying to execute the soffice process
+ // twice: in that case the 2nd instance forwards to the 1st instance and then uses the same code
+ // path.
+ for (int i = 0; i < 2; ++i)
+ {
+ auto pURL = std::make_unique<OUString>(m_directories.getURLFromSrc(DATA_DIRECTORY)
+ + "double-loading.odt");
+ Application::PostUserEvent(LINK(nullptr, DocumentOpener, OpenDocument), pURL.release());
+ }
+ Scheduler::ProcessEventsToIdle();
+
+ // Verify that the 2nd load didn't happen, since it's the same document.
+ uno::Reference<frame::XFrames> xFrames = mxDesktop->getFrames();
+ // Without the accompanying fix in place, this failed with:
+ // - Expected: 1
+ // - Actual : 2
+ // i.e. the document was loaded twice, into two separate frames/windows.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), xFrames->getCount());
+
+ // Close the document, now that we know we have a single one.
+ uno::Reference<frame::XFrame> xFrame(xFrames->getByIndex(0), uno::UNO_QUERY);
+ xFrame->getController()->getModel()->dispose();
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/qa/cppunit/services.cxx b/framework/qa/cppunit/services.cxx
new file mode 100644
index 000000000..873ea5938
--- /dev/null
+++ b/framework/qa/cppunit/services.cxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+
+#include <comphelper/propertyvalue.hxx>
+#include <salhelper/thread.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/scheduler.hxx>
+#include <vcl/wrkwin.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Covers framework/source/services/ fixes.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+protected:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+/// Invokes XFrameImpl::loadComponentFromURL() on a thread.
+class TestThread : public salhelper::Thread
+{
+ uno::Reference<frame::XComponentLoader> mxComponentLoader;
+ uno::Reference<lang::XComponent>& mrComponent;
+
+public:
+ TestThread(const uno::Reference<frame::XComponentLoader>& xComponentLoader,
+ uno::Reference<lang::XComponent>& rComponent);
+ void execute() override;
+};
+
+TestThread::TestThread(const uno::Reference<frame::XComponentLoader>& xComponentLoader,
+ uno::Reference<lang::XComponent>& rComponent)
+ : salhelper::Thread("TestThread")
+ , mxComponentLoader(xComponentLoader)
+ , mrComponent(rComponent)
+{
+}
+
+void TestThread::execute()
+{
+ sal_Int32 nSearchFlags = frame::FrameSearchFlag::AUTO;
+ uno::Sequence<beans::PropertyValue> aArguments = {
+ comphelper::makePropertyValue("OnMainThread", true),
+ };
+ // Note how this is invoking loadComponentFromURL() on a frame, not on the desktop, as usual.
+ mrComponent = mxComponentLoader->loadComponentFromURL("private:factory/swriter", "_self",
+ nSearchFlags, aArguments);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testLoadComponentFromURL)
+{
+ // Without the accompanying fix in place, this test would have failed with:
+ // thread 1: comphelper::SolarMutex::doRelease end: m_nCount is 1
+ // thread 2: vcl::SolarThreadExecutor::execute: before SolarMutexReleaser ctor
+ // thread 2: comphelper::SolarMutex::doRelease start: m_nCount is 1, bUnlockAll is 1
+ // thread 2: comphelper::SolarMutex::doRelease: failed IsCurrentThread() check, will abort
+ // Notice how thread 2 attempts to release the solar mutex while thread 1 holds it.
+
+ // Create a default window, so by the time the thread would post a user event, it doesn't need
+ // the solar mutex to process a SendMessageW() call on Windows.
+ ScopedVclPtrInstance<WorkWindow> xWindow(nullptr, WB_APP | WB_STDWORK);
+ // Variable is not used, it holds the default window.
+ (void)xWindow;
+
+ rtl::Reference<TestThread> xThread;
+ {
+ // Start the thread that will load the component, but hold the solar mutex for now, so we
+ // can see if it blocks.
+ SolarMutexGuard guard;
+ uno::Reference<frame::XFrame> xFrame = mxDesktop->findFrame("_blank", /*nSearchFlags=*/0);
+ uno::Reference<frame::XComponentLoader> xComponentLoader(xFrame, uno::UNO_QUERY);
+ xThread = new TestThread(xComponentLoader, getComponent());
+ xThread->launch();
+ // If loadComponentFromURL() doesn't lock the solar mutex, the test will abort here.
+ osl::Thread::wait(std::chrono::seconds(1));
+ }
+ {
+ // Now release the solar mutex, so the thread can post the task on the main loop.
+ SolarMutexReleaser releaser;
+ osl::Thread::wait(std::chrono::seconds(1));
+ }
+ {
+ // Spin the main loop.
+ SolarMutexGuard guard;
+ Scheduler::ProcessEventsToIdle();
+ }
+ {
+ // Stop the thread.
+ SolarMutexReleaser releaser;
+ xThread->join();
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testURLTransformer_parseSmart)
+{
+ // Without the accompanying fix in place, this test would have failed with
+ // "www.example.com:" treated as scheme, "/8080/foo/" as path, "bar?q=baz"
+ // as name, and "F" as fragment.
+
+ css::util::URL aURL;
+ aURL.Complete = "www.example.com:8080/foo/bar?q=baz#F";
+ css::uno::Reference xParser(css::util::URLTransformer::create(mxComponentContext));
+ CPPUNIT_ASSERT(xParser->parseSmart(aURL, "http:"));
+ CPPUNIT_ASSERT_EQUAL(OUString("http://www.example.com:8080/foo/bar?q=baz#F"), aURL.Complete);
+ CPPUNIT_ASSERT_EQUAL(OUString("http://www.example.com:8080/foo/bar"), aURL.Main);
+ CPPUNIT_ASSERT_EQUAL(OUString("http://"), aURL.Protocol);
+ CPPUNIT_ASSERT(aURL.User.isEmpty());
+ CPPUNIT_ASSERT(aURL.Password.isEmpty());
+ CPPUNIT_ASSERT_EQUAL(OUString("www.example.com"), aURL.Server);
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(8080), aURL.Port);
+ CPPUNIT_ASSERT_EQUAL(OUString("/foo/"), aURL.Path);
+ CPPUNIT_ASSERT_EQUAL(OUString("bar"), aURL.Name);
+ CPPUNIT_ASSERT_EQUAL(OUString("q=baz"), aURL.Arguments);
+ CPPUNIT_ASSERT_EQUAL(OUString("F"), aURL.Mark);
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/framework/qa/unoapi/framework.sce b/framework/qa/unoapi/framework.sce
new file mode 100644
index 000000000..ed1497d6d
--- /dev/null
+++ b/framework/qa/unoapi/framework.sce
@@ -0,0 +1,51 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+-o fwl.ContentHandlerFactory
+-o fwl.FilterFactory
+-o fwl.FrameLoaderFactory
+-o fwl.SubstituteVariables
+#i113245 -o fwl.TypeDetection
+#i84346 -o fwl.PathSettings
+-o fwk.DispatchRecorder
+-o fwk.DispatchRecorderSupplier
+-o fwk.FooterMenuController
+-o fwk.StatusBarControllerFactory
+-o fwk.ToolBarsMenuController
+-o fwk.UICategoryDescription
+#i84423 -o fwk.JobExecutor
+#i84423 -o fwk.JobHandler
+-o fwk.MailToDispatcher
+-o fwk.ServiceHandler
+-o fwk.URLTransformer
+-o fwk.MacrosMenuController
+#i112746 -o fwk.ModuleManager
+-o fwk.UIElementFactoryManager
+-o fwk.UICommandDescription
+-o fwk.LayoutManager
+-o fwk.UIConfigurationManager
+-o fwk.MenuBarFactory
+-o fwk.FontSizeMenuController
+-o fwk.HeaderMenuController
+-o fwk.ControlMenuController
+-o fwk.FontMenuController
+-o fwk.ModuleUIConfigurationManagerSupplier
+-o fwk.ModuleUIConfigurationManager
+#i84321 -o fwk.PopupMenuControllerFactory
+#i88644 -o fwk.Frame
+-o fwk.Desktop
+
diff --git a/framework/qa/unoapi/knownissues.xcl b/framework/qa/unoapi/knownissues.xcl
new file mode 100644
index 000000000..d1255e611
--- /dev/null
+++ b/framework/qa/unoapi/knownissues.xcl
@@ -0,0 +1,77 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+### 112552 ###
+fwk.JobHandler::com::sun::star::frame::XDispatchProvider
+fwk.JobHandler::com::sun::star::lang::XInitialization
+
+### i8242 ###
+fwk.Desktop::com::sun::star::lang::XComponent
+
+### i30570 ###
+fwl.TypeDetection::com::sun::star::container::XNameReplace
+
+### i50165 ###
+fwk.UIConfigurationManager::com::sun::star::ui::XUIConfigurationStorage
+fwk.UIConfigurationManager::com::sun::star::ui::XUIConfigurationPersistence
+fwk.UIConfigurationManager::com::sun::star::ui::XUIConfiguration
+fwk.UIConfigurationManager::com::sun::star::ui::XUIConfigurationManager
+
+### i50578 ###
+fwk.StatusBarControllerFactory::com::sun::star::lang::XMultiComponentFactory
+
+### i68698 ###
+fwl.PathSettings::com::sun::star::beans::XMultiPropertySet
+
+### i74020 ###
+fwl.FilterFactory::com::sun::star::lang::XMultiServiceFactory
+
+### i30570 ###
+fwl.FilterFactory::com::sun::star::container::XNameReplace
+
+### i84321 ###
+fwk.PopupMenuControllerFactory
+# -> disabled in framework.sce
+
+### i84346 ###
+fwl.PathSettings::com::sun::star::beans::XMultiPropertySet
+#-> disabled in framework.sce
+
+### i84423 ###
+fwk.JobExecutor
+fwk.JobHandler
+#-> disabled in framework.sce
+
+### i88635 ###
+fwk.Desktop::com::sun::star::frame::XFramesSupplier
+
+### i87526 ###
+fwk.Frame::com::sun::star::lang::XComponent
+
+### i87865 ###
+fwk.Desktop::com::sun::star::frame::XDesktop
+
+### i88644 ###
+fwk.Frame
+#-> disabled in framework.sce
+
+### i90345 ###
+fwk.URLTransformer::com::sun::star::util::XURLTransformer
+
+### i111180 ###
+fwk.Desktop::com::sun::star::frame::XComponentLoader
diff --git a/framework/qa/unoapi/testdocuments/Calc_Link.sxc b/framework/qa/unoapi/testdocuments/Calc_Link.sxc
new file mode 100644
index 000000000..086c04fe0
--- /dev/null
+++ b/framework/qa/unoapi/testdocuments/Calc_Link.sxc
Binary files differ
diff --git a/framework/qa/unoapi/testdocuments/Writer_link.sxw b/framework/qa/unoapi/testdocuments/Writer_link.sxw
new file mode 100644
index 000000000..5e5c8bdcb
--- /dev/null
+++ b/framework/qa/unoapi/testdocuments/Writer_link.sxw
Binary files differ
diff --git a/framework/qa/unoapi/testdocuments/XTypeDetection.sxw b/framework/qa/unoapi/testdocuments/XTypeDetection.sxw
new file mode 100644
index 000000000..b241f4ed8
--- /dev/null
+++ b/framework/qa/unoapi/testdocuments/XTypeDetection.sxw
Binary files differ
diff --git a/framework/qa/unoapi/testdocuments/delete.cfg b/framework/qa/unoapi/testdocuments/delete.cfg
new file mode 100644
index 000000000..31fef95a0
--- /dev/null
+++ b/framework/qa/unoapi/testdocuments/delete.cfg
Binary files differ