diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /framework/qa | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.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')
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 Binary files differnew file mode 100644 index 000000000..d23344389 --- /dev/null +++ b/framework/qa/complex/contextMenuInterceptor/space-metal.jpg 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(" "); + 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 Binary files differnew file mode 100644 index 000000000..4b2b57208 --- /dev/null +++ b/framework/qa/complex/loadAllDocuments/testdocuments/Calc_6.sxc diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/Writer6.sxw b/framework/qa/complex/loadAllDocuments/testdocuments/Writer6.sxw Binary files differnew file mode 100644 index 000000000..1b2c2cb2d --- /dev/null +++ b/framework/qa/complex/loadAllDocuments/testdocuments/Writer6.sxw diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/draw1.sxd b/framework/qa/complex/loadAllDocuments/testdocuments/draw1.sxd Binary files differnew file mode 100644 index 000000000..58c8772cb --- /dev/null +++ b/framework/qa/complex/loadAllDocuments/testdocuments/draw1.sxd diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/imp1.sxi b/framework/qa/complex/loadAllDocuments/testdocuments/imp1.sxi Binary files differnew file mode 100644 index 000000000..efcdf9b6a --- /dev/null +++ b/framework/qa/complex/loadAllDocuments/testdocuments/imp1.sxi diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/password_check.sxw b/framework/qa/complex/loadAllDocuments/testdocuments/password_check.sxw Binary files differnew file mode 100644 index 000000000..ec545b99e --- /dev/null +++ b/framework/qa/complex/loadAllDocuments/testdocuments/password_check.sxw diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/pic.gif b/framework/qa/complex/loadAllDocuments/testdocuments/pic.gif Binary files differnew file mode 100644 index 000000000..abbbc65f6 --- /dev/null +++ b/framework/qa/complex/loadAllDocuments/testdocuments/pic.gif diff --git a/framework/qa/complex/loadAllDocuments/testdocuments/pic.jpg b/framework/qa/complex/loadAllDocuments/testdocuments/pic.jpg Binary files differnew file mode 100644 index 000000000..6b4b744f8 --- /dev/null +++ b/framework/qa/complex/loadAllDocuments/testdocuments/pic.jpg 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 Binary files differnew file mode 100644 index 000000000..ce990fc5c --- /dev/null +++ b/framework/qa/cppunit/data/double-loading.odt 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 Binary files differnew file mode 100644 index 000000000..086c04fe0 --- /dev/null +++ b/framework/qa/unoapi/testdocuments/Calc_Link.sxc diff --git a/framework/qa/unoapi/testdocuments/Writer_link.sxw b/framework/qa/unoapi/testdocuments/Writer_link.sxw Binary files differnew file mode 100644 index 000000000..5e5c8bdcb --- /dev/null +++ b/framework/qa/unoapi/testdocuments/Writer_link.sxw diff --git a/framework/qa/unoapi/testdocuments/XTypeDetection.sxw b/framework/qa/unoapi/testdocuments/XTypeDetection.sxw Binary files differnew file mode 100644 index 000000000..b241f4ed8 --- /dev/null +++ b/framework/qa/unoapi/testdocuments/XTypeDetection.sxw diff --git a/framework/qa/unoapi/testdocuments/delete.cfg b/framework/qa/unoapi/testdocuments/delete.cfg Binary files differnew file mode 100644 index 000000000..31fef95a0 --- /dev/null +++ b/framework/qa/unoapi/testdocuments/delete.cfg |