1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 package complex.toolkit; 25 26 import com.sun.star.awt.XControl; 27 import com.sun.star.awt.XControlContainer; 28 import com.sun.star.awt.XControlModel; 29 import com.sun.star.awt.XToolkit; 30 import com.sun.star.awt.grid.DefaultGridDataModel; 31 import com.sun.star.awt.grid.XGridColumn; 32 import com.sun.star.awt.grid.XGridColumnModel; 33 import com.sun.star.awt.grid.XGridControl; 34 import com.sun.star.awt.grid.XGridDataModel; 35 import com.sun.star.awt.grid.XMutableGridDataModel; 36 import com.sun.star.awt.grid.XSortableMutableGridDataModel; 37 import com.sun.star.beans.Pair; 38 import com.sun.star.beans.XPropertySet; 39 import com.sun.star.container.ContainerEvent; 40 import com.sun.star.container.XContainerListener; 41 import com.sun.star.container.XNameContainer; 42 import com.sun.star.lang.EventObject; 43 import com.sun.star.lang.IndexOutOfBoundsException; 44 import com.sun.star.lang.XComponent; 45 import com.sun.star.lang.XEventListener; 46 import com.sun.star.lang.XMultiServiceFactory; 47 import com.sun.star.uno.Exception; 48 import com.sun.star.uno.UnoRuntime; 49 import com.sun.star.uno.XComponentContext; 50 import com.sun.star.uno.XInterface; 51 import com.sun.star.util.XCloneable; 52 import complex.toolkit.awtgrid.DummyColumn; 53 import complex.toolkit.awtgrid.TMutableGridDataModel; 54 import java.lang.reflect.Method; 55 import java.util.ArrayList; 56 import java.util.List; 57 import java.util.Random; 58 import org.junit.AfterClass; 59 import org.junit.BeforeClass; 60 import org.junit.After; 61 import org.junit.Before; 62 import org.junit.Test; 63 import static org.junit.Assert.*; 64 import org.openoffice.test.OfficeConnection; 65 66 /** is a unit test for the grid control related implementations 67 * @author frank.schoenheit@sun.com 68 */ 69 public class GridControl 70 { 71 // ----------------------------------------------------------------------------------------------------------------- GridControl()72 public GridControl() 73 { 74 m_context = m_connection.getComponentContext(); 75 } 76 77 // ----------------------------------------------------------------------------------------------------------------- impl_dispose( final Object... i_components )78 private static void impl_dispose( final Object... i_components ) 79 { 80 for ( int i=0; i<i_components.length; ++i ) 81 { 82 if ( i_components[i] != null ) 83 { 84 final XComponent component = UnoRuntime.queryInterface( XComponent.class, i_components[i] ); 85 component.dispose(); 86 } 87 } 88 } 89 90 // ----------------------------------------------------------------------------------------------------------------- impl_recreateGridModel()91 private void impl_recreateGridModel() throws Exception 92 { 93 impl_dispose( m_gridControlModel, m_columnModel, m_dataModel ); 94 95 // create a grid control model, and ensure it has a proper data and column model already 96 m_gridControlModel = UnoRuntime.queryInterface( XPropertySet.class, 97 createInstance( "com.sun.star.awt.grid.UnoControlGridModel" ) ); 98 assertNotNull( "grid control model does not provide XPropertySet interface", m_gridControlModel ); 99 100 // ensure that the model has default column/data models 101 m_columnModel = UnoRuntime.queryInterface( XGridColumnModel.class, m_gridControlModel.getPropertyValue( "ColumnModel" ) ); 102 assertNotNull( "the control model is expected to have an initial column model", m_columnModel ); 103 final XGridDataModel dataModel = UnoRuntime.queryInterface( XGridDataModel.class, m_gridControlModel.getPropertyValue( "GridDataModel" ) ); 104 assertNotNull( "the control model is expected to have an initial data model", dataModel ); 105 m_dataModel = UnoRuntime.queryInterface( XSortableMutableGridDataModel.class, 106 dataModel ); 107 assertNotNull( "the out-of-the-box data model should be mutable and sortable", m_dataModel ); 108 } 109 110 // ----------------------------------------------------------------------------------------------------------------- 111 @Test testGridControlCloning()112 public void testGridControlCloning() throws Exception 113 { 114 impl_recreateGridModel(); 115 116 // give the test something to compare, actually 117 XGridColumnModel columnModel = UnoRuntime.queryInterface( XGridColumnModel.class, 118 m_gridControlModel.getPropertyValue( "ColumnModel" ) ); 119 columnModel.setDefaultColumns( 10 ); 120 121 // clone the grid model 122 final XCloneable cloneable = UnoRuntime.queryInterface( XCloneable.class, m_gridControlModel ); 123 assertNotNull( "all UnoControlModel's are expected to be cloneable", cloneable ); 124 125 final XInterface clone = cloneable.createClone(); 126 final XPropertySet clonedProps = UnoRuntime.queryInterface( XPropertySet.class, clone ); 127 128 // TODO: check all those generic properties for equality 129 130 // the data model and the column model should have been cloned, too 131 // in particular, the clone should not share the sub models with the orignal 132 final XMutableGridDataModel originalDataModel = UnoRuntime.queryInterface( XMutableGridDataModel.class, 133 m_gridControlModel.getPropertyValue( "GridDataModel" ) ); 134 final XMutableGridDataModel clonedDataModel = UnoRuntime.queryInterface( XMutableGridDataModel.class, 135 clonedProps.getPropertyValue( "GridDataModel" ) ); 136 assertFalse( "data model should not be shared after cloning", UnoRuntime.areSame( originalDataModel, clonedDataModel ) ); 137 impl_assertEquality( originalDataModel, clonedDataModel ); 138 139 final XGridColumnModel originalColumnModel = columnModel; 140 final XGridColumnModel clonedColumnModel = UnoRuntime.queryInterface( XGridColumnModel.class, 141 clonedProps.getPropertyValue( "ColumnModel" ) ); 142 assertFalse( "column model should not be shared after cloning", UnoRuntime.areSame( originalColumnModel, clonedColumnModel ) ); 143 impl_assertEquality( originalColumnModel, clonedColumnModel ); 144 } 145 146 // ----------------------------------------------------------------------------------------------------------------- 147 @Test testDisposal()148 public void testDisposal() throws Exception 149 { 150 impl_recreateGridModel(); 151 152 final int columnCount = 3; 153 m_columnModel.setDefaultColumns( columnCount ); 154 155 // add disposal listeners to all columns so far 156 final XGridColumn[] columns = m_columnModel.getColumns(); 157 assertEquals( "creating default columns resulted in unexpected column count", columnCount, columns.length ); 158 final DisposeListener[] columnListeners = new DisposeListener[columnCount]; 159 for ( int i=0; i<columnCount; ++i ) 160 columnListeners[i] = new DisposeListener( columns[i] ); 161 162 // add another column, and check that upon removal, it is disposed 163 final int newColumnIndex = m_columnModel.addColumn( m_columnModel.createColumn() ); 164 final DisposeListener columnListener = new DisposeListener( m_columnModel.getColumn( newColumnIndex ) ); 165 m_columnModel.removeColumn( newColumnIndex ); 166 assertTrue( "explicit column removal is expected to dispose the column", columnListener.isDisposed() ); 167 168 // by definition, the grid control model is the owner of both the column and the data model. So, setting 169 // a new column/data model should implicitly dispose the old models 170 final DisposeListener oldDataModelListener = new DisposeListener( m_dataModel ); 171 final DisposeListener oldColumnModelListener = new DisposeListener( m_columnModel ); 172 173 final Object newDataModel = createInstance( "com.sun.star.awt.grid.DefaultGridDataModel" ); 174 final Object newColumnModel = createInstance( "com.sun.star.awt.grid.DefaultGridColumnModel" ); 175 final DisposeListener newDataModelListener = new DisposeListener( newDataModel ); 176 final DisposeListener newColumnModelListener = new DisposeListener( newColumnModel ); 177 178 m_gridControlModel.setPropertyValue( "GridDataModel", newDataModel ); 179 assertTrue( "setting a new data model failed", impl_areSameInterface( newDataModel, m_gridControlModel.getPropertyValue( "GridDataModel" ) ) ); 180 m_gridControlModel.setPropertyValue( "ColumnModel", newColumnModel ); 181 assertTrue( "setting a new column model failed", impl_areSameInterface( newColumnModel, m_gridControlModel.getPropertyValue( "ColumnModel" ) ) ); 182 183 assertTrue( "old data model has not been disposed", oldDataModelListener.isDisposed() ); 184 assertTrue( "old column model has not been disposed", oldColumnModelListener.isDisposed() ); 185 for ( int i=0; i<columnCount; ++i ) 186 assertTrue( "column no. " + i + " has not been disposed", columnListeners[i].isDisposed() ); 187 188 // the same holds if the grid control model itself is disposed - it should dispose the depending models, too 189 assertFalse( "new data model is already disposed - this is unexpected", newDataModelListener.isDisposed() ); 190 assertFalse( "new column model is already disposed - this is unexpected", newColumnModelListener.isDisposed() ); 191 impl_dispose( m_gridControlModel ); 192 assertTrue( "new data model is not disposed after disposing the grid column model", newDataModelListener.isDisposed() ); 193 assertTrue( "new column model is not disposed after disposing the grid column model", newColumnModelListener.isDisposed() ); 194 } 195 196 // ----------------------------------------------------------------------------------------------------------------- 197 /** 198 * tests various aspects of the <code>XMutableGridDataModel</code> interface 199 */ 200 @Test testMutableGridDataModel()201 public void testMutableGridDataModel() throws Exception 202 { 203 impl_recreateGridModel(); 204 205 TMutableGridDataModel test = new TMutableGridDataModel( m_dataModel ); 206 test.testAddRow(); 207 test.testAddRows(); 208 test.testInsertRow(); 209 test.testInsertRows(); 210 test.testRemoveRow(); 211 test.testRemoveAllRows(); 212 test.testUpdateCellData(); 213 test.testUpdateRowData(); 214 test.testUpdateRowHeading(); 215 test.cleanup(); 216 217 // a somehwat less straight-forward test: the data model is expected to implicitly increase its column count 218 // when you add a row which has more columns than currently known 219 final XMutableGridDataModel dataModel = DefaultGridDataModel.create( m_context ); 220 dataModel.addRow( 0, new Object[] { 1 } ); 221 assertEquals( "unexpected column count after adding the most simple row", 1, dataModel.getColumnCount() ); 222 dataModel.addRow( 1, new Object[] { 1, 2 } ); 223 assertEquals( "implicit extension of the column count doesn't work", 2, dataModel.getColumnCount() ); 224 } 225 226 // ----------------------------------------------------------------------------------------------------------------- 227 @Test testGridColumnModel()228 public void testGridColumnModel() throws Exception 229 { 230 impl_recreateGridModel(); 231 232 ColumnModelListener listener = new ColumnModelListener(); 233 m_columnModel.addContainerListener( listener ); 234 235 // insert default columns into the previously empty model, ensure we get the right notifications 236 final int defaultColumnsCount = 3; 237 m_columnModel.setDefaultColumns( defaultColumnsCount ); 238 impl_assertColumnModelConsistency(); 239 List< ContainerEvent > events = listener.assertExclusiveInsertionEvents(); 240 listener.reset(); 241 assertEquals( "wrong number of events fired by setDefaulColumns", defaultColumnsCount, events.size() ); 242 for ( int i=0; i<defaultColumnsCount; ++i ) 243 { 244 final ContainerEvent event = events.get(i); 245 final int index = impl_assertInteger( event.Accessor ); 246 assertEquals( "unexpected Accessor value in insert notification", i, index ); 247 assertTrue( "wrong column object notified in insert notification", 248 impl_areSameInterface( event.Element, m_columnModel.getColumn(i) ) ); 249 } 250 251 // insert some more default columns, ensure that all previously existing columns are removed 252 final int moreDefaultColumnsCount = 5; 253 m_columnModel.setDefaultColumns( moreDefaultColumnsCount ); 254 impl_assertColumnModelConsistency(); 255 assertEquals( "setting default columns is expected to remove all previously existing columns", 256 moreDefaultColumnsCount, m_columnModel.getColumnCount() ); 257 258 // in this situation, both removal and insertion events have been notified 259 final List< ContainerEvent > removalEvents = listener.getRemovalEvents(); 260 final List< ContainerEvent > insertionEvents = listener.getInsertionEvents(); 261 listener.reset(); 262 263 // for the removal events, check the indexes 264 assertEquals( "wrong number of columns removed (or notified) upon setting default columns", 265 defaultColumnsCount, removalEvents.size() ); 266 for ( int i=0; i<removalEvents.size(); ++i ) 267 { 268 final ContainerEvent event = removalEvents.get(i); 269 final int removedIndex = impl_assertInteger( event.Accessor ); 270 271 // The implementation is allowed to remove the columns from the beginning, in which case the 272 // index of the removed column must always be 0, since e.g. the second column has index 0 273 // after the first column (which previously had index 0) had been removed. 274 // Alternatively, the implementation is allowed to remove columns from the end, which means 275 // that the column index given in the event is steadily increasing. 276 assertTrue( "unexpected column removal event column index", 277 ( removedIndex == 0 ) || ( removedIndex == removalEvents.size() - 1 - i ) ); 278 } 279 280 // for the insertion events, check the indexes as well 281 assertEquals( "wrong number of insertion events when setting default columns over existing columns", 282 moreDefaultColumnsCount, insertionEvents.size() ); 283 for ( int i=0; i<insertionEvents.size(); ++i ) 284 { 285 final ContainerEvent event = insertionEvents.get(i); 286 final int index = impl_assertInteger( event.Accessor ); 287 assertEquals( i, index ); 288 } 289 290 // okay, remove all those columns 291 while ( m_columnModel.getColumnCount() != 0 ) 292 { 293 final int columnCount = m_columnModel.getColumnCount(); 294 final int removeColumnIndex = m_randomGenerator.nextInt( columnCount ); 295 m_columnModel.removeColumn( removeColumnIndex ); 296 events = listener.assertExclusiveRemovalEvents(); 297 listener.reset(); 298 assertEquals( "removing a single column should notify a single event", 1, events.size() ); 299 final ContainerEvent event = events.get(0); 300 final int removalIndex = impl_assertInteger( event.Accessor ); 301 assertEquals( "removing an arbitrary column does not notify the proper accessor", 302 removeColumnIndex, removalIndex ); 303 } 304 305 // calling addColumn with a column not created by the given model/implementatoion should not succeed 306 boolean caughtExpected = false; 307 try 308 { 309 m_columnModel.addColumn( new DummyColumn() ); 310 } 311 catch( final com.sun.star.lang.IllegalArgumentException e ) 312 { 313 assertTrue( impl_areSameInterface( e.Context, m_columnModel ) ); 314 caughtExpected = true; 315 } 316 assertTrue( "adding a dummy (self-implemented) grid column to the model should not succeed", caughtExpected ); 317 318 // adding a single column to the end should succeed, properly notify, and still be consistent 319 final XGridColumn newColumn = m_columnModel.createColumn(); 320 m_columnModel.addColumn( newColumn ); 321 impl_assertColumnModelConsistency(); 322 events = listener.assertExclusiveInsertionEvents(); 323 listener.reset(); 324 assertEquals( "addColumn notifies the wrong number of insertion events", 1, events.size() ); 325 final int insertionIndex = impl_assertInteger( events.get(0).Accessor ); 326 assertEquals( insertionIndex, newColumn.getIndex() ); 327 } 328 329 // ----------------------------------------------------------------------------------------------------------------- 330 @Test testDataModel()331 public void testDataModel() throws Exception 332 { 333 impl_recreateGridModel(); 334 335 // ensure that getCellData and getRowData have the same opinion on the data they deliver 336 final Object[][] data = new Object[][] { 337 new Object[] { 15, 17, 0 }, 338 new Object[] { 9, 8, 14 }, 339 new Object[] { 17, 2, 16 }, 340 new Object[] { 0, 7, 14 }, 341 new Object[] { 10, 16, 16 }, 342 }; 343 m_dataModel.addRows( new Object[ data.length ], data ); 344 345 for ( int row = 0; row < data.length; ++row ) 346 { 347 assertArrayEquals( "getRowData delivers wrong data in row " + row, data[row], m_dataModel.getRowData( row ) ); 348 for ( int col = 0; col < data[row].length; ++col ) 349 { 350 assertEquals( "getCellData delivers wrong data at position (" + col + ", " + row + ")", 351 data[row][col], m_dataModel.getCellData( col, row ) ); 352 } 353 } 354 } 355 356 // ----------------------------------------------------------------------------------------------------------------- 357 @Test testSortableDataModel()358 public void testSortableDataModel() throws Exception 359 { 360 impl_recreateGridModel(); 361 362 final int colCount = 3; 363 final int rowCount = 10; 364 // initialize with some data 365 final Object[][] data = new Object[][] { 366 new Object[] { 15, 17, 0 }, 367 new Object[] { 9, 8, 14 }, 368 new Object[] { 17, 2, 16 }, 369 new Object[] { 0, 7, 14 }, 370 new Object[] { 10, 16, 16 }, 371 new Object[] { 2, 8, 10 }, 372 new Object[] { 4, 8, 3 }, 373 new Object[] { 7, 9, 0 }, 374 new Object[] { 15, 6, 19 }, 375 new Object[] { 2, 14, 19 } 376 }; 377 final Object[] rowHeadings = new Object[] { 378 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 379 }; 380 // ensure consistency of the test data 381 assertEquals( rowHeadings.length, rowCount ); 382 assertEquals( data.length, rowCount ); 383 for ( Object[] rowData : data ) 384 assertEquals( rowData.length, colCount ); 385 386 // add the test data 387 m_dataModel.addRows( rowHeadings, data ); 388 assertEquals( rowCount, m_dataModel.getRowCount() ); 389 assertEquals( colCount, m_dataModel.getColumnCount() ); 390 391 // sort by each column 392 for ( int colIndex = 0; colIndex < colCount; ++colIndex ) 393 { 394 for ( boolean ascending : new boolean[] { true, false } ) 395 { 396 m_dataModel.sortByColumn( colIndex, ascending ); 397 Pair currentSortOrder = m_dataModel.getCurrentSortOrder(); 398 assertEquals( "invalid current sort column (column " + colIndex + ")", ((Integer)currentSortOrder.First).intValue(), colIndex ); 399 assertEquals( "invalid current sort direction", ((Boolean)currentSortOrder.Second).booleanValue(), ascending ); 400 401 /*for ( int i=0; i<rowCount; ++i ) 402 { 403 for ( int j=0; j<colCount; ++j ) 404 System.out.print( m_dataModel.getCellData( j, i ).toString() + ", " ); 405 System.out.println(); 406 }*/ 407 408 // verify the data is actually sorted by this column 409 for ( int rowIndex = 0; rowIndex < rowCount - 1; ++rowIndex ) 410 { 411 final Object currentValue = m_dataModel.getCellData( colIndex, rowIndex ); 412 final int currentIntValue = impl_assertInteger( currentValue ); 413 final Object nextValue = m_dataModel.getCellData( colIndex, rowIndex + 1 ); 414 final int nextIntValue = impl_assertInteger( nextValue ); 415 assertTrue( "data in row " + rowIndex + " is actually not sorted " + ( ascending ? "ascending" : "descending" ), 416 ascending ? currentIntValue <= nextIntValue 417 : currentIntValue >= nextIntValue ); 418 419 // ensure the data in the other columns, and the row headings, are sorted as well 420 final Object rowHeading = m_dataModel.getRowHeading( rowIndex ); 421 final int unsortedRowIndex = impl_assertInteger( rowHeading ); 422 for ( int innerColIndex = 0; innerColIndex < colCount; ++innerColIndex ) 423 { 424 assertEquals( "sorted row " + rowIndex + ", unsorted row " + unsortedRowIndex + ", col " + innerColIndex + 425 ": wrong data", 426 data[unsortedRowIndex][innerColIndex], m_dataModel.getCellData( innerColIndex, rowIndex ) ); 427 } 428 } 429 } 430 } 431 } 432 433 // ----------------------------------------------------------------------------------------------------------------- 434 @Test testView()435 public void testView() throws Exception 436 { 437 final XControl control = impl_createDialogWithGridControl(); 438 final XPropertySet gridModelProps = 439 UnoRuntime.queryInterface( XPropertySet.class, control.getModel() ); 440 441 // in the current implementation (not sure this is a good idea at all), the control (more precise: the peer) 442 // ensures that if there are no columns in the column model, but in the data model, then the column model 443 // will implicitly have the needed columns added. 444 // To ensure that clients which rely on this do not break in the future, check this here. 445 final XMutableGridDataModel dataModel = UnoRuntime.queryInterface( XMutableGridDataModel.class, 446 gridModelProps.getPropertyValue( "GridDataModel" ) ); 447 assertNotNull( dataModel ); 448 assertEquals( 0, dataModel.getColumnCount() ); 449 450 final XGridColumnModel columnModel = UnoRuntime.queryInterface( XGridColumnModel.class, 451 gridModelProps.getPropertyValue( "ColumnModel" ) ); 452 assertNotNull( columnModel ); 453 assertEquals( 0, columnModel.getColumnCount() ); 454 455 final int columnCount = 3; 456 final int rowCount = 2; 457 dataModel.addRow( null, new Object[] { 1, 2, 3 } ); 458 dataModel.addRow( null, new Object[] { 6, 5, 4 } ); 459 460 assertEquals( columnCount, dataModel.getColumnCount() ); 461 assertEquals( columnCount, columnModel.getColumnCount() ); 462 463 // some cursor traveling 464 final XGridControl gridControl = UnoRuntime.queryInterface( XGridControl.class, control ); 465 gridControl.goToCell( 0, 0 ); 466 assertEquals( "wrong 'current column' (1)", 0, gridControl.getCurrentColumn() ); 467 assertEquals( "wrong 'current row' (1)", 0, gridControl.getCurrentRow() ); 468 gridControl.goToCell( columnCount - 1, rowCount - 1 ); 469 assertEquals( "wrong 'current column' (2)", dataModel.getColumnCount() - 1, gridControl.getCurrentColumn() ); 470 assertEquals( "wrong 'current row' (2)", dataModel.getRowCount() - 1, gridControl.getCurrentRow() ); 471 472 // removing the last column, while the active cell is in this very last column, is expected to adjust 473 // the active cell 474 columnModel.removeColumn( columnCount - 1 ); 475 assertEquals( "removed the last and active column, active column was not adjusted!", 476 columnCount - 2, gridControl.getCurrentColumn() ); 477 // same holds for rows 478 dataModel.removeRow( rowCount - 1 ); 479 assertEquals( "removed the last and active row, active row was not adjusted!", 480 rowCount - 2, gridControl.getCurrentRow() ); 481 } 482 483 // ----------------------------------------------------------------------------------------------------------------- impl_createDialogWithGridControl()484 private XControl impl_createDialogWithGridControl() throws Exception 485 { 486 // create a simple dialog model/control/peer trinity 487 final XControlModel dialogModel = createInstance( XControlModel.class, "com.sun.star.awt.UnoControlDialogModel" ); 488 m_disposables.add( dialogModel ); 489 final XPropertySet dialogProps = UnoRuntime.queryInterface( XPropertySet.class, dialogModel ); 490 dialogProps.setPropertyValue( "Width", 200 ); 491 dialogProps.setPropertyValue( "Height", 100 ); 492 dialogProps.setPropertyValue( "Title", "Grid Control Unit Test" ); 493 final XControl dialogControl = createInstance( XControl.class, "com.sun.star.awt.UnoControlDialog" ); 494 m_disposables.add( dialogControl ); 495 dialogControl.setModel( dialogModel ); 496 dialogControl.createPeer( createInstance( XToolkit.class, "com.sun.star.awt.Toolkit" ), null ); 497 498 // insert a grid control model 499 final XMultiServiceFactory controlModelFactory = UnoRuntime.queryInterface( XMultiServiceFactory.class, 500 dialogModel ); 501 final XPropertySet gridModelProps = UnoRuntime.queryInterface( XPropertySet.class, 502 controlModelFactory.createInstance( "com.sun.star.awt.grid.UnoControlGridModel" ) ); 503 m_disposables.add( gridModelProps ); 504 gridModelProps.setPropertyValue( "PositionX", 6 ); 505 gridModelProps.setPropertyValue( "PositionY", 6 ); 506 gridModelProps.setPropertyValue( "Width", 188 ); 507 gridModelProps.setPropertyValue( "Height", 88 ); 508 final XNameContainer modelContainer = UnoRuntime.queryInterface( XNameContainer.class, dialogModel ); 509 modelContainer.insertByName( "grid", gridModelProps ); 510 511 // check the respective control has been created 512 final XControlContainer controlContainer = UnoRuntime.queryInterface( XControlContainer.class, dialogControl ); 513 final XControl gridControl = controlContainer.getControl( "grid" ); 514 assertNotNull( "no grid control created in the dialog", gridControl ); 515 516 return gridControl; 517 } 518 519 // ----------------------------------------------------------------------------------------------------------------- impl_assertInteger( final Object i_object )520 private int impl_assertInteger( final Object i_object ) 521 { 522 assertTrue( i_object instanceof Integer ); 523 return ((Integer)i_object).intValue(); 524 } 525 526 // ----------------------------------------------------------------------------------------------------------------- impl_assertColumnModelConsistency()527 private void impl_assertColumnModelConsistency() throws IndexOutOfBoundsException 528 { 529 for ( int col = 0; col < m_columnModel.getColumnCount(); ++col ) 530 { 531 final XGridColumn column = m_columnModel.getColumn( col ); 532 assertNotNull( column ); 533 assertEquals( "column/model inconsistency: column " + col + " has a wrong index!", col, column.getIndex() ); 534 } 535 536 final XGridColumn[] allColumns = m_columnModel.getColumns(); 537 assertEquals( "getColumns returns the wrong number of column objects", 538 m_columnModel.getColumnCount(), allColumns.length ); 539 for ( int col = 0; col < m_columnModel.getColumnCount(); ++col ) 540 { 541 assertTrue( "getColumns inconsistency", impl_areSameInterface( allColumns[col], m_columnModel.getColumn(col) ) ); 542 } 543 } 544 545 // ----------------------------------------------------------------------------------------------------------------- impl_assertEquality( final XGridDataModel i_reference, final XGridDataModel i_compare )546 private void impl_assertEquality( final XGridDataModel i_reference, final XGridDataModel i_compare ) throws IndexOutOfBoundsException 547 { 548 assertNotNull( i_reference ); 549 assertNotNull( i_compare ); 550 551 assertEquals( "data model comparison: wrong column counts", i_reference.getColumnCount(), i_compare.getColumnCount() ); 552 assertEquals( "data model comparison: wrong row counts", i_reference.getRowCount(), i_compare.getRowCount() ); 553 554 for ( int row = 0; row < i_reference.getRowCount(); ++row ) 555 { 556 assertEquals( "data model comparison: wrong row heading content in row " + row, 557 i_reference.getRowHeading( row ) ); 558 for ( int col = 0; col < i_reference.getRowCount(); ++col ) 559 { 560 assertEquals( "data model comparison: wrong cell content in cell (" + col + ", " + row + ")", 561 i_reference.getCellData( col, row ) ); 562 assertEquals( "data model comparison: wrong tooltip content in cell (" + col + ", " + row + ")", 563 i_reference.getCellToolTip( col, row ) ); 564 } 565 } 566 } 567 568 // ----------------------------------------------------------------------------------------------------------------- impl_assertEquality( final XGridColumnModel i_reference, final XGridColumnModel i_compare )569 private void impl_assertEquality( final XGridColumnModel i_reference, final XGridColumnModel i_compare ) throws IndexOutOfBoundsException 570 { 571 assertEquals( "column model comparison: wrong column counts", i_reference.getColumnCount(), i_compare.getColumnCount() ); 572 for ( int col = 0; col < i_reference.getColumnCount(); ++col ) 573 { 574 final XGridColumn referenceColumn = i_reference.getColumn( col ); 575 final XGridColumn compareColumn = i_compare.getColumn( col ); 576 impl_assertEquality( referenceColumn, compareColumn ); 577 } 578 } 579 580 // ----------------------------------------------------------------------------------------------------------------- impl_assertEquality( final XGridColumn i_reference, final XGridColumn i_compare )581 private void impl_assertEquality( final XGridColumn i_reference, final XGridColumn i_compare ) 582 { 583 final Method[] methods = XGridColumn.class.getMethods(); 584 for ( int m=0; m<methods.length; ++m ) 585 { 586 if ( !methods[m].getName().startsWith( "get" ) ) 587 continue; 588 try 589 { 590 final Object referenceValue = methods[m].invoke( i_reference ); 591 final Object compareValue = methods[m].invoke( i_compare ); 592 assertEquals( "grid column comparison: column attribute '" + methods[m].getName().substring(3) + "' does not match", 593 referenceValue, compareValue ); 594 } 595 catch ( java.lang.Exception ex ) 596 { 597 fail( " could not retrieve object attributes: " + ex.toString() ); 598 } 599 } 600 } 601 602 // ----------------------------------------------------------------------------------------------------------------- impl_areSameInterface( final Object i_lhs, final Object i_rhs )603 private boolean impl_areSameInterface( final Object i_lhs, final Object i_rhs ) 604 { 605 final XInterface lhs = UnoRuntime.queryInterface( XInterface.class, i_lhs ); 606 final XInterface rhs = UnoRuntime.queryInterface( XInterface.class, i_rhs ); 607 return UnoRuntime.areSame( lhs, rhs ); 608 } 609 610 // ----------------------------------------------------------------------------------------------------------------- 611 @Before initTestCase()612 public void initTestCase() 613 { 614 m_disposables.clear(); 615 } 616 617 // ----------------------------------------------------------------------------------------------------------------- 618 @After cleanupTestCase()619 public void cleanupTestCase() 620 { 621 impl_dispose( m_disposables.toArray() ); 622 } 623 624 // ----------------------------------------------------------------------------------------------------------------- 625 @BeforeClass setUpConnection()626 public static void setUpConnection() throws java.lang.Exception 627 { 628 System.out.println( "--------------------------------------------------------------------------------" ); 629 System.out.println( "starting class: " + GridControl.class.getName() ); 630 System.out.print( "connecting ... " ); 631 m_connection.setUp(); 632 System.out.println( "done."); 633 634 final long seed = m_randomGenerator.nextLong(); 635 m_randomGenerator.setSeed( seed ); 636 System.out.println( "seeding random number generator with " + seed ); 637 } 638 639 // ----------------------------------------------------------------------------------------------------------------- 640 @AfterClass tearDownConnection()641 public static void tearDownConnection() 642 throws InterruptedException, com.sun.star.uno.Exception 643 { 644 System.out.println(); 645 System.out.println( "tearing down connection" ); 646 m_connection.tearDown(); 647 System.out.println( "finished class: " + GridControl.class.getName() ); 648 System.out.println( "--------------------------------------------------------------------------------" ); 649 } 650 651 // ----------------------------------------------------------------------------------------------------------------- createInstance( Class<T> i_interfaceClass, final String i_serviceIndentifer )652 public <T> T createInstance( Class<T> i_interfaceClass, final String i_serviceIndentifer ) throws Exception 653 { 654 return UnoRuntime.queryInterface( i_interfaceClass, createInstance( i_serviceIndentifer ) ); 655 } 656 657 // ----------------------------------------------------------------------------------------------------------------- createInstance( final String i_serviceName )658 private Object createInstance( final String i_serviceName ) throws Exception 659 { 660 Object instance = m_context.getServiceManager().createInstanceWithContext( i_serviceName, m_context ); 661 assertNotNull( "could not create an instance of '" + i_serviceName + "'", instance ); 662 return instance; 663 } 664 // ----------------------------------------------------------------------------------------------------------------- 665 private static final class DisposeListener implements XEventListener 666 { DisposeListener( final Object i_component )667 DisposeListener( final Object i_component ) 668 { 669 m_component = UnoRuntime.queryInterface( XComponent.class, i_component ); 670 assertNotNull( m_component ); 671 m_component.addEventListener( this ); 672 } 673 disposing( EventObject i_event )674 public void disposing( EventObject i_event ) 675 { 676 assertTrue( UnoRuntime.areSame( i_event.Source, m_component ) ); 677 m_isDisposed = true; 678 } 679 isDisposed()680 final boolean isDisposed() { return m_isDisposed; } 681 682 private final XComponent m_component; 683 private boolean m_isDisposed; 684 }; 685 686 // ----------------------------------------------------------------------------------------------------------------- 687 private static final class ColumnModelListener implements XContainerListener 688 { ColumnModelListener()689 ColumnModelListener() 690 { 691 } 692 elementInserted( ContainerEvent i_event )693 public void elementInserted( ContainerEvent i_event ) 694 { 695 m_insertionEvents.add( i_event ); 696 } 697 elementRemoved( ContainerEvent i_event )698 public void elementRemoved( ContainerEvent i_event ) 699 { 700 m_removalEvents.add( i_event ); 701 } 702 elementReplaced( ContainerEvent i_event )703 public void elementReplaced( ContainerEvent i_event ) 704 { 705 m_replacementEvents.add( i_event ); 706 } 707 disposing( EventObject eo )708 public void disposing( EventObject eo ) 709 { 710 m_isDisposed = true; 711 } 712 assertExclusiveInsertionEvents()713 private List< ContainerEvent > assertExclusiveInsertionEvents() 714 { 715 assertFalse( m_insertionEvents.isEmpty() ); 716 assertTrue( m_removalEvents.isEmpty() ); 717 assertTrue( m_replacementEvents.isEmpty() ); 718 return m_insertionEvents; 719 } 720 assertExclusiveRemovalEvents()721 private List< ContainerEvent > assertExclusiveRemovalEvents() 722 { 723 assertTrue( m_insertionEvents.isEmpty() ); 724 assertFalse( m_removalEvents.isEmpty() ); 725 assertTrue( m_replacementEvents.isEmpty() ); 726 return m_removalEvents; 727 } 728 reset()729 private void reset() 730 { 731 m_insertionEvents = new ArrayList< ContainerEvent >(); 732 m_removalEvents = new ArrayList< ContainerEvent >(); 733 m_replacementEvents = new ArrayList< ContainerEvent >(); 734 } 735 getInsertionEvents()736 private List< ContainerEvent > getInsertionEvents() { return m_insertionEvents; } getRemovalEvents()737 private List< ContainerEvent > getRemovalEvents() { return m_removalEvents; } 738 isDisposed()739 final boolean isDisposed() { return m_isDisposed; } 740 741 private List< ContainerEvent > m_insertionEvents = new ArrayList< ContainerEvent >(); 742 private List< ContainerEvent > m_removalEvents = new ArrayList< ContainerEvent >(); 743 private List< ContainerEvent > m_replacementEvents = new ArrayList< ContainerEvent >(); 744 private boolean m_isDisposed = false; 745 }; 746 747 // ----------------------------------------------------------------------------------------------------------------- 748 private static final OfficeConnection m_connection = new OfficeConnection(); 749 private static Random m_randomGenerator = new Random(); 750 private final XComponentContext m_context; 751 752 private XPropertySet m_gridControlModel; 753 private XGridColumnModel m_columnModel; 754 private XSortableMutableGridDataModel m_dataModel; 755 private final List< Object > m_disposables = new ArrayList< Object >(); 756 } 757