summaryrefslogtreecommitdiffstats
path: root/toolkit/qa/complex/toolkit/GridControl.java
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--toolkit/qa/complex/toolkit/GridControl.java746
1 files changed, 746 insertions, 0 deletions
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 >();
+}