diff options
Diffstat (limited to '')
31 files changed, 6532 insertions, 0 deletions
diff --git a/toolkit/qa/complex/toolkit/AccessibleStatusBarItem.java b/toolkit/qa/complex/toolkit/AccessibleStatusBarItem.java new file mode 100644 index 000000000..a3fac8c3d --- /dev/null +++ b/toolkit/qa/complex/toolkit/AccessibleStatusBarItem.java @@ -0,0 +1,359 @@ +/* + * 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.toolkit; + +import java.util.logging.Logger; +import java.util.logging.Level; +import complex.toolkit.accessibility._XAccessibleEventBroadcaster; +import complex.toolkit.accessibility._XAccessibleExtendedComponent; +import complex.toolkit.accessibility._XAccessibleText; +import complex.toolkit.accessibility._XAccessibleComponent; +import complex.toolkit.accessibility._XAccessibleContext; +import util.SOfficeFactory; +import util.AccessibilityTools; +import com.sun.star.awt.XWindow; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XServiceInfo; +import com.sun.star.sheet.XSpreadsheetDocument; +import com.sun.star.text.XTextDocument; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.XCloseable; +import com.sun.star.accessibility.AccessibleRole; +import com.sun.star.accessibility.XAccessible; +import com.sun.star.accessibility.XAccessibleContext; +import com.sun.star.awt.XExtendedToolkit; + + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openoffice.test.OfficeConnection; +import static org.junit.Assert.*; + +/** + * + */ +public class AccessibleStatusBarItem { + + XMultiServiceFactory xMSF = null; + XAccessibleContext testObject = null; + XWindow xWindow = null; + + /** + * Check document types + */ + @Test + public void checkDocs() + { + checkWriterDoc(); + checkMathDoc(); + checkDrawDoc(); + checkImpressDoc(); + checkCalcDoc(); + } + + private XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + /** + * Test the interfaces on a writer document + */ + private void checkWriterDoc() { + xMSF = getMSF(); + SOfficeFactory xSOF = SOfficeFactory.getFactory(xMSF); + XTextDocument xTextDoc = null; + try { + System.out.println("****** Open a new writer document"); + xTextDoc = xSOF.createTextDoc("_blank"); + getTestObject(); + } + catch(com.sun.star.uno.Exception e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + runAllInterfaceTests(); + + if (xTextDoc != null) { + XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xTextDoc); + try { + xClose.close(false); + } + catch(com.sun.star.util.CloseVetoException e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + } + } + + /** + * Test the interfaces on a math document + */ + public void checkMathDoc() { + xMSF = getMSF(); + SOfficeFactory xSOF = SOfficeFactory.getFactory(xMSF); + XComponent xMathDoc = null; + try { + System.out.println("****** Open a new math document"); + xMathDoc = xSOF.createMathDoc("_blank"); + getTestObject(); + } + catch(com.sun.star.uno.Exception e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + runAllInterfaceTests(); + + if (xMathDoc != null) { + XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xMathDoc); + try { + xClose.close(false); + } + catch(com.sun.star.util.CloseVetoException e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + } + } + + /** + * Test the interfaces on a draw document + */ + public void checkDrawDoc() { + xMSF = getMSF(); + SOfficeFactory xSOF = SOfficeFactory.getFactory(xMSF); + XComponent xDrawDoc = null; + try { + System.out.println("****** Open a new draw document"); + xDrawDoc = xSOF.createDrawDoc("_blank"); + getTestObject(); + } + catch(com.sun.star.uno.Exception e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + runAllInterfaceTests(); + + if (xDrawDoc != null) { + XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xDrawDoc); + try { + xClose.close(false); + } + catch(com.sun.star.util.CloseVetoException e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + } + } + + /** + * Test the interfaces on an impress document + */ + public void checkImpressDoc() { + xMSF = getMSF(); + SOfficeFactory xSOF = SOfficeFactory.getFactory(xMSF); + XComponent xImpressDoc = null; + try { + System.out.println("****** Open a new impress document"); + xImpressDoc = xSOF.createImpressDoc("_blank"); + getTestObject(); + } + catch(com.sun.star.uno.Exception e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + runAllInterfaceTests(); + + if (xImpressDoc != null) { + XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xImpressDoc); + try { + xClose.close(false); + } + catch(com.sun.star.util.CloseVetoException e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + } + } + /** + * Test the interfaces on a calc document + */ + public void checkCalcDoc() { + xMSF = getMSF(); + SOfficeFactory xSOF = SOfficeFactory.getFactory(xMSF); + XSpreadsheetDocument xSpreadsheetDoc = null; + try { + System.out.println("****** Open a new calc document"); + xSpreadsheetDoc = xSOF.createCalcDoc("_blank"); + util.utils.waitForEventIdle(xMSF); + getTestObject(); + } + catch(com.sun.star.uno.Exception e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + runAllInterfaceTests(); + + if (xSpreadsheetDoc != null) { + XCloseable xClose = UnoRuntime.queryInterface(XCloseable.class, xSpreadsheetDoc); + try { + xClose.close(false); + } + catch(com.sun.star.util.CloseVetoException e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + } + } + + public void getTestObject() { + try { + XInterface xIfc = (XInterface) xMSF.createInstance( + "com.sun.star.awt.Toolkit") ; + XExtendedToolkit tk = + UnoRuntime.queryInterface(XExtendedToolkit.class,xIfc); + + util.utils.waitForEventIdle(xMSF); + xWindow = UnoRuntime.queryInterface( + XWindow.class,tk.getActiveTopWindow()); + + util.utils.waitForEventIdle(xMSF); + XAccessible xRoot = AccessibilityTools.getAccessibleObject(xWindow); + XAccessibleContext parentContext = null; + + System.out.println("Get the accessible status bar."); + parentContext = AccessibilityTools.getAccessibleObjectForRole( + xRoot, AccessibleRole.STATUS_BAR, ""); + util.utils.waitForEventIdle(xMSF); + if ( parentContext == null ) { + fail("Could not create a test object."); + } + System.out.println("...OK."); + + testObject=parentContext; + } + catch(com.sun.star.uno.Exception e) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", e ); + } + catch(Throwable t) { + Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, "caught an exception", t ); + } + } + + public void runAllInterfaceTests() { + int count = testObject.getAccessibleChildCount(); + System.out.println("*****"); + System.out.println("**** Found items to test: " + count); + for (int i=0;i<count;i++){ + System.out.println("**** Now testing StatusBarItem " + i + "."); + XAccessible object = null; + try { + object = testObject.getAccessibleChild(i); + } + catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("* Cannot get item Nr: " + i); + continue; + } + XServiceInfo xSI = UnoRuntime.queryInterface( + XServiceInfo.class,object); + String[] services = xSI.getSupportedServiceNames(); + System.out.println("* Implementation Name: " + xSI.getImplementationName()); + String accName = object.getAccessibleContext().getAccessibleName(); + System.out.println("* Accessible Name: " + accName); + for (int j=0; j<services.length; j++) + { + System.out.println("* ServiceName "+j+": "+ services[j]); + } + System.out.println("*****"); + + System.out.println("*** Now testing XAccessibleComponent ***"); + _XAccessibleComponent _xAccCompTest = + new _XAccessibleComponent(object); + assertTrue("failed: "+accName+" - XAccessibleComponent::getBounds", _xAccCompTest._getBounds()); + assertTrue("failed: "+accName+" - XAccessibleComponent::contains", _xAccCompTest._containsPoint()); + assertTrue("failed: "+accName+" - XAccessibleComponent::getAccessibleAt", _xAccCompTest._getAccessibleAtPoint()); + assertTrue("failed: "+accName+" - XAccessibleComponent::getBackground", _xAccCompTest._getBackground()); + assertTrue("failed: "+accName+" - XAccessibleComponent::getForeground", _xAccCompTest._getForeground()); + assertTrue("failed: "+accName+" - XAccessibleComponent::getLocation", _xAccCompTest._getLocation()); + assertTrue("failed: "+accName+" - XAccessibleComponent::getLocationOnScreen", _xAccCompTest._getLocationOnScreen()); + assertTrue("failed: "+accName+" - XAccessibleComponent::getSize", _xAccCompTest._getSize()); + assertTrue("failed: "+accName+" - XAccessibleComponent::grabFocus", _xAccCompTest._grabFocus()); + + System.out.println("*** Now testing XAccessibleContext ***"); + _XAccessibleContext _xAccContext = + new _XAccessibleContext(object); + assertTrue("failed: "+accName+" - XAccessibleContext::getAccessibleChildCount", _xAccContext._getAccessibleChildCount()); + assertTrue("failed: "+accName+" - XAccessibleContext::getAccessibleChild", _xAccContext._getAccessibleChild()); + assertTrue("failed: "+accName+" - XAccessibleContext::getAccessibleDescription", _xAccContext._getAccessibleDescription()); + assertTrue("failed: "+accName+" - XAccessibleContext::getAccessibleName", _xAccContext._getAccessibleName()); + assertTrue("failed: "+accName+" - XAccessibleContext::getAccessibleParent", _xAccContext._getAccessibleParent()); + assertTrue("failed: "+accName+" - XAccessibleContext::getAccessibleIndexInParent", _xAccContext._getAccessibleIndexInParent()); + assertTrue("failed: "+accName+" - XAccessibleContext::getAccessibleRelationSet", _xAccContext._getAccessibleRelationSet()); + assertTrue("failed: "+accName+" - XAccessibleContext::getAccessibleRole", _xAccContext._getAccessibleRole()); + assertTrue("failed: "+accName+" - XAccessibleContext::getAccessibleStateSet", _xAccContext._getAccessibleStateSet()); + assertTrue("failed: "+accName+" - XAccessibleContext::getLocale", _xAccContext._getLocale()); + + System.out.println("*** Now testing XAccessibleExtendedComponent ***"); + _XAccessibleExtendedComponent _xAccExtComp = + new _XAccessibleExtendedComponent(object); + assertTrue("failed: "+accName+" - XAccessibleExtendedComponent::getFont", _xAccExtComp._getFont()); + assertTrue("failed: "+accName+" - XAccessibleExtendedComponent::getTitledBorderText", _xAccExtComp._getTitledBorderText()); + assertTrue("failed: "+accName+" - XAccessibleExtendedComponent::getToolTipText", _xAccExtComp._getToolTipText()); + + System.out.println("*** Now testing XAccessibleEventBroadcaster ***"); + _XAccessibleEventBroadcaster _xAccEvBcast = + new _XAccessibleEventBroadcaster(object, xWindow); + assertTrue("failed: "+accName+" - XAccessibleEventBroadcaster::addEventListener", _xAccEvBcast._addEventListener(xMSF)); + assertTrue("failed: "+accName+" - XAccessibleEventBroadcaster::removeEventListener", _xAccEvBcast._removeEventListener(xMSF)); + + System.out.println("*** Now testing XAccessibleText ***"); + _XAccessibleText _xAccText = + new _XAccessibleText(object, xMSF, "true"); + assertTrue("failed: "+accName+" - XAccessibleText::getText", _xAccText._getText()); + assertTrue("failed: "+accName+" - XAccessibleText::getCharacterCount", _xAccText._getCharacterCount()); + assertTrue("failed: "+accName+" - XAccessibleText::getCharacterBounds", _xAccText._getCharacterBounds()); + assertTrue("failed: "+accName+" - XAccessibleText::setSelection", _xAccText._setSelection()); + assertTrue("failed: "+accName+" - XAccessibleText::copyText", _xAccText._copyText()); + assertTrue("failed: "+accName+" - XAccessibleText::getCharacter", _xAccText._getCharacter()); + assertTrue("failed: "+accName+" - XAccessibleText::getCharacterAttributes", _xAccText._getCharacterAttributes()); + assertTrue("failed: "+accName+" - XAccessibleText::getIndexAtPoint", _xAccText._getIndexAtPoint()); + assertTrue("failed: "+accName+" - XAccessibleText::getSelectedText", _xAccText._getSelectedText()); + assertTrue("failed: "+accName+" - XAccessibleText::getSelectionEnd", _xAccText._getSelectionEnd()); + assertTrue("failed: "+accName+" - XAccessibleText::getSelectionStart", _xAccText._getSelectionStart()); + assertTrue("failed: "+accName+" - XAccessibleText::getTextAtIndex", _xAccText._getTextAtIndex()); + assertTrue("failed: "+accName+" - XAccessibleText::getTextBeforeIndex", _xAccText._getTextBeforeIndex()); + assertTrue("failed: "+accName+" - XAccessibleText::getBehindIndex", _xAccText._getTextBehindIndex()); + assertTrue("failed: "+accName+" - XAccessibleText::getTextRange", _xAccText._getTextRange()); + assertTrue("failed: "+accName+" - XAccessibleText::setCaretPosition", _xAccText._setCaretPosition()); + assertTrue("failed: "+accName+" - XAccessibleText::getCaretPosition", _xAccText._getCaretPosition()); + } + } + + + + + @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/toolkit/qa/complex/toolkit/Assert.java b/toolkit/qa/complex/toolkit/Assert.java new file mode 100644 index 000000000..f7988270a --- /dev/null +++ b/toolkit/qa/complex/toolkit/Assert.java @@ -0,0 +1,185 @@ +/* + * 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.toolkit; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import static org.junit.Assert.*; + +/** + * provides assertion capabilities not found in {@link org.junit.Assert} + */ +public class Assert +{ + + /** invokes a given method on a given object, and assures a certain exception is caught + * @param i_message + * is the message to print when the check fails + * @param i_object + * is the object to invoke the method on + * @param i_methodName + * is the name of the method to invoke + * @param i_methodArgs + * are the arguments to pass to the method. + * @param i_argClasses + * are the classes to assume for the arguments of the methods + * @param i_expectedExceptionClass + * is the class of the exception to be caught. If this is null, + * it means that <em>no</em> exception must be throw by invoking the method. + */ + public static void assertException( final String i_message, final Object i_object, final String i_methodName, + final Class<?>[] i_argClasses, final Object[] i_methodArgs, final Class<?> i_expectedExceptionClass ) + { + Class<?> objectClass = i_object.getClass(); + + boolean noExceptionAllowed = ( i_expectedExceptionClass == null ); + + boolean caughtExpected = noExceptionAllowed; + try + { + Method method = impl_getMethod( objectClass, i_methodName, i_argClasses ); + method.invoke(i_object, i_methodArgs ); + } + catch ( NoSuchMethodException e ) + { + StringBuilder message = new StringBuilder(); + message.append( "no such method: " ).append( objectClass.getName() ).append( '.' ).append( i_methodName ).append( "( " ); + for ( int i=0; i<i_argClasses.length; ++i ) + { + message.append( i_argClasses[i].getName() ); + if ( i<i_argClasses.length - 1 ) + message.append( ", " ); + } + message.append( " )" ); + fail( message.toString() ); + } + catch ( InvocationTargetException e ) + { + caughtExpected = noExceptionAllowed + ? false + : ( e.getTargetException().getClass().equals( i_expectedExceptionClass ) ); + } + catch( Exception e ) + { + caughtExpected = false; + } + + assertTrue( i_message, caughtExpected ); + } + + /** + * retrieves a method, given by name and parameter signature, from the given class + * + * The method does somewhat more than simply calling {@link Class#getMethod}. In particular, it recognizes + * primitive parameter types, and attempts to find a method taking the given primitive type, instead of the + * type represented by the parameter class. + * + * For instance, if you have a method <code>foo( int )</code>, {@link Class#getMethod} would not return this + * method when you pass <code>Integer.class</code>. <code>impl_getMethod</code> will recognize this, and + * properly retrieve the method. + * + * Note: <code>impl_getMethod</code> is limited in that it will not try all possible combinations of primitive + * and non-primitive types. That is, a method like <code>foo( int, Integer, int )</code> is likely to not be + * found. + * + * @param i_objectClass + * @param i_methodName + * @param i_argClasses + * @return + */ + private static Method impl_getMethod( final Class<?> i_objectClass, final String i_methodName, final Class<?>[] i_argClasses ) throws NoSuchMethodException + { + try + { + return i_objectClass.getMethod( i_methodName, i_argClasses ); + } + catch ( NoSuchMethodException ex ) + { + } + + int substitutedTypes = 0; + int substitutedTypesLastRound = 0; + final Class<?>[][] substitutionTable = new Class[][] { + new Class[] { Long.class, long.class }, + new Class[] { Integer.class, int.class }, + new Class[] { Short.class, short.class }, + new Class[] { Byte.class, byte.class }, + new Class[] { Double.class, double.class }, + new Class[] { Float.class, float.class }, + new Class[] { Character.class, char.class } + }; + do + { + substitutedTypes = 0; + final Class<?>[] argClasses = new Class[ i_argClasses.length ]; + for ( int i=0; i < argClasses.length; ++i ) + { + argClasses[i] = i_argClasses[i]; + if ( substitutedTypes > substitutedTypesLastRound ) + continue; + + for ( int c=0; c<substitutionTable.length; ++c ) + { + if ( i_argClasses[i].equals( substitutionTable[c][0] ) ) + { + argClasses[i] = substitutionTable[c][1]; + ++substitutedTypes; + break; + } + } + } + if ( substitutedTypes == substitutedTypesLastRound ) + throw new NoSuchMethodException(); + substitutedTypesLastRound = substitutedTypes; + + try + { + return i_objectClass.getMethod( i_methodName, argClasses ); + } + catch ( NoSuchMethodException e ) + { + } + } + while ( substitutedTypes > 0 ); + throw new NoSuchMethodException(); + } + + /** invokes a given method on a given object, and assures a certain exception is caught + * @param i_message is the message to print when the check fails + * @param i_object is the object to invoke the method on + * @param i_methodName is the name of the method to invoke + * @param i_methodArgs are the arguments to pass to the method. Those implicitly define + * the classes of the arguments of the method which is called. + * @param i_expectedExceptionClass is the class of the exception to be caught. If this is null, + * it means that <em>no</em> exception must be throw by invoking the method. + */ + public static void assertException( final String i_message, final Object i_object, final String i_methodName, + final Object[] i_methodArgs, final Class<?> i_expectedExceptionClass ) + { + Class<?>[] argClasses = new Class[ i_methodArgs.length ]; + for ( int i=0; i<i_methodArgs.length; ++i ) + argClasses[i] = i_methodArgs[i].getClass(); + assertException( i_message, i_object, i_methodName, argClasses, i_methodArgs, i_expectedExceptionClass ); + } + + + + + +} diff --git a/toolkit/qa/complex/toolkit/GridControl.java b/toolkit/qa/complex/toolkit/GridControl.java new file mode 100644 index 000000000..b2338ee68 --- /dev/null +++ b/toolkit/qa/complex/toolkit/GridControl.java @@ -0,0 +1,746 @@ +/* + * 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.toolkit; + +import com.sun.star.awt.XControl; +import com.sun.star.awt.XControlContainer; +import com.sun.star.awt.XControlModel; +import com.sun.star.awt.XToolkit; +import com.sun.star.awt.grid.DefaultGridDataModel; +import com.sun.star.awt.grid.XGridColumn; +import com.sun.star.awt.grid.XGridColumnModel; +import com.sun.star.awt.grid.XGridControl; +import com.sun.star.awt.grid.XGridDataModel; +import com.sun.star.awt.grid.XMutableGridDataModel; +import com.sun.star.awt.grid.XSortableMutableGridDataModel; +import com.sun.star.beans.Pair; +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.ContainerEvent; +import com.sun.star.container.XContainerListener; +import com.sun.star.container.XNameContainer; +import com.sun.star.lang.EventObject; +import com.sun.star.lang.IndexOutOfBoundsException; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XEventListener; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.uno.Exception; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +import com.sun.star.uno.XInterface; +import com.sun.star.util.XCloneable; +import complex.toolkit.awtgrid.DummyColumn; +import complex.toolkit.awtgrid.TMutableGridDataModel; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; +import org.openoffice.test.OfficeConnection; + +/** is a unit test for the grid control related implementations + */ +public class GridControl +{ + + public GridControl() + { + m_context = m_connection.getComponentContext(); + } + + + private static void impl_dispose( final Object... i_components ) + { + for ( int i=0; i<i_components.length; ++i ) + { + if ( i_components[i] != null ) + { + final XComponent component = UnoRuntime.queryInterface( XComponent.class, i_components[i] ); + component.dispose(); + } + } + } + + + private void impl_recreateGridModel() throws Exception + { + impl_dispose( m_gridControlModel, m_columnModel, m_dataModel ); + + // create a grid control model, and ensure it has a proper data and column model already + m_gridControlModel = UnoRuntime.queryInterface( XPropertySet.class, + createInstance( "com.sun.star.awt.grid.UnoControlGridModel" ) ); + assertNotNull( "grid control model does not provide XPropertySet interface", m_gridControlModel ); + + // ensure that the model has default column/data models + m_columnModel = UnoRuntime.queryInterface( XGridColumnModel.class, m_gridControlModel.getPropertyValue( "ColumnModel" ) ); + assertNotNull( "the control model is expected to have an initial column model", m_columnModel ); + final XGridDataModel dataModel = UnoRuntime.queryInterface( XGridDataModel.class, m_gridControlModel.getPropertyValue( "GridDataModel" ) ); + assertNotNull( "the control model is expected to have an initial data model", dataModel ); + m_dataModel = UnoRuntime.queryInterface( XSortableMutableGridDataModel.class, + dataModel ); + assertNotNull( "the out-of-the-box data model should be mutable and sortable", m_dataModel ); + } + + + @Test + public void testGridControlCloning() throws Exception + { + impl_recreateGridModel(); + + // give the test something to compare, actually + XGridColumnModel columnModel = UnoRuntime.queryInterface( XGridColumnModel.class, + m_gridControlModel.getPropertyValue( "ColumnModel" ) ); + columnModel.setDefaultColumns( 10 ); + + // clone the grid model + final XCloneable cloneable = UnoRuntime.queryInterface( XCloneable.class, m_gridControlModel ); + assertNotNull( "all UnoControlModel's are expected to be clonable", cloneable ); + + final XInterface clone = cloneable.createClone(); + final XPropertySet clonedProps = UnoRuntime.queryInterface( XPropertySet.class, clone ); + + // TODO: check all those generic properties for equality + + // the data model and the column model should have been cloned, too + // in particular, the clone should not share the sub models with the original + final XMutableGridDataModel originalDataModel = UnoRuntime.queryInterface( XMutableGridDataModel.class, + m_gridControlModel.getPropertyValue( "GridDataModel" ) ); + final XMutableGridDataModel clonedDataModel = UnoRuntime.queryInterface( XMutableGridDataModel.class, + clonedProps.getPropertyValue( "GridDataModel" ) ); + assertFalse( "data model should not be shared after cloning", UnoRuntime.areSame( originalDataModel, clonedDataModel ) ); + impl_assertEquality( originalDataModel, clonedDataModel ); + + final XGridColumnModel originalColumnModel = columnModel; + final XGridColumnModel clonedColumnModel = UnoRuntime.queryInterface( XGridColumnModel.class, + clonedProps.getPropertyValue( "ColumnModel" ) ); + assertFalse( "column model should not be shared after cloning", UnoRuntime.areSame( originalColumnModel, clonedColumnModel ) ); + impl_assertEquality( originalColumnModel, clonedColumnModel ); + } + + + @Test + public void testDisposal() throws Exception + { + impl_recreateGridModel(); + + final int columnCount = 3; + m_columnModel.setDefaultColumns( columnCount ); + + // add disposal listeners to all columns so far + final XGridColumn[] columns = m_columnModel.getColumns(); + assertEquals( "creating default columns resulted in unexpected column count", columnCount, columns.length ); + final DisposeListener[] columnListeners = new DisposeListener[columnCount]; + for ( int i=0; i<columnCount; ++i ) + columnListeners[i] = new DisposeListener( columns[i] ); + + // add another column, and check that upon removal, it is disposed + final int newColumnIndex = m_columnModel.addColumn( m_columnModel.createColumn() ); + final DisposeListener columnListener = new DisposeListener( m_columnModel.getColumn( newColumnIndex ) ); + m_columnModel.removeColumn( newColumnIndex ); + assertTrue( "explicit column removal is expected to dispose the column", columnListener.isDisposed() ); + + // by definition, the grid control model is the owner of both the column and the data model. So, setting + // a new column/data model should implicitly dispose the old models + final DisposeListener oldDataModelListener = new DisposeListener( m_dataModel ); + final DisposeListener oldColumnModelListener = new DisposeListener( m_columnModel ); + + final Object newDataModel = createInstance( "com.sun.star.awt.grid.DefaultGridDataModel" ); + final Object newColumnModel = createInstance( "com.sun.star.awt.grid.DefaultGridColumnModel" ); + final DisposeListener newDataModelListener = new DisposeListener( newDataModel ); + final DisposeListener newColumnModelListener = new DisposeListener( newColumnModel ); + + m_gridControlModel.setPropertyValue( "GridDataModel", newDataModel ); + assertTrue( "setting a new data model failed", impl_areSameInterface( newDataModel, m_gridControlModel.getPropertyValue( "GridDataModel" ) ) ); + m_gridControlModel.setPropertyValue( "ColumnModel", newColumnModel ); + assertTrue( "setting a new column model failed", impl_areSameInterface( newColumnModel, m_gridControlModel.getPropertyValue( "ColumnModel" ) ) ); + + assertTrue( "old data model has not been disposed", oldDataModelListener.isDisposed() ); + assertTrue( "old column model has not been disposed", oldColumnModelListener.isDisposed() ); + for ( int i=0; i<columnCount; ++i ) + assertTrue( "column no. " + i + " has not been disposed", columnListeners[i].isDisposed() ); + + // the same holds if the grid control model itself is disposed - it should dispose the depending models, too + assertFalse( "new data model is already disposed - this is unexpected", newDataModelListener.isDisposed() ); + assertFalse( "new column model is already disposed - this is unexpected", newColumnModelListener.isDisposed() ); + impl_dispose( m_gridControlModel ); + assertTrue( "new data model is not disposed after disposing the grid column model", newDataModelListener.isDisposed() ); + assertTrue( "new column model is not disposed after disposing the grid column model", newColumnModelListener.isDisposed() ); + } + + + /** + * tests various aspects of the <code>XMutableGridDataModel</code> interface + */ + @Test + public void testMutableGridDataModel() throws Exception + { + impl_recreateGridModel(); + + TMutableGridDataModel test = new TMutableGridDataModel( m_dataModel ); + test.testAddRow(); + test.testAddRows(); + test.testInsertRow(); + test.testInsertRows(); + test.testRemoveRow(); + test.testRemoveAllRows(); + test.testUpdateCellData(); + test.testUpdateRowData(); + test.testUpdateRowHeading(); + test.cleanup(); + + // a somewhat less straight-forward test: the data model is expected to implicitly increase its column count + // when you add a row which has more columns than currently known + final XMutableGridDataModel dataModel = DefaultGridDataModel.create( m_context ); + dataModel.addRow( 0, new Object[] { 1 } ); + assertEquals( "unexpected column count after adding the most simple row", 1, dataModel.getColumnCount() ); + dataModel.addRow( 1, new Object[] { 1, 2 } ); + assertEquals( "implicit extension of the column count doesn't work", 2, dataModel.getColumnCount() ); + } + + + @Test + public void testGridColumnModel() throws Exception + { + impl_recreateGridModel(); + + ColumnModelListener listener = new ColumnModelListener(); + m_columnModel.addContainerListener( listener ); + + // insert default columns into the previously empty model, ensure we get the right notifications + final int defaultColumnsCount = 3; + m_columnModel.setDefaultColumns( defaultColumnsCount ); + impl_assertColumnModelConsistency(); + List< ContainerEvent > events = listener.assertExclusiveInsertionEvents(); + listener.reset(); + assertEquals( "wrong number of events fired by setDefaultColumns", defaultColumnsCount, events.size() ); + for ( int i=0; i<defaultColumnsCount; ++i ) + { + final ContainerEvent event = events.get(i); + final int index = impl_assertInteger( event.Accessor ); + assertEquals( "unexpected Accessor value in insert notification", i, index ); + assertTrue( "wrong column object notified in insert notification", + impl_areSameInterface( event.Element, m_columnModel.getColumn(i) ) ); + } + + // insert some more default columns, ensure that all previously existing columns are removed + final int moreDefaultColumnsCount = 5; + m_columnModel.setDefaultColumns( moreDefaultColumnsCount ); + impl_assertColumnModelConsistency(); + assertEquals( "setting default columns is expected to remove all previously existing columns", + moreDefaultColumnsCount, m_columnModel.getColumnCount() ); + + // in this situation, both removal and insertion events have been notified + final List< ContainerEvent > removalEvents = listener.getRemovalEvents(); + final List< ContainerEvent > insertionEvents = listener.getInsertionEvents(); + listener.reset(); + + // for the removal events, check the indexes + assertEquals( "wrong number of columns removed (or notified) upon setting default columns", + defaultColumnsCount, removalEvents.size() ); + for ( int i=0; i<removalEvents.size(); ++i ) + { + final ContainerEvent event = removalEvents.get(i); + final int removedIndex = impl_assertInteger( event.Accessor ); + + // The implementation is allowed to remove the columns from the beginning, in which case the + // index of the removed column must always be 0, since e.g. the second column has index 0 + // after the first column (which previously had index 0) had been removed. + // Alternatively, the implementation is allowed to remove columns from the end, which means + // that the column index given in the event is steadily increasing. + assertTrue( "unexpected column removal event column index", + ( removedIndex == 0 ) || ( removedIndex == removalEvents.size() - 1 - i ) ); + } + + // for the insertion events, check the indexes as well + assertEquals( "wrong number of insertion events when setting default columns over existing columns", + moreDefaultColumnsCount, insertionEvents.size() ); + for ( int i=0; i<insertionEvents.size(); ++i ) + { + final ContainerEvent event = insertionEvents.get(i); + final int index = impl_assertInteger( event.Accessor ); + assertEquals( i, index ); + } + + // okay, remove all those columns + while ( m_columnModel.getColumnCount() != 0 ) + { + final int columnCount = m_columnModel.getColumnCount(); + final int removeColumnIndex = m_randomGenerator.nextInt( columnCount ); + m_columnModel.removeColumn( removeColumnIndex ); + events = listener.assertExclusiveRemovalEvents(); + listener.reset(); + assertEquals( "removing a single column should notify a single event", 1, events.size() ); + final ContainerEvent event = events.get(0); + final int removalIndex = impl_assertInteger( event.Accessor ); + assertEquals( "removing an arbitrary column does not notify the proper accessor", + removeColumnIndex, removalIndex ); + } + + // calling addColumn with a column not created by the given model/implementation should not succeed + boolean caughtExpected = false; + try + { + m_columnModel.addColumn( new DummyColumn() ); + } + catch( final com.sun.star.lang.IllegalArgumentException e ) + { + assertTrue( impl_areSameInterface( e.Context, m_columnModel ) ); + caughtExpected = true; + } + assertTrue( "adding a dummy (self-implemented) grid column to the model should not succeed", caughtExpected ); + + // adding a single column to the end should succeed, properly notify, and still be consistent + final XGridColumn newColumn = m_columnModel.createColumn(); + m_columnModel.addColumn( newColumn ); + impl_assertColumnModelConsistency(); + events = listener.assertExclusiveInsertionEvents(); + listener.reset(); + assertEquals( "addColumn notifies the wrong number of insertion events", 1, events.size() ); + final int insertionIndex = impl_assertInteger( events.get(0).Accessor ); + assertEquals( insertionIndex, newColumn.getIndex() ); + } + + + @Test + public void testDataModel() throws Exception + { + impl_recreateGridModel(); + + // ensure that getCellData and getRowData have the same opinion on the data they deliver + final Object[][] data = new Object[][] { + new Object[] { 15, 17, 0 }, + new Object[] { 9, 8, 14 }, + new Object[] { 17, 2, 16 }, + new Object[] { 0, 7, 14 }, + new Object[] { 10, 16, 16 }, + }; + m_dataModel.addRows( new Object[ data.length ], data ); + + for ( int row = 0; row < data.length; ++row ) + { + assertArrayEquals( "getRowData delivers wrong data in row " + row, data[row], m_dataModel.getRowData( row ) ); + for ( int col = 0; col < data[row].length; ++col ) + { + assertEquals( "getCellData delivers wrong data at position (" + col + ", " + row + ")", + data[row][col], m_dataModel.getCellData( col, row ) ); + } + } + } + + + @Test + public void testSortableDataModel() throws Exception + { + impl_recreateGridModel(); + + final int colCount = 3; + final int rowCount = 10; + // initialize with some data + final Object[][] data = new Object[][] { + new Object[] { 15, 17, 0 }, + new Object[] { 9, 8, 14 }, + new Object[] { 17, 2, 16 }, + new Object[] { 0, 7, 14 }, + new Object[] { 10, 16, 16 }, + new Object[] { 2, 8, 10 }, + new Object[] { 4, 8, 3 }, + new Object[] { 7, 9, 0 }, + new Object[] { 15, 6, 19 }, + new Object[] { 2, 14, 19 } + }; + final Object[] rowHeadings = new Object[] { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }; + // ensure consistency of the test data + assertEquals( rowHeadings.length, rowCount ); + assertEquals( data.length, rowCount ); + for ( Object[] rowData : data ) + assertEquals( rowData.length, colCount ); + + // add the test data + m_dataModel.addRows( rowHeadings, data ); + assertEquals( rowCount, m_dataModel.getRowCount() ); + assertEquals( colCount, m_dataModel.getColumnCount() ); + + // sort by each column + for ( int colIndex = 0; colIndex < colCount; ++colIndex ) + { + for ( boolean ascending : new boolean[] { true, false } ) + { + m_dataModel.sortByColumn( colIndex, ascending ); + Pair<Integer,Boolean> currentSortOrder = m_dataModel.getCurrentSortOrder(); + assertEquals( "invalid current sort column (column " + colIndex + ")", currentSortOrder.First.intValue(), colIndex ); + assertEquals( "invalid current sort direction", currentSortOrder.Second.booleanValue(), ascending ); + + /*for ( int i=0; i<rowCount; ++i ) + { + for ( int j=0; j<colCount; ++j ) + System.out.print( m_dataModel.getCellData( j, i ).toString() + ", " ); + System.out.println(); + }*/ + + // verify the data is actually sorted by this column + for ( int rowIndex = 0; rowIndex < rowCount - 1; ++rowIndex ) + { + final Object currentValue = m_dataModel.getCellData( colIndex, rowIndex ); + final int currentIntValue = impl_assertInteger( currentValue ); + final Object nextValue = m_dataModel.getCellData( colIndex, rowIndex + 1 ); + final int nextIntValue = impl_assertInteger( nextValue ); + assertTrue( "data in row " + rowIndex + " is actually not sorted " + ( ascending ? "ascending" : "descending" ), + ascending ? currentIntValue <= nextIntValue + : currentIntValue >= nextIntValue ); + + // ensure the data in the other columns, and the row headings, are sorted as well + final Object rowHeading = m_dataModel.getRowHeading( rowIndex ); + final int unsortedRowIndex = impl_assertInteger( rowHeading ); + for ( int innerColIndex = 0; innerColIndex < colCount; ++innerColIndex ) + { + assertEquals( "sorted row " + rowIndex + ", unsorted row " + unsortedRowIndex + ", col " + innerColIndex + + ": wrong data", + data[unsortedRowIndex][innerColIndex], m_dataModel.getCellData( innerColIndex, rowIndex ) ); + } + } + } + } + } + + + @Test + public void testView() throws Exception + { + final XControl control = impl_createDialogWithGridControl(); + final XPropertySet gridModelProps = + UnoRuntime.queryInterface( XPropertySet.class, control.getModel() ); + + // in the current implementation (not sure this is a good idea at all), the control (more precise: the peer) + // ensures that if there are no columns in the column model, but in the data model, then the column model + // will implicitly have the needed columns added. + // To ensure that clients which rely on this do not break in the future, check this here. + final XMutableGridDataModel dataModel = UnoRuntime.queryInterface( XMutableGridDataModel.class, + gridModelProps.getPropertyValue( "GridDataModel" ) ); + assertNotNull( dataModel ); + assertEquals( 0, dataModel.getColumnCount() ); + + final XGridColumnModel columnModel = UnoRuntime.queryInterface( XGridColumnModel.class, + gridModelProps.getPropertyValue( "ColumnModel" ) ); + assertNotNull( columnModel ); + assertEquals( 0, columnModel.getColumnCount() ); + + final int columnCount = 3; + final int rowCount = 2; + dataModel.addRow( null, new Object[] { 1, 2, 3 } ); + dataModel.addRow( null, new Object[] { 6, 5, 4 } ); + + assertEquals( columnCount, dataModel.getColumnCount() ); + assertEquals( columnCount, columnModel.getColumnCount() ); + + // some cursor traveling + final XGridControl gridControl = UnoRuntime.queryInterface( XGridControl.class, control ); + gridControl.goToCell( 0, 0 ); + assertEquals( "wrong 'current column' (1)", 0, gridControl.getCurrentColumn() ); + assertEquals( "wrong 'current row' (1)", 0, gridControl.getCurrentRow() ); + gridControl.goToCell( columnCount - 1, rowCount - 1 ); + assertEquals( "wrong 'current column' (2)", dataModel.getColumnCount() - 1, gridControl.getCurrentColumn() ); + assertEquals( "wrong 'current row' (2)", dataModel.getRowCount() - 1, gridControl.getCurrentRow() ); + + // removing the last column, while the active cell is in this very last column, is expected to adjust + // the active cell + columnModel.removeColumn( columnCount - 1 ); + assertEquals( "removed the last and active column, active column was not adjusted!", + columnCount - 2, gridControl.getCurrentColumn() ); + // same holds for rows + dataModel.removeRow( rowCount - 1 ); + assertEquals( "removed the last and active row, active row was not adjusted!", + rowCount - 2, gridControl.getCurrentRow() ); + } + + + private XControl impl_createDialogWithGridControl() throws Exception + { + // create a simple dialog model/control/peer trinity + final XControlModel dialogModel = createInstance( XControlModel.class, "com.sun.star.awt.UnoControlDialogModel" ); + m_disposables.add( dialogModel ); + final XPropertySet dialogProps = UnoRuntime.queryInterface( XPropertySet.class, dialogModel ); + dialogProps.setPropertyValue( "Width", 200 ); + dialogProps.setPropertyValue( "Height", 100 ); + dialogProps.setPropertyValue( "Title", "Grid Control Unit Test" ); + final XControl dialogControl = createInstance( XControl.class, "com.sun.star.awt.UnoControlDialog" ); + m_disposables.add( dialogControl ); + dialogControl.setModel( dialogModel ); + dialogControl.createPeer( createInstance( XToolkit.class, "com.sun.star.awt.Toolkit" ), null ); + + // insert a grid control model + final XMultiServiceFactory controlModelFactory = UnoRuntime.queryInterface( XMultiServiceFactory.class, + dialogModel ); + final XPropertySet gridModelProps = UnoRuntime.queryInterface( XPropertySet.class, + controlModelFactory.createInstance( "com.sun.star.awt.grid.UnoControlGridModel" ) ); + m_disposables.add( gridModelProps ); + gridModelProps.setPropertyValue( "PositionX", 6 ); + gridModelProps.setPropertyValue( "PositionY", 6 ); + gridModelProps.setPropertyValue( "Width", 188 ); + gridModelProps.setPropertyValue( "Height", 88 ); + final XNameContainer modelContainer = UnoRuntime.queryInterface( XNameContainer.class, dialogModel ); + modelContainer.insertByName( "grid", gridModelProps ); + + // check the respective control has been created + final XControlContainer controlContainer = UnoRuntime.queryInterface( XControlContainer.class, dialogControl ); + final XControl gridControl = controlContainer.getControl( "grid" ); + assertNotNull( "no grid control created in the dialog", gridControl ); + + return gridControl; + } + + + private int impl_assertInteger( final Object i_object ) + { + assertTrue( i_object instanceof Integer ); + return ((Integer)i_object).intValue(); + } + + + private void impl_assertColumnModelConsistency() throws IndexOutOfBoundsException + { + for ( int col = 0; col < m_columnModel.getColumnCount(); ++col ) + { + final XGridColumn column = m_columnModel.getColumn( col ); + assertNotNull( column ); + assertEquals( "column/model inconsistency: column " + col + " has a wrong index!", col, column.getIndex() ); + } + + final XGridColumn[] allColumns = m_columnModel.getColumns(); + assertEquals( "getColumns returns the wrong number of column objects", + m_columnModel.getColumnCount(), allColumns.length ); + for ( int col = 0; col < m_columnModel.getColumnCount(); ++col ) + { + assertTrue( "getColumns inconsistency", impl_areSameInterface( allColumns[col], m_columnModel.getColumn(col) ) ); + } + } + + + private void impl_assertEquality( final XGridDataModel i_reference, final XGridDataModel i_compare ) throws IndexOutOfBoundsException + { + assertNotNull( i_reference ); + assertNotNull( i_compare ); + + assertEquals( "data model comparison: wrong column counts", i_reference.getColumnCount(), i_compare.getColumnCount() ); + assertEquals( "data model comparison: wrong row counts", i_reference.getRowCount(), i_compare.getRowCount() ); + + for ( int row = 0; row < i_reference.getRowCount(); ++row ) + { + assertEquals( "data model comparison: wrong row heading content in row " + row, + i_reference.getRowHeading( row ) ); + for ( int col = 0; col < i_reference.getRowCount(); ++col ) + { + assertEquals( "data model comparison: wrong cell content in cell (" + col + ", " + row + ")", + i_reference.getCellData( col, row ) ); + assertEquals( "data model comparison: wrong tooltip content in cell (" + col + ", " + row + ")", + i_reference.getCellToolTip( col, row ) ); + } + } + } + + + private void impl_assertEquality( final XGridColumnModel i_reference, final XGridColumnModel i_compare ) throws IndexOutOfBoundsException + { + assertEquals( "column model comparison: wrong column counts", i_reference.getColumnCount(), i_compare.getColumnCount() ); + for ( int col = 0; col < i_reference.getColumnCount(); ++col ) + { + final XGridColumn referenceColumn = i_reference.getColumn( col ); + final XGridColumn compareColumn = i_compare.getColumn( col ); + impl_assertEquality( referenceColumn, compareColumn ); + } + } + + + private void impl_assertEquality( final XGridColumn i_reference, final XGridColumn i_compare ) + { + final Method[] methods = XGridColumn.class.getMethods(); + for ( int m=0; m<methods.length; ++m ) + { + if ( !methods[m].getName().startsWith( "get" ) ) + continue; + try + { + final Object referenceValue = methods[m].invoke( i_reference ); + final Object compareValue = methods[m].invoke( i_compare ); + assertEquals( "grid column comparison: column attribute '" + methods[m].getName().substring(3) + "' does not match", + referenceValue, compareValue ); + } + catch ( java.lang.Exception ex ) + { + fail( " could not retrieve object attributes: " + ex.toString() ); + } + } + } + + + private boolean impl_areSameInterface( final Object i_lhs, final Object i_rhs ) + { + final XInterface lhs = UnoRuntime.queryInterface( XInterface.class, i_lhs ); + final XInterface rhs = UnoRuntime.queryInterface( XInterface.class, i_rhs ); + return UnoRuntime.areSame( lhs, rhs ); + } + + + @Before + public void initTestCase() + { + m_disposables.clear(); + } + + + @After + public void cleanupTestCase() + { + impl_dispose( m_disposables.toArray() ); + } + + + @BeforeClass + public static void setUpConnection() throws java.lang.Exception + { + System.out.println( "--------------------------------------------------------------------------------" ); + System.out.println( "starting class: " + GridControl.class.getName() ); + System.out.print( "connecting ... " ); + m_connection.setUp(); + System.out.println( "done."); + + final long seed = m_randomGenerator.nextLong(); + m_randomGenerator.setSeed( seed ); + System.out.println( "seeding random number generator with " + seed ); + } + + + @AfterClass + public static void tearDownConnection() + throws InterruptedException, com.sun.star.uno.Exception + { + System.out.println(); + System.out.println( "tearing down connection" ); + m_connection.tearDown(); + System.out.println( "finished class: " + GridControl.class.getName() ); + System.out.println( "--------------------------------------------------------------------------------" ); + } + + + public <T> T createInstance( Class<T> i_interfaceClass, final String i_serviceIndentifier ) throws Exception + { + return UnoRuntime.queryInterface( i_interfaceClass, createInstance( i_serviceIndentifier ) ); + } + + + private Object createInstance( final String i_serviceName ) throws Exception + { + Object instance = m_context.getServiceManager().createInstanceWithContext( i_serviceName, m_context ); + assertNotNull( "could not create an instance of '" + i_serviceName + "'", instance ); + return instance; + } + + private static final class DisposeListener implements XEventListener + { + DisposeListener( final Object i_component ) + { + m_component = UnoRuntime.queryInterface( XComponent.class, i_component ); + assertNotNull( m_component ); + m_component.addEventListener( this ); + } + + public void disposing( EventObject i_event ) + { + assertTrue( UnoRuntime.areSame( i_event.Source, m_component ) ); + m_isDisposed = true; + } + + final boolean isDisposed() { return m_isDisposed; } + + private final XComponent m_component; + private boolean m_isDisposed; + } + + + private static final class ColumnModelListener implements XContainerListener + { + ColumnModelListener() + { + } + + public void elementInserted( ContainerEvent i_event ) + { + m_insertionEvents.add( i_event ); + } + + public void elementRemoved( ContainerEvent i_event ) + { + m_removalEvents.add( i_event ); + } + + public void elementReplaced( ContainerEvent i_event ) + { + m_replacementEvents.add( i_event ); + } + + public void disposing( EventObject eo ) + { + } + + private List< ContainerEvent > assertExclusiveInsertionEvents() + { + assertFalse( m_insertionEvents.isEmpty() ); + assertTrue( m_removalEvents.isEmpty() ); + assertTrue( m_replacementEvents.isEmpty() ); + return m_insertionEvents; + } + + private List< ContainerEvent > assertExclusiveRemovalEvents() + { + assertTrue( m_insertionEvents.isEmpty() ); + assertFalse( m_removalEvents.isEmpty() ); + assertTrue( m_replacementEvents.isEmpty() ); + return m_removalEvents; + } + + private void reset() + { + m_insertionEvents = new ArrayList< ContainerEvent >(); + m_removalEvents = new ArrayList< ContainerEvent >(); + m_replacementEvents = new ArrayList< ContainerEvent >(); + } + + private List< ContainerEvent > getInsertionEvents() { return m_insertionEvents; } + private List< ContainerEvent > getRemovalEvents() { return m_removalEvents; } + + private List< ContainerEvent > m_insertionEvents = new ArrayList< ContainerEvent >(); + private List< ContainerEvent > m_removalEvents = new ArrayList< ContainerEvent >(); + private List< ContainerEvent > m_replacementEvents = new ArrayList< ContainerEvent >(); + } + + + private static final OfficeConnection m_connection = new OfficeConnection(); + private static Random m_randomGenerator = new Random(); + private final XComponentContext m_context; + + private XPropertySet m_gridControlModel; + private XGridColumnModel m_columnModel; + private XSortableMutableGridDataModel m_dataModel; + private final List< Object > m_disposables = new ArrayList< Object >(); +} diff --git a/toolkit/qa/complex/toolkit/accessibility/_XAccessibleComponent.java b/toolkit/qa/complex/toolkit/accessibility/_XAccessibleComponent.java new file mode 100644 index 000000000..3d4df2c5f --- /dev/null +++ b/toolkit/qa/complex/toolkit/accessibility/_XAccessibleComponent.java @@ -0,0 +1,463 @@ +/* + * 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.toolkit.accessibility; + +import java.util.ArrayList; + +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.Size; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +/** + * Testing <code>com.sun.star.accessibility.XAccessibleComponent</code> + * interface methods : + * <ul> + * <li><code> containsPoint()</code></li> + * <li><code> getAccessibleAtPoint()</code></li> + * <li><code> getBounds()</code></li> + * <li><code> getLocation()</code></li> + * <li><code> getLocationOnScreen()</code></li> + * <li><code> getSize()</code></li> + * <li><code> grabFocus()</code></li> + * </ul> <p> + * + * @see com.sun.star.accessibility.XAccessibleComponent + */ +public class _XAccessibleComponent { + + private final XAccessibleComponent oObj; + + private Rectangle bounds = null ; + + /** + * Constructor + */ + public _XAccessibleComponent(XInterface object/*, LogWriter log*/) { + oObj = UnoRuntime.queryInterface( + XAccessibleComponent.class, object); + } + + /** + * First checks 4 inner bounds (upper, lower, left and right) + * of component bounding box to contain + * at least one point of the component. Second 4 outer bounds + * are checked to not contain any component points.<p> + * + * Has <b> OK </b> status if inner bounds contain component points + * and outer bounds don't contain any component points. <p> + * + * The following method tests are to be completed successfully before : + * <ul> + * <li> <code> getBounds() </code> : to have size of a component.</li> + * </ul> + */ + public boolean _containsPoint() { + + boolean result = true ; + + int curX = 0; + while (!oObj.containsPoint(new Point(curX, 0)) && curX < bounds.Width) { + curX++; + } + if (curX < bounds.Width) { + System.out.println("Upper bound of box contains point (" + + curX + ",0) - OK"); + } else { + System.out.println + ("Upper bound of box contains no component points - FAILED"); + result = false; + } + + curX = 0; + while (!oObj.containsPoint(new Point(curX, bounds.Height - 1)) + && curX < bounds.Width) { + + System.out.println("Contains returns false for ("+curX+","+bounds.Height+")"); + curX++; + } + if (curX < bounds.Width) { + System.out.println("Lower bound of box contains point (" + + curX + "," + (bounds.Height - 1) + ") - OK"); + } else { + System.out.println + ("Lower bound of box contains no component points - FAILED"); + result = false; + } + + int curY = 0; + while (!oObj.containsPoint(new Point(0, curY)) && curY < bounds.Height) { + curY++; + } + if (curY < bounds.Height) { + System.out.println("Left bound of box contains point (0," + + curY + ") - OK"); + } else { + System.out.println + ("Left bound of box contains no component points - FAILED"); + result = false; + } + + curY = 0; + while (!oObj.containsPoint(new Point(bounds.Width - 1, curY)) && curY < bounds.Height) { + curY++; + } + if (curY < bounds.Height) { + System.out.println("Right bound of box contains point (" + + (bounds.Width - 1) + "," + curY + ") - OK"); + } else { + System.out.println + ("Right bound of box contains no component points - FAILED"); + result = false; + } + + boolean locRes = true; + for (int x = -1; x <= bounds.Width; x++) { + locRes &= !oObj.containsPoint(new Point(x, -1)); + locRes &= !oObj.containsPoint(new Point(x, bounds.Height+bounds.Y)); + } + if (locRes) { + System.out.println("Outer upper and lower bounds contain no component " + + "points - OK"); + } else { + System.out.println("Outer upper and lower bounds CONTAIN some component " + + "points - FAILED"); + result = false; + } + + locRes = true; + for (int y = -1; y <= bounds.Height; y++) { + locRes &= !oObj.containsPoint(new Point(-1, y)); + locRes &= !oObj.containsPoint(new Point(bounds.X+bounds.Width, y)); + } + if (locRes) { + System.out.println("Outer left and right bounds contain no component " + + "points - OK"); + } else { + System.out.println("Outer left and right bounds CONTAIN some component " + + "points - FAILED"); + result = false; + } + + return result; + } + + /** + * Iterates through all children which implement + * <code>XAccessibleComponent</code> (if they exist) determines their + * boundaries and tries to get each child by <code>getAccessibleAtPoint</code> + * passing point which belongs to the child. + * Also the point is checked which doesn't belong to child boundary + * box. <p> + * + * Has <b> OK </b> status if in the first cases the right children + * are returned, and in the second <code>null</code> or + * another child is returned. + */ + public boolean _getAccessibleAtPoint() { + + boolean result = true ; + XAccessibleComponent[] children = getChildrenComponents(); + + if (children.length > 0) { + for (int i = 0; i < children.length; i++) { + Rectangle chBnd = children[i].getBounds(); + if (chBnd.X == -1) + { + continue; + } + System.out.println("Checking child with bounds " + + "(" + chBnd.X + "," + chBnd.Y + "),(" + + chBnd.Width + "," + chBnd.Height + "): " + + util.AccessibilityTools.accessibleToString(children[i])); + + System.out.println("finding the point which lies on the component"); + int curX = 0; + int curY = 0; + while (!children[i].containsPoint(new Point(curX, curY)) + && curX < chBnd.Width) { + curX++; + curY++; + } + + if (curX==chBnd.Width) { + System.out.println("Couldn't find a point with contains"); + continue; + } + + // trying the point laying on child + XAccessible xAcc = oObj.getAccessibleAtPoint + (new Point(chBnd.X , chBnd.Y)); + if (xAcc == null) { + System.out.println("The child not found at point (" + + (chBnd.X ) + "," + chBnd.Y + ") - FAILED"); + result = false; + } else { + XAccessible xAccCh = UnoRuntime.queryInterface + (XAccessible.class, children[i]); + System.out.println("Child found at point (" + + (chBnd.X ) + "," + chBnd.Y + ") - OK"); + boolean res = util.AccessibilityTools.equals(xAccCh, xAcc); + if (!res) { + int expIndex = xAccCh.getAccessibleContext().getAccessibleIndexInParent(); + int gotIndex = xAcc.getAccessibleContext().getAccessibleIndexInParent(); + if (expIndex < gotIndex) { + System.out.println("The children found is not the same"); + System.out.println("The expected child " + + xAccCh.getAccessibleContext().getAccessibleName()); + System.out.println("is hidden behind the found Child "); + System.out.println(xAcc.getAccessibleContext().getAccessibleName()+" - OK"); + } else { + System.out.println("The children found is not the same - FAILED"); + System.out.println("Expected: " + +xAccCh.getAccessibleContext().getAccessibleName()); + System.out.println("Found: " + +xAcc.getAccessibleContext().getAccessibleName()); + result = false ; + } + } + } + + // trying the point NOT laying on child + xAcc = oObj.getAccessibleAtPoint + (new Point(chBnd.X - 1, chBnd.Y - 1)); + if (xAcc == null) { + System.out.println("No children found at point (" + + (chBnd.X - 1) + "," + (chBnd.Y - 1) + ") - OK"); + result &= true; + } else { + XAccessible xAccCh = UnoRuntime.queryInterface(XAccessible.class, children[i]); + boolean res = util.AccessibilityTools.equals(xAccCh, xAcc); + if (res) { + System.out.println("The same child found outside " + + "its bounds - FAILED"); + result = false ; + } + } + } + } else { + System.out.println("There are no children supporting " + + "XAccessibleComponent"); + } + + return result; + } + + /** + * Retrieves the component bounds and stores it. <p> + * + * Has <b> OK </b> status if boundary position (x,y) is not negative + * and size (Width, Height) is greater than 0. + */ + public boolean _getBounds() { + boolean result = true ; + + bounds = oObj.getBounds() ; + result &= bounds != null + && bounds.X >=0 && bounds.Y >=0 + && bounds.Width >0 && bounds.Height >0; + + System.out.println("Bounds = " + (bounds != null + ? "(" + bounds.X + "," + bounds.Y + "),(" + + bounds.Width + "," + bounds.Height + ")" : "null")); + + return result; + } + + /** + * Gets the location. <p> + * + * Has <b> OK </b> status if the location is the same as location + * of boundary obtained by <code>getBounds()</code> method. + * + * The following method tests are to be completed successfully before : + * <ul> + * <li> <code> getBounds() </code> : to have bounds </li> + * </ul> + */ + public boolean _getLocation() { + + boolean result = true ; + Point loc = oObj.getLocation() ; + + result &= loc.X == bounds.X && loc.Y == bounds.Y ; + + return result; + } + + /** + * Get the screen location of the component and its parent + * (if it exists and supports <code>XAccessibleComponent</code>). <p> + * + * Has <b> OK </b> status if component screen location equals + * to screen location of its parent plus location of the component + * relative to the parent. <p> + * + * The following method tests are to be completed successfully before : + * <ul> + * <li> <code> getBounds() </code> : to have location of the component + * relative to its parent</li> + * </ul> + */ + public boolean _getLocationOnScreen() { + + XAccessibleComponent parent = getParentComponent(); + + boolean result = true ; + Point loc = oObj.getLocationOnScreen(); + System.out.println("Location is (" + loc.X + "," + loc.Y + ")"); + + if (parent != null) { + Point parLoc = parent.getLocationOnScreen(); + System.out.println("Parent location is (" + + parLoc.X + "," + parLoc.Y + ")"); + + result &= parLoc.X + bounds.X == loc.X; + result &= parLoc.Y + bounds.Y == loc.Y; + } + + return result; + } + + /** + * Obtains the size of the component. <p> + * + * Has <b> OK </b> status if the size is the same as in bounds. <p> + * + * The following method tests are to be completed successfully before : + * <ul> + * <li> <code> getBounds() </code> </li> + * </ul> + */ + public boolean _getSize() { + + boolean result = true ; + Size size = oObj.getSize() ; + + result &= size.Width == bounds.Width; + result &= size.Height == bounds.Height; + + return result; + } + + /** + * Just calls the method. <p> + * + * Has <b> OK </b> status if no runtime exceptions occurred. + */ + public boolean _grabFocus() { + + boolean result = true ; + oObj.grabFocus() ; + + return result ; + } + + /** + * Retrieves all children (not more than 50) of the current + * component which support <code>XAccessibleComponent</code>. + * + * @return The array of children. Empty array returned if + * such children were not found or some error occurred. + */ + private XAccessibleComponent[] getChildrenComponents() { + XAccessible xAcc = UnoRuntime.queryInterface(XAccessible.class, oObj) ; + if (xAcc == null) { + System.out.println("Component doesn't support XAccessible."); + return new XAccessibleComponent[0]; + } + XAccessibleContext xAccCon = xAcc.getAccessibleContext(); + int cnt = xAccCon.getAccessibleChildCount(); + + // for cases when too many children exist checking only first 50 + if (cnt > 50) + { + cnt = 50; + } + + ArrayList<XAccessibleComponent> childComp = new ArrayList<XAccessibleComponent>(); + for (int i = 0; i < cnt; i++) { + try { + XAccessible child = xAccCon.getAccessibleChild(i); + XAccessibleContext xAccConCh = child.getAccessibleContext(); + XAccessibleComponent xChAccComp = UnoRuntime.queryInterface(XAccessibleComponent.class, xAccConCh); + if (xChAccComp != null) { + childComp.add(xChAccComp) ; + } + } catch (com.sun.star.lang.IndexOutOfBoundsException e) {} + } + + return childComp.toArray(new XAccessibleComponent[childComp.size()]); + } + + /** + * Gets the parent of the current component which support + * <code>XAccessibleComponent</code>. + * + * @return The parent or <code>null</code> if the component + * has no parent or some errors occurred. + */ + private XAccessibleComponent getParentComponent() { + XAccessible xAcc = UnoRuntime.queryInterface(XAccessible.class, oObj) ; + if (xAcc == null) { + System.out.println("Component doesn't support XAccessible."); + return null; + } + + XAccessibleContext xAccCon = xAcc.getAccessibleContext(); + XAccessible xAccPar = xAccCon.getAccessibleParent(); + + if (xAccPar == null) { + System.out.println("Component has no accessible parent."); + return null; + } + XAccessibleContext xAccConPar = xAccPar.getAccessibleContext(); + XAccessibleComponent parent = UnoRuntime.queryInterface(XAccessibleComponent.class, xAccConPar); + if (parent == null) { + System.out.println + ("Accessible parent doesn't support XAccessibleComponent"); + return null; + } + + return parent; + } + + /** + * Just calls the method. + */ + public boolean _getForeground() { + int forColor = oObj.getForeground(); + System.out.println("getForeground(): " + forColor); + return true; + } + + /** + * Just calls the method. + */ + public boolean _getBackground() { + int backColor = oObj.getBackground(); + System.out.println("getBackground(): " + backColor); + return true; + } + +} diff --git a/toolkit/qa/complex/toolkit/accessibility/_XAccessibleContext.java b/toolkit/qa/complex/toolkit/accessibility/_XAccessibleContext.java new file mode 100644 index 000000000..df7ef76ab --- /dev/null +++ b/toolkit/qa/complex/toolkit/accessibility/_XAccessibleContext.java @@ -0,0 +1,246 @@ +/* + * 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.toolkit.accessibility; + +import com.sun.star.lang.Locale; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.accessibility.IllegalAccessibleComponentStateException; +import com.sun.star.accessibility.XAccessible; +import com.sun.star.accessibility.XAccessibleContext; +import com.sun.star.accessibility.XAccessibleRelationSet; +import com.sun.star.accessibility.XAccessibleStateSet; +import util.AccessibilityTools; + +/** + * Testing <code>com.sun.star.accessibility.XAccessibleContext</code> + * interface methods : + * <ul> + * <li><code> getAccessibleChildCount()</code></li> + * <li><code> getAccessibleChild()</code></li> + * <li><code> getAccessibleParent()</code></li> + * <li><code> getAccessibleIndexInParent()</code></li> + * <li><code> getAccessibleRole()</code></li> + * <li><code> getAccessibleDescription()</code></li> + * <li><code> getAccessibleName()</code></li> + * <li><code> getAccessibleRelationSet()</code></li> + * <li><code> getAccessibleStateSet()</code></li> + * <li><code> getLocale()</code></li> + * </ul> <p> + * + * @see com.sun.star.accessibility.XAccessibleContext + */ +public class _XAccessibleContext { + + private final XAccessibleContext oObj; + + private int childCount = 0; + private XAccessible parent = null ; + + public _XAccessibleContext(XInterface object) { + oObj = UnoRuntime.queryInterface(XAccessibleContext.class, object); + } + + /** + * Calls the method and stores the number of children. <p> + * Has <b> OK </b> status if non-negative number rutrned. + */ + public boolean _getAccessibleChildCount() { + childCount = oObj.getAccessibleChildCount(); + System.out.println(childCount + " children found."); + return childCount > -1; + } + + /** + * Tries to get every child and checks its parent. <p> + * + * Has <b> OK </b> status if parent of every child + * and the tested component are the same objects. + * + * The following method tests are to be completed successfully before : + * <ul> + * <li> <code> getAccessibleChildCount() </code> : to have a number of + * children </li> + * </ul> + */ + public boolean _getAccessibleChild() { + boolean bOK = true; + int counter = childCount; + if (childCount > 500) + { + counter = 500; + } + for (int i = 0; i < counter; i++) { + try { + XAccessible ch = oObj.getAccessibleChild(i) ; + XAccessibleContext chAC = ch.getAccessibleContext(); + + System.out.println(" Child " + i + ": " + + chAC.getAccessibleDescription()) ; + + if (!AccessibilityTools.equals + (chAC.getAccessibleParent().getAccessibleContext(), oObj)){ + + System.out.println("Role:"); + System.out.println("Getting: "+chAC.getAccessibleParent().getAccessibleContext().getAccessibleRole()); + System.out.println("Expected: "+oObj.getAccessibleRole()); + + System.out.println("ImplementationName:"); + System.out.println("Getting: "+util.utils.getImplName(chAC.getAccessibleParent().getAccessibleContext())); + System.out.println("Expected: "+util.utils.getImplName(oObj)); + + System.out.println("The parent of child and component "+ + "itself differ."); + System.out.println("Getting(Description): " + +chAC.getAccessibleParent().getAccessibleContext().getAccessibleDescription()); + System.out.println("Expected(Description): " + +oObj.getAccessibleDescription()); + + bOK = false; + } else { + System.out.println("Getting the expected Child -- OK"); + } + } catch (com.sun.star.lang.IndexOutOfBoundsException e) { + e.printStackTrace(); + bOK = false; + } + } + + return bOK; + } + + /** + * Just gets the parent. <p> + * + * Has <b> OK </b> status if parent is not null. + */ + public boolean _getAccessibleParent() { + // assume that the component is not ROOT + parent = oObj.getAccessibleParent(); + return parent != null; + } + + /** + * Retrieves the index of tested component in its parent. + * Then gets the parent's child by this index and compares + * it with tested component.<p> + * + * Has <b> OK </b> status if the parent's child and the tested + * component are the same objects. + * + * The following method tests are to be completed successfully before : + * <ul> + * <li> <code> getAccessibleParent() </code> : to have a parent </li> + * </ul> + */ + public boolean _getAccessibleIndexInParent() { + + boolean bOK = true; + int idx = oObj.getAccessibleIndexInParent(); + + XAccessibleContext parentAC = parent.getAccessibleContext() ; + try { + bOK &= AccessibilityTools.equals( + parentAC.getAccessibleChild(idx).getAccessibleContext(),oObj); + if (!bOK) { + System.out.println("Expected: "+util.utils.getImplName(oObj)); + System.out.println("Getting: "+util.utils.getImplName( + parentAC.getAccessibleChild(idx).getAccessibleContext())); + } + } catch (com.sun.star.lang.IndexOutOfBoundsException e) { + e.printStackTrace(); + bOK = false; + } + return bOK; + } + + /** + * Get the accessible role of component. <p> + * + * Has <b> OK </b> status if non-negative number rutrned. + */ + public boolean _getAccessibleRole() { + short role = oObj.getAccessibleRole(); + System.out.println("The role is " + role); + return role > -1; + } + + /** + * Get the accessible name of the component. <p> + * + * Has <b> OK </b> status if the name has non-zero length. + */ + public boolean _getAccessibleName() { + String name = oObj.getAccessibleName(); + System.out.println("The name is '" + name + "'"); + return name != null; + } + + /** + * Get the accessible description of the component. <p> + * + * Has <b> OK </b> status if the description has non-zero length. + */ + public boolean _getAccessibleDescription() { + String descr = oObj.getAccessibleDescription(); + System.out.println("The description is '" + descr + "'"); + return descr != null; + } + + /** + * Just gets the set. <p> + * + * Has <b> OK </b> status if the set is not null. + */ + public boolean _getAccessibleRelationSet() { + XAccessibleRelationSet set = oObj.getAccessibleRelationSet(); + return set != null; + } + + /** + * Just gets the set. <p> + * + * Has <b> OK </b> status if the set is not null. + */ + public boolean _getAccessibleStateSet() { + XAccessibleStateSet set = oObj.getAccessibleStateSet(); + return set != null; + } + + /** + * Gets the locale. <p> + * + * Has <b> OK </b> status if <code>Country</code> and + * <code>Language</code> fields of locale structure + * are not empty. + */ + public boolean _getLocale() { + Locale loc = null ; + try { + loc = oObj.getLocale(); + System.out.println("The locale is " + loc.Language + "," + loc.Country); + } catch (IllegalAccessibleComponentStateException e) { + e.printStackTrace(); + } + + return loc != null && loc.Language.length() > 0 && + loc.Country.length() > 0; + } +} + diff --git a/toolkit/qa/complex/toolkit/accessibility/_XAccessibleEventBroadcaster.java b/toolkit/qa/complex/toolkit/accessibility/_XAccessibleEventBroadcaster.java new file mode 100644 index 000000000..fe48a6cb8 --- /dev/null +++ b/toolkit/qa/complex/toolkit/accessibility/_XAccessibleEventBroadcaster.java @@ -0,0 +1,177 @@ +/* + * 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.toolkit.accessibility; + +import com.sun.star.accessibility.AccessibleEventObject; +import com.sun.star.accessibility.AccessibleStateType; +import com.sun.star.accessibility.XAccessible; +import com.sun.star.accessibility.XAccessibleContext; +import com.sun.star.accessibility.XAccessibleEventBroadcaster; +import com.sun.star.accessibility.XAccessibleEventListener; +import com.sun.star.awt.PosSize; +import com.sun.star.awt.Rectangle; +import com.sun.star.awt.XWindow; +import com.sun.star.lang.EventObject; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +/** + * Testing <code> + * com.sun.star.accessibility.XAccessibleEventBroadcaster</code> + * interface methods : + * <ul> + * <li><code> addAccessibleEventListener()</code></li> + * <li><code> removeAccessibleEventListener()</code></li> + * </ul> + * + * <p>This test needs the following object relations :</p> + * <ul> + * <li> <code>'EventProducer'</code> (of type + * <code>ifc.accessibility._XAccessibleEventBroadcaster.EventProducer</code>): + * this must be an implementation of the interface which could perform + * some actions for generating any kind of <code>AccessibleEvent</code></li> + * </ul> + * + * @see com.sun.star.accessibility.XAccessibleEventBroadcaster + */ +public class _XAccessibleEventBroadcaster { + + private final XAccessibleEventBroadcaster oObj; + private final EventProducer prod; + private final EvListener list = new EvListener(); + + /** + * An event producer + */ + private static class EventProducer { + private final XWindow xWindow; + private EventProducer(XWindow window) { + xWindow = window; + } + + private void fireEvent() { + Rectangle newPosSize = xWindow.getPosSize(); + newPosSize.Width = newPosSize.Width - 20; + newPosSize.Height = newPosSize.Height - 20; + newPosSize.X = newPosSize.X + 20; + newPosSize.Y = newPosSize.Y + 20; + xWindow.setPosSize(newPosSize.X, newPosSize.Y, newPosSize.Width, + newPosSize.Height, PosSize.POSSIZE); + } + } + + /** + * Listener implementation which registers listener calls. + */ + private class EvListener implements XAccessibleEventListener { + public AccessibleEventObject notifiedEvent = null ; + public void notifyEvent(AccessibleEventObject ev) { + System.out.println("Listener, Event : " + ev.EventId); + System.out.println("EventID: " + ev.EventId); + Object old=ev.OldValue; + if (old instanceof com.sun.star.accessibility.XAccessible) { + System.out.println("Old: "+((XAccessible)old).getAccessibleContext().getAccessibleName()); + } + + Object nev=ev.NewValue; + if (nev instanceof com.sun.star.accessibility.XAccessible) { + System.out.println("New: "+((XAccessible)nev).getAccessibleContext().getAccessibleName()); + } + notifiedEvent = ev; + } + + public void disposing(EventObject ev) {} + } + + public _XAccessibleEventBroadcaster(XInterface object, XWindow window) { + oObj = UnoRuntime.queryInterface(XAccessibleEventBroadcaster.class, object); + prod = new EventProducer(window); + } + + /** + * Adds two listeners and fires event by mean of object relation. <p> + * Has <b> OK </b> status if both listeners were called + */ + public boolean _addEventListener(XMultiServiceFactory xMSF) { + System.out.println("adding two listeners"); + oObj.addAccessibleEventListener(list); + boolean isTransient = chkTransient(oObj); + System.out.println("fire event"); + prod.fireEvent() ; + + util.utils.waitForEventIdle(xMSF); + + boolean works = true; + + if (list.notifiedEvent == null) { + if (!isTransient) { + System.out.println("listener wasn't called"); + works = false; + } else { + System.out.println("Object is Transient, listener isn't expected to be called"); + } + oObj.removeAccessibleEventListener(list); + } + + return works; + } + + /** + * Removes one of two listeners added before and fires event + * by mean of object relation. <p> + * + * Has <b> OK </b> status if the removed listener wasn't called. <p> + * + * The following method tests are to be completed successfully before : + * <ul> + * <li> <code>addEventListener()</code> : to have added listeners </li> + * </ul> + */ + public boolean _removeEventListener(XMultiServiceFactory xMSF) { + + list.notifiedEvent = null; + + System.out.println("remove first listener"); + oObj.removeAccessibleEventListener(list); + + System.out.println("fire event"); + prod.fireEvent() ; + + util.utils.waitForEventIdle(xMSF); + + if (list.notifiedEvent == null) { + System.out.println("listener wasn't called -- OK"); + } + + return list.notifiedEvent == null; + + } + + private static boolean chkTransient(Object Testcase) { + XAccessibleContext accCon = UnoRuntime.queryInterface(XAccessibleContext.class, Testcase); + return accCon.getAccessibleStateSet().contains( + AccessibleStateType.TRANSIENT) + && accCon.getAccessibleParent().getAccessibleContext() + .getAccessibleStateSet().contains( + AccessibleStateType.MANAGES_DESCENDANTS); + } + +} + diff --git a/toolkit/qa/complex/toolkit/accessibility/_XAccessibleExtendedComponent.java b/toolkit/qa/complex/toolkit/accessibility/_XAccessibleExtendedComponent.java new file mode 100644 index 000000000..64dd66fcb --- /dev/null +++ b/toolkit/qa/complex/toolkit/accessibility/_XAccessibleExtendedComponent.java @@ -0,0 +1,75 @@ +/* + * 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.toolkit.accessibility; + +import com.sun.star.accessibility.XAccessibleExtendedComponent; +import com.sun.star.awt.XFont; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.UnoRuntime; + +/** + * Testing <code>com.sun.star.accessibility.XAccessibleExtendedComponent</code> + * interface methods : + * <ul> + * <li><code> getForeground()</code></li> + * <li><code> getBackground()</code></li> + * <li><code> getFont()</code></li> + * <li><code> isEnabled()</code></li> + * <li><code> getTitledBorderText()</code></li> + * <li><code> getToolTipText()</code></li> + * </ul> <p> + * @see com.sun.star.accessibility.XAccessibleExtendedComponent + */ +public class _XAccessibleExtendedComponent { + + private final XAccessibleExtendedComponent oObj; + + public _XAccessibleExtendedComponent(XInterface object/*, LogWriter log*/) { + oObj = UnoRuntime.queryInterface(XAccessibleExtendedComponent.class, object); + } + + /** + * Just calls the method. + */ + public boolean _getFont() { + XFont font = oObj.getFont(); + System.out.println("getFont(): " + font); + return true; + } + + /** + * Calls the method and checks returned value. + * Has OK status if returned value isn't null. + */ + public boolean _getTitledBorderText() { + String titleBorderText = oObj.getTitledBorderText(); + System.out.println("getTitledBorderText(): '" + titleBorderText + "'"); + return titleBorderText != null; + } + + /** + * Calls the method and checks returned value. + * Has OK status if returned value isn't null. + */ + public boolean _getToolTipText() { + String toolTipText = oObj.getToolTipText(); + System.out.println("getToolTipText(): '" + toolTipText + "'"); + return toolTipText != null; + } +} diff --git a/toolkit/qa/complex/toolkit/accessibility/_XAccessibleText.java b/toolkit/qa/complex/toolkit/accessibility/_XAccessibleText.java new file mode 100644 index 000000000..1cd97d63a --- /dev/null +++ b/toolkit/qa/complex/toolkit/accessibility/_XAccessibleText.java @@ -0,0 +1,1001 @@ +/* + * 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.toolkit.accessibility; + +import com.sun.star.accessibility.XAccessibleText; +import com.sun.star.beans.PropertyValue; +import com.sun.star.awt.Rectangle; +import com.sun.star.awt.Point; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.accessibility.AccessibleTextType; +import com.sun.star.accessibility.TextSegment; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.UnoRuntime; + +/** + * Testing <code>com.sun.star.accessibility.XAccessibleText</code> + * interface methods : + * <ul> + * <li><code> getCaretPosition()</code></li> + * <li><code> setCaretPosition()</code></li> + * <li><code> getCharacter()</code></li> + * <li><code> getCharacterAttributes()</code></li> + * <li><code> getCharacterBounds()</code></li> + * <li><code> getCharacterCount()</code></li> + * <li><code> getIndexAtPoint()</code></li> + * <li><code> getSelectedText()</code></li> + * <li><code> getSelectionStart()</code></li> + * <li><code> getSelectionEnd()</code></li> + * <li><code> setSelection()</code></li> + * <li><code> getText()</code></li> + * <li><code> getTextRange()</code></li> + * <li><code> getTextAtIndex()</code></li> + * <li><code> getTextBeforeIndex()</code></li> + * <li><code> getTextBehindIndex()</code></li> + * <li><code> copyText()</code></li> + * </ul> + * <p>This test needs the following object relations :</p> + * <ul> + * <li> <code>'XAccessibleText.Text'</code> (of type <code>String</code>) + * <b> optional </b> : + * the string presentation of component's text. If the relation + * is not specified, then text from method <code>getText()</code> + * is used. + * </li> + * </ul> + * @see com.sun.star.accessibility.XAccessibleText + */ +public class _XAccessibleText { + + private final XAccessibleText oObj; + private final XMultiServiceFactory xMSF; + + private Rectangle chBounds = null; + private int chCount = 0; + + private String text = null; + private final String editOnly; + + + public _XAccessibleText(XInterface object, XMultiServiceFactory xMSF, String editOnly) { + this.oObj = UnoRuntime.queryInterface(XAccessibleText.class, object); + this.xMSF = xMSF; + this.editOnly = editOnly; + } + + + /** + * Calls the method and checks returned value. + * Has OK status if returned value is equal to <code>chCount - 1</code>. + * The following method tests are to be executed before: + * <ul> + * <li> <code>setCaretPosition()</code> </li> + * </ul> + */ + public boolean _getCaretPosition() { + + if (editOnly != null) { + System.out.println(editOnly); + return true; + } + + boolean res = true; + if ( chCount > 0 ) { + try { + oObj.setCaretPosition(chCount - 1); + } catch (com.sun.star.lang.IndexOutOfBoundsException ie) { + + } + int carPos = oObj.getCaretPosition(); + System.out.println("getCaretPosition: " + carPos); + res = carPos == (chCount - 1); + } + return res; + } + + /** + * Calls the method with the wrong index and with the correct index + * <code>chCount - 1</code>. + * Has OK status if exception was thrown for wrong index and + * if exception wasn't thrown for the correct index. + * The following method tests are to be executed before: + * <ul> + * <li> <code>getCharacterCount()</code> </li> + * </ul> + */ + public boolean _setCaretPosition() { + boolean res = true; + + try { + System.out.println("setCaretPosition(-1):"); + oObj.setCaretPosition(-1); + res &= false; + System.out.println("exception was expected"); + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("expected exception"); + res &= true; + } + + try { + System.out.println("setCaretPosition(chCount+1):"); + oObj.setCaretPosition(chCount+1); + res &= false; + System.out.println("exception was expected"); + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("expected exception"); + res &= true; + } + if ( chCount > 0 ) { + try { + System.out.println("setCaretPosition(chCount - 1)"); + oObj.setCaretPosition(chCount - 1); + res &= true; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("unexpected exception"); + e.printStackTrace(); + res &= false; + } + } + + return res; + } + + /** + * Calls the method with the wrong index and with the correct indexes. + * Checks every character in the text. + * Has OK status if exception was thrown for wrong index, + * if exception wasn't thrown for the correct index and + * if every character is equal to corresponding character in the text. + * The following method tests are to be executed before: + * <ul> + * <li> <code>getCharacterCount()</code> </li> + * </ul> + */ + public boolean _getCharacter() { + boolean res = true; + + try { + System.out.println("getCharacter(-1)"); + oObj.getCharacter(-1); + System.out.println("Exception was expected"); + res = false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res = true; + } + + try { + System.out.println("getCharacter(chCount)"); + oObj.getCharacter(chCount); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } + + try { + System.out.println("Checking of every character in the text..."); + boolean isEqCh = true; + for(int i = 0; i < chCount; i++) { + char ch = oObj.getCharacter(i); + isEqCh = ch == text.charAt(i); + res &= isEqCh; + if (!isEqCh) { + System.out.println("At the position " + i + + "was expected character: " + text.charAt(i)); + System.out.println("but was returned: " + ch); + break; + } + } + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } + + return res; + } + + /** + * Calls the method with the wrong indexes and with the correct index, + * checks a returned value. + * Has OK status if exception was thrown for the wrong indexes, + * if exception wasn't thrown for the correct index and + * if returned value isn't <code>null</code>. + * The following method tests are to be executed before: + * <ul> + * <li> <code>getCharacterCount()</code> </li> + * </ul> + */ + public boolean _getCharacterAttributes() { + boolean res = true; + + try { + System.out.println("getCharacterAttributes(-1)"); + oObj.getCharacterAttributes(-1, new String[0]); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } catch(UnknownPropertyException e) { + System.out.println("unexpected exception => FAILED"); + res &= false; + } + + try { + System.out.println("getCharacterAttributes(chCount)"); + oObj.getCharacterAttributes(chCount, new String[0]); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } catch(UnknownPropertyException e) { + System.out.println("unexpected exception => FAILED"); + res &= false; + } + + try { + if ( chCount > 0 ) { + System.out.println("getCharacterAttributes(chCount-1)"); + PropertyValue[] props = oObj.getCharacterAttributes(chCount - 1, new String[0]); + res &= props != null; + } + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } catch(UnknownPropertyException e) { + System.out.println("unexpected exception => FAILED"); + res &= false; + } + + return res; + } + + + /** + * Calls the method with the wrong indexes and with the correct index. + * checks and stores a returned value. + * Has OK status if exception was thrown for the wrong indexes, + * if exception wasn't thrown for the correct index and + * if returned value isn't <code>null</code>. + * The following method tests are to be executed before: + * <ul> + * <li> <code>getCharacterCount()</code> </li> + * </ul> + */ + public boolean _getCharacterBounds() { + boolean res = true; + + try { + System.out.println("getCharacterBounds(-1)"); + oObj.getCharacterBounds(-1); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } + + try { + System.out.println("getCharacterBounds(chCount)"); + oObj.getCharacterBounds(chCount); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } + + try { + if (chCount > 0) { + System.out.println("getCharacterBounds(chCount-1)"); + chBounds = oObj.getCharacterBounds(chCount-1); + res &= chBounds != null; + System.out.println("rect: " + chBounds.X + ", " + chBounds.Y + ", " + + chBounds.Width + ", " + chBounds.Height); + } + + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } + + return res; + } + + + /** + * Calls the method and stores a returned value to the variable + * <code>chCount</code>. + * Has OK status if a returned value is equal to the text length. + */ + public boolean _getCharacterCount() { + chCount = oObj.getCharacterCount(); + System.out.println("Character count:" + chCount); + boolean res = chCount == text.length(); + return res; + } + + /** + * Calls the method for an invalid point and for the point of rectangle + * returned by the method <code>getCharacterBounds()</code>. + * Has OK status if returned value is equal to <code>-1</code> for an + * invalid point and if returned value is equal to <code>chCount-1</code> + * for a valid point. + * The following method tests are to be executed before: + * <ul> + * <li> <code>getCharacterBounds()</code> </li> + * </ul> + */ + public boolean _getIndexAtPoint() { + + boolean res = true; + System.out.println("getIndexAtPoint(-1, -1):"); + Point pt = new Point(-1, -1); + int index = oObj.getIndexAtPoint(pt); + System.out.println(Integer.toString(index)); + res &= index == -1; + + if (chBounds != null) { + pt = new Point(chBounds.X , chBounds.Y ); + System.out.println("getIndexAtPoint(" + pt.X + ", " + pt.Y + "):"); + index = oObj.getIndexAtPoint(pt); + System.out.println(Integer.toString(index)); + res &= index == (chCount - 1); + } + + return res; + } + + /** + * Checks a returned values after different calls of the method + * <code>setSelection()</code>. + * The following method tests are to be executed before: + * <ul> + * <li> <code>setSelection()</code> </li> + * </ul> + */ + public boolean _getSelectedText() { + if (editOnly != null) { + System.out.println(editOnly); + return true; + } + + boolean res = true; + + try { + System.out.println("setSelection(0, 0)"); + oObj.setSelection(0, 0); + System.out.println("getSelectedText():"); + String txt = oObj.getSelectedText(); + System.out.println("'" + txt + "'"); + res &= txt.length() == 0; + + System.out.println("setSelection(0, chCount)"); + oObj.setSelection(0, chCount); + System.out.println("getSelectedText():"); + txt = oObj.getSelectedText(); + System.out.println("'" + txt + "'"); + res &= txt.equals(text); + + if (chCount > 2) { + System.out.println("setSelection(1, chCount-1)"); + oObj.setSelection(1, chCount - 1); + System.out.println("getSelectedText():"); + txt = oObj.getSelectedText(); + System.out.println("'" + txt + "'"); + res &= txt.equals(text.substring(1, chCount - 1)); + } + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } + + return res; + } + + /** + * Checks a returned values after different calls of the method + * <code>setSelection()</code>. + * The following method tests are to be executed before: + * <ul> + * <li> <code>setSelection()</code> </li> + * </ul> + */ + public boolean _getSelectionStart() { + if (editOnly != null) { + System.out.println(editOnly); + return true; + } + + boolean res = true; + + try { + System.out.println("setSelection(0, chCount)"); + oObj.setSelection(0, chCount); + int start = oObj.getSelectionStart(); + System.out.println("getSelectionStart():" + start); + res &= start == 0; + + if (chCount > 2) { + System.out.println("setSelection(1, chCount-1)"); + oObj.setSelection(1, chCount - 1); + start = oObj.getSelectionStart(); + System.out.println("getSelectionStart():" + start); + res &= start == 1; + } + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } + + return res; + } + + /** + * Checks a returned values after different calls of the method + * <code>setSelection()</code>. + * The following method tests are to be executed before: + * <ul> + * <li> <code>setSelection()</code> </li> + * </ul> + */ + public boolean _getSelectionEnd() { + if (editOnly != null) { + System.out.println(editOnly); + return true; + } + + boolean res = true; + + try { + System.out.println("setSelection(0, chCount)"); + oObj.setSelection(0, chCount); + int end = oObj.getSelectionEnd(); + System.out.println("getSelectionEnd():" + end); + res &= end == chCount; + + if (chCount > 2) { + System.out.println("setSelection(1, chCount-1)"); + oObj.setSelection(1, chCount - 1); + end = oObj.getSelectionEnd(); + System.out.println("getSelectionEnd():" + end); + res &= end == chCount - 1; + } + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } + + return res; + } + + /** + * Calls the method with invalid parameters and with valid parameters. + * Has OK status if exception was thrown for invalid parameters, + * if exception wasn't thrown for valid parameters. + * The following method tests are to be executed before: + * <ul> + * <li> <code>getCharacterCount()</code> </li> + * </ul> + */ + public boolean _setSelection() { + boolean res = true; + boolean locRes = true; + + if (editOnly != null) { + System.out.println(editOnly); + return true; + } + + try { + System.out.println("setSelection(-1, chCount-1):"); + locRes = oObj.setSelection(-1, chCount - 1); + System.out.println(locRes + " exception was expected"); + res &= !locRes; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } + + try { + System.out.println("setSelection(0, chCount+1):"); + locRes = oObj.setSelection(0, chCount + 1); + System.out.println(locRes + " exception was expected"); + res &= !locRes; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } + + try { + if (chCount > 2) { + System.out.println("setSelection(1, chCount-1):"); + locRes = oObj.setSelection(1, chCount - 1); + System.out.println(Boolean.toString(locRes)); + res &= locRes; + + System.out.println("setSelection(chCount-1, 1):"); + locRes = oObj.setSelection(chCount - 1, 1); + System.out.println(Boolean.toString(locRes)); + res &= locRes; + } + + if (chCount > 1) { + System.out.println("setSelection(0, chCount-1):"); + locRes = oObj.setSelection(0, chCount-1); + System.out.println(Boolean.toString(locRes)); + res &= locRes; + + System.out.println("setSelection(chCount-1, 0):"); + locRes = oObj.setSelection(chCount-1, 0); + System.out.println(Boolean.toString(locRes)); + res &= locRes; + } + + System.out.println("setSelection(0, 0):"); + locRes = oObj.setSelection(0, 0); + System.out.println(Boolean.toString(locRes)); + res &= locRes; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } + + return res; + } + + /** + * Calls the method and checks returned value. + * Has OK status if returned string is not null + * received from relation. + */ + public boolean _getText() { + text = oObj.getText(); + System.out.println("getText: '" + text + "'"); + return (text != null); + } + + /** + * Calls the method with invalid parameters and with valid parameters, + * checks returned values. + * Has OK status if exception was thrown for invalid parameters, + * if exception wasn't thrown for valid parameters and if returned values + * are equal to corresponding substrings of the text received by relation. + * The following method tests are to be executed before: + * <ul> + * <li> <code>getCharacterCount()</code> </li> + * </ul> + */ + public boolean _getTextRange() { + boolean res = true; + boolean locRes = true; + + try { + if (chCount > 3) { + System.out.println("getTextRange(1, chCount - 2): "); + String txtRange = oObj.getTextRange(1, chCount - 2); + System.out.println(txtRange); + locRes = txtRange.equals(text.substring(1, chCount - 2)); + res &= locRes; + if (!locRes) { + System.out.println("Was expected: " + + text.substring(1, chCount - 2)); + } + } + + if (chCount > 0) { + System.out.println("getTextRange(0, chCount-1): "); + String txtRange = oObj.getTextRange(0, chCount-1); + System.out.println(txtRange); + locRes = txtRange.equals(text.substring(0, chCount - 1)); + res &= locRes; + if (!locRes) { + System.out.println("Was expected: " + + text.substring(0, chCount - 1)); + } + + System.out.println("getTextRange(chCount, 0): "); + txtRange = oObj.getTextRange(chCount, 0); + System.out.println(txtRange); + res &= txtRange.equals(text); + + System.out.println("getTextRange(0, 0): "); + txtRange = oObj.getTextRange(0, 0); + System.out.println(txtRange); + locRes = txtRange.length() == 0; + res &= locRes; + if (!locRes) { + System.out.println("Empty string was expected"); + } + } + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } + + try { + System.out.println("getTextRange(-1, chCount - 1): "); + oObj.getTextRange(-1, chCount - 1); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } + + try { + System.out.println("getTextRange(0, chCount + 1): "); + oObj.getTextRange(0, chCount + 1); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } + + try { + System.out.println("getTextRange(chCount+1, -1): "); + oObj.getTextRange(chCount+1, -1); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } + + return res; + } + + /** + * Calls the method with invalid parameters and with valid parameters, + * checks returned values. + * Has OK status if exception was thrown for invalid parameters, + * if exception wasn't thrown for valid parameters and if returned values + * are equal to corresponding substrings of the text received by relation. + * The following method tests are to be executed before: + * <ul> + * <li> <code>getCharacterCount()</code> </li> + * </ul> + */ + public boolean _getTextAtIndex() { + boolean res = true; + + try { + System.out.println("getTextAtIndex(-1, AccessibleTextType.PARAGRAPH):"); + oObj.getTextAtIndex(-1, AccessibleTextType.PARAGRAPH); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } catch(com.sun.star.lang.IllegalArgumentException e) { + System.out.println("Expected exception"); + res &= true; + } + + try { + System.out.println("getTextAtIndex(chCount+1," + + " AccessibleTextType.PARAGRAPH):"); + oObj.getTextAtIndex(chCount + 1, AccessibleTextType.PARAGRAPH); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } catch(com.sun.star.lang.IllegalArgumentException e) { + System.out.println("Expected exception"); + res &= true; + } + + + try { + if ( chCount > 0 ) { + System.out.println("getTextAtIndex(chCount," + + " AccessibleTextType.PARAGRAPH):"); + TextSegment txt = oObj.getTextAtIndex(chCount, + AccessibleTextType.PARAGRAPH); + System.out.println("'" + txt.SegmentText + "'"); + res &= txt.SegmentText.length() == 0; + + System.out.println("getTextAtIndex(1," + + " AccessibleTextType.PARAGRAPH):"); + txt = oObj.getTextAtIndex(1, + AccessibleTextType.PARAGRAPH); + System.out.println("'" + txt.SegmentText + "'"); + res &= txt.SegmentText.equals(text); + } + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } catch(com.sun.star.lang.IllegalArgumentException e) { + System.out.println("Unexpected exception"); + res &= false; + } + + + return res; + } + + /** + * Calls the method with invalid parameters and with valid parameters, + * checks returned values. + * Has OK status if exception was thrown for invalid parameters, + * if exception wasn't thrown for valid parameters and if returned values + * are equal to corresponding substrings of the text received by relation. + * The following method tests are to be executed before: + * <ul> + * <li> <code>getCharacterCount()</code> </li> + * </ul> + */ + public boolean _getTextBeforeIndex() { + boolean res = true; + + try { + System.out.println("getTextBeforeIndex(-1, AccessibleTextType.PARAGRAPH):"); + oObj.getTextBeforeIndex(-1, AccessibleTextType.PARAGRAPH); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } catch(com.sun.star.lang.IllegalArgumentException e) { + System.out.println("Expected exception"); + res &= true; + } + + + try { + System.out.println("getTextBeforeIndex(chCount+1, " + + "AccessibleTextType.PARAGRAPH):"); + oObj.getTextBeforeIndex(chCount + 1, AccessibleTextType.PARAGRAPH); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } catch(com.sun.star.lang.IllegalArgumentException e) { + System.out.println("Expected exception"); + res &= true; + } + + TextSegment txt = null; + try { + if (chCount > 0) { + System.out.println("getTextBeforeIndex(chCount," + + " AccessibleTextType.PARAGRAPH):"); + txt = oObj.getTextBeforeIndex(chCount, + AccessibleTextType.PARAGRAPH); + System.out.println("'" + txt.SegmentText + "'"); + res &= txt.SegmentText.length() == chCount ; + + System.out.println("getTextBeforeIndex(1," + + " AccessibleTextType.PARAGRAPH):"); + txt = oObj.getTextBeforeIndex(1, + AccessibleTextType.PARAGRAPH); + System.out.println("'" + txt.SegmentText + "'"); + res &= txt.SegmentText.length() == 0; + } + + if (chCount > 2) { + System.out.println("getTextBeforeIndex(chCount-1," + + " AccessibleTextType.CHARACTER):"); + txt = oObj.getTextBeforeIndex(chCount - 1, + AccessibleTextType.CHARACTER); + System.out.println("'" + txt.SegmentText + "'"); + res &= txt.SegmentText.equals(text.substring(chCount - 2, chCount - 1)); + System.out.println("getTextBeforeIndex(2," + + " AccessibleTextType.CHARACTER):"); + txt = oObj.getTextBeforeIndex(2, + AccessibleTextType.CHARACTER); + System.out.println("'" + txt.SegmentText + "'"); + res &= txt.SegmentText.equals(text.substring(1, 2)); + } + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } catch(com.sun.star.lang.IllegalArgumentException e) { + System.out.println("Unexpected exception"); + res &= false; + } + + + return res; + } + + /** + * Calls the method with invalid parameters and with valid parameters, + * checks returned values. + * Has OK status if exception was thrown for invalid parameters, + * if exception wasn't thrown for valid parameters and if returned values + * are equal to corresponding substrings of the text received by relation. + * The following method tests are to be executed before: + * <ul> + * <li> <code>getCharacterCount()</code> </li> + * </ul> + */ + public boolean _getTextBehindIndex() { + boolean res = true; + + try { + System.out.println("getTextBehindIndex(-1, AccessibleTextType.PARAGRAPH):"); + oObj.getTextBehindIndex(-1, AccessibleTextType.PARAGRAPH); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } catch(com.sun.star.lang.IllegalArgumentException e) { + System.out.println("Expected exception"); + res &= true; + } + + + try { + System.out.println("getTextBehindIndex(chCount+1, " + + "AccessibleTextType.PARAGRAPH):"); + oObj.getTextBehindIndex(chCount + 1, AccessibleTextType.PARAGRAPH); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } catch(com.sun.star.lang.IllegalArgumentException e) { + System.out.println("Expected exception"); + res &= true; + } + + + try { + if ( chCount > 0 ) { + System.out.println("getTextBehindIndex(chCount," + + " AccessibleTextType.PARAGRAPH):"); + TextSegment txt = oObj.getTextBehindIndex(chCount, + AccessibleTextType.PARAGRAPH); + System.out.println("'" + txt.SegmentText + "'"); + res &= txt.SegmentText.length() == 0; + + System.out.println("getTextBehindIndex(chCount-1," + + " AccessibleTextType.PARAGRAPH):"); + txt = oObj.getTextBehindIndex(chCount - 1, + AccessibleTextType.PARAGRAPH); + System.out.println("'" + txt.SegmentText + "'"); + res &= txt.SegmentText.length() == 0; + } + if ( chCount > 1 ) { + System.out.println("getTextBehindIndex(1," + + " AccessibleTextType.CHARACTER):"); + TextSegment txt = oObj.getTextBehindIndex(1, + AccessibleTextType.CHARACTER); + System.out.println("'" + txt.SegmentText + "'"); + res &= txt.SegmentText.equals(text.substring(2, 3)); + } + if (chCount > 2) { + System.out.println("getTextBehindIndex(chCount-2," + + " AccessibleTextType.CHARACTER):"); + TextSegment txt = oObj.getTextBehindIndex(chCount - 2, + AccessibleTextType.CHARACTER); + System.out.println("'" + txt.SegmentText + "'"); + res &= txt.SegmentText.equals(text.substring(chCount - 1, chCount)); + } + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } catch(com.sun.star.lang.IllegalArgumentException e) { + System.out.println("Unexpected exception"); + res &= false; + } + + + return res; + } + + /** + * Calls the method with invalid parameters and with valid parameter, + * checks returned values. + * Has OK status if exception was thrown for invalid parameters, + * if exception wasn't thrown for valid parameter and if returned value for + * valid parameter is equal to <code>true</code>. + */ + public boolean _copyText() { + boolean res = true; + boolean locRes = true; + + if (editOnly != null) { + System.out.println(editOnly); + return true; + } + + try { + System.out.println("copyText(-1,chCount):"); + oObj.copyText(-1, chCount); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } + + try { + System.out.println("copyText(0,chCount+1):"); + oObj.copyText(0, chCount + 1); + System.out.println("Exception was expected"); + res &= false; + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Expected exception"); + res &= true; + } + + try { + System.out.println("copyText(0,chCount):"); + locRes = oObj.copyText(0, chCount); + System.out.println(locRes); + res &= locRes; + + String cbText = null; + try { + cbText = + util.SysUtils.getSysClipboardText(xMSF); + } catch (com.sun.star.uno.Exception e) { + System.out.println("Couldn't access system clipboard :"); + e.printStackTrace(); + } + System.out.println("Clipboard: '" + cbText + "'"); + res &= text.equals(cbText); + + if (chCount > 2) { + System.out.println("copyText(1,chCount-1):"); + locRes = oObj.copyText(1, chCount - 1); + System.out.println(locRes); + res &= locRes; + + try { + cbText = util.SysUtils.getSysClipboardText(xMSF); + } catch (com.sun.star.uno.Exception e) { + System.out.println("Couldn't access system clipboard :"); + e.printStackTrace(); + } + + System.out.println("Clipboard: '" + cbText + "'"); + res &= text.substring(1, chCount - 1).equals(cbText); + } + + } catch(com.sun.star.lang.IndexOutOfBoundsException e) { + System.out.println("Unexpected exception"); + e.printStackTrace(); + res &= false; + } + + return res; + } +} diff --git a/toolkit/qa/complex/toolkit/awtgrid/DummyColumn.java b/toolkit/qa/complex/toolkit/awtgrid/DummyColumn.java new file mode 100644 index 000000000..d86df3f1c --- /dev/null +++ b/toolkit/qa/complex/toolkit/awtgrid/DummyColumn.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.toolkit.awtgrid; + +import com.sun.star.awt.grid.XGridColumn; +import com.sun.star.awt.grid.XGridColumnListener; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.XEventListener; +import com.sun.star.style.HorizontalAlignment; +import com.sun.star.util.XCloneable; + +/** + * a dummy implementation of css.awt.grid.XGridColumn + */ +public class DummyColumn implements XGridColumn +{ + public Object getIdentifier() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setIdentifier( Object o ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public int getColumnWidth() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setColumnWidth( int i ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public int getMinWidth() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setMinWidth( int i ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public int getMaxWidth() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setMaxWidth( int i ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public boolean getResizeable() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setResizeable( boolean bln ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public int getFlexibility() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setFlexibility( int i ) throws IllegalArgumentException + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public HorizontalAlignment getHorizontalAlign() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setHorizontalAlign( HorizontalAlignment ha ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public String getTitle() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setTitle( String string ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public String getHelpText() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setHelpText( String string ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public int getIndex() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public int getDataColumnIndex() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void setDataColumnIndex( int i ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void addGridColumnListener( XGridColumnListener xl ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void removeGridColumnListener( XGridColumnListener xl ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void dispose() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void addEventListener( XEventListener xl ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public void removeEventListener( XEventListener xl ) + { + throw new UnsupportedOperationException( "Not supported yet." ); + } + + public XCloneable createClone() + { + throw new UnsupportedOperationException( "Not supported yet." ); + } +} diff --git a/toolkit/qa/complex/toolkit/awtgrid/GridDataListener.java b/toolkit/qa/complex/toolkit/awtgrid/GridDataListener.java new file mode 100644 index 000000000..800727bb3 --- /dev/null +++ b/toolkit/qa/complex/toolkit/awtgrid/GridDataListener.java @@ -0,0 +1,107 @@ +/* + * 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.toolkit.awtgrid; + +import com.sun.star.awt.grid.GridDataEvent; +import com.sun.star.awt.grid.XGridDataListener; +import com.sun.star.lang.EventObject; +import static org.junit.Assert.*; + +final public class GridDataListener implements XGridDataListener +{ + public void rowsInserted( GridDataEvent i_event ) + { + assertNull( m_rowInsertionEvent ); + m_rowInsertionEvent = i_event; + } + + public void rowsRemoved( GridDataEvent i_event ) + { + assertNull( m_rowRemovalEvent ); + m_rowRemovalEvent = i_event; + } + + public void dataChanged( GridDataEvent i_event ) + { + assertNull( m_dataChangeEvent ); + m_dataChangeEvent = i_event; + } + + public void rowHeadingChanged( GridDataEvent i_event ) + { + assertNull( m_rowHeadingChangeEvent ); + m_rowHeadingChangeEvent = i_event; + } + + public void disposing( EventObject eo ) + { + m_disposed = true; + } + + public final GridDataEvent assertSingleRowInsertionEvent() + { + assertNotNull( m_rowInsertionEvent ); + assertNull( m_rowRemovalEvent ); + assertNull( m_dataChangeEvent ); + assertNull( m_rowHeadingChangeEvent ); + assertFalse( m_disposed ); + return m_rowInsertionEvent; + } + + public final GridDataEvent assertSingleRowRemovalEvent() + { + assertNull( m_rowInsertionEvent ); + assertNotNull( m_rowRemovalEvent ); + assertNull( m_dataChangeEvent ); + assertNull( m_rowHeadingChangeEvent ); + assertFalse( m_disposed ); + return m_rowRemovalEvent; + } + + public final GridDataEvent assertSingleDataChangeEvent() + { + assertNull( m_rowInsertionEvent ); + assertNull( m_rowRemovalEvent ); + assertNotNull( m_dataChangeEvent ); + assertNull( m_rowHeadingChangeEvent ); + assertFalse( m_disposed ); + return m_dataChangeEvent; + } + + public final GridDataEvent assertSingleRowHeadingChangeEvent() + { + assertNull( m_rowInsertionEvent ); + assertNull( m_rowRemovalEvent ); + assertNull( m_dataChangeEvent ); + assertNotNull( m_rowHeadingChangeEvent ); + assertFalse( m_disposed ); + return m_rowHeadingChangeEvent; + } + + public final void reset() + { + m_rowInsertionEvent = m_rowRemovalEvent = m_dataChangeEvent = m_rowHeadingChangeEvent = null; + // m_disposed is not reset intentionally + } + private GridDataEvent m_rowInsertionEvent = null; + private GridDataEvent m_rowRemovalEvent = null; + private GridDataEvent m_dataChangeEvent = null; + private GridDataEvent m_rowHeadingChangeEvent = null; + private boolean m_disposed = false; +} diff --git a/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java b/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java new file mode 100644 index 000000000..1623af8b6 --- /dev/null +++ b/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java @@ -0,0 +1,449 @@ +/* + * 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.toolkit.awtgrid; + +import com.sun.star.awt.grid.GridDataEvent; +import com.sun.star.awt.grid.XMutableGridDataModel; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.IndexOutOfBoundsException; +import static org.junit.Assert.*; +import static complex.toolkit.Assert.*; + +/** test for the <code>css.awt.grid.XMutableGridData</code> interface + * + */ +public class TMutableGridDataModel +{ + public TMutableGridDataModel( final XMutableGridDataModel i_dataModel ) + { + m_dataModel = i_dataModel; + + m_listener = new GridDataListener(); + m_dataModel.addGridDataListener( m_listener ); + } + + /* + * tests the XMutableGridDataModel.addRow method + */ + public void testAddRow() throws IndexOutOfBoundsException + { + m_dataModel.addRow( m_rowHeadings[0], m_rowValues[0] ); + GridDataEvent event = m_listener.assertSingleRowInsertionEvent(); + m_listener.reset(); + assertEquals( "row insertion: wrong FirstRow (1)", 0, event.FirstRow ); + assertEquals( "row insertion: wrong LastRow (1)", 0, event.LastRow ); + impl_assertRowData( 0 ); + + m_dataModel.addRow( m_rowHeadings[1], m_rowValues[1] ); + event = m_listener.assertSingleRowInsertionEvent(); + m_listener.reset(); + assertEquals( "row insertion: wrong FirstRow (2)", 1, event.FirstRow ); + assertEquals( "row insertion: wrong LastRow (2)", 1, event.LastRow ); + impl_assertRowData( 1 ); + } + + /** + * tests the XMutableGridDataModel.addRows method + */ + public void testAddRows() throws IndexOutOfBoundsException, IllegalArgumentException + { + assertEquals( "precondition not met: call this directly after testAddRow, please!", 2, m_dataModel.getRowCount() ); + + m_dataModel.addRows( + new Object[] { m_rowHeadings[2], m_rowHeadings[3], m_rowHeadings[4] }, + new Object[][] { m_rowValues[2], m_rowValues[3], m_rowValues[4] } ); + GridDataEvent event = m_listener.assertSingleRowInsertionEvent(); + assertEquals( "row insertion: wrong FirstRow (1)", 2, event.FirstRow ); + assertEquals( "row insertion: wrong LastRow (1)", 4, event.LastRow ); + m_listener.reset(); + + assertEquals( "data model's row count is not adjusted when adding rows", m_rowValues.length, m_dataModel.getRowCount() ); + assertEquals( "data model's column count is not adjusted when adding rows", m_rowValues[0].length, m_dataModel.getColumnCount() ); + for ( int row=0; row<m_rowValues.length; ++row ) + { + for ( int col=0; col<m_rowValues[row].length; ++col ) + { + assertEquals( "added row values are not preserved", + m_rowValues[row][col], m_dataModel.getCellData( col, row ) ); + } + } + + assertException( "addRows is expected to throw when invoked with different-sized arrays", + m_dataModel, "addRows", new Object[] { new Object[0], new Object[1][2] }, IllegalArgumentException.class ); + } + + /** + * tests the XMutableGridDataModel.insertRow method + */ + public void testInsertRow() throws IndexOutOfBoundsException + { + int expectedRowCount = m_rowValues.length; + assertEquals( "precondition not met: call this directly after testAddRows, please!", expectedRowCount, m_dataModel.getRowCount() ); + + // inserting some row somewhere between the other rows + final Object heading = "inbetweenRow"; + final Object[] inbetweenRow = new Object[] { "foo", "bar", 3, 4, 5 }; + final int insertionPos = 2; + m_dataModel.insertRow( insertionPos, heading, inbetweenRow ); + ++expectedRowCount; + assertEquals( "inserting a row is expected to increment the row count", + expectedRowCount, m_dataModel.getRowCount() ); + + final GridDataEvent event = m_listener.assertSingleRowInsertionEvent(); + assertEquals( "inserting a row results in wrong FirstRow being notified", insertionPos, event.FirstRow ); + assertEquals( "inserting a row results in wrong LastRow being notified", insertionPos, event.LastRow ); + m_listener.reset(); + + for ( int row=0; row<expectedRowCount; ++row ) + { + final Object[] actualRowData = m_dataModel.getRowData( row ); + final Object[] expectedRowData = + ( row < insertionPos ) + ? m_rowValues[ row ] + : ( row == insertionPos ) + ? inbetweenRow + : m_rowValues[ row - 1 ]; + assertArrayEquals( "row number " + row + " has wrong content after inserting a row", + expectedRowData, actualRowData ); + + final Object actualHeading = m_dataModel.getRowHeading(row); + final Object expectedHeading = + ( row < insertionPos ) + ? m_rowHeadings[ row ] + : ( row == insertionPos ) + ? heading + : m_rowHeadings[ row - 1 ]; + assertEquals( "row " + row + " has a wrong heading after invoking insertRow", + expectedHeading, actualHeading ); + } + + // exceptions + assertException( "inserting a row at a position > rowCount is expected to throw", + m_dataModel, "insertRow", + new Class[] { Integer.class, Object.class, Object[].class }, + new Object[] { expectedRowCount + 1, "", new Object[] { "1", 2, 3 } }, + IndexOutOfBoundsException.class ); + assertException( "inserting a row at a position < 0 is expected to throw", + m_dataModel, "insertRow", + new Class[] { Integer.class, Object.class, Object[].class }, + new Object[] { -1, "", new Object[] { "1", 2, 3 } }, + IndexOutOfBoundsException.class ); + + // remove the row, to create the situation expected by the next test + m_dataModel.removeRow( insertionPos ); + m_listener.reset(); + } + + /** + * tests the XMutableGridDataModel.insertRows method + */ + public void testInsertRows() throws IndexOutOfBoundsException, IllegalArgumentException + { + int expectedRowCount = m_rowValues.length; + assertEquals( "precondition not met: call this directly after testInsertRow, please!", expectedRowCount, m_dataModel.getRowCount() ); + + // inserting some rows somewhere between the other rows + final int insertionPos = 3; + final Object[] rowHeadings = new Object[] { "A", "B", "C" }; + final Object[][] rowData = new Object[][] { + new Object[] { "A", "B", "C", "D", "E" }, + new Object[] { "J", "I", "H", "G", "F" }, + new Object[] { "K", "L", "M", "N", "O" } + }; + final int insertedRowCount = rowData.length; + assertEquals( "invalid test data", rowHeadings.length, insertedRowCount ); + + m_dataModel.insertRows( insertionPos, rowHeadings, rowData ); + expectedRowCount += insertedRowCount; + + final GridDataEvent event = m_listener.assertSingleRowInsertionEvent(); + assertEquals( "inserting multiple rows results in wrong FirstRow being notified", + insertionPos, event.FirstRow ); + assertEquals( "inserting multiple rows results in wrong LastRow being notified", + insertionPos + insertedRowCount - 1, event.LastRow ); + m_listener.reset(); + + for ( int row=0; row<expectedRowCount; ++row ) + { + final Object[] actualRowData = m_dataModel.getRowData( row ); + final Object[] expectedRowData = + ( row < insertionPos ) + ? m_rowValues[ row ] + : ( row >= insertionPos ) && ( row < insertionPos + insertedRowCount ) + ? rowData[ row - insertionPos ] + : m_rowValues[ row - insertedRowCount ]; + assertArrayEquals( "row number " + row + " has wrong content after inserting multiple rows", + expectedRowData, actualRowData ); + + final Object actualHeading = m_dataModel.getRowHeading(row); + final Object expectedHeading = + ( row < insertionPos ) + ? m_rowHeadings[ row ] + : ( row >= insertionPos ) && ( row < insertionPos + insertedRowCount ) + ? rowHeadings[ row - insertionPos ] + : m_rowHeadings[ row - insertedRowCount ]; + assertEquals( "row " + row + " has a wrong heading after invoking insertRows", + expectedHeading, actualHeading ); + } + + // exceptions + assertException( "inserting multiple rows at a position > rowCount is expected to throw an IndexOutOfBoundsException", + m_dataModel, "insertRows", + new Class[] { Integer.class, Object[].class, Object[][].class }, + new Object[] { expectedRowCount + 1, new Object[0], new Object[][] { } }, + IndexOutOfBoundsException.class ); + assertException( "inserting multiple rows at a position < 0 is expected to throw an IndexOutOfBoundsException", + m_dataModel, "insertRows", + new Class[] { Integer.class, Object[].class, Object[][].class }, + new Object[] { -1, new Object[0], new Object[][] { } }, + IndexOutOfBoundsException.class ); + assertException( "inserting multiple rows with inconsistent array lengths is expected to throw an IllegalArgumentException", + m_dataModel, "insertRows", + new Class[] { Integer.class, Object[].class, Object[][].class }, + new Object[] { 0, new Object[0], new Object[][] { new Object[0] } }, + IllegalArgumentException.class ); + + // remove the row, to create the situation expected by the next test + for ( int i=0; i<insertedRowCount; ++i ) + { + m_dataModel.removeRow( insertionPos ); + m_listener.reset(); + } + } + + /** + * tests the XMutableGridDataModel.removeRow method + */ + public void testRemoveRow() throws IndexOutOfBoundsException + { + assertEquals( "precondition not met: call this directly after testAddRows, please!", m_rowValues.length, m_dataModel.getRowCount() ); + + final int rowToRemove = 2; + m_dataModel.removeRow( rowToRemove ); + GridDataEvent event = m_listener.assertSingleRowRemovalEvent(); + assertEquals( "incorrect notification of row removal (FirstRow)", rowToRemove, event.FirstRow ); + assertEquals( "incorrect notification of row removal (LastRow)", rowToRemove, event.LastRow ); + m_listener.reset(); + + assertEquals( "data model's row count does not reflect the removed row", m_rowValues.length - 1, m_dataModel.getRowCount() ); + for ( int row = rowToRemove; row<m_rowValues.length-1; ++row ) + { + for ( int col=0; col<m_rowValues[row].length; ++col ) + { + assertEquals( "unexpected row values after removing a row (col: " + col + ", row: " + row + ")", + m_rowValues[row+1][col], m_dataModel.getCellData( col, row ) ); + } + } + + assertException( "removeRow silently ignores an invalid index (1)", + m_dataModel, "removeRow", new Object[] { -1 }, IndexOutOfBoundsException.class ); + assertException( "removeRow silently ignores an invalid index (2)", + m_dataModel, "removeRow", new Object[] { m_dataModel.getRowCount() }, IndexOutOfBoundsException.class ); + } + + /** + * tests the XMutableGridDataModel.removeAllRows method + */ + public void testRemoveAllRows() + { + assertEquals( "precondition not met: call this directly after testRemoveRow, please!", m_rowValues.length - 1, m_dataModel.getRowCount() ); + + m_dataModel.removeAllRows(); + final GridDataEvent event = m_listener.assertSingleRowRemovalEvent(); + if ( event.FirstRow != -1 ) + { // notifying "-1" is allowed, this means "all rows affected", by definition + assertEquals( "removeAllRows is not notifying properly (1)", 0, event.FirstRow ); + assertEquals( "removeAllRows is not notifying properly (2)", m_rowValues.length - 1, event.LastRow ); + } + m_listener.reset(); + } + + /** + * tests the XMutableGridDataModel.updateCellData method + */ + public void testUpdateCellData() throws IndexOutOfBoundsException, IllegalArgumentException + { + assertEquals( "precondition not met: call this directly after testRemoveAllRows, please!", 0, m_dataModel.getRowCount() ); + + m_dataModel.addRows( m_rowHeadings, m_rowValues ); + m_listener.assertSingleRowInsertionEvent(); + m_listener.reset(); + + final Object[][] modifyValues = new Object[][] { + new Object[] { 2, 1, "text" }, + new Object[] { 3, 0, null }, + new Object[] { 0, 4, new Double( 33.0 ) } + }; + for ( int i = 0; i < modifyValues.length; ++i ) + { + final int row = ((Integer)modifyValues[i][0]).intValue(); + final int col = ((Integer)modifyValues[i][1]).intValue(); + final Object value = modifyValues[i][2]; + m_dataModel.updateCellData( col, row, value ); + + final GridDataEvent event = m_listener.assertSingleDataChangeEvent(); + assertEquals( "data change notification: FirstRow is invalid", row, event.FirstRow ); + assertEquals( "data change notification: LastRow is invalid", row, event.LastRow ); + assertEquals( "data change notification: FirstColumn is invalid", col, event.FirstColumn ); + assertEquals( "data change notification: LastColumn is invalid", col, event.LastColumn ); + m_listener.reset(); + + assertEquals( "data change at (" + col + ", " + row + ") not successful", value, m_dataModel.getCellData( col, row ) ); + } + + assertException( "updateCellData silently ignores an invalid index (1)", + m_dataModel, "updateCellData", new Class[] { int.class, int.class, Object.class }, + new Object[] { -1, -1, "text" }, IndexOutOfBoundsException.class ); + assertException( "updateCellData silently ignores an invalid index (2)", + m_dataModel, "updateCellData", new Class[] { int.class, int.class, Object.class }, + new Object[] { 0, m_dataModel.getRowCount(), "text" }, IndexOutOfBoundsException.class ); + assertException( "updateCellData silently ignores an invalid index (3)", + m_dataModel, "updateCellData", new Class[] { int.class, int.class, Object.class }, + new Object[] { m_dataModel.getColumnCount(), 0, "text" }, IndexOutOfBoundsException.class ); + } + + /** + * tests the XMutableGridDataModel.updateRowData method + */ + public void testUpdateRowData() throws IndexOutOfBoundsException, IllegalArgumentException + { + assertEquals( "precondition not met: call this directly after testRemoveAllRows, please!", m_rowValues.length, m_dataModel.getRowCount() ); + + // get data from before the update + final Object[][] preUpdateValues = impl_getCurrentData(); + + // do the update + final int[] colIndexes = new int[] { + 0, 3, 4 + }; + final Object[] values = new Object[] { + 13, null, 42.0 + }; + final int rowToUpdate = 2; + m_dataModel.updateRowData( colIndexes, rowToUpdate, values ); + final GridDataEvent event = m_listener.assertSingleDataChangeEvent(); + assertEquals( "row update notification: FirstRow is invalid", rowToUpdate, event.FirstRow ); + assertEquals( "row update notification: LastRow is invalid", rowToUpdate, event.LastRow ); + assertEquals( "row update notification: FirstColumn is invalid", 0, event.FirstColumn ); + assertEquals( "row update notification: LastColumn is invalid", 4, event.LastColumn ); + m_listener.reset(); + + // reflect the changes made in the pre-update data + for ( int i=0; i<colIndexes.length; ++i ) + { + preUpdateValues[rowToUpdate][colIndexes[i]] = values[i]; + } + + // get data from after the update + final Object[][] postUpdateValues = impl_getCurrentData(); + + // ensure both the manually updated pre-update data and the post-update data are identical + assertArrayEquals( preUpdateValues, postUpdateValues ); + + + assertException( "updateRowData silently ignores an invalid index (1)", + m_dataModel, "updateRowData", new Class[] { int[].class, int.class, Object[].class }, + new Object[] { new int[] { -1 }, 0, new Object[] { "text" } }, IndexOutOfBoundsException.class ); + assertException( "updateRowData silently ignores an invalid index (2)", + m_dataModel, "updateRowData", new Class[] { int[].class, int.class, Object[].class }, + new Object[] { new int[] { 0 }, -1, new Object[] { "" } }, IndexOutOfBoundsException.class ); + assertException( "updateRowData silently ignores different-sized arrays", + m_dataModel, "updateRowData", new Class[] { int[].class, int.class, Object[].class }, + new Object[] { new int[] { 0, 0 }, 0, new Object[] { "" } }, IllegalArgumentException.class ); + } + + /** + * tests the XMutableGridDataModel.updateRowHeading method + */ + public void testUpdateRowHeading() throws IndexOutOfBoundsException + { + assertEquals( "precondition not met: call this directly after testUpdateRowData, please!", m_rowValues.length, m_dataModel.getRowCount() ); + + final Object[] preUpdateHeadings = impl_getCurrentRowHeadings(); + + final int rowToUpdate = 2; + final String valueToUpdate = "some text"; + m_dataModel.updateRowHeading( rowToUpdate, valueToUpdate ); + final GridDataEvent event = m_listener.assertSingleRowHeadingChangeEvent(); + assertEquals( "row heading update notification: FirstRow is invalid", rowToUpdate, event.FirstRow ); + assertEquals( "row heading update notification: FirstRow is invalid", rowToUpdate, event.LastRow ); + m_listener.reset(); + + preUpdateHeadings[rowToUpdate] = valueToUpdate; + + final Object[] postUpdateHeadings = impl_getCurrentRowHeadings(); + assertArrayEquals( preUpdateHeadings, postUpdateHeadings ); + + assertException( "updateRowHeading silently ignores an invalid index", + m_dataModel, "updateRowHeading", new Class[] { int.class, Object.class }, + new Object[] { -1, "" }, IndexOutOfBoundsException.class ); + } + + public void cleanup() + { + m_dataModel.removeGridDataListener( m_listener ); + } + + private Object[][] impl_getCurrentData() throws IndexOutOfBoundsException + { + final int rowCount = m_dataModel.getRowCount(); + final int colCount = m_dataModel.getColumnCount(); + final Object[][] data = new Object[rowCount][colCount]; + for ( int row=0; row<rowCount; ++row ) + { + for ( int col=0; col<colCount; ++col ) + { + data[row][col] = m_dataModel.getCellData( col, row ); + } + } + return data; + } + + private Object[] impl_getCurrentRowHeadings() throws IndexOutOfBoundsException + { + final int rowCount = m_dataModel.getRowCount(); + final Object[] headings = new Object[rowCount]; + for ( int row=0; row<rowCount; ++row ) + headings[row] = m_dataModel.getRowHeading( row ); + return headings; + } + + private void impl_assertRowData( final int i_rowIndex ) throws IndexOutOfBoundsException + { + for ( int i=0; i<m_rowValues[i_rowIndex].length; ++i ) + { + assertEquals( m_rowValues[i_rowIndex][i], m_dataModel.getCellData( i, i_rowIndex ) ); + } + } + + private final XMutableGridDataModel m_dataModel; + private final GridDataListener m_listener; + + private static final Object[][] m_rowValues = new Object[][] { + new Object[] { 1, 2, "3", 4, 5 }, + new Object[] { 2, 3, 4, "5", 6 }, + new Object[] { "3", 4, 5, 6, 7 }, + new Object[] { 4, 5, 6, 7, "8" }, + new Object[] { 5, "6", 7, 8, 9 }, + }; + + private static final Object[] m_rowHeadings = new Object[] { + "1", 2, 3.0, "4", (float)5.0 + }; +} diff --git a/toolkit/qa/cppunit/Dialog.cxx b/toolkit/qa/cppunit/Dialog.cxx new file mode 100644 index 000000000..6ddf3f725 --- /dev/null +++ b/toolkit/qa/cppunit/Dialog.cxx @@ -0,0 +1,73 @@ +/* -*- 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/awt/UnoControlDialog.hpp> +#include <com/sun/star/awt/XUnoControlDialog.hpp> +#include <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> + +#include <comphelper/processfactory.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/vclptr.hxx> +#include <vcl/window.hxx> + +using namespace css; + +namespace +{ +/// Test dialogs constructed via UNO +class DialogTest : public test::BootstrapFixture, public unotest::MacrosTest +{ +protected: + uno::Reference<uno::XComponentContext> mxContext; + +public: + virtual void setUp() override; +}; + +void DialogTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxContext.set(comphelper::getComponentContext(getMultiServiceFactory())); +} + +CPPUNIT_TEST_FIXTURE(DialogTest, testDialogSizeable) +{ + uno::Reference<awt::XDialog> xDialog; + uno::Reference<lang::XMultiComponentFactory> xFactory(mxContext->getServiceManager(), + uno::UNO_SET_THROW); + uno::Reference<awt::XControlModel> xControlModel( + xFactory->createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", mxContext), + uno::UNO_QUERY_THROW); + + uno::Reference<beans::XPropertySet> xPropSet(xControlModel, uno::UNO_QUERY_THROW); + xPropSet->setPropertyValue("Sizeable", uno::Any(true)); + + uno::Reference<awt::XUnoControlDialog> xControl = awt::UnoControlDialog::create(mxContext); + xControl->setModel(xControlModel); + xControl->setVisible(true); + xDialog.set(xControl, uno::UNO_QUERY_THROW); + xDialog->execute(); + + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(xControl->getPeer()); + CPPUNIT_ASSERT(pWindow); + CPPUNIT_ASSERT(pWindow->GetStyle() & WB_SIZEABLE); + + xDialog->endExecute(); + css::uno::Reference<css::lang::XComponent>(xDialog, css::uno::UNO_QUERY_THROW)->dispose(); + css::uno::Reference<css::lang::XComponent>(xControlModel, css::uno::UNO_QUERY_THROW)->dispose(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/qa/cppunit/EventContainer.cxx b/toolkit/qa/cppunit/EventContainer.cxx new file mode 100644 index 000000000..ad62f9310 --- /dev/null +++ b/toolkit/qa/cppunit/EventContainer.cxx @@ -0,0 +1,84 @@ +/* -*- 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 <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +#include <com/sun/star/script/ScriptEventDescriptor.hpp> +#include <com/sun/star/script/XScriptEventsSupplier.hpp> +#include <com/sun/star/uno/Reference.hxx> + +#include <comphelper/processfactory.hxx> + +using namespace css; +using namespace css::awt; +using namespace css::container; +using namespace css::lang; +using namespace css::script; +using namespace css::uno; + +namespace +{ +/// Test EventContainer class +class EventContainerTest : public test::BootstrapFixture +{ +protected: + Reference<XComponentContext> mxContext; + +public: + virtual void setUp() override; +}; + +void EventContainerTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxContext.set(comphelper::getComponentContext(getMultiServiceFactory())); +} + +// Make sure that EventContainer keeps insertion order, and does not reorder its elements. +// Otherwise this would break macro signatures. +CPPUNIT_TEST_FIXTURE(EventContainerTest, testInsertOrder) +{ + Reference<XMultiComponentFactory> xFactory(mxContext->getServiceManager(), UNO_SET_THROW); + Reference<XControlModel> xControlModel( + xFactory->createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", mxContext), + UNO_QUERY_THROW); + + Reference<beans::XPropertySet> xPropSet(xControlModel, UNO_QUERY_THROW); + + Reference<XScriptEventsSupplier> xEventsSupplier(xPropSet, UNO_QUERY_THROW); + Reference<XNameContainer> xEvents(xEventsSupplier->getEvents(), UNO_SET_THROW); + script::ScriptEventDescriptor descr1; + script::ScriptEventDescriptor descr2; + script::ScriptEventDescriptor descr3; + script::ScriptEventDescriptor descr4; + xEvents->insertByName("b", Any(descr1)); + xEvents->insertByName("a", Any(descr2)); + xEvents->insertByName("1", Any(descr3)); + xEvents->insertByName("A", Any(descr4)); + + Sequence<OUString> aEventNames(xEvents->getElementNames()); + sal_Int32 nEventCount = aEventNames.getLength(); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), nEventCount); + + CPPUNIT_ASSERT_EQUAL(OUString("b"), aEventNames[0]); + CPPUNIT_ASSERT_EQUAL(OUString("a"), aEventNames[1]); + CPPUNIT_ASSERT_EQUAL(OUString("1"), aEventNames[2]); + CPPUNIT_ASSERT_EQUAL(OUString("A"), aEventNames[3]); + + css::uno::Reference<css::lang::XComponent>(xControlModel, css::uno::UNO_QUERY_THROW)->dispose(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/qa/cppunit/UnitConversion.cxx b/toolkit/qa/cppunit/UnitConversion.cxx new file mode 100644 index 000000000..5e28667f5 --- /dev/null +++ b/toolkit/qa/cppunit/UnitConversion.cxx @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#include <test/bootstrapfixture.hxx> + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/util/MeasureUnit.hpp> +#include <com/sun/star/awt/VclWindowPeerAttribute.hpp> +#include <com/sun/star/awt/WindowAttribute.hpp> +#include <com/sun/star/awt/WindowDescriptor.hpp> +#include <com/sun/star/awt/XUnitConversion.hpp> +#include <com/sun/star/awt/XWindowPeer.hpp> +#include <com/sun/star/awt/XWindow.hpp> + +#ifdef _WIN32 +#include <windows.h> +#endif + +using namespace ::com::sun::star; + +namespace +{ +class ToolkitTest : public test::BootstrapFixture +{ +public: + void testXUnitConversion(); + + CPPUNIT_TEST_SUITE(ToolkitTest); + CPPUNIT_TEST(testXUnitConversion); + CPPUNIT_TEST_SUITE_END(); +}; + +/** + * Creates a floating XWindow on the given position and size. + * @return a floating XWindow + * @param X the X-Position of the floating XWindow + * @param Y the Y-Position of the floating XWindow + * @param width the width of the floating XWindow + * @param height the height of the floating XWindow + * @param xMSF the MultiServiceFactory + */ +uno::Reference<awt::XWindowPeer> +createFloatingWindow(uno::Reference<lang::XMultiServiceFactory> const& xMSF, sal_Int32 const nX, + sal_Int32 const nY, sal_Int32 const nWidth, sal_Int32 const nHeight) +{ + uno::Reference<awt::XToolkit> const xTk(xMSF->createInstance("com.sun.star.awt.Toolkit"), + uno::UNO_QUERY); + + awt::WindowDescriptor descriptor; + descriptor.Type = awt::WindowClass_TOP; + descriptor.WindowServiceName = "modelessdialog"; + descriptor.ParentIndex = -1; + descriptor.Bounds.X = nX; + descriptor.Bounds.Y = nY; + descriptor.Bounds.Width = nWidth; + descriptor.Bounds.Height = nHeight; + descriptor.WindowAttributes + = (awt::WindowAttribute::BORDER + awt::WindowAttribute::MOVEABLE + + awt::WindowAttribute::SIZEABLE + awt::WindowAttribute::CLOSEABLE + + awt::VclWindowPeerAttribute::CLIPCHILDREN); + + return xTk->createWindow(descriptor); +} + +/** + * Not really a check, + * only a simple test call to convertSizeToLogic(...) with different parameters + */ +void checkSize(uno::Reference<awt::XUnitConversion> const& xConv, awt::Size const& rSize, + sal_Int16 const nMeasureUnit, OUString const& rUnit) +{ + awt::Size const aSizeIn = xConv->convertSizeToLogic(rSize, nMeasureUnit); + std::cerr << "Window size:\n"; + std::cerr << "Width: " << aSizeIn.Width << " " << rUnit << "\n"; + std::cerr << "Height: " << aSizeIn.Height << " " << rUnit << "\n"; +} + +/** + * The real test function + * 2. try to create an empty window + * 3. try to convert the WindowPeer to an XWindow + * 4. try to resize and move the window to another position, so we get a well knowing position and size. + * 5. run some more tests + */ +void ToolkitTest::testXUnitConversion() +{ +#ifdef _WIN32 + HKEY hkey; + DWORD type; + DWORD data; + DWORD size(sizeof(data)); + LONG ret = ::RegOpenKeyW(HKEY_CURRENT_USER, L"Control Panel\\Desktop", &hkey); + if (ret == ERROR_SUCCESS) + { + ret = ::RegQueryValueExW(hkey, L"LogPixels", nullptr, &type, + reinterpret_cast<LPBYTE>(&data), &size); + if (ret == ERROR_SUCCESS && type == REG_DWORD && data != 96) + { + std::cerr << "non-default resolution, skipping textXUnitConversion\n"; + return; + } + } +#endif + + // create a window + sal_Int32 x = 100; + sal_Int32 y = 100; + sal_Int32 width = 640; + sal_Int32 height = 480; + uno::Reference<awt::XWindowPeer> const xWindowPeer + = createFloatingWindow(getMultiServiceFactory(), x, y, width, height); + CPPUNIT_ASSERT(xWindowPeer.is()); + + // resize and move the window to a well known position and size + uno::Reference<awt::XWindow> const xWindow(xWindowPeer, uno::UNO_QUERY); + CPPUNIT_ASSERT(xWindow.is()); + + xWindow->setVisible(true); + + awt::Rectangle aRect = xWindow->getPosSize(); + awt::Point aPoint(aRect.X, aRect.Y); + awt::Size aSize(aRect.Width, aRect.Height); + + std::cerr << "Window position and size in pixel:\n"; + std::cerr << "X: " << aPoint.X << "\n"; + std::cerr << "Y: " << aPoint.Y << "\n"; + std::cerr << "Width: " << aSize.Width << "\n"; + std::cerr << "Height: " << aSize.Height << "\n"; + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Window size wrong", width, aSize.Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Window size wrong", height, aSize.Height); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Window pos wrong", x, aPoint.X); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Window pos wrong", y, aPoint.Y); + + uno::Reference<awt::XUnitConversion> const xConv(xWindowPeer, uno::UNO_QUERY); + + // try to get the position of the window in 1/100mm with the XUnitConversion method + awt::Point const aPointInMM_100TH + = xConv->convertPointToLogic(aPoint, util::MeasureUnit::MM_100TH); + std::cerr << "Window position:\n"; + std::cerr << "X: " << aPointInMM_100TH.X << " 1/100mm\n"; + std::cerr << "Y: " << aPointInMM_100TH.Y << " 1/100mm\n"; + + // try to get the size of the window in 1/100mm with the XUnitConversion method + awt::Size const aSizeInMM_100TH = xConv->convertSizeToLogic(aSize, util::MeasureUnit::MM_100TH); + std::cerr << "Window size:\n"; + std::cerr << "Width: " << aSizeInMM_100TH.Width << " 1/100mm\n"; + std::cerr << "Height: " << aSizeInMM_100TH.Height << " 1/100mm\n"; + + // try to get the size of the window in 1/10mm with the XUnitConversion method + awt::Size const aSizeInMM_10TH = xConv->convertSizeToLogic(aSize, util::MeasureUnit::MM_10TH); + std::cerr << "Window size:\n"; + std::cerr << "Width: " << aSizeInMM_10TH.Width << " 1/10mm\n"; + std::cerr << "Height: " << aSizeInMM_10TH.Height << " 1/10mm\n"; + + // check the size with a delta which must be smaller a given difference + CPPUNIT_ASSERT_MESSAGE("Size.Width not correct", + std::abs(aSizeInMM_100TH.Width - aSizeInMM_10TH.Width * 10) < 10); + CPPUNIT_ASSERT_MESSAGE("Size.Height not correct", + std::abs(aSizeInMM_100TH.Height - aSizeInMM_10TH.Height * 10) < 10); + + // new + checkSize(xConv, aSize, util::MeasureUnit::PIXEL, "pixel"); + checkSize(xConv, aSize, util::MeasureUnit::APPFONT, "appfont"); + checkSize(xConv, aSize, util::MeasureUnit::SYSFONT, "sysfont"); + + // simply check some more parameters + checkSize(xConv, aSize, util::MeasureUnit::MM, "mm"); + checkSize(xConv, aSize, util::MeasureUnit::CM, "cm"); + checkSize(xConv, aSize, util::MeasureUnit::INCH_1000TH, "1/1000inch"); + checkSize(xConv, aSize, util::MeasureUnit::INCH_100TH, "1/100inch"); + checkSize(xConv, aSize, util::MeasureUnit::INCH_10TH, "1/10inch"); + checkSize(xConv, aSize, util::MeasureUnit::INCH, "inch"); + checkSize(xConv, aSize, util::MeasureUnit::POINT, "point"); + checkSize(xConv, aSize, util::MeasureUnit::TWIP, "twip"); + + // convert the 1/100mm window size back to pixel + awt::Size const aNewSize + = xConv->convertSizeToPixel(aSizeInMM_100TH, util::MeasureUnit::MM_100TH); + std::cerr << "Window size:\n"; + std::cerr << "Width: " << aNewSize.Width << " pixel\n"; + std::cerr << "Height: " << aNewSize.Height << " pixel\n"; + + // assure the pixels are the same as we already know + CPPUNIT_ASSERT_EQUAL_MESSAGE("failed: Size from pixel to 1/100mm to pixel", aNewSize.Width, + aSize.Width); + CPPUNIT_ASSERT_EQUAL_MESSAGE("failed: Size from pixel to 1/100mm to pixel", aNewSize.Height, + aSize.Height); + + // close the window. + xWindow->dispose(); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(ToolkitTest); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/AccessibilityTools.cxx b/toolkit/qa/cppunit/a11y/AccessibilityTools.cxx new file mode 100644 index 000000000..572f82e62 --- /dev/null +++ b/toolkit/qa/cppunit/a11y/AccessibilityTools.cxx @@ -0,0 +1,515 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#include "AccessibilityTools.hxx" + +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> + +#include <sal/log.hxx> +#include <vcl/scheduler.hxx> +#include <vcl/timer.hxx> + +using namespace css; + +/* FIXME: mostly copied from sw/qa/extras/accessibility/accessible_relation_set.cxx */ +css::uno::Reference<css::accessibility::XAccessibleContext> +AccessibilityTools::getAccessibleObjectForRole( + const css::uno::Reference<css::accessibility::XAccessible>& xacc, sal_Int16 role) +{ + css::uno::Reference<css::accessibility::XAccessibleContext> ac = xacc->getAccessibleContext(); + bool isShowing + = ac->getAccessibleStateSet()->contains(accessibility::AccessibleStateType::SHOWING); + + if ((ac->getAccessibleRole() == role) && isShowing) + { + return ac; + } + else + { + int count = ac->getAccessibleChildCount(); + + for (int i = 0; i < count && i < AccessibilityTools::MAX_CHILDREN; i++) + { + css::uno::Reference<css::accessibility::XAccessibleContext> ac2 + = AccessibilityTools::getAccessibleObjectForRole(ac->getAccessibleChild(i), role); + if (ac2.is()) + return ac2; + } + } + return nullptr; +} +/* FIXME: end copy */ + +bool AccessibilityTools::equals(const uno::Reference<accessibility::XAccessible>& xacc1, + const uno::Reference<accessibility::XAccessible>& xacc2) +{ + if (!xacc1.is() || !xacc2.is()) + return xacc1.is() == xacc2.is(); + return equals(xacc1->getAccessibleContext(), xacc2->getAccessibleContext()); +} + +bool AccessibilityTools::equals(const uno::Reference<accessibility::XAccessibleContext>& xctx1, + const uno::Reference<accessibility::XAccessibleContext>& xctx2) +{ + if (!xctx1.is() || !xctx2.is()) + return xctx1.is() == xctx2.is(); + + if (xctx1->getAccessibleRole() != xctx2->getAccessibleRole()) + return false; + + if (xctx1->getAccessibleName() != xctx2->getAccessibleName()) + return false; + + if (xctx1->getAccessibleDescription() != xctx2->getAccessibleDescription()) + return false; + + if (xctx1->getAccessibleChildCount() != xctx2->getAccessibleChildCount()) + return false; + + /* this one was not in the Java version */ + if (xctx1->getAccessibleIndexInParent() != xctx2->getAccessibleIndexInParent()) + return false; + + return equals(xctx1->getAccessibleParent(), xctx2->getAccessibleParent()); +} + +bool AccessibilityTools::equals(const uno::Reference<accessibility::XAccessibleStateSet>& xsts1, + const uno::Reference<accessibility::XAccessibleStateSet>& xsts2) +{ + if (!xsts1.is() || !xsts2.is()) + return xsts1.is() == xsts2.is(); + return xsts1->getStates() == xsts2->getStates(); +} + +OUString AccessibilityTools::getRoleName(const sal_Int16 role) +{ + switch (role) + { + case accessibility::AccessibleRole::UNKNOWN: + return "UNKNOWN"; + case accessibility::AccessibleRole::ALERT: + return "ALERT"; + case accessibility::AccessibleRole::BUTTON_DROPDOWN: + return "BUTTON_DROPDOWN"; + case accessibility::AccessibleRole::BUTTON_MENU: + return "BUTTON_MENU"; + case accessibility::AccessibleRole::CANVAS: + return "CANVAS"; + case accessibility::AccessibleRole::CAPTION: + return "CAPTION"; + case accessibility::AccessibleRole::CHART: + return "CHART"; + case accessibility::AccessibleRole::CHECK_BOX: + return "CHECK_BOX"; + case accessibility::AccessibleRole::CHECK_MENU_ITEM: + return "CHECK_MENU_ITEM"; + case accessibility::AccessibleRole::COLOR_CHOOSER: + return "COLOR_CHOOSER"; + case accessibility::AccessibleRole::COLUMN_HEADER: + return "COLUMN_HEADER"; + case accessibility::AccessibleRole::COMBO_BOX: + return "COMBO_BOX"; + case accessibility::AccessibleRole::COMMENT: + return "COMMENT"; + case accessibility::AccessibleRole::COMMENT_END: + return "COMMENT_END"; + case accessibility::AccessibleRole::DATE_EDITOR: + return "DATE_EDITOR"; + case accessibility::AccessibleRole::DESKTOP_ICON: + return "DESKTOP_ICON"; + case accessibility::AccessibleRole::DESKTOP_PANE: + return "DESKTOP_PANE"; + case accessibility::AccessibleRole::DIALOG: + return "DIALOG"; + case accessibility::AccessibleRole::DIRECTORY_PANE: + return "DIRECTORY_PANE"; + case accessibility::AccessibleRole::DOCUMENT: + return "DOCUMENT"; + case accessibility::AccessibleRole::DOCUMENT_PRESENTATION: + return "DOCUMENT_PRESENTATION"; + case accessibility::AccessibleRole::DOCUMENT_SPREADSHEET: + return "DOCUMENT_SPREADSHEET"; + case accessibility::AccessibleRole::DOCUMENT_TEXT: + return "DOCUMENT_TEXT"; + case accessibility::AccessibleRole::EDIT_BAR: + return "EDIT_BAR"; + case accessibility::AccessibleRole::EMBEDDED_OBJECT: + return "EMBEDDED_OBJECT"; + case accessibility::AccessibleRole::END_NOTE: + return "END_NOTE"; + case accessibility::AccessibleRole::FILE_CHOOSER: + return "FILE_CHOOSER"; + case accessibility::AccessibleRole::FILLER: + return "FILLER"; + case accessibility::AccessibleRole::FONT_CHOOSER: + return "FONT_CHOOSER"; + case accessibility::AccessibleRole::FOOTER: + return "FOOTER"; + case accessibility::AccessibleRole::FOOTNOTE: + return "FOOTNOTE"; + case accessibility::AccessibleRole::FORM: + return "FORM"; + case accessibility::AccessibleRole::FRAME: + return "FRAME"; + case accessibility::AccessibleRole::GLASS_PANE: + return "GLASS_PANE"; + case accessibility::AccessibleRole::GRAPHIC: + return "GRAPHIC"; + case accessibility::AccessibleRole::GROUP_BOX: + return "GROUP_BOX"; + case accessibility::AccessibleRole::HEADER: + return "HEADER"; + case accessibility::AccessibleRole::HEADING: + return "HEADING"; + case accessibility::AccessibleRole::HYPER_LINK: + return "HYPER_LINK"; + case accessibility::AccessibleRole::ICON: + return "ICON"; + case accessibility::AccessibleRole::IMAGE_MAP: + return "IMAGE_MAP"; + case accessibility::AccessibleRole::INTERNAL_FRAME: + return "INTERNAL_FRAME"; + case accessibility::AccessibleRole::LABEL: + return "LABEL"; + case accessibility::AccessibleRole::LAYERED_PANE: + return "LAYERED_PANE"; + case accessibility::AccessibleRole::LIST: + return "LIST"; + case accessibility::AccessibleRole::LIST_ITEM: + return "LIST_ITEM"; + case accessibility::AccessibleRole::MENU: + return "MENU"; + case accessibility::AccessibleRole::MENU_BAR: + return "MENU_BAR"; + case accessibility::AccessibleRole::MENU_ITEM: + return "MENU_ITEM"; + case accessibility::AccessibleRole::NOTE: + return "NOTE"; + case accessibility::AccessibleRole::OPTION_PANE: + return "OPTION_PANE"; + case accessibility::AccessibleRole::PAGE: + return "PAGE"; + case accessibility::AccessibleRole::PAGE_TAB: + return "PAGE_TAB"; + case accessibility::AccessibleRole::PAGE_TAB_LIST: + return "PAGE_TAB_LIST"; + case accessibility::AccessibleRole::PANEL: + return "PANEL"; + case accessibility::AccessibleRole::PARAGRAPH: + return "PARAGRAPH"; + case accessibility::AccessibleRole::PASSWORD_TEXT: + return "PASSWORD_TEXT"; + case accessibility::AccessibleRole::POPUP_MENU: + return "POPUP_MENU"; + case accessibility::AccessibleRole::PROGRESS_BAR: + return "PROGRESS_BAR"; + case accessibility::AccessibleRole::PUSH_BUTTON: + return "PUSH_BUTTON"; + case accessibility::AccessibleRole::RADIO_BUTTON: + return "RADIO_BUTTON"; + case accessibility::AccessibleRole::RADIO_MENU_ITEM: + return "RADIO_MENU_ITEM"; + case accessibility::AccessibleRole::ROOT_PANE: + return "ROOT_PANE"; + case accessibility::AccessibleRole::ROW_HEADER: + return "ROW_HEADER"; + case accessibility::AccessibleRole::RULER: + return "RULER"; + case accessibility::AccessibleRole::SCROLL_BAR: + return "SCROLL_BAR"; + case accessibility::AccessibleRole::SCROLL_PANE: + return "SCROLL_PANE"; + case accessibility::AccessibleRole::SECTION: + return "SECTION"; + case accessibility::AccessibleRole::SEPARATOR: + return "SEPARATOR"; + case accessibility::AccessibleRole::SHAPE: + return "SHAPE"; + case accessibility::AccessibleRole::SLIDER: + return "SLIDER"; + case accessibility::AccessibleRole::SPIN_BOX: + return "SPIN_BOX"; + case accessibility::AccessibleRole::SPLIT_PANE: + return "SPLIT_PANE"; + case accessibility::AccessibleRole::STATIC: + return "STATIC"; + case accessibility::AccessibleRole::STATUS_BAR: + return "STATUS_BAR"; + case accessibility::AccessibleRole::TABLE: + return "TABLE"; + case accessibility::AccessibleRole::TABLE_CELL: + return "TABLE_CELL"; + case accessibility::AccessibleRole::TEXT: + return "TEXT"; + case accessibility::AccessibleRole::TEXT_FRAME: + return "TEXT_FRAME"; + case accessibility::AccessibleRole::TOGGLE_BUTTON: + return "TOGGLE_BUTTON"; + case accessibility::AccessibleRole::TOOL_BAR: + return "TOOL_BAR"; + case accessibility::AccessibleRole::TOOL_TIP: + return "TOOL_TIP"; + case accessibility::AccessibleRole::TREE: + return "TREE"; + case accessibility::AccessibleRole::TREE_ITEM: + return "TREE_ITEM"; + case accessibility::AccessibleRole::TREE_TABLE: + return "TREE_TABLE"; + case accessibility::AccessibleRole::VIEW_PORT: + return "VIEW_PORT"; + case accessibility::AccessibleRole::WINDOW: + return "WINDOW"; + }; + return "unknown"; +} + +OUString AccessibilityTools::getStateName(const sal_Int16 state) +{ + switch (state) + { + case accessibility::AccessibleStateType::ACTIVE: + return "ACTIVE"; + case accessibility::AccessibleStateType::ARMED: + return "ARMED"; + case accessibility::AccessibleStateType::BUSY: + return "BUSY"; + case accessibility::AccessibleStateType::CHECKED: + return "CHECKED"; + case accessibility::AccessibleStateType::COLLAPSE: + return "COLLAPSE"; + case accessibility::AccessibleStateType::DEFAULT: + return "DEFAULT"; + case accessibility::AccessibleStateType::DEFUNC: + return "DEFUNC"; + case accessibility::AccessibleStateType::EDITABLE: + return "EDITABLE"; + case accessibility::AccessibleStateType::ENABLED: + return "ENABLED"; + case accessibility::AccessibleStateType::EXPANDABLE: + return "EXPANDABLE"; + case accessibility::AccessibleStateType::EXPANDED: + return "EXPANDED"; + case accessibility::AccessibleStateType::FOCUSABLE: + return "FOCUSABLE"; + case accessibility::AccessibleStateType::FOCUSED: + return "FOCUSED"; + case accessibility::AccessibleStateType::HORIZONTAL: + return "HORIZONTAL"; + case accessibility::AccessibleStateType::ICONIFIED: + return "ICONIFIED"; + case accessibility::AccessibleStateType::INDETERMINATE: + return "INDETERMINATE"; + case accessibility::AccessibleStateType::INVALID: + return "INVALID"; + case accessibility::AccessibleStateType::MANAGES_DESCENDANTS: + return "MANAGES_DESCENDANTS"; + case accessibility::AccessibleStateType::MODAL: + return "MODAL"; + case accessibility::AccessibleStateType::MOVEABLE: + return "MOVEABLE"; + case accessibility::AccessibleStateType::MULTI_LINE: + return "MULTI_LINE"; + case accessibility::AccessibleStateType::MULTI_SELECTABLE: + return "MULTI_SELECTABLE"; + case accessibility::AccessibleStateType::OFFSCREEN: + return "OFFSCREEN"; + case accessibility::AccessibleStateType::OPAQUE: + return "OPAQUE"; + case accessibility::AccessibleStateType::PRESSED: + return "PRESSED"; + case accessibility::AccessibleStateType::RESIZABLE: + return "RESIZABLE"; + case accessibility::AccessibleStateType::SELECTABLE: + return "SELECTABLE"; + case accessibility::AccessibleStateType::SELECTED: + return "SELECTED"; + case accessibility::AccessibleStateType::SENSITIVE: + return "SENSITIVE"; + case accessibility::AccessibleStateType::SHOWING: + return "SHOWING"; + case accessibility::AccessibleStateType::SINGLE_LINE: + return "SINGLE_LINE"; + case accessibility::AccessibleStateType::STALE: + return "STALE"; + case accessibility::AccessibleStateType::TRANSIENT: + return "TRANSIENT"; + case accessibility::AccessibleStateType::VERTICAL: + return "VERTICAL"; + case accessibility::AccessibleStateType::VISIBLE: + return "VISIBLE"; + } + return "unknown"; +} + +OUString AccessibilityTools::getEventIdName(const sal_Int16 event_id) +{ + switch (event_id) + { + case accessibility::AccessibleEventId::ACTION_CHANGED: + return "ACTION_CHANGED"; + case accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + return "ACTIVE_DESCENDANT_CHANGED"; + case accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS: + return "ACTIVE_DESCENDANT_CHANGED_NOFOCUS"; + case accessibility::AccessibleEventId::BOUNDRECT_CHANGED: + return "BOUNDRECT_CHANGED"; + case accessibility::AccessibleEventId::CARET_CHANGED: + return "CARET_CHANGED"; + case accessibility::AccessibleEventId::CHILD: + return "CHILD"; + case accessibility::AccessibleEventId::COLUMN_CHANGED: + return "COLUMN_CHANGED"; + case accessibility::AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED: + return "CONTENT_FLOWS_FROM_RELATION_CHANGED"; + case accessibility::AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED: + return "CONTENT_FLOWS_TO_RELATION_CHANGED"; + case accessibility::AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED: + return "CONTROLLED_BY_RELATION_CHANGED"; + case accessibility::AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED: + return "CONTROLLER_FOR_RELATION_CHANGED"; + case accessibility::AccessibleEventId::DESCRIPTION_CHANGED: + return "DESCRIPTION_CHANGED"; + case accessibility::AccessibleEventId::HYPERTEXT_CHANGED: + return "HYPERTEXT_CHANGED"; + case accessibility::AccessibleEventId::INVALIDATE_ALL_CHILDREN: + return "INVALIDATE_ALL_CHILDREN"; + case accessibility::AccessibleEventId::LABELED_BY_RELATION_CHANGED: + return "LABELED_BY_RELATION_CHANGED"; + case accessibility::AccessibleEventId::LABEL_FOR_RELATION_CHANGED: + return "LABEL_FOR_RELATION_CHANGED"; + case accessibility::AccessibleEventId::LISTBOX_ENTRY_COLLAPSED: + return "LISTBOX_ENTRY_COLLAPSED"; + case accessibility::AccessibleEventId::LISTBOX_ENTRY_EXPANDED: + return "LISTBOX_ENTRY_EXPANDED"; + case accessibility::AccessibleEventId::MEMBER_OF_RELATION_CHANGED: + return "MEMBER_OF_RELATION_CHANGED"; + case accessibility::AccessibleEventId::NAME_CHANGED: + return "NAME_CHANGED"; + case accessibility::AccessibleEventId::PAGE_CHANGED: + return "PAGE_CHANGED"; + case accessibility::AccessibleEventId::ROLE_CHANGED: + return "ROLE_CHANGED"; + case accessibility::AccessibleEventId::SECTION_CHANGED: + return "SECTION_CHANGED"; + case accessibility::AccessibleEventId::SELECTION_CHANGED: + return "SELECTION_CHANGED"; + case accessibility::AccessibleEventId::SELECTION_CHANGED_ADD: + return "SELECTION_CHANGED_ADD"; + case accessibility::AccessibleEventId::SELECTION_CHANGED_REMOVE: + return "SELECTION_CHANGED_REMOVE"; + case accessibility::AccessibleEventId::SELECTION_CHANGED_WITHIN: + return "SELECTION_CHANGED_WITHIN"; + case accessibility::AccessibleEventId::STATE_CHANGED: + return "STATE_CHANGED"; + case accessibility::AccessibleEventId::SUB_WINDOW_OF_RELATION_CHANGED: + return "SUB_WINDOW_OF_RELATION_CHANGED"; + case accessibility::AccessibleEventId::TABLE_CAPTION_CHANGED: + return "TABLE_CAPTION_CHANGED"; + case accessibility::AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED: + return "TABLE_COLUMN_DESCRIPTION_CHANGED"; + case accessibility::AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED: + return "TABLE_COLUMN_HEADER_CHANGED"; + case accessibility::AccessibleEventId::TABLE_MODEL_CHANGED: + return "TABLE_MODEL_CHANGED"; + case accessibility::AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED: + return "TABLE_ROW_DESCRIPTION_CHANGED"; + case accessibility::AccessibleEventId::TABLE_ROW_HEADER_CHANGED: + return "TABLE_ROW_HEADER_CHANGED"; + case accessibility::AccessibleEventId::TABLE_SUMMARY_CHANGED: + return "TABLE_SUMMARY_CHANGED"; + case accessibility::AccessibleEventId::TEXT_ATTRIBUTE_CHANGED: + return "TEXT_ATTRIBUTE_CHANGED"; + case accessibility::AccessibleEventId::TEXT_CHANGED: + return "TEXT_CHANGED"; + case accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED: + return "TEXT_SELECTION_CHANGED"; + case accessibility::AccessibleEventId::VALUE_CHANGED: + return "VALUE_CHANGED"; + case accessibility::AccessibleEventId::VISIBLE_DATA_CHANGED: + return "VISIBLE_DATA_CHANGED"; + } + return "unknown"; +} + +OUString AccessibilityTools::debugName(accessibility::XAccessibleContext* ctx) +{ + return "role=" + AccessibilityTools::getRoleName(ctx->getAccessibleRole()) + " name=\"" + + ctx->getAccessibleName() + "\" description=\"" + ctx->getAccessibleDescription() + + "\""; +} + +OUString AccessibilityTools::debugName(accessibility::XAccessible* acc) +{ + return debugName(acc->getAccessibleContext().get()); +} + +OUString AccessibilityTools::debugName(accessibility::XAccessibleStateSet* xsts) +{ + OUString name; + + for (auto state : xsts->getStates()) + { + if (name.getLength()) + name += " | "; + name += AccessibilityTools::getStateName(state); + } + + return name; +} + +OUString AccessibilityTools::debugName(const accessibility::AccessibleEventObject* evobj) +{ + return "(AccessibleEventObject) { id=" + getEventIdName(evobj->EventId) + + " old=" + evobj->OldValue.getValueTypeName() + + " new=" + evobj->NewValue.getValueTypeName() + " }"; +} + +bool AccessibilityTools::Await(const std::function<bool()>& cUntilCallback, sal_uInt64 nTimeoutMs) +{ + bool success = false; + Timer aTimer("wait for event"); + aTimer.SetTimeout(nTimeoutMs); + aTimer.Start(); + do + { + Scheduler::ProcessEventsToIdle(); + success = cUntilCallback(); + } while (!success && aTimer.IsActive()); + SAL_WARN_IF(!success, "test", "timeout reached"); + return success; +} + +void AccessibilityTools::Wait(sal_uInt64 nTimeoutMs) +{ + Timer aTimer("wait for event"); + aTimer.SetTimeout(nTimeoutMs); + aTimer.Start(); + std::cout << "waiting for " << nTimeoutMs << "ms... "; + do + { + Scheduler::ProcessEventsToIdle(); + } while (aTimer.IsActive()); + std::cout << "ok." << std::endl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/AccessibilityTools.hxx b/toolkit/qa/cppunit/a11y/AccessibilityTools.hxx new file mode 100644 index 000000000..a16338a85 --- /dev/null +++ b/toolkit/qa/cppunit/a11y/AccessibilityTools.hxx @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#pragma once + +#include <functional> +#include <string> + +#include <cppunit/TestAssert.h> + +#include <com/sun/star/accessibility/AccessibleEventObject.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleStateSet.hpp> + +class AccessibilityTools +{ +public: + /** Maximum number of children to work on. This is especially useful for + * Calc which has a million elements, if not more. */ + static const sal_Int32 MAX_CHILDREN = 500; + + static css::uno::Reference<css::accessibility::XAccessibleContext> + getAccessibleObjectForRole(const css::uno::Reference<css::accessibility::XAccessible>& xacc, + sal_Int16 role); + + static bool equals(const css::uno::Reference<css::accessibility::XAccessible>& xacc1, + const css::uno::Reference<css::accessibility::XAccessible>& xacc2); + static bool equals(const css::uno::Reference<css::accessibility::XAccessibleContext>& xctx1, + const css::uno::Reference<css::accessibility::XAccessibleContext>& xctx2); + static bool equals(const css::uno::Reference<css::accessibility::XAccessibleStateSet>& xsts1, + const css::uno::Reference<css::accessibility::XAccessibleStateSet>& xsts2); + + static OUString getRoleName(const sal_Int16 role); + static OUString getStateName(const sal_Int16 state); + static OUString getEventIdName(const sal_Int16 event_id); + + template <typename T> static std::string debugString(const css::uno::Reference<T>& x) + { + return debugString(x.get()); + } + + template <typename T> static std::string debugString(const T& x) { return debugString(&x); } + + template <typename T> static std::string debugString(const T* p) + { + /* only the forwarding to debugName() might actually dereference @c p, + * and we rely on specializations to be as constant as possible and not + * violate the cast here. In practice it'll be the case for all types + * handle if we carefully write the specializations. In most case the + * specialization could take a const itself if the methods were + * properly marked const, but well. */ + return debugString(const_cast<T*>(p)); + } + + template <typename T> static std::string debugString(T* p) + { + CPPUNIT_NS::OStringStream ost; + + ost << "(" << static_cast<const void*>(p) << ")"; + if (p != nullptr) + ost << " " << debugName(p); + + return ost.str(); + } + + /** + * @brief Process events until a condition or a timeout + * @param cUntilCallback Callback condition + * @param nTimeoutMs Maximum time in ms to wait for condition + * @returns @c true if the condition was met, or @c false if the timeout + * has been reached. + * + * Processes events until idle, and either until the given condition + * becomes @c true or a timeout is reached. + * + * This is similar to Scheduler::ProcessEventsToIdle() but awaits a + * condition up to a timeout. This is useful if the waited-on condition + * might happen after the first idle time. The timeout helps in case the + * condition is not satisfied in reasonable time. + * + * @p cUntilCallback is called each time the scheduler reaches idle to check + * whether the condition is met. + * + * Example: + * @code + * ProcessEvents([&]() { return taskHasRun; }); + * @endcode + * + * @see Scheduler::ProcessEventsToIdle() + */ + static bool Await(const std::function<bool()>& cUntilCallback, sal_uInt64 nTimeoutMs = 3000); + + /** + * @brief Process events for a given time + * @param nTimeoutMs Time to dispatch events for + * + * Process events for a given time. This can be useful if waiting is in + * order but there is no actual condition to wait on (e.g. expect + * something *not* to happen). This similar in spirit to + * @c sleep(nTimeoutMs), but dispatches events during the wait. + * + * This function should be used sparsely because waiting a given time is + * rarely a good solution for a problem, but in some specific situations + * there is no better alternative (like, again, waiting for something not + * to happen). + */ + static void Wait(sal_uInt64 nTimeoutMs); + +private: + static OUString debugName(css::accessibility::XAccessibleContext* xctx); + static OUString debugName(css::accessibility::XAccessible* xacc); + static OUString debugName(css::accessibility::XAccessibleStateSet* xsts); + static OUString debugName(const css::accessibility::AccessibleEventObject* evobj); +}; + +CPPUNIT_NS_BEGIN +/* How to generate those automatically? We don't want to match all types + * not to mess up cppunit for types we don't support */ +#define AT_ASSERTION_TRAITS(T) \ + template <> struct assertion_traits<css::uno::Reference<T>> \ + { \ + static bool equal(const css::uno::Reference<T>& x, const css::uno::Reference<T>& y) \ + { \ + return AccessibilityTools::equals(x, y); \ + } \ + \ + static std::string toString(const css::uno::Reference<T>& x) \ + { \ + return AccessibilityTools::debugString(x); \ + } \ + } + +AT_ASSERTION_TRAITS(css::accessibility::XAccessible); +AT_ASSERTION_TRAITS(css::accessibility::XAccessibleContext); +AT_ASSERTION_TRAITS(css::accessibility::XAccessibleStateSet); + +#undef AT_ASSERTION_TRAITS + +CPPUNIT_NS_END + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/AccessibleStatusBarTest.cxx b/toolkit/qa/cppunit/a11y/AccessibleStatusBarTest.cxx new file mode 100644 index 000000000..822223a74 --- /dev/null +++ b/toolkit/qa/cppunit/a11y/AccessibleStatusBarTest.cxx @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#include <string> + +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/awt/XTopWindow.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/util/XCloseable.hpp> + +#include <comphelper/sequence.hxx> +#include <rtl/ustrbuf.hxx> +#include <test/bootstrapfixture.hxx> +#include <vcl/scheduler.hxx> + +#include "AccessibilityTools.hxx" +#include "XAccessibleComponentTester.hxx" +#include "XAccessibleContextTester.hxx" +#include "XAccessibleExtendedComponentTester.hxx" +#include "XAccessibleEventBroadcasterTester.hxx" + +using namespace css; + +namespace +{ +class AccessibleStatusBarTest : public test::BootstrapFixture +{ +private: + uno::Reference<frame::XDesktop2> mxDesktop; + + uno::Reference<accessibility::XAccessibleContext> + getTestObject(const uno::Reference<awt::XWindow>& xWindow); + void runAllTests(const uno::Reference<awt::XWindow>& xWindow); + uno::Reference<lang::XComponent> openDocument(std::string_view sKind); + void testDocument(std::string_view sKind); + + void testWriterDoc() { testDocument("swriter"); } + void testMathDoc() { testDocument("smath"); } + void testDrawDoc() { testDocument("sdraw"); } + void testImpressDoc() { testDocument("simpress"); } + void testCalcDoc() { testDocument("scalc"); } + +public: + virtual void setUp() override; + + CPPUNIT_TEST_SUITE(AccessibleStatusBarTest); + CPPUNIT_TEST(testWriterDoc); + CPPUNIT_TEST(testMathDoc); + CPPUNIT_TEST(testDrawDoc); + CPPUNIT_TEST(testImpressDoc); + CPPUNIT_TEST(testCalcDoc); + CPPUNIT_TEST_SUITE_END(); +}; + +void AccessibleStatusBarTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop = frame::Desktop::create(mxComponentContext); +} + +uno::Reference<accessibility::XAccessibleContext> +AccessibleStatusBarTest::getTestObject(const uno::Reference<awt::XWindow>& xWindow) +{ + uno::Reference<accessibility::XAccessible> xAccessible(xWindow, uno::UNO_QUERY_THROW); + std::cout << "got accessible: " << xAccessible << std::endl; + std::cout << "accessible name: " << AccessibilityTools::debugString(xAccessible) << std::endl; + + auto xContext = AccessibilityTools::getAccessibleObjectForRole( + xAccessible, accessibility::AccessibleRole::STATUS_BAR); + std::cout << "got context: " << xContext << std::endl; + std::cout << "context name: " << AccessibilityTools::debugString(xContext) << std::endl; + + Scheduler::ProcessEventsToIdle(); // not sure why? + + uno::Reference<lang::XServiceInfo> xSI(xContext, uno::UNO_QUERY_THROW); + std::cout << "implementation name: " << xSI->getImplementationName() << std::endl; + auto serviceNames = xSI->getSupportedServiceNames(); + std::cout << "has " << serviceNames.size() << " services:" << std::endl; + for (auto& service : serviceNames) + std::cout << " * service: " << service << std::endl; + + return xContext; +} + +void AccessibleStatusBarTest::runAllTests(const uno::Reference<awt::XWindow>& xWindow) +{ + auto xContext = getTestObject(xWindow); + + uno::Reference<accessibility::XAccessibleComponent> xAccessibleComponent(xContext, + uno::UNO_QUERY_THROW); + XAccessibleComponentTester componentTester(xAccessibleComponent); + componentTester.testAll(); + + XAccessibleContextTester contextTester(xContext); + contextTester.testAll(); + + uno::Reference<accessibility::XAccessibleExtendedComponent> xAccessibleExtendedComponent( + xContext, uno::UNO_QUERY_THROW); + XAccessibleExtendedComponentTester extendedComponentTester(xAccessibleExtendedComponent); + extendedComponentTester.testAll(); + + uno::Reference<accessibility::XAccessibleEventBroadcaster> xAccessibleEventBroadcaster( + xContext, uno::UNO_QUERY_THROW); + XAccessibleEventBroadcasterTester eventBroadcasterTester(xAccessibleEventBroadcaster, xWindow); + eventBroadcasterTester.testAll(); +} + +uno::Reference<lang::XComponent> AccessibleStatusBarTest::openDocument(std::string_view sKind) +{ + /* not sure what's that about, but from SOfficeFactory.java:openDoc() */ + // that noargs thing for load attributes + std::vector<beans::PropertyValue> aArgs; + if (sKind == "simpress") + { + beans::PropertyValue aValue; + aValue.Name = "OpenFlags"; + aValue.Handle = -1; + aValue.Value <<= OUString("S"); + aValue.State = beans::PropertyState_DIRECT_VALUE; + aArgs.push_back(aValue); + } + + rtl::OUStringBuffer sURL("private:factory/"); + sURL.appendAscii(sKind.data(), sKind.length()); + + return mxDesktop->loadComponentFromURL(sURL.makeStringAndClear(), "_blank", 40, + comphelper::containerToSequence(aArgs)); +} + +void AccessibleStatusBarTest::testDocument(std::string_view sKind) +{ + auto xDoc = openDocument(sKind); + std::cout << "got document: " << xDoc << std::endl; + CPPUNIT_ASSERT(xDoc.is()); + uno::Reference<frame::XModel> xModel(xDoc, uno::UNO_QUERY_THROW); + std::cout << "got model: " << xModel << std::endl; + uno::Reference<awt::XWindow> xWindow( + xModel->getCurrentController()->getFrame()->getContainerWindow()); + std::cout << "got window: " << xWindow << std::endl; + uno::Reference<awt::XTopWindow> xTopWindow(xWindow, uno::UNO_QUERY_THROW); + std::cout << "got top window: " << xTopWindow << std::endl; + xTopWindow->toFront(); + + Scheduler::ProcessEventsToIdle(); + + runAllTests(xWindow); + + // close document + uno::Reference<css::util::XCloseable> xCloseable(xDoc, uno::UNO_QUERY_THROW); + xCloseable->close(false); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(AccessibleStatusBarTest); +} // namespace + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/XAccessibleComponentTester.cxx b/toolkit/qa/cppunit/a11y/XAccessibleComponentTester.cxx new file mode 100644 index 000000000..ea46ff778 --- /dev/null +++ b/toolkit/qa/cppunit/a11y/XAccessibleComponentTester.cxx @@ -0,0 +1,290 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#include "XAccessibleComponentTester.hxx" + +#include <cppunit/TestAssert.h> + +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/uno/Reference.hxx> + +#include <tools/color.hxx> + +#include "AccessibilityTools.hxx" + +using namespace css; + +/** + * @brief Checks the component's bounds + * + * Checks the X and Y coordinates are non-negative, and that the width and + * height are greater than 0. + * + * Coherence with @c getLocation() is tested in the test for the + * latter. + */ +void XAccessibleComponentTester::testBounds() +{ + auto bounds = mxComponent->getBounds(); + std::cout << "bounds: " << bounds.Width << "x" << bounds.Height << std::showpos << bounds.X + << bounds.Y << std::noshowpos << std::endl; + CPPUNIT_ASSERT_GREATEREQUAL(static_cast<sal_Int32>(0), bounds.X); + CPPUNIT_ASSERT_GREATEREQUAL(static_cast<sal_Int32>(0), bounds.Y); + CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32>(0), bounds.Width); + CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32>(0), bounds.Height); +} + +/** + * @brief Tests results of XAccessibleComponent::getSize() + * + * Succeeds if the size is the same as in bounds. + */ +void XAccessibleComponentTester::testSize() +{ + auto bounds = mxComponent->getBounds(); + auto size = mxComponent->getSize(); + CPPUNIT_ASSERT_EQUAL(bounds.Width, size.Width); + CPPUNIT_ASSERT_EQUAL(bounds.Height, size.Height); +} + +/** + * @brief Tests results of XAccessibleComponent::getBounds() + * + * First checks 4 inner bounds (upper, lower, left and right) of component + * bounding box to contain at least one point of the component. Second 4 outer + * bounds are checked to not contain any component points. + * + * Succeeds if inner bounds contain component points and outer bounds don't + * contain any component points. + */ +void XAccessibleComponentTester::testContainsPoint() +{ + auto bounds = mxComponent->getBounds(); + + /* upper end */ + int curX = 0; + while (!mxComponent->containsPoint(awt::Point(curX, 0)) && curX < bounds.Width) + curX++; + CPPUNIT_ASSERT_MESSAGE("Upper bound of box contains no component points", curX < bounds.Width); + std::cout << "Upper bound of box contains point (" << curX << ",0)" << std::endl; + /* lower end */ + curX = 0; + while (!mxComponent->containsPoint(awt::Point(curX, bounds.Height - 1)) && curX < bounds.Width) + curX++; + CPPUNIT_ASSERT_MESSAGE("Lower bound of box contains no component points", curX < bounds.Width); + std::cout << "Lower bound of box contains point (" << curX << "," << (bounds.Height - 1) << ")" + << std::endl; + /* left end */ + int curY = 0; + while (!mxComponent->containsPoint(awt::Point(0, curY)) && curY < bounds.Height) + curY++; + CPPUNIT_ASSERT_MESSAGE("Left bound of box contains no component points", curY < bounds.Height); + std::cout << "Left bound of box contains point (0," << curY << ")" << std::endl; + /* right end */ + curY = 0; + while (!mxComponent->containsPoint(awt::Point(bounds.Width - 1, curY)) && curY < bounds.Height) + curY++; + CPPUNIT_ASSERT_MESSAGE("Right bound of box contains no component points", curY < bounds.Height); + std::cout << "Right bound of box contains point (" << (bounds.Width - 1) << "," << curY << ")" + << std::endl; + /* no match outside the bounds */ + for (int x = -1; x <= bounds.Width; x++) + { + CPPUNIT_ASSERT_MESSAGE("Outer upper bound CONTAINS a component point", + !mxComponent->containsPoint(awt::Point(x, -1))); + CPPUNIT_ASSERT_MESSAGE("Outer lower bound CONTAINS a component point", + !mxComponent->containsPoint(awt::Point(x, bounds.Height))); + } + for (int y = -1; y <= bounds.Height; y++) + { + CPPUNIT_ASSERT_MESSAGE("Outer left bound CONTAINS a component point", + !mxComponent->containsPoint(awt::Point(-1, y))); + CPPUNIT_ASSERT_MESSAGE("Outer right bound CONTAINS a component point", + !mxComponent->containsPoint(awt::Point(bounds.Width, y))); + } +} + +/** + * @brief Tests results of XAccessibleComponent::getAccessibleAtPoint() + * + * Iterates through all children which implement + * <code>XAccessibleComponent</code> (if they exist) determines their + * boundaries and tries to get each child by <code>getAccessibleAtPoint</code> + * passing point which belongs to the child. + * Also the point is checked which doesn't belong to child boundary box. + * + * Succeeds if in the first cases the right children are returned, and in the + * second <code>null</code> or another child is returned. + */ +void XAccessibleComponentTester::testAccessibleAtPoint() +{ + int count = mxContext->getAccessibleChildCount(); + std::cout << "Found " << count << " children" << std::endl; + for (int i = 0; i < count && i < AccessibilityTools::MAX_CHILDREN; i++) + { + auto child = mxContext->getAccessibleChild(i); + uno::Reference<accessibility::XAccessibleContext> childContext( + child->getAccessibleContext(), uno::UNO_SET_THROW); + std::cout << "* Found child: " << AccessibilityTools::debugString(child) << std::endl; + std::cout << " states: " + << AccessibilityTools::debugString(childContext->getAccessibleStateSet()) + << std::endl; + uno::Reference<accessibility::XAccessibleComponent> xChildComponent(childContext, + uno::UNO_QUERY); + std::cout << " component: " << xChildComponent << std::endl; + if (!xChildComponent) + continue; + + auto childBounds = xChildComponent->getBounds(); + if (childBounds.X == -1) + continue; + std::cout << " bounds: " << childBounds.Width << "x" << childBounds.Height << std::showpos + << childBounds.X << childBounds.Y << std::noshowpos << std::endl; + + std::cout << "finding the point which lies on the component" << std::endl; + int curX = 0; + int curY = 0; + while (!xChildComponent->containsPoint(awt::Point(curX, curY)) && curX < childBounds.Width) + { + curX++; + curY++; + } + if (curX >= childBounds.Width) + { + std::cout << "Couldn't find a point with contains" << std::endl; + continue; + } + else + { + std::cout << "Child found at point +" << childBounds.X + curX << "+" + << childBounds.Y + curY << std::endl; + } + + // trying the point laying on child + auto xAccAtPoint + = mxComponent->getAccessibleAtPoint(awt::Point(childBounds.X, childBounds.Y)); + CPPUNIT_ASSERT_MESSAGE("Child not found at point", xAccAtPoint.is()); + if (!AccessibilityTools::equals(child, xAccAtPoint)) + { + auto idxExpected = childContext->getAccessibleIndexInParent(); + auto idxResult = xAccAtPoint->getAccessibleContext()->getAccessibleIndexInParent(); + std::cout << "The child found (" << AccessibilityTools::debugString(xAccAtPoint) + << ") is not the expected one (" << AccessibilityTools::debugString(child) + << ")" << std::endl; + if (idxExpected < idxResult) + { + std::cout << "-- it probably is hidden behind? Skipping." << std::endl; + } + else + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("The child found is NOT the expected one", child, + xAccAtPoint); + } + } + + // trying the point NOT laying on child + xAccAtPoint + = mxComponent->getAccessibleAtPoint(awt::Point(childBounds.X - 1, childBounds.Y - 1)); + if (xAccAtPoint.is()) + { + CPPUNIT_ASSERT_MESSAGE("Child found OUTSIDE its bounds", + !AccessibilityTools::equals(child, xAccAtPoint)); + } + } +} + +/** + * @brief Tests results of XAccessibleComponent::getLocation() + * + * Succeeds if the location is the same as location of boundary obtained by + * the <code>getBounds()</code> method. + */ +void XAccessibleComponentTester::testLocation() +{ + auto bounds = mxComponent->getBounds(); + auto location = mxComponent->getLocation(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalid X location", bounds.X, location.X); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalid Y location", bounds.Y, location.Y); +} + +/** + * @brief Tests results of XAccessibleComponent::getLocationOnScreen() + * @returns @c true on success. + * + * Get the screen location of the component and its parent + * (if it exists and supports <code>XAccessibleComponent</code>). + * + * Succeeds component screen location equals to screen location of its parent + * plus location of the component relative to the parent. + */ +void XAccessibleComponentTester::testLocationOnScreen() +{ + auto location = mxComponent->getLocationOnScreen(); + std::cout << "location on screen: +" << location.X << "+" << location.Y << std::endl; + + auto xParent = mxContext->getAccessibleParent(); + if (!xParent.is()) + std::cout << "No parent" << std::endl; + else + { + std::cout << "Found parent: " << AccessibilityTools::debugString(xParent) << std::endl; + uno::Reference<accessibility::XAccessibleComponent> xParentComponent( + xParent->getAccessibleContext(), uno::UNO_QUERY); + if (!xParentComponent.is()) + std::cout << "Parent is not a Component" << std::endl; + else + { + auto bounds = mxComponent->getBounds(); + auto parentLocation = xParentComponent->getLocationOnScreen(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalid X screen location", parentLocation.X + bounds.X, + location.X); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalid Y screen location", parentLocation.Y + bounds.Y, + location.Y); + } + } +} + +/** + * Just calls the method. + */ +void XAccessibleComponentTester::testGrabFocus() { mxComponent->grabFocus(); } + +/** + * Just calls the method. + */ +void XAccessibleComponentTester::testGetForeground() +{ + auto color = mxComponent->getForeground(); + std::cout << "foreground color: " << Color(ColorAlpha, color) << std::endl; +} + +/** + * Just calls the method. + */ +void XAccessibleComponentTester::testGetBackground() +{ + auto color = mxComponent->getBackground(); + std::cout << "background color: " << Color(ColorAlpha, color) << std::endl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/XAccessibleComponentTester.hxx b/toolkit/qa/cppunit/a11y/XAccessibleComponentTester.hxx new file mode 100644 index 000000000..ba84fbbac --- /dev/null +++ b/toolkit/qa/cppunit/a11y/XAccessibleComponentTester.hxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#pragma once + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> + +#include "AccessibilityTools.hxx" + +class XAccessibleComponentTester +{ +private: + const css::uno::Reference<css::accessibility::XAccessibleComponent> mxComponent; + const css::uno::Reference<css::accessibility::XAccessibleContext> mxContext; + +public: + XAccessibleComponentTester( + const css::uno::Reference<css::accessibility::XAccessibleComponent>& component) + : mxComponent(component) + , mxContext(component, css::uno::UNO_QUERY_THROW) + { + } + + void testBounds(); + void testSize(); + void testContainsPoint(); + void testAccessibleAtPoint(); + void testLocation(); + void testLocationOnScreen(); + void testGrabFocus(); + void testGetForeground(); + void testGetBackground(); + + void testAll() + { + testBounds(); + testSize(); + testContainsPoint(); + testAccessibleAtPoint(); + testLocation(); + testLocationOnScreen(); + testGrabFocus(); + testGetForeground(); + testGetBackground(); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/XAccessibleContextTester.cxx b/toolkit/qa/cppunit/a11y/XAccessibleContextTester.cxx new file mode 100644 index 000000000..b8c7898f9 --- /dev/null +++ b/toolkit/qa/cppunit/a11y/XAccessibleContextTester.cxx @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#include "XAccessibleContextTester.hxx" + +#include <cppunit/TestAssert.h> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> + +#include "AccessibilityTools.hxx" + +/** + * @brief Tries to get every child and checks its parent. + * + * Checks that the parent of every child and the tested component are the same object. + */ +void XAccessibleContextTester::testGetAccessibleChild() +{ + int count = mxContext->getAccessibleChildCount(); + for (int i = 0; i < count && i < AccessibilityTools::MAX_CHILDREN; i++) + { + auto child = mxContext->getAccessibleChild(i); + auto childCtx = child->getAccessibleContext(); + + std::cout << " Child " << i << ": " << AccessibilityTools::debugString(childCtx) + << std::endl; + + CPPUNIT_ASSERT_EQUAL_MESSAGE("child's parent context is not parent's context!", + childCtx->getAccessibleParent()->getAccessibleContext(), + mxContext); + } +} + +/** + * @brief Calls the method. + * + * Checks that the child count is non-negative. + */ +void XAccessibleContextTester::testGetAccessibleChildCount() +{ + auto childCount = mxContext->getAccessibleChildCount(); + std::cout << childCount << " children found." << std::endl; + CPPUNIT_ASSERT_GREATEREQUAL(static_cast<sal_Int32>(0), childCount); +} + +/** + * @brief Get the accessible description of the component. + */ +void XAccessibleContextTester::testGetAccessibleDescription() +{ + auto desc = mxContext->getAccessibleDescription(); + std::cout << "The description is '" << desc << "'" << std::endl; +} + +/** + * @brief Checks the index in parent + * + * Checks that the parent's child and the tested component are the same objects. + * + * Retrieves the index of tested component in its parent. + * Then gets the parent's child by this index and compares + * it with tested component. + */ +void XAccessibleContextTester::testGetAccessibleIndexInParent() +{ + int idx = mxContext->getAccessibleIndexInParent(); + std::cout << "The index in parent is " << idx << std::endl; + + auto parent = mxContext->getAccessibleParent(); + CPPUNIT_ASSERT(parent.is()); + auto parentCtx = parent->getAccessibleContext(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Parent's child context at our index is not us!", mxContext, + parentCtx->getAccessibleChild(idx)->getAccessibleContext()); +} + +/** + * @brief Get the accessible name of the component. + */ +void XAccessibleContextTester::testGetAccessibleName() +{ + auto name = mxContext->getAccessibleName(); + std::cout << "The name is '" << name << "'" << std::endl; +} + +/** + * @brief Just gets the parent. + * + * Checks that the parent is not null. + */ +void XAccessibleContextTester::testGetAccessibleParent() +{ + // assume that the component is not ROOT + auto parent = mxContext->getAccessibleParent(); + std::cout << "The parent is " << AccessibilityTools::debugString(parent) << std::endl; + CPPUNIT_ASSERT_MESSAGE("parent is not set", parent.is()); +} + +/** + * @brief Just gets the relation set. + * + * Checks that the relation set is not null. + */ +void XAccessibleContextTester::testGetAccessibleRelationSet() +{ + auto relSet = mxContext->getAccessibleRelationSet(); + CPPUNIT_ASSERT_MESSAGE("relation set is not set", relSet.is()); +} + +/** + * @brief Get the accessible role of component. + * + * Checks that the role is a non-negative number. + */ +void XAccessibleContextTester::testGetAccessibleRole() +{ + sal_Int32 role = mxContext->getAccessibleRole(); + std::cout << "The role is " << role << " (" << AccessibilityTools::getRoleName(role) << ")" + << std::endl; + CPPUNIT_ASSERT_GREATEREQUAL(static_cast<sal_Int32>(0), role); +} + +/** + * @brief Just gets the state set. + * + * Checks that the state set is not null. + */ +void XAccessibleContextTester::testGetAccessibleStateSet() +{ + auto stateSet = mxContext->getAccessibleStateSet(); + std::cout << "The state set is: " << AccessibilityTools::debugString(stateSet) << std::endl; + CPPUNIT_ASSERT_MESSAGE("state set is not set", stateSet.is()); +} + +/** + * @brief Gets the locale. + * + * Checks that @c Country and @c Language fields of locale structure are not empty. + */ +void XAccessibleContextTester::testGetLocale() +{ + auto loc = mxContext->getLocale(); + std::cout << "The locale is " << loc.Language << "," << loc.Country << std::endl; + CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32>(0), loc.Language.getLength()); + CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32>(0), loc.Country.getLength()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/XAccessibleContextTester.hxx b/toolkit/qa/cppunit/a11y/XAccessibleContextTester.hxx new file mode 100644 index 000000000..b399028cf --- /dev/null +++ b/toolkit/qa/cppunit/a11y/XAccessibleContextTester.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#pragma once + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> + +class XAccessibleContextTester +{ +protected: + const css::uno::Reference<css::accessibility::XAccessibleContext> mxContext; + +public: + XAccessibleContextTester(const css::uno::Reference<css::accessibility::XAccessibleContext>& ctx) + : mxContext(ctx) + { + } + + void testGetAccessibleChild(); + void testGetAccessibleChildCount(); + void testGetAccessibleDescription(); + void testGetAccessibleIndexInParent(); + void testGetAccessibleName(); + void testGetAccessibleParent(); + void testGetAccessibleRelationSet(); + void testGetAccessibleRole(); + void testGetAccessibleStateSet(); + void testGetLocale(); + + void testAll() + { + testGetAccessibleChild(); + testGetAccessibleChildCount(); + testGetAccessibleDescription(); + testGetAccessibleIndexInParent(); + testGetAccessibleName(); + testGetAccessibleParent(); + testGetAccessibleRelationSet(); + testGetAccessibleRole(); + testGetAccessibleStateSet(); + testGetLocale(); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/XAccessibleEventBroadcasterTester.cxx b/toolkit/qa/cppunit/a11y/XAccessibleEventBroadcasterTester.cxx new file mode 100644 index 000000000..80aa2c079 --- /dev/null +++ b/toolkit/qa/cppunit/a11y/XAccessibleEventBroadcasterTester.cxx @@ -0,0 +1,186 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#include "XAccessibleEventBroadcasterTester.hxx" + +#include <iostream> + +#include <cppunit/TestAssert.h> + +#include <com/sun/star/accessibility/AccessibleEventObject.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/lang/EventObject.hpp> + +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> +#include <sal/log.hxx> + +#include "AccessibilityTools.hxx" + +using namespace css; + +namespace +{ +class EvListener : public cppu::WeakImplHelper<accessibility::XAccessibleEventListener> +{ +public: + bool mbGotEvent; + + EvListener() + : mbGotEvent(false) + { + } + + // XEventListener + virtual void SAL_CALL disposing(const lang::EventObject&) override {} + + // XAccessibleEventListener + virtual void SAL_CALL notifyEvent(const accessibility::AccessibleEventObject& aEvent) override + { + std::cout << "Listener got event: " << AccessibilityTools::debugString(aEvent) << std::endl; + uno::Reference<accessibility::XAccessible> xOld(aEvent.OldValue, uno::UNO_QUERY); + if (xOld.is()) + std::cout << "Old: " << AccessibilityTools::debugString(xOld) << std::endl; + + uno::Reference<accessibility::XAccessible> xNew(aEvent.NewValue, uno::UNO_QUERY); + if (xNew.is()) + std::cout << "New: " << AccessibilityTools::debugString(xNew) << std::endl; + + mbGotEvent = true; + } +}; +} + +XAccessibleEventBroadcasterTester::XAccessibleEventBroadcasterTester( + const uno::Reference<accessibility::XAccessibleEventBroadcaster>& xBroadcaster, + const uno::Reference<awt::XWindow>& xWindow) + : mxBroadcaster(xBroadcaster) + , mxWindow(xWindow) +{ +} + +bool XAccessibleEventBroadcasterTester::isTransient( + const uno::Reference<accessibility::XAccessibleEventBroadcaster> xBroadcaster) +{ + uno::Reference<accessibility::XAccessibleContext> xCtx(xBroadcaster, uno::UNO_QUERY_THROW); + return isTransient(xCtx); +} + +bool XAccessibleEventBroadcasterTester::isTransient( + const uno::Reference<accessibility::XAccessibleContext> xCtx) +{ + return ( + xCtx->getAccessibleStateSet()->contains(accessibility::AccessibleStateType::TRANSIENT) + && xCtx->getAccessibleParent()->getAccessibleContext()->getAccessibleStateSet()->contains( + accessibility::AccessibleStateType::MANAGES_DESCENDANTS)); +} + +/** + * @brief Generates an event on @c mxBroadcaster. + * + * This method indirectly alters the state of @c mxBroadcaster so that an + * accessible event will be fired for it. It can be called as many times as + * needed and triggers an event each time. + */ +void XAccessibleEventBroadcasterTester::fireEvent() +{ + awt::Rectangle newPosSize = mxWindow->getPosSize(); + newPosSize.Width = newPosSize.Width - 20; + newPosSize.Height = newPosSize.Height - 20; + newPosSize.X = newPosSize.X + 20; + newPosSize.Y = newPosSize.Y + 20; + mxWindow->setPosSize(newPosSize.X, newPosSize.Y, newPosSize.Width, newPosSize.Height, + awt::PosSize::POSSIZE); +} + +/** + * @brief Adds a listener and fires events by mean of object relation. + * + * Asserts that the listener was properly called. + */ +void XAccessibleEventBroadcasterTester::testAddEventListener() +{ + rtl::Reference<EvListener> xListener(new EvListener); + mxBroadcaster->addAccessibleEventListener(xListener); + bool transient = isTransient(mxBroadcaster); + + std::cout << "firing event" << std::endl; + fireEvent(); + + AccessibilityTools::Await([&xListener]() { return xListener->mbGotEvent; }); + + if (!transient) + CPPUNIT_ASSERT_MESSAGE("listener wasn't called", xListener->mbGotEvent); + else + CPPUNIT_ASSERT_MESSAGE("Object is Transient, listener isn't expected to be called", + !xListener->mbGotEvent); + + mxBroadcaster->removeAccessibleEventListener(xListener); +} + +/** + * @brief Similar to @c testAddEventListener() but also removes the listener + * + * Adds an event listener just like @c testAddEventListener(), and then removes it and verifies an + * event doesn't trigger the supposedly removed listener. + * + * @see testAddEventListener() + */ +void XAccessibleEventBroadcasterTester::testRemoveEventListener() +{ + /* there is nothing we can really test for transient objects */ + if (isTransient(mxBroadcaster)) + { + std::cerr << "could not test removing listener on transient object " << mxBroadcaster + << std::endl; + return; + } + + rtl::Reference<EvListener> xListener(new EvListener); + mxBroadcaster->addAccessibleEventListener(xListener); + + std::cout << "firing event (with listener)" << std::endl; + fireEvent(); + + AccessibilityTools::Await([&xListener]() { return xListener->mbGotEvent; }); + + CPPUNIT_ASSERT_MESSAGE("listener wasn't called", xListener->mbGotEvent); + + /* reset listener, remove it and try again */ + xListener->mbGotEvent = false; + + std::cout << "removing listener" << std::endl; + mxBroadcaster->removeAccessibleEventListener(xListener); + + std::cout << "firing event (without listener)" << std::endl; + fireEvent(); + + AccessibilityTools::Wait(500); + + CPPUNIT_ASSERT_MESSAGE("removed listener was called", !xListener->mbGotEvent); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/XAccessibleEventBroadcasterTester.hxx b/toolkit/qa/cppunit/a11y/XAccessibleEventBroadcasterTester.hxx new file mode 100644 index 000000000..0fc7c23bd --- /dev/null +++ b/toolkit/qa/cppunit/a11y/XAccessibleEventBroadcasterTester.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#pragma once + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/awt/XWindow.hpp> + +class XAccessibleEventBroadcasterTester +{ +private: + const css::uno::Reference<css::accessibility::XAccessibleEventBroadcaster> mxBroadcaster; + const css::uno::Reference<css::awt::XWindow> mxWindow; + + static bool isTransient( + const css::uno::Reference<css::accessibility::XAccessibleEventBroadcaster> xBroadcaster); + static bool isTransient(const css::uno::Reference<css::accessibility::XAccessibleContext> xCtx); + + void fireEvent(); + +public: + XAccessibleEventBroadcasterTester( + const css::uno::Reference<css::accessibility::XAccessibleEventBroadcaster>& xBroadcaster, + const css::uno::Reference<css::awt::XWindow>& xWindow); + + void testAddEventListener(); + void testRemoveEventListener(); + + void testAll() + { + testAddEventListener(); + testRemoveEventListener(); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/XAccessibleExtendedComponentTester.cxx b/toolkit/qa/cppunit/a11y/XAccessibleExtendedComponentTester.cxx new file mode 100644 index 000000000..a7137c4ba --- /dev/null +++ b/toolkit/qa/cppunit/a11y/XAccessibleExtendedComponentTester.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#include "XAccessibleExtendedComponentTester.hxx" + +#include <iostream> + +#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp> + +/** + * @brief Just calls the method. + */ +void XAccessibleExtendedComponentTester::testGetFont() +{ + auto font = mxExtendedComponent->getFont(); + std::cout << "font: " << font << std::endl; +} + +/** + * @brief Just calls the method. + */ +void XAccessibleExtendedComponentTester::testGetTitledBorderText() +{ + auto titleBorderText = mxExtendedComponent->getTitledBorderText(); + std::cout << "getTitledBorderText(): '" << titleBorderText << "'" << std::endl; +} + +/** + * @brief Just calls the method. + */ +void XAccessibleExtendedComponentTester::testGetToolTipText() +{ + auto toolTipText = mxExtendedComponent->getToolTipText(); + std::cout << "getToolTipText(): '" << toolTipText << "'" << std::endl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/cppunit/a11y/XAccessibleExtendedComponentTester.hxx b/toolkit/qa/cppunit/a11y/XAccessibleExtendedComponentTester.hxx new file mode 100644 index 000000000..129705282 --- /dev/null +++ b/toolkit/qa/cppunit/a11y/XAccessibleExtendedComponentTester.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ + +#pragma once + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp> + +class XAccessibleExtendedComponentTester +{ +protected: + const css::uno::Reference<css::accessibility::XAccessibleExtendedComponent> mxExtendedComponent; + +public: + XAccessibleExtendedComponentTester( + const css::uno::Reference<css::accessibility::XAccessibleExtendedComponent>& + extendedComponent) + : mxExtendedComponent(extendedComponent) + { + } + + void testGetFont(); + void testGetTitledBorderText(); + void testGetToolTipText(); + + void testAll() + { + testGetFont(); + testGetTitledBorderText(); + testGetToolTipText(); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/toolkit/qa/unoapi/knownissues.xcl b/toolkit/qa/unoapi/knownissues.xcl new file mode 100644 index 000000000..7a2f95577 --- /dev/null +++ b/toolkit/qa/unoapi/knownissues.xcl @@ -0,0 +1,259 @@ +# +# 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 . +# + +### i86545 ### +toolkit.AccessibleToolBoxItem::com::sun::star::accessibility::XAccessibleText + +### i30818 ### +toolkit.AccessibleToolBox::com::sun::star::accessibility::XAccessibleEventBroadcaster + +### i68852 ### +toolkit.TabControllerModel::com::sun::star::io::XPersistObject + +### i79111 ### +toolkit.UnoControlButtonModel::com::sun::star::awt::UnoControlButtonModel + +### i79110 ### +toolkit.UnoControlCheckBoxModel::com::sun::star::awt::UnoControlCheckBoxModel + +### i84314 ### +toolkit.UnoControlImageControlModel::com::sun::star::awt::UnoControlImageControlModel + +### i86542 ### +toolkit.UnoControlProgressBarModel::com::sun::star::awt::UnoControlProgressBarModel + +### i86543 ### +toolkit.UnoControlRadioButtonModel::com::sun::star::awt::UnoControlRadioButtonModel + +### i79098 ### +toolkit.UnoControlScrollBarModel::com::sun::star::awt::UnoControlScrollBarModel + +### i86544 ### +toolkit.UnoTreeModel::com::sun::star::awt::tree::TreeControlModel + +### i74011 ### +toolkit.UnoControlDateField::com::sun::star::awt::XWindow +toolkit.UnoSpinButtonControl::com::sun::star::awt::XWindow +toolkit.UnoControlPatternField::com::sun::star::awt::XWindow +toolkit.UnoControlRadioButton::com::sun::star::awt::XWindow +toolkit.UnoControlButton::com::sun::star::awt::XWindow +toolkit.UnoControlTimeField::com::sun::star::awt::XWindow +toolkit.UnoControlFormattedField::com::sun::star::awt::XWindow +toolkit.UnoControlContainer::com::sun::star::awt::XWindow +toolkit.UnoControlGroupBox::com::sun::star::awt::XWindow +toolkit.UnoControlFixedText::com::sun::star::awt::XWindow +toolkit.UnoControlListBox::com::sun::star::awt::XWindow +toolkit.UnoControlImageControl::com::sun::star::awt::XWindow +toolkit.UnoControlDialog::com::sun::star::awt::XWindow +toolkit.UnoControlEdit::com::sun::star::awt::XWindow +toolkit.UnoControlCurrencyField::com::sun::star::awt::XWindow +toolkit.UnoControlFileControl::com::sun::star::awt::XWindow +toolkit.UnoControlComboBox::com::sun::star::awt::XWindow +toolkit.UnoControlNumericField::com::sun::star::awt::XWindow +toolkit.UnoControlCheckBox::com::sun::star::awt::XWindow +toolkit.UnoScrollBarControl::com::sun::star::awt::XWindow + +### i86296 ### +toolkit.UnoControlContainerModel::com::sun::star::awt::UnoControlContainerModel + +### i86297 ### +toolkit.UnoControlFixedTextModel::com::sun::star::awt::UnoControlFixedTextModel + +### i86299 ### +toolkit.UnoTreeModel::com::sun::star::awt::UnoControlModel + +### i86300 ### +toolkit.UnoTreeModel::com::sun::star::beans::XMultiPropertySet + +### i86007 ### +toolkit.AccessibleButton +# -> disabled in toolkit.sce + +### i86008 ### +toolkit.AccessibleComboBox +# -> disabled in toolkit.sce + +### i86110 ### +toolkit.AccessibleEdit +toolkit.AccessibleList +toolkit.AccessibleListBox +toolkit.AccessibleListItem +toolkit.AccessibleRadioButton +# -> disabled in toolkit.sce + +### i86009 ### +toolkit.AccessibleMenuItem +# -> disabled in toolkit.sce + +### i86107 ### +toolkit.AccessibleRadioButton +# -> disabled in toolkit.sce + +### i86287 ### +toolkit.AccessibleToolBox +# -> disabled in toolkit.sce + +### i86011 ### +toolkit.UnoControlFileControl +# -> disabled in toolkit.sce + +### i86013 ### +toolkit.UnoControlFormattedField +# -> disabled in toolkit.sce + +### i86019 ### +toolkit.UnoControlListBox +# -> disabled in toolkit.sce + +### i86298 ### +toolkit.UnoTreeControl +# -> disabled in toolkit.sce + +### i52607 ### +toolkit.AccessiblePopupMenu +# -> disabled in toolkit.sce + +### i86660 ### +toolkit.UnoControlDateField::com::sun::star::awt::XView +toolkit.UnoSpinButtonControl::com::sun::star::awt::XView +toolkit.UnoControlPatternField::com::sun::star::awt::XView +toolkit.UnoControlRadioButton::com::sun::star::awt::XView +toolkit.UnoControlButton::com::sun::star::awt::XView +toolkit.UnoControlTimeField::com::sun::star::awt::XView +toolkit.UnoControlFormattedField::com::sun::star::awt::XView +toolkit.UnoControlGroupBox::com::sun::star::awt::XView +toolkit.UnoControlContainer::com::sun::star::awt::XView +toolkit.UnoControlFixedText::com::sun::star::awt::XView +toolkit.UnoControlListBox::com::sun::star::awt::XView +toolkit.UnoControlEdit::com::sun::star::awt::XView +toolkit.UnoControlImageControl::com::sun::star::awt::XView +toolkit.UnoControlDialog::com::sun::star::awt::XView +toolkit.UnoControlFileControl::com::sun::star::awt::XView +toolkit.UnoControlCurrencyField::com::sun::star::awt::XView +toolkit.UnoControlComboBox::com::sun::star::awt::XView +toolkit.UnoControlNumericField::com::sun::star::awt::XView +toolkit.UnoControlCheckBox::com::sun::star::awt::XView +toolkit.UnoScrollBarControl::com::sun::star::awt::XView + +### i37643 ### +toolkit.AccessibleStatusBarItem::com::sun::star::accessibility::XAccessibleEventBroadcaster + +### i87864 ### +toolkit.UnoControlContainerModel::com::sun::star::lang::XComponent +toolkit.UnoTreeModel::com::sun::star::lang::XComponent +toolkit.UnoControlTimeFieldModel::com::sun::star::lang::XComponent +toolkit.UnoControlDateField::com::sun::star::lang::XComponent +toolkit.UnoControlButtonModel::com::sun::star::lang::XComponent +toolkit.UnoControlPatternFieldModel::com::sun::star::lang::XComponent +toolkit.UnoSpinButtonControl::com::sun::star::lang::XComponent +toolkit.UnoControlDateFieldModel::com::sun::star::lang::XComponent +toolkit.UnoControlPatternField::com::sun::star::lang::XComponent +toolkit.UnoControlRadioButtonModel::com::sun::star::lang::XComponent +toolkit.UnoControlFormattedFieldModel::com::sun::star::lang::XComponent +toolkit.UnoControlRadioButton::com::sun::star::lang::XComponent +toolkit.UnoControlButton::com::sun::star::lang::XComponent +toolkit.UnoControlTimeField::com::sun::star::lang::XComponent +toolkit.UnoControlFormattedField::com::sun::star::lang::XComponent +toolkit.UnoControlFixedLineModel::com::sun::star::lang::XComponent +toolkit.UnoControlDialogModel::com::sun::star::lang::XComponent +toolkit.UnoControlFileControlModel::com::sun::star::lang::XComponent +toolkit.UnoControlGroupBox::com::sun::star::lang::XComponent +toolkit.UnoControlContainer::com::sun::star::lang::XComponent +toolkit.UnoControlFixedText::com::sun::star::lang::XComponent +toolkit.UnoControlListBox::com::sun::star::lang::XComponent +toolkit.UnoControlCheckBoxModel::com::sun::star::lang::XComponent +toolkit.UnoControlEditModel::com::sun::star::lang::XComponent +toolkit.UnoControlEdit::com::sun::star::lang::XComponent +toolkit.UnoControlImageControl::com::sun::star::lang::XComponent +toolkit.UnoControlDialog::com::sun::star::lang::XComponent +toolkit.UnoControlGroupBoxModel::com::sun::star::lang::XComponent +toolkit.UnoControlImageControlModel::com::sun::star::lang::XComponent +toolkit.UnoControlNumericFieldModel::com::sun::star::lang::XComponent +toolkit.UnoControlFileControl::com::sun::star::lang::XComponent +toolkit.UnoControlCurrencyField::com::sun::star::lang::XComponent +toolkit.UnoControlComboBoxModel::com::sun::star::lang::XComponent +toolkit.UnoControlComboBox::com::sun::star::lang::XComponent +toolkit.UnoControlNumericField::com::sun::star::lang::XComponent +toolkit.UnoControlScrollBarModel::com::sun::star::lang::XComponent +toolkit.UnoControlProgressBarModel::com::sun::star::lang::XComponent +toolkit.UnoControlListBoxModel::com::sun::star::lang::XComponent +toolkit.UnoControlFixedTextModel::com::sun::star::lang::XComponent +toolkit.UnoSpinButtonControlModel::com::sun::star::lang::XComponent +toolkit.UnoControlCurrencyFieldModel::com::sun::star::lang::XComponent +toolkit.UnoControlCheckBox::com::sun::star::lang::XComponent +toolkit.UnoScrollBarControl::com::sun::star::lang::XComponent + +### i89415 ### +toolkit.UnoControlContainer::com::sun::star::awt::XControl + +### i89417 ### +toolkit.UnoControlContainer::com::sun::star::accessibility::XAccessible + +### i89418 ### +toolkit.UnoSpinButtonControl::com::sun::star::awt::XSpinValue + +### i88332 ### +toolkit.AccessibleCheckBox +# -> disabled in toolkit.sce + +### i88605 ### +toolkit.AccessibleToolBoxItem +# -> disabled in toolkit.sce + +### i89019 ### +toolkit.AccessibleWindow::com::sun::star::accessibility::XAccessibleEventBroadcaster + +### i90354 ### +toolkit.AccessibleScrollBar::com::sun::star::accessibility::XAccessibleComponent + +### i90356 ### +toolkit.UnoScrollBarControl::com::sun::star::awt::XScrollBar + +### i94344 ### +toolkit.AccessibleTabPage::com::sun::star::accessibility::XAccessibleText + +### i109643 ### +toolkit.AccessibleMenu::com::sun::star::accessibility::XAccessibleValue +toolkit.AccessibleMenuBar::com::sun::star::accessibility::XAccessibleEventBroadcaster +toolkit.AccessibleMenuBar::com::sun::star::accessibility::XAccessibleSelection + +### i111113 ### +toolkit.AccessibleStatusBarItem::com::sun::star::accessibility::XAccessibleComponent +toolkit.AccessibleStatusBarItem::com::sun::star::accessibility::XAccessibleContext + +### i111195 ### +toolkit.AccessibleScrollBar::com::sun::star::accessibility::XAccessibleValue + +### i113489 ### +toolkit.AccessibleMenu::com::sun::star::accessibility::XAccessibleText +toolkit.AccessibleMenuBar::com::sun::star::accessibility::XAccessibleComponent +toolkit.AccessibleMenuSeparator::com::sun::star::accessibility::XAccessibleComponent + +### i114213 ### +toolkit.AccessibleMenu::com::sun::star::accessibility::XAccessibleSelection + +### i114636 ### +toolkit.AccessibleScrollBar::com::sun::star::accessibility::XAccessibleAction +toolkit.AccessibleScrollBar::com::sun::star::accessibility::XAccessibleContext +toolkit.AccessibleScrollBar::com::sun::star::accessibility::XAccessibleEventBroadcaster + +### fd#35666 ### +toolkit.UnoControlDialogModel::com::sun::star::io::XPersistObject + +### fd#35772 ### +toolkit.Toolkit::com::sun::star::awt::XMessageBoxFactory diff --git a/toolkit/qa/unoapi/testdocuments/poliball.gif b/toolkit/qa/unoapi/testdocuments/poliball.gif Binary files differnew file mode 100644 index 000000000..dda461bd3 --- /dev/null +++ b/toolkit/qa/unoapi/testdocuments/poliball.gif diff --git a/toolkit/qa/unoapi/toolkit_1.sce b/toolkit/qa/unoapi/toolkit_1.sce new file mode 100644 index 000000000..3cee05dc3 --- /dev/null +++ b/toolkit/qa/unoapi/toolkit_1.sce @@ -0,0 +1,40 @@ +# +# 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 . +# + +#i86007 -o toolkit.AccessibleButton +#i88332 -o toolkit.AccessibleCheckBox +#i86008 -o toolkit.AccessibleComboBox +-o toolkit.AccessibleDropDownComboBox +-o toolkit.AccessibleDropDownListBox +#i86110 -o toolkit.AccessibleEdit +-o toolkit.AccessibleFixedText +#i86110 -o toolkit.AccessibleList +#i86110 -o toolkit.AccessibleListBox +#i86110 -o toolkit.AccessibleListItem +-o toolkit.AccessibleMenu +-o toolkit.AccessibleMenuBar +#i86009 -o toolkit.AccessibleMenuItem +-o toolkit.AccessibleMenuSeparator +#i52607 -o toolkit.AccessiblePopupMenu +#i86107,i86110 -o toolkit.AccessibleRadioButton +-o toolkit.AccessibleScrollBar +-o toolkit.AccessibleStatusBarItem +#i109643 -o toolkit.AccessibleTabControl +#i109643 -o toolkit.AccessibleTabPage +#i86287 -o toolkit.AccessibleToolBox +#i88605 -o toolkit.AccessibleToolBoxItem diff --git a/toolkit/qa/unoapi/toolkit_2.sce b/toolkit/qa/unoapi/toolkit_2.sce new file mode 100644 index 000000000..2c5957f34 --- /dev/null +++ b/toolkit/qa/unoapi/toolkit_2.sce @@ -0,0 +1,36 @@ +# +# 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 toolkit.AccessibleWindow +-o toolkit.MutableTreeDataModel +-o toolkit.MutableTreeNode +-o toolkit.TabController +-o toolkit.TabControllerModel +-o toolkit.Toolkit +-o toolkit.UnoControlButton +-o toolkit.UnoControlButtonModel +-o toolkit.UnoControlCheckBox +-o toolkit.UnoControlCheckBoxModel +-o toolkit.UnoControlComboBox +-o toolkit.UnoControlComboBoxModel +-o toolkit.UnoControlContainer +-o toolkit.UnoControlContainerModel +-o toolkit.UnoControlCurrencyField +-o toolkit.UnoControlCurrencyFieldModel +-o toolkit.UnoControlDateField +-o toolkit.UnoControlDateFieldModel diff --git a/toolkit/qa/unoapi/toolkit_3.sce b/toolkit/qa/unoapi/toolkit_3.sce new file mode 100644 index 000000000..91f07709e --- /dev/null +++ b/toolkit/qa/unoapi/toolkit_3.sce @@ -0,0 +1,37 @@ +# +# 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 . +# + +#allegedly was i80788, but still broken: -o toolkit.UnoControlDialog +-o toolkit.UnoControlDialogModel +-o toolkit.UnoControlEdit +-o toolkit.UnoControlEditModel +#i86011 -o toolkit.UnoControlFileControl +-o toolkit.UnoControlFileControlModel +-o toolkit.UnoControlFixedLineModel +-o toolkit.UnoControlFixedText +-o toolkit.UnoControlFixedTextModel +#i86013 -o toolkit.UnoControlFormattedField +-o toolkit.UnoControlFormattedFieldModel +-o toolkit.UnoControlGroupBox +-o toolkit.UnoControlGroupBoxModel +-o toolkit.UnoControlImageControl +-o toolkit.UnoControlImageControlModel +#i86019 -o toolkit.UnoControlListBox +-o toolkit.UnoControlListBoxModel +-o toolkit.UnoControlNumericField +-o toolkit.UnoControlNumericFieldModel diff --git a/toolkit/qa/unoapi/toolkit_4.sce b/toolkit/qa/unoapi/toolkit_4.sce new file mode 100644 index 000000000..d8cdcbe38 --- /dev/null +++ b/toolkit/qa/unoapi/toolkit_4.sce @@ -0,0 +1,31 @@ +# +# 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 toolkit.UnoControlPatternField +-o toolkit.UnoControlPatternFieldModel +-o toolkit.UnoControlProgressBarModel +-o toolkit.UnoControlRadioButton +-o toolkit.UnoControlRadioButtonModel +-o toolkit.UnoControlScrollBarModel +-o toolkit.UnoControlTimeField +-o toolkit.UnoControlTimeFieldModel +-o toolkit.UnoScrollBarControl +-o toolkit.UnoSpinButtonControl +-o toolkit.UnoSpinButtonControlModel +#i86298 -o toolkit.UnoTreeControl +-o toolkit.UnoTreeModel |