forked from amazingfate/loongoffice
* remove redirects * use https links * replace old attchment links with working ones Change-Id: Ic9a154f46e142138f0adea7d7b8be3b6cfe8af18 Reviewed-on: https://gerrit.libreoffice.org/52224 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
401 lines
18 KiB
Java
401 lines
18 KiB
Java
/*
|
|
* 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 integration.forms;
|
|
|
|
import com.sun.star.beans.NamedValue;
|
|
import com.sun.star.beans.XPropertySet;
|
|
import com.sun.star.container.XIndexContainer;
|
|
|
|
import com.sun.star.uno.UnoRuntime;
|
|
import com.sun.star.lang.XMultiServiceFactory;
|
|
import com.sun.star.container.XNameContainer;
|
|
import com.sun.star.embed.XComponentSupplier;
|
|
import com.sun.star.form.XGridColumnFactory;
|
|
import com.sun.star.form.XGridFieldDataSupplier;
|
|
import com.sun.star.form.XLoadable;
|
|
import com.sun.star.lang.XComponent;
|
|
import com.sun.star.sdb.CommandType;
|
|
import com.sun.star.sdb.XFormDocumentsSupplier;
|
|
import com.sun.star.sdbc.SQLException;
|
|
import com.sun.star.sdbc.XColumnLocate;
|
|
import com.sun.star.ucb.Command;
|
|
import com.sun.star.ucb.OpenMode;
|
|
import com.sun.star.ucb.XCommandProcessor;
|
|
import com.sun.star.uno.Type;
|
|
import com.sun.star.util.XModifiable;
|
|
import connectivity.tools.CRMDatabase;
|
|
import connectivity.tools.HsqlColumnDescriptor;
|
|
import connectivity.tools.HsqlDatabase;
|
|
import connectivity.tools.HsqlTableDescriptor;
|
|
import org.openoffice.complex.forms.tools.ResultSet;
|
|
|
|
|
|
public class MasterDetailForms extends complexlib.ComplexTestCase implements com.sun.star.form.XLoadListener
|
|
{
|
|
private XMultiServiceFactory m_orb;
|
|
|
|
private XPropertySet m_masterForm;
|
|
private XPropertySet m_detailForm;
|
|
private ResultSet m_masterResult;
|
|
private ResultSet m_detailResult;
|
|
|
|
final private Object m_waitForLoad = new Object();
|
|
private boolean m_loaded = false;
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
@Override
|
|
public String[] getTestMethodNames()
|
|
{
|
|
return new String[] {
|
|
"checkMultipleKeys",
|
|
"checkDetailFormDefaults"
|
|
};
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
public void before()
|
|
{
|
|
m_orb = param.getMSF();
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
@Override
|
|
public String getTestObjectName()
|
|
{
|
|
return "Form Control Spreadsheet Cell Binding Test";
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/** creates the table structure needed for the test
|
|
*/
|
|
private void impl_createTableStructure( final HsqlDatabase _databaseDocument ) throws SQLException
|
|
{
|
|
HsqlColumnDescriptor[] masterColumns = {
|
|
new HsqlColumnDescriptor( "ID1", "INTEGER", HsqlColumnDescriptor.PRIMARY ),
|
|
new HsqlColumnDescriptor( "ID2", "INTEGER", HsqlColumnDescriptor.PRIMARY ),
|
|
new HsqlColumnDescriptor( "value", "VARCHAR(50)" ),
|
|
};
|
|
HsqlColumnDescriptor[] detailColumns = {
|
|
new HsqlColumnDescriptor( "ID", "INTEGER", HsqlColumnDescriptor.PRIMARY ),
|
|
new HsqlColumnDescriptor( "FK_ID1", "INTEGER", HsqlColumnDescriptor.REQUIRED, "master", "ID1" ),
|
|
new HsqlColumnDescriptor( "FK_ID2", "INTEGER", HsqlColumnDescriptor.REQUIRED, "master", "ID2" ),
|
|
new HsqlColumnDescriptor( "name", "VARCHAR(50)" ),
|
|
};
|
|
_databaseDocument.createTable( new HsqlTableDescriptor( "master", masterColumns ) );
|
|
_databaseDocument.createTable( new HsqlTableDescriptor( "detail", detailColumns ) );
|
|
|
|
_databaseDocument.executeSQL( "INSERT INTO \"master\" VALUES ( 1, 1, 'First Record' )" );
|
|
_databaseDocument.executeSQL( "INSERT INTO \"master\" VALUES ( 1, 2, 'Second Record' )" );
|
|
_databaseDocument.executeSQL( "INSERT INTO \"detail\" VALUES ( 1, 1, 1, 'record 1.1 (1)')");
|
|
_databaseDocument.executeSQL( "INSERT INTO \"detail\" VALUES ( 2, 1, 1, 'record 1.1 (2)')");
|
|
_databaseDocument.executeSQL( "INSERT INTO \"detail\" VALUES ( 3, 1, 2, 'record 1.2 (1)')");
|
|
|
|
_databaseDocument.defaultConnection().refreshTables();
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
private void impl_createForms( final HsqlDatabase _databaseDocument ) throws com.sun.star.uno.Exception
|
|
{
|
|
m_masterForm = dbfTools.queryPropertySet( m_orb.createInstance( "com.sun.star.form.component.DataForm" ) );
|
|
m_masterForm.setPropertyValue( "ActiveConnection", _databaseDocument.defaultConnection().getXConnection() );
|
|
m_masterForm.setPropertyValue( "CommandType", Integer.valueOf( com.sun.star.sdb.CommandType.TABLE ) );
|
|
m_masterForm.setPropertyValue( "Command", "master" );
|
|
|
|
m_masterResult = new ResultSet( m_masterForm );
|
|
|
|
m_detailForm = dbfTools.queryPropertySet( m_orb.createInstance( "com.sun.star.form.component.DataForm" ) );
|
|
m_detailForm.setPropertyValue( "ActiveConnection", _databaseDocument.defaultConnection().getXConnection() );
|
|
m_detailForm.setPropertyValue( "CommandType", Integer.valueOf( com.sun.star.sdb.CommandType.TABLE ) );
|
|
m_detailForm.setPropertyValue( "Command", "detail" );
|
|
|
|
m_detailResult = new ResultSet( m_detailForm );
|
|
|
|
XNameContainer masterContainer = UnoRuntime.queryInterface( XNameContainer.class, m_masterForm );
|
|
masterContainer.insertByName( "slave", m_detailForm );
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/** checks if master-detail relationships including multiple keys work
|
|
*/
|
|
public void checkMultipleKeys() throws com.sun.star.uno.Exception, java.lang.Exception
|
|
{
|
|
HsqlDatabase databaseDocument = null;
|
|
try
|
|
{
|
|
databaseDocument = new HsqlDatabase( m_orb );
|
|
impl_createTableStructure( databaseDocument );
|
|
impl_createForms( databaseDocument );
|
|
|
|
m_detailForm.setPropertyValue( "MasterFields", new String[] { "ID1", "ID2" } );
|
|
m_detailForm.setPropertyValue( "DetailFields", new String[] { "FK_ID1", "FK_ID2" } );
|
|
|
|
XLoadable loadMaster = UnoRuntime.queryInterface( XLoadable.class, m_masterForm );
|
|
XLoadable loadDetail = UnoRuntime.queryInterface( XLoadable.class, m_detailForm );
|
|
loadDetail.addLoadListener( this );
|
|
|
|
// wait until the detail form is loaded
|
|
loadMaster.load();
|
|
impl_waitForLoadedEvent();
|
|
|
|
// okay, now the master form should be on the first record
|
|
assure( "wrong form state after loading (ID1)", m_masterResult.getInt(1) == 1 );
|
|
assure( "wrong form state after loading (ID2)", m_masterResult.getInt(2) == 1 );
|
|
assure( "wrong form state after loading (value)", m_masterResult.getString(3).equals( "First Record" ) );
|
|
|
|
// the values in the linked fields should be identical
|
|
int expectedDetailRowCounts[] = { 2, 1 };
|
|
do
|
|
{
|
|
verifyColumnValueIdentity( "ID1", "FK_ID1" );
|
|
verifyColumnValueIdentity( "ID2", "FK_ID2" );
|
|
|
|
m_detailResult.last();
|
|
int masterPos = m_masterResult.getRow();
|
|
assure( "wrong number of records in detail form, for master form at pos " + masterPos,
|
|
((Integer)m_detailForm.getPropertyValue( "RowCount" )).intValue() == expectedDetailRowCounts[ masterPos - 1 ] );
|
|
|
|
if (!m_masterResult.next())
|
|
return;
|
|
impl_waitForLoadedEvent();
|
|
}
|
|
while ( !m_masterResult.isAfterLast() );
|
|
assure( "wrong number of records in master form", 2 == ((Integer)m_masterForm.getPropertyValue( "RowCount" )).intValue() );
|
|
}
|
|
finally
|
|
{
|
|
if ( databaseDocument != null )
|
|
databaseDocument.closeAndDelete();
|
|
impl_cleanUpStep();
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
private final void impl_cleanUpStep()
|
|
{
|
|
if ( m_masterForm != null )
|
|
dbfTools.disposeComponent( m_masterForm );
|
|
if ( m_detailForm != null )
|
|
dbfTools.disposeComponent( m_detailForm );
|
|
m_masterForm = m_detailForm = null;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/** checks whether default values in detail forms work as expected.
|
|
*
|
|
* Effectively, this test case verifies the issues #i106574# and #i105235# did not creep back in.
|
|
*/
|
|
public void checkDetailFormDefaults() throws Exception
|
|
{
|
|
CRMDatabase database = null;
|
|
XCommandProcessor subComponentCommands = null;
|
|
try
|
|
{
|
|
// create our standard CRM database document
|
|
database = new CRMDatabase( m_orb, true );
|
|
|
|
// create a form document therein
|
|
XFormDocumentsSupplier formDocSupp = UnoRuntime.queryInterface( XFormDocumentsSupplier.class, database.getDatabase().getModel() );
|
|
XMultiServiceFactory formFactory = UnoRuntime.queryInterface( XMultiServiceFactory.class, formDocSupp.getFormDocuments() );
|
|
NamedValue[] loadArgs = new NamedValue[] {
|
|
new NamedValue( "ActiveConnection", database.getConnection().getXConnection() ),
|
|
new NamedValue( "MediaType", "application/vnd.oasis.opendocument.text" )
|
|
};
|
|
|
|
subComponentCommands = UnoRuntime.queryInterface(
|
|
XCommandProcessor.class,
|
|
formFactory.createInstanceWithArguments( "com.sun.star.sdb.DocumentDefinition", loadArgs ) );
|
|
Command command = new Command();
|
|
command.Name = "openDesign";
|
|
command.Argument = Short.valueOf( OpenMode.DOCUMENT );
|
|
|
|
DocumentHelper subDocument = new DocumentHelper( m_orb,
|
|
UnoRuntime.queryInterface( XComponent.class,
|
|
subComponentCommands.execute( command, subComponentCommands.createCommandIdentifier(), null )
|
|
)
|
|
);
|
|
FormLayer formLayer = new FormLayer( subDocument );
|
|
XPropertySet controlModel = formLayer.insertControlLine( "DatabaseNumericField", "ID", "", 10 );
|
|
formLayer.insertControlLine( "DatabaseTextField", "Name", "", 20 );
|
|
formLayer.insertControlLine( "DatabaseTextField", "Description", "", 30 );
|
|
|
|
m_masterForm = (XPropertySet)dbfTools.getParent( controlModel, XPropertySet.class );
|
|
m_masterForm.setPropertyValue( "Command", "categories" );
|
|
m_masterForm.setPropertyValue( "CommandType", Integer.valueOf( CommandType.TABLE ) );
|
|
|
|
// create a detail form
|
|
m_detailForm = UnoRuntime.queryInterface( XPropertySet.class, subDocument.createSubForm( m_masterForm, "products" ) );
|
|
m_detailForm.setPropertyValue( "Command", "SELECT \"ID\", \"Name\", \"CategoryID\" FROM \"products\"" );
|
|
m_detailForm.setPropertyValue( "CommandType", Integer.valueOf( CommandType.COMMAND ) );
|
|
m_detailForm.setPropertyValue( "MasterFields", new String[] { "ID" } );
|
|
m_detailForm.setPropertyValue( "DetailFields", new String[] { "CategoryID" } );
|
|
|
|
// create a grid control in the detail form, with some columns
|
|
XPropertySet gridControlModel = formLayer.createControlAndShape( "GridControl", 20, 40, 130, 50, m_detailForm );
|
|
gridControlModel.setPropertyValue( "Name", "product list" );
|
|
XIndexContainer gridColumns = UnoRuntime.queryInterface( XIndexContainer.class, gridControlModel );
|
|
impl_createGridColumn( gridColumns, "TextField", "ID" );
|
|
XPropertySet nameColumn = impl_createGridColumn( gridColumns, "TextField", "Name" );
|
|
nameColumn.setPropertyValue( "Width", Integer.valueOf( 600 ) ); // 6 cm
|
|
nameColumn.setPropertyValue( "DefaultText", "default text" );
|
|
|
|
// go live
|
|
m_masterResult = new ResultSet( m_masterForm );
|
|
m_detailResult = new ResultSet( m_detailForm );
|
|
|
|
XLoadable loadDetail = UnoRuntime.queryInterface( XLoadable.class, m_detailForm );
|
|
loadDetail.addLoadListener( this );
|
|
|
|
subDocument.getCurrentView().toggleFormDesignMode();
|
|
impl_waitForLoadedEvent();
|
|
|
|
// now that we set up this, do the actual tests
|
|
// First, https://bz.apache.org/ooo/show_bug.cgi?id=105235 described the problem
|
|
// that default values in the sub form didn't work when the master form was navigated to a row
|
|
// for which no detail records were present, and the default of the column/control is the same
|
|
// as the last known value.
|
|
|
|
// so, take the current value of the "Name" column, and set it as default value ...
|
|
String defaultValue = m_detailResult.getString( 2 );
|
|
nameColumn.setPropertyValue( "DefaultText", defaultValue );
|
|
// ... then move to the second main form row ...
|
|
m_masterResult.absolute( 2 );
|
|
impl_waitForLoadedEvent();
|
|
// ... which should result in an empty sub form ...
|
|
assure( "test precondition not met: The second master form record is expected to have no detail records, " +
|
|
"else the test becomes meaningless", impl_isNewRecord( m_detailForm ) );
|
|
// ... and in the "Name" column having the proper text
|
|
String actualValue = (String)nameColumn.getPropertyValue( "Text" );
|
|
assureEquals( "#i105235#: default value in sub form not working (not propagated to column model)", defaultValue, actualValue );
|
|
// However, checking the column model's value alone is not enough - we need to ensure it is properly
|
|
// propagated to the control.
|
|
XGridFieldDataSupplier gridData = subDocument.getCurrentView().getControl(
|
|
gridControlModel, XGridFieldDataSupplier.class );
|
|
actualValue = (String)(gridData.queryFieldData( 0, Type.STRING )[1]);
|
|
assureEquals( "#i105235#: default value in sub form not working (not propagated to column)", defaultValue, actualValue );
|
|
}
|
|
finally
|
|
{
|
|
if ( subComponentCommands != null )
|
|
{
|
|
XComponentSupplier componentSupplier = UnoRuntime.queryInterface( XComponentSupplier.class, subComponentCommands );
|
|
XModifiable modifySubComponent = UnoRuntime.queryInterface( XModifiable.class, componentSupplier.getComponent() );
|
|
modifySubComponent.setModified( false );
|
|
Command command = new Command();
|
|
command.Name = "close";
|
|
subComponentCommands.execute( command, subComponentCommands.createCommandIdentifier(), null );
|
|
}
|
|
|
|
if ( database != null )
|
|
database.saveAndClose();
|
|
|
|
impl_cleanUpStep();
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
private boolean impl_isNewRecord( final XPropertySet _rowSet )
|
|
{
|
|
boolean isNew = false;
|
|
try
|
|
{
|
|
isNew = ((Boolean)_rowSet.getPropertyValue( "IsNew" )).booleanValue();
|
|
}
|
|
catch ( Exception ex )
|
|
{
|
|
failed( "obtaining the IsNew property failed" );
|
|
}
|
|
return isNew;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
private XPropertySet impl_createGridColumn( final XIndexContainer _gridModel, final String _columnType, final String _boundField ) throws Exception
|
|
{
|
|
final XGridColumnFactory columnFactory = UnoRuntime.queryInterface( XGridColumnFactory.class, _gridModel );
|
|
XPropertySet column = columnFactory.createColumn( _columnType );
|
|
column.setPropertyValue( "DataField", _boundField );
|
|
column.setPropertyValue( "Name", _boundField );
|
|
column.setPropertyValue( "Label", _boundField );
|
|
_gridModel.insertByIndex( _gridModel.getCount(), column );
|
|
return column;
|
|
}
|
|
|
|
private void impl_waitForLoadedEvent()
|
|
{
|
|
synchronized( m_waitForLoad )
|
|
{
|
|
while ( !m_loaded )
|
|
{
|
|
try { m_waitForLoad.wait(); }
|
|
catch( InterruptedException e ) { }
|
|
}
|
|
// reset the flag for the next time
|
|
m_loaded = false;
|
|
}
|
|
}
|
|
|
|
/** assures that the (integer) values in the given columns of our master and detail forms are identical
|
|
*/
|
|
private void verifyColumnValueIdentity( final String masterColName, final String detailColName ) throws SQLException
|
|
{
|
|
XColumnLocate locateMasterCols = UnoRuntime.queryInterface( XColumnLocate.class, m_masterForm );
|
|
XColumnLocate locateDetailCols = UnoRuntime.queryInterface( XColumnLocate.class, m_detailForm );
|
|
|
|
int masterValue = m_masterResult.getInt( locateMasterCols.findColumn( masterColName ) );
|
|
int detailValue = m_detailResult.getInt( locateDetailCols.findColumn( detailColName ) );
|
|
|
|
assure( "values in linked column pair " + detailColName + "->" + masterColName + " (" +
|
|
detailValue + "->" + masterValue + ") do not match (master position: " + m_masterResult.getRow() + ")!",
|
|
masterValue == detailValue );
|
|
}
|
|
|
|
public void disposing(com.sun.star.lang.EventObject eventObject)
|
|
{
|
|
}
|
|
|
|
public void loaded(com.sun.star.lang.EventObject eventObject)
|
|
{
|
|
synchronized( m_waitForLoad )
|
|
{
|
|
m_loaded = true;
|
|
m_waitForLoad.notify();
|
|
}
|
|
}
|
|
|
|
public void reloaded(com.sun.star.lang.EventObject eventObject)
|
|
{
|
|
synchronized( m_waitForLoad )
|
|
{
|
|
m_loaded = true;
|
|
m_waitForLoad.notify();
|
|
}
|
|
}
|
|
|
|
public void reloading(com.sun.star.lang.EventObject eventObject)
|
|
{
|
|
}
|
|
|
|
public void unloaded(com.sun.star.lang.EventObject eventObject)
|
|
{
|
|
}
|
|
|
|
public void unloading(com.sun.star.lang.EventObject eventObject)
|
|
{
|
|
}
|
|
}
|