/* * 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 .
*/
// 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 );
}
// 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 );
}
// 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 finalint 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 publicvoid 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() );
}
ColumnModelListener listener = new ColumnModelListener();
m_columnModel.addContainerListener( listener );
// insert default columns into the previously empty model, ensure we get the right notifications finalint 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); finalint 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 finalint 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); finalint 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); finalint index = impl_assertInteger( event.Accessor );
assertEquals( i, index );
}
// okay, remove all those columns while ( m_columnModel.getColumnCount() != 0 )
{ finalint columnCount = m_columnModel.getColumnCount(); finalint 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); finalint 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() ); finalint insertionIndex = impl_assertInteger( events.get(0).Accessor );
assertEquals( insertionIndex, newColumn.getIndex() );
}
// 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 ) );
}
}
}
finalint colCount = 3; finalint 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 : newboolean[] { 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 ); finalint currentIntValue = impl_assertInteger( currentValue ); final Object nextValue = m_dataModel.getCellData( colIndex, rowIndex + 1 ); finalint 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 ); finalint 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 publicvoid 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() );
// 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() );
}
// 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 );
privatevoid 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) ) );
}
}
privatevoid 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 ) );
}
}
}
privatevoid 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 );
}
}
privatevoid 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() );
}
}
}
privateboolean 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 );
}
privatestaticfinal OfficeConnection m_connection = new OfficeConnection(); privatestatic Random m_randomGenerator = new Random(); privatefinal XComponentContext m_context;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.