summaryrefslogtreecommitdiffstats
path: root/odk/examples/DevelopersGuide/Forms/DataAwareness.java
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /odk/examples/DevelopersGuide/Forms/DataAwareness.java
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'odk/examples/DevelopersGuide/Forms/DataAwareness.java')
-rw-r--r--odk/examples/DevelopersGuide/Forms/DataAwareness.java940
1 files changed, 940 insertions, 0 deletions
diff --git a/odk/examples/DevelopersGuide/Forms/DataAwareness.java b/odk/examples/DevelopersGuide/Forms/DataAwareness.java
new file mode 100644
index 000000000..fbb3b7fe5
--- /dev/null
+++ b/odk/examples/DevelopersGuide/Forms/DataAwareness.java
@@ -0,0 +1,940 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * The Contents of this file are made available subject to the terms of
+ * the BSD license.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *************************************************************************/
+import com.sun.star.beans.PropertyChangeEvent;
+import com.sun.star.beans.XPropertyChangeListener;
+import com.sun.star.beans.XPropertySet;
+
+
+// __________ Imports __________
+import com.sun.star.beans.XPropertySetInfo;
+
+// base classes
+import com.sun.star.container.XIndexContainer;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.container.XNamed;
+import com.sun.star.form.FormComponentType;
+import com.sun.star.form.ListSourceType;
+import com.sun.star.form.XGridColumnFactory;
+import com.sun.star.form.XReset;
+import com.sun.star.form.XResetListener;
+import com.sun.star.form.runtime.FormFeature;
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.XComponent;
+import com.sun.star.sdb.CommandType;
+import com.sun.star.sdb.XColumnUpdate;
+import com.sun.star.sdbc.ResultSetConcurrency;
+import com.sun.star.sdbc.XConnection;
+import com.sun.star.sdbc.XDataSource;
+import com.sun.star.sdbc.XStatement;
+import com.sun.star.sdbcx.XColumnsSupplier;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XInterface;
+
+/**************************************************************************/
+/** a class for enumerating a form component tree
+*/
+class PrintComponentTree extends ComponentTreeTraversal
+{
+ private String m_sPrefix;
+
+ public PrintComponentTree()
+ {
+ m_sPrefix = "";
+ }
+
+ @Override
+ public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
+ {
+ // the name of the child
+ XNamed xName = UnoRuntime.queryInterface( XNamed.class, aFormComponent );
+
+ // if it's a form control model, check it's type
+ XPropertySet xProps = UNO.queryPropertySet( aFormComponent );
+ String sTypeName = FLTools.classifyFormComponentType( xProps );
+
+ String sName;
+ if ( null == xName )
+ sName = "<unnamed>";
+ else
+ sName = xName.getName();
+
+ // print the component's name
+ if ( 0 != sTypeName.length() )
+ {
+ System.out.println( m_sPrefix + sName + " (" + sTypeName + ")" );
+ }
+ else
+ {
+ System.out.println( m_sPrefix + sName );
+ }
+
+ // let the super class step down the tree
+ m_sPrefix = m_sPrefix + " ";
+ super.handle( aFormComponent );
+ m_sPrefix = m_sPrefix.substring( 0, m_sPrefix.length() - 1 );
+ }
+}
+
+/**************************************************************************/
+/** a class revoking button models from a ButtonOperator instance
+*/
+class RevokeButtons extends ComponentTreeTraversal
+{
+ private ButtonOperator m_aOperator;
+
+ public RevokeButtons( ButtonOperator aOperator )
+ {
+ m_aOperator = aOperator;
+ }
+
+ @Override
+ public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
+ {
+ // check if it's a button
+ XPropertySet xProps = UNO.queryPropertySet( aFormComponent );
+ XPropertySetInfo xPI = null;
+ if ( null != xProps )
+ xPI = xProps.getPropertySetInfo();
+ if ( ( null != xPI ) && xPI.hasPropertyByName( "ClassId" ) )
+ {
+ Short nClassId = (Short)xProps.getPropertyValue( "ClassId" );
+ if ( FormComponentType.COMMANDBUTTON == nClassId.shortValue() )
+ {
+ // yes, it is
+ m_aOperator.revokeButton( xProps );
+ }
+ }
+
+ // let the super class step down the tree (if possible)
+ super.handle( aFormComponent );
+ }
+}
+
+/**************************************************************************/
+public class DataAwareness extends DocumentBasedExample implements XPropertyChangeListener, XResetListener
+{
+ /* ================================================================== */
+ private HsqlDatabase m_database;
+
+ private static final String s_tableNameSalesmen = "SALESMEN";
+ private static final String s_tableNameCustomers = "CUSTOMERS";
+ private static final String s_tableNameSales = "SALES";
+
+ private XPropertySet m_xMasterForm;
+ private ButtonOperator m_aOperator;
+
+ private KeyGenerator m_aSalesmanKeyGenerator;
+ private KeyGenerator m_aSalesKeyGenerator;
+ private ControlLock m_aSalesmenLocker;
+ private ControlLock m_aSalesLocker;
+ private GridFieldValidator m_aSalesNameValidator;
+
+ private boolean m_bDefaultSalesDate;
+ private boolean m_bProtectKeyFields;
+ private boolean m_bAllowEmptySales;
+
+ /* ------------------------------------------------------------------ */
+ public DataAwareness()
+ {
+ super( DocumentType.WRITER );
+ m_bDefaultSalesDate = false;
+ m_bProtectKeyFields = false;
+ m_bAllowEmptySales = false;
+ }
+
+ /* ==================================================================
+ = form components
+ ================================================================== */
+
+ /* ------------------------------------------------------------------ */
+ /** enumerates and prints all the elements in the given container, together with the container itself
+ */
+ protected void enumFormComponents( XNameAccess xContainer ) throws java.lang.Exception
+ {
+ String sObjectName;
+
+ XNamed xNameAcc = UnoRuntime.queryInterface( XNamed.class, xContainer );
+ if ( null == xNameAcc )
+ sObjectName = "<unnamed>";
+ else
+ sObjectName = xNameAcc.getName();
+ System.out.println( "enumerating the container named \"" + sObjectName +
+ "\"\n" );
+
+ PrintComponentTree aPrinter = new PrintComponentTree();
+ aPrinter.handle( xContainer );
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** enumerates and prints all form elements in the document
+ */
+ protected void enumFormComponents( ) throws java.lang.Exception
+ {
+ enumFormComponents( m_document.getFormComponentTreeRoot() );
+ }
+
+ /* ==================================================================
+ = UNO callbacks
+ ================================================================== */
+
+ /* ------------------------------------------------------------------ */
+ // XResetListener overridables
+ /* ------------------------------------------------------------------ */
+ public boolean approveReset( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
+ {
+ // not interested in vetoing this
+ return true;
+ }
+
+ /* ------------------------------------------------------------------ */
+ public void resetted( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
+ {
+ // check if this reset occurred because we're on a new record
+ XPropertySet xFormProps = UNO.queryPropertySet( aEvent.Source );
+ try
+ {
+ Boolean aIsNew = (Boolean)xFormProps.getPropertyValue( "IsNew" );
+ if ( aIsNew.booleanValue() )
+ { // yepp
+
+ if ( !m_bDefaultSalesDate )
+ { // we're interested to do all this only if the user told us to default the sales date
+ // to "today"
+ // As date fields do this defaulting automatically, the semantics is inverted here:
+ // If we're told to default, we must do nothing, if we should not default, we must
+ // reset the value which the date field set automatically.
+
+ Integer aConcurrency = (Integer)xFormProps.getPropertyValue( "ResultSetConcurrency" );
+ if ( ResultSetConcurrency.READ_ONLY != aConcurrency.intValue() )
+ {
+ // we're going to modify the record, though after that, to the user, it should look
+ // like it has not been modified
+ // So we need to ensure that we do not change the IsModified property with whatever we do
+ Object aModifiedFlag = xFormProps.getPropertyValue( "IsModified" );
+
+
+ // get the columns of our master form
+ XColumnsSupplier xSuppCols = UnoRuntime.queryInterface(
+ XColumnsSupplier.class, xFormProps );
+ XNameAccess xCols = xSuppCols.getColumns();
+
+ // and update the date column with a NULL value
+ XColumnUpdate xDateColumn = UnoRuntime.queryInterface(
+ XColumnUpdate.class, xCols.getByName( "SALEDATE" ) );
+ xDateColumn.updateNull();
+
+
+ // then restore the flag
+ xFormProps.setPropertyValue( "IsModified", aModifiedFlag );
+ }
+ }
+ }
+ }
+ catch( com.sun.star.uno.Exception e )
+ {
+ System.out.println(e);
+ e.printStackTrace();
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ // XPropertyChangeListener overridables
+ /* ------------------------------------------------------------------ */
+ public void propertyChange( PropertyChangeEvent aEvent ) throws com.sun.star.uno.RuntimeException
+ {
+ try
+ {
+ // did it come from a radio button or checkbox?
+ if ( aEvent.PropertyName.equals( "State" ) )
+ { // yep
+ Short aNewState = (Short)aEvent.NewValue;
+
+ XPropertySet xModel = UNO.queryPropertySet( aEvent.Source );
+ String sName = (String)xModel.getPropertyValue( "Name" );
+
+ Short aClassId = (Short)xModel.getPropertyValue( "ClassId" );
+ if ( FormComponentType.RADIOBUTTON == aClassId.shortValue() )
+ {
+ String sRefValue = (String)xModel.getPropertyValue( "RefValue" );
+
+ short nNewValue = ((Short)aEvent.NewValue).shortValue();
+ if ( sName.equals( "KeyGen" ) )
+ {
+ // it's one of the options for key generation
+ if ( sRefValue.equals( "none" ) )
+ { // no automatic generation at all
+ m_aSalesmanKeyGenerator.stopGenerator( );
+ m_aSalesKeyGenerator.stopGenerator( );
+ }
+ else
+ {
+ boolean bGenerateOnReset = true;
+ if ( sRefValue.equals( "update" ) )
+ { // generate on update
+ bGenerateOnReset = ( 0 == nNewValue );
+ }
+ else if ( sRefValue.equals( "reset" ) )
+ { // generate on reset
+ bGenerateOnReset = ( 0 != nNewValue );
+ }
+ m_aSalesmanKeyGenerator.activateKeyGenerator( bGenerateOnReset );
+ m_aSalesKeyGenerator.activateKeyGenerator( bGenerateOnReset );
+ }
+ }
+ }
+ else if ( FormComponentType.CHECKBOX == aClassId.shortValue() )
+ {
+ boolean bEnabled = ( 0 != aNewState.shortValue() );
+ if ( sName.equals( "defaultdate" ) )
+ {
+ m_bDefaultSalesDate = bEnabled;
+ }
+ else if ( sName.equals( "protectkeys" ) )
+ {
+ m_bProtectKeyFields = bEnabled;
+ m_aSalesmenLocker.enableLock( m_bProtectKeyFields );
+ m_aSalesLocker.enableLock( m_bProtectKeyFields );
+ }
+ else if ( sName.equals( "emptysales" ) )
+ {
+ m_bAllowEmptySales = bEnabled;
+ m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales );
+ }
+ }
+ }
+ }
+ catch(com.sun.star.uno.Exception e)
+ {
+ System.out.println(e);
+ e.printStackTrace();
+ }
+ }
+
+ /* ------------------------------------------------------------------ */
+ // XEventListener overridables
+ /* ------------------------------------------------------------------ */
+ @Override
+ public void disposing( EventObject aEvent )
+ {
+ // simply disambiguate
+ super.disposing( aEvent );
+ }
+
+ /* ==================================================================
+ = miscellaneous
+ ================================================================== */
+
+ /* ------------------------------------------------------------------ */
+ /** skips line feeds in the input stream
+
+ @returns
+ the first character which does not belong to a line feed
+ */
+ protected int skipLineFeeds( java.io.InputStream aInput ) throws java.io.IOException
+ {
+ // read characters, until we encounter something which is not a line feed character
+ int nChar = aInput.read( );
+ while ( ( 13 == nChar ) || ( 10 == nChar ) )
+ nChar = aInput.read( );
+
+ // now read everything which is behind this single character we are interested in
+ while ( 0 < aInput.available() )
+ aInput.read( );
+
+ return nChar;
+ }
+
+ /* ==================================================================
+ = table handling
+ ================================================================== */
+ /* ------------------------------------------------------------------ */
+ /** checks if a given table exists.
+
+ <p>The check is made using a SELECT statement, so even if the connection
+ is a n SDB-level connection, which may filter tables in its table
+ supplier, the result may be reliable...</p>
+ */
+ protected boolean existsInvisibleTable( XConnection xConn, String sTableName ) throws java.lang.Exception
+ {
+ String sStatement = "SELECT * FROM ";
+ sStatement += sTableName;
+ sStatement += " WHERE 0=1";
+
+ boolean bSuccess = false;
+ try
+ {
+ XStatement xStatement = xConn.createStatement();
+ xStatement.execute( sStatement );
+ // if we reached this point, the table probably exists
+ bSuccess = true;
+ }
+ catch(com.sun.star.sdbc.SQLException e)
+ {
+ }
+ return bSuccess;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** add a specified table name to the table filter of the given data source.
+ */
+ protected void makeTableVisible( XDataSource xDS, String sTableName ) throws java.lang.Exception
+ {
+ // get the table filter
+ XPropertySet xDSP = UNO.queryPropertySet( xDS );
+ String[] aCurrentFilter = (String[])xDSP.getPropertyValue( "TableFilter" );
+
+ // check if the table name is already part of it
+ String sAllTables = "*"; // all tables
+
+ for ( int i=0; i<aCurrentFilter.length; ++i )
+ {
+ String sCurrentTableFilter = aCurrentFilter[i];
+
+ if ( sCurrentTableFilter.equals( sTableName ) )
+ return;
+ if ( sCurrentTableFilter.equals( sAllTables ) )
+ return;
+ }
+
+ // if we are here, we have to add our table to the filter sequence
+ String[] aNewFilter = new String[ aCurrentFilter.length + 1 ];
+ // copy the existent filter entries
+ for ( int i=0; i<aCurrentFilter.length; ++i )
+ aNewFilter[i] = aCurrentFilter[i];
+ // add our table
+ aNewFilter[ aCurrentFilter.length ] = sTableName;
+
+ xDSP.setPropertyValue( "TableFilter", aNewFilter );
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** executes the given statement on the given connection
+ */
+ protected boolean implExecuteStatement( XConnection xConn, String sStatement ) throws java.lang.Exception
+ {
+ try
+ {
+ XStatement xStatement = xConn.createStatement( );
+ xStatement.execute( sStatement );
+ }
+ catch(com.sun.star.sdbc.SQLException e)
+ {
+ System.err.println( e );
+ return false;
+ }
+
+ return true;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** creates the table with the given name, using the given statement
+ */
+ protected boolean implCreateTable( XConnection xConn, String sCreateStatement, String sTableName ) throws java.lang.Exception
+ {
+ if ( !implExecuteStatement( xConn, sCreateStatement ) )
+ {
+ System.out.println( " could not create the table " + sTableName + "." );
+ System.out.println( );
+ return false;
+ }
+
+ return true;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** creates the table SALESMEN
+
+ @return
+ <TRUE/> if and only if the creation succeeded
+ */
+ protected boolean createTableSalesman( XConnection xConn ) throws java.lang.Exception
+ {
+ String sCreateStatement = "CREATE TABLE " + s_tableNameSalesmen + " ";
+ sCreateStatement += "(SNR INTEGER NOT NULL, ";
+ sCreateStatement += "FIRSTNAME VARCHAR(50), ";
+ sCreateStatement += "LASTNAME VARCHAR(100), ";
+ sCreateStatement += "STREET VARCHAR(50), ";
+ sCreateStatement += "STATE VARCHAR(50), ";
+ sCreateStatement += "ZIP INTEGER, ";
+ sCreateStatement += "BIRTHDATE DATE, ";
+ sCreateStatement += "PRIMARY KEY(SNR))";
+
+ if ( implCreateTable( xConn, sCreateStatement, s_tableNameSalesmen) )
+ {
+ String sInsertionPrefix = "INSERT INTO " + s_tableNameSalesmen + " VALUES ";
+
+ implExecuteStatement( xConn, sInsertionPrefix + "(1, 'Joseph', 'Smith', 'Bond Street', 'CA', 95460, '1946-07-02')" );
+ implExecuteStatement( xConn, sInsertionPrefix + "(2, 'Frank', 'Jones', 'Lake silver', 'CA', 95460, '1963-12-24')" );
+ implExecuteStatement( xConn, sInsertionPrefix + "(3, 'Jane', 'Esperansa', '23 Hollywood driver', 'CA', 95460, '1972-04-01')" );
+
+ return true;
+ }
+ return false;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** creates the table CUSTOMERS
+
+ @return
+ <TRUE/> if and only if the creation succeeded
+ */
+ protected boolean createTableCustomer( XConnection xConn ) throws java.lang.Exception
+ {
+ String sCreateStatement = "CREATE TABLE " + s_tableNameCustomers + " ";
+ sCreateStatement += "(COS_NR INTEGER NOT NULL, ";
+ sCreateStatement += "LASTNAME VARCHAR(100), ";
+ sCreateStatement += "STREET VARCHAR(50), ";
+ sCreateStatement += "CITY VARCHAR(50), ";
+ sCreateStatement += "STATE VARCHAR(50), ";
+ sCreateStatement += "ZIP INTEGER, ";
+ sCreateStatement += "PRIMARY KEY(COS_NR))";
+
+ if ( implCreateTable( xConn, sCreateStatement, s_tableNameCustomers ) )
+ {
+ String sInsertionPrefix = "INSERT INTO " + s_tableNameCustomers + " VALUES ";
+
+ implExecuteStatement( xConn, sInsertionPrefix + "(100, 'Acme, Inc.', '99 Market Street', 'Groundsville', 'CA', 95199)" );
+ implExecuteStatement( xConn, sInsertionPrefix + "(101, 'Superior BugSoft', '1 Party Place', 'Mendocino', 'CA', 95460)");
+ implExecuteStatement( xConn, sInsertionPrefix + "(102, 'WeKnowAll, Inc.', '100 Coffee Lane', 'Meadows', 'CA', 93699)");
+
+ return true;
+ }
+ return false;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** creates the table SALES
+
+ @return
+ <TRUE/> if and only if the creation succeeded
+ */
+ protected boolean createTableSales( XConnection xConn ) throws java.lang.Exception
+ {
+ String sCreateStatement = "CREATE TABLE " + s_tableNameSales + " ";
+ sCreateStatement += "(SALENR INTEGER NOT NULL, ";
+ sCreateStatement += "COS_NR INTEGER NOT NULL, ";
+ sCreateStatement += "SNR INTEGER NOT NULL, ";
+ sCreateStatement += "NAME VARCHAR(50), ";
+ sCreateStatement += "SALEDATE DATE, ";
+ sCreateStatement += "PRICE DECIMAL(8,2), ";
+ sCreateStatement += "PRIMARY KEY(SALENR))";
+
+ if ( implCreateTable( xConn, sCreateStatement, s_tableNameSales ) )
+ {
+ String sInsertionPrefix = "INSERT INTO " + s_tableNameSales + " VALUES ";
+
+ implExecuteStatement( xConn, sInsertionPrefix + "(1, 100, 1, 'Fruits', '2005-02-12', 39.99)" );
+ implExecuteStatement( xConn, sInsertionPrefix + "(2, 101, 3, 'Beef', '2005-10-18', 15.78)" );
+ implExecuteStatement( xConn, sInsertionPrefix + "(3, 102, 3, 'Orange Juice', '2005-09-08', 25.63)" );
+ implExecuteStatement( xConn, sInsertionPrefix + "(4, 101, 2, 'Oil', '2005-03-01', 12.30)" );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** ensures that the tables we need for our example exist
+ */
+ protected void ensureTables() throws java.lang.Exception
+ {
+ // get the data source
+ XDataSource xDS = m_database.getDataSource();
+ XPropertySet xDSProps = UNO.queryPropertySet( xDS );
+
+ // connect to this data source
+ XConnection xConn = xDS.getConnection( "", "" );
+ XComponent xConnComp = UNO.queryComponent( xConn );
+
+ createTableSalesman( xConn );
+ createTableCustomer( xConn );
+ createTableSales( xConn );
+
+ // free the resources acquired by the connection
+ xConnComp.dispose();
+ }
+
+ /* ==================================================================
+ = sample document handling
+ ================================================================== */
+
+ /* ------------------------------------------------------------------ */
+ /** creates the button used for demonstrating (amongst others) event handling
+ @param nXPos
+ x-position of the to be inserted shape
+ @param nYPos
+ y-position of the to be inserted shape
+ @param nXSize
+ width of the to be inserted shape
+ @param sName
+ the name of the model in the form component hierarchy
+ @param sLabel
+ the label of the button control
+ @param sActionURL
+ the URL of the action which should be triggered by the button
+ @return
+ the model of the newly created button
+ */
+ protected XPropertySet createButton( int nXPos, int nYPos, int nXSize, String sName, String sLabel, short _formFeature ) throws java.lang.Exception
+ {
+ XPropertySet xButton = m_formLayer.createControlAndShape( "CommandButton", nXPos, nYPos, nXSize, 6 );
+ // the name for referring to it later:
+ xButton.setPropertyValue( "Name", sName );
+ // the label
+ xButton.setPropertyValue( "Label", sLabel );
+ // use the name as help text
+ xButton.setPropertyValue( "HelpText", sName );
+ // don't want buttons to be accessible by the "tab" key - this would be uncomfortable when traveling
+ // with records with "tab"
+ xButton.setPropertyValue( "Tabstop", Boolean.FALSE );
+ // similar, they should not steal the focus when clicked
+ xButton.setPropertyValue( "FocusOnClick", Boolean.FALSE );
+
+ m_aOperator.addButton( xButton, _formFeature );
+
+ return xButton;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** creates a column in a grid
+ @param xGridModel
+ specifies the model of the grid where the new column should be inserted
+ @param sColumnService
+ specifies the service name of the column to create (e.g. "NumericField")
+ @param sDataField
+ specifies the database field to which the column should be bound
+ @param nWidth
+ specifies the column width (in mm). If 0, no width is set.
+ @return
+ the newly created column
+ */
+ XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField, int nWidth )
+ throws com.sun.star.uno.Exception
+ {
+ // the container to insert columns into
+ XIndexContainer xColumnContainer = UNO.queryIndexContainer( aGridModel );
+ // the factory for creating column models
+ XGridColumnFactory xColumnFactory = UnoRuntime.queryInterface(
+ XGridColumnFactory.class, aGridModel );
+
+ // (let) create the new col
+ XInterface xNewCol = xColumnFactory.createColumn( sColumnService );
+ XPropertySet xColProps = UNO.queryPropertySet( xNewCol );
+
+ // some props
+ // the field the column is bound to
+ xColProps.setPropertyValue( "DataField", sDataField );
+ // the "display name" of the column
+ xColProps.setPropertyValue( "Label", sDataField );
+ // the name of the column within its parent
+ xColProps.setPropertyValue( "Name", sDataField );
+
+ if ( nWidth > 0 )
+ xColProps.setPropertyValue( "Width", Integer.valueOf( nWidth * 10 ) );
+
+ // insert
+ xColumnContainer.insertByIndex( xColumnContainer.getCount(), xNewCol );
+
+ // outta here
+ return xColProps;
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** creates a column in a grid
+ */
+ XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField )
+ throws com.sun.star.uno.Exception
+ {
+ return createGridColumn( aGridModel, sColumnService, sDataField );
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** creates our sample document
+ */
+ @Override
+ protected void prepareDocument() throws com.sun.star.uno.Exception, java.lang.Exception
+ {
+ super.prepareDocument();
+
+ m_database = new HsqlDatabase( m_xCtx );
+
+ // ensure that we have the tables needed for our example
+ ensureTables();
+
+
+ /* create some shapes */
+ XPropertySet xSNRField = m_formLayer.insertControlLine( "NumericField", "SNR", "", 3 );
+ m_formLayer.insertControlLine( "TextField", "FIRSTNAME", "", 11);
+ m_formLayer.insertControlLine( "TextField", "LASTNAME", "", 19 );
+ m_formLayer.insertControlLine( "TextField", "STREET", "", 27 );
+ m_formLayer.insertControlLine( "TextField", "STATE", "", 35 );
+ XPropertySet xZipField = m_formLayer.insertControlLine( "NumericField", "ZIP", "", 43 );
+ m_formLayer.insertControlLine( "FormattedField", "BIRTHDATE", "", 51 );
+
+ // for the salesman number / zip code, we don't want to have decimal places:
+ xSNRField.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) );
+ xZipField.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) );
+
+
+ /** need the form the control models belong to
+ for this, we simply obtain the parent for any of the control models we have
+
+ Note that this involves knowledge about the implementation: If a control shape is
+ inserted into a document, where the control model does not belong to the form component
+ hierarchy, yet, it is automatically inserted into the first form, which is created
+ if necessary.
+ */
+ m_xMasterForm = FLTools.getParent( xZipField );
+
+ // set the data source signature at the form
+ m_xMasterForm.setPropertyValue( "DataSourceName", m_database.getDocumentURL() );
+ m_xMasterForm.setPropertyValue( "CommandType", Integer.valueOf( CommandType.TABLE ) );
+ m_xMasterForm.setPropertyValue( "Command", "SALESMEN" );
+
+
+ // insert the buttons
+ // create our button operator, if necessary
+ m_aOperator = new ButtonOperator( m_xCtx, m_document, m_xMasterForm );
+
+ createButton( 2, 63, 8, "first", "<<", FormFeature.MoveToFirst );
+ createButton( 12, 63, 8, "prev", "<", FormFeature.MoveToPrevious );
+ createButton( 22, 63, 8, "next", ">", FormFeature.MoveToNext );
+ createButton( 32, 63, 8, "last", ">>", FormFeature.MoveToLast );
+ createButton( 42, 63, 8, "new", ">*", FormFeature.MoveToInsertRow );
+ createButton( 58, 63, 13, "reload", "reload", FormFeature.ReloadForm );
+
+
+ // create a sub form for the sales
+
+ // for this, first create a sub form and bind it to the SALES table
+ XIndexContainer xSalesForm = m_document.createSubForm( m_xMasterForm, "Sales" );
+ XPropertySet xSalesFormProps = UNO.queryPropertySet( xSalesForm );
+
+ xSalesFormProps.setPropertyValue( "DataSourceName", m_database.getDocumentURL() );
+ xSalesFormProps.setPropertyValue( "CommandType", Integer.valueOf( CommandType.COMMAND ) );
+
+ String sCommand = "SELECT * FROM ";
+ sCommand += s_tableNameSales;
+ sCommand += " WHERE " + s_tableNameSales + ".SNR = :salesmen";
+ xSalesFormProps.setPropertyValue( "Command", sCommand );
+
+ // the master-details connection
+ String[] aMasterFields = new String[] { "SNR" }; // the field in the master form
+ String[] aDetailFields = new String[] { "salesmen" }; // the name in the detail form
+ xSalesFormProps.setPropertyValue( "MasterFields", aMasterFields );
+ xSalesFormProps.setPropertyValue( "DetailFields", aDetailFields );
+
+ // the create thr grid model
+ XPropertySet xSalesGridModel = m_formLayer.createControlAndShape( "GridControl", 2, 80, 162, 40, xSalesForm );
+ xSalesGridModel.setPropertyValue( "Name", "SalesTable" );
+ XPropertySet xKeyColumn = createGridColumn( xSalesGridModel, "NumericField", "SALENR", 12 );
+ XPropertySet xCustomerColumn = createGridColumn( xSalesGridModel, "ListBox", "COS_NR", 40 );
+ XPropertySet xSalesNameColumn = createGridColumn( xSalesGridModel, "TextField", "NAME", 25 );
+ createGridColumn( xSalesGridModel, "DateField", "SALEDATE", 24 );
+ createGridColumn( xSalesGridModel, "CurrencyField", "PRICE", 16 );
+
+ // please note that a better solution for the SALEDATE field would have been to use
+ // a FormattedField. But we want to demonstrate some effects with DateFields here ...
+
+ m_aSalesNameValidator = new GridFieldValidator( m_xCtx, xSalesNameColumn );
+ m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales );
+
+ xKeyColumn.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) );
+
+ // init the list box which is for choosing the customer a sale belongs to
+ xCustomerColumn.setPropertyValue( "BoundColumn", Short.valueOf( (short)1 ) );
+ xCustomerColumn.setPropertyValue( "Label", "Customer" );
+ xCustomerColumn.setPropertyValue( "ListSourceType", ListSourceType.SQL );
+
+ String sListSource = "SELECT LASTNAME, COS_NR FROM ";
+ sListSource += s_tableNameCustomers;
+ String[] aListSource = new String[] { sListSource };
+ xCustomerColumn.setPropertyValue( "ListSource", aListSource );
+
+ // We want to demonstrate how to reset fields to NULL, we do this with the SALEDATE field
+ // above. For this, we add as reset listener to the form
+ XReset xFormReset = UNO.queryReset( xSalesForm );
+ xFormReset.addResetListener( this );
+
+
+
+ // the option for filtering the sales form
+ XIndexContainer xSalesFilterForm = m_document.createSiblingForm( xSalesForm, "SalesFilter" );
+ XPropertySet xSFFProps = UNO.queryPropertySet( xSalesFilterForm );
+ XPropertySet xLabel = m_formLayer.createControlAndShape( "FixedText", 2, 125, 35, 6, xSalesFilterForm );
+ xLabel.setPropertyValue( "Label", "show only sales since" );
+ xLabel.setPropertyValue( "Name", "FilterLabel" );
+
+ XPropertySet xFilterSelection = m_formLayer.createControlAndShape( "ListBox", 40, 125, 59, 6, xSalesFilterForm );
+ xFilterSelection.setPropertyValue( "Name", "FilterList" );
+ xFilterSelection.setPropertyValue( "LabelControl", xLabel );
+ XPropertySet xManualFilter = m_formLayer.createControlAndShape( "DateField", 104, 125, 30, 6, xSalesFilterForm );
+ xManualFilter.setPropertyValue( "Name", "ManualFilter" );
+ XPropertySet xApplyFilter = m_formLayer.createControlAndShape( "CommandButton", 139, 125, 25, 6, xSalesFilterForm );
+ xApplyFilter.setPropertyValue( "Name", "ApplyFilter" );
+ xApplyFilter.setPropertyValue( "DefaultButton", Boolean.TRUE );
+ new SalesFilter( m_document, xSalesFormProps, xFilterSelection,
+ xManualFilter, xApplyFilter );
+
+
+
+ // the options section
+ // for this, we need a form which is a sibling of our master form (don't want to interfere
+ // the controls which represent options only with the controls which are used for data access)
+
+ XIndexContainer xOptionsForm = m_document.createSiblingForm( m_xMasterForm, "Options" );
+
+ xLabel = m_formLayer.createControlAndShape( "GroupBox", 98, 0, 66, 62, xOptionsForm );
+ xLabel.setPropertyValue( "Name", "Options" );
+ xLabel.setPropertyValue( "Label", "Options" );
+
+ // radio buttons which controls how we generate unique keys
+ xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 5, 56, 25, xOptionsForm );
+ xLabel.setPropertyValue( "Label", "key generation" );
+ xLabel.setPropertyValue( "Name", "KeyGeneration" );
+ XPropertySet xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 11, 50, 6, xOptionsForm );
+ xKeyGen.setPropertyValue( "Name", "KeyGen" );
+ xKeyGen.setPropertyValue( "Label", "no automatic generation" );
+ xKeyGen.setPropertyValue( "RefValue", "none" );
+ xKeyGen.addPropertyChangeListener( "State", this );
+
+ xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 17, 50, 6, xOptionsForm );
+ xKeyGen.setPropertyValue( "Name", "KeyGen" );
+ xKeyGen.setPropertyValue( "Label", "before inserting a record" );
+ xKeyGen.setPropertyValue( "RefValue", "update" );
+ xKeyGen.addPropertyChangeListener( "State", this );
+
+ xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 23, 50, 6, xOptionsForm );
+ xKeyGen.setPropertyValue( "Name", "KeyGen" );
+ xKeyGen.setPropertyValue( "Label", "when moving to a new record" );
+ xKeyGen.setPropertyValue( "RefValue", "reset" );
+ xKeyGen.addPropertyChangeListener( "State", this );
+
+ // initialize listeners
+ // master form - key generation
+ m_aSalesmanKeyGenerator = new KeyGenerator( m_xMasterForm, "SNR", m_xCtx );
+ m_aSalesmanKeyGenerator.activateKeyGenerator( true );
+ // master form - control locking
+ m_aSalesmenLocker = new ControlLock( m_xMasterForm, "SNR" );
+ m_aSalesmenLocker.enableLock( m_bProtectKeyFields );
+
+ // details form - key generation
+ m_aSalesKeyGenerator = new KeyGenerator( xSalesFormProps, "SALENR", m_xCtx );
+ m_aSalesKeyGenerator.activateKeyGenerator( true );
+
+ // details form - control locking
+ m_aSalesLocker = new ControlLock( xSalesFormProps, "SALENR" );
+ m_aSalesLocker.enableLock( m_bProtectKeyFields );
+
+ // initially, we want to generate keys when moving to a new record
+ xKeyGen.setPropertyValue( "DefaultState", Short.valueOf( (short)1 ) );
+
+
+ // second options block
+ xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 33, 56, 25, xOptionsForm );
+ xLabel.setPropertyValue( "Name", "Misc" );
+ xLabel.setPropertyValue( "Label", "Miscellaneous" );
+
+ XPropertySet xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 39, 60, 6, xOptionsForm );
+ xCheck.setPropertyValue( "Name", "defaultdate" );
+ xCheck.setPropertyValue( "Label", "default sales date to \"today\"" );
+ xCheck.setPropertyValue( "HelpText", "When checked, newly entered sales records are pre-filled with today's date, else left empty." );
+ xCheck.addPropertyChangeListener( "State", this );
+
+ xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 45, 60, 6, xOptionsForm );
+ xCheck.setPropertyValue( "Name", "protectkeys" );
+ xCheck.setPropertyValue( "Label", "protect key fields from editing" );
+ xCheck.setPropertyValue( "HelpText", "When checked, you cannot modify the values in the table's key fields (SNR and SALENR)" );
+ xCheck.addPropertyChangeListener( "State", this );
+
+ xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 51, 60, 6, xOptionsForm );
+ xCheck.setPropertyValue( "Name", "emptysales" );
+ xCheck.setPropertyValue( "Label", "check for empty sales names" );
+ xCheck.setPropertyValue( "HelpText", "When checked, you cannot enter empty values into the NAME column of the 'Sales' table." );
+ xCheck.addPropertyChangeListener( "State", this );
+
+ // dump the form component tree
+ enumFormComponents( );
+ }
+
+ /* ------------------------------------------------------------------ */
+ @Override
+ protected void onFormsAlive()
+ {
+ m_aOperator.onFormsAlive();
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** performs any cleanup before exiting the program
+ */
+ @Override
+ protected void cleanUp( ) throws java.lang.Exception
+ {
+ // remove the listeners at the buttons
+ RevokeButtons aRevoke = new RevokeButtons( m_aOperator );
+ aRevoke.handle( m_document.getFormComponentTreeRoot( ) );
+
+ // remove the key generator listeners from the form
+ m_aSalesmanKeyGenerator.stopGenerator( );
+ m_aSalesKeyGenerator.stopGenerator( );
+
+ // and the control lockers
+ m_aSalesmenLocker.enableLock( false );
+ m_aSalesLocker.enableLock( false );
+
+ // the validator for the grid column
+ m_aSalesNameValidator.enableColumnWatch( false );
+
+ // remove our own reset listener from the form
+ XNameAccess xMasterAsNames = UnoRuntime.queryInterface(
+ XNameAccess.class, m_xMasterForm );
+ XReset xFormReset = UNO.queryReset( xMasterAsNames.getByName( "Sales" ) );
+ xFormReset.removeResetListener( this );
+
+ super.cleanUp();
+ }
+
+ /* ------------------------------------------------------------------ */
+ /** class entry point
+ */
+ public static void main(String argv[]) throws java.lang.Exception
+ {
+ DataAwareness aSample = new DataAwareness();
+ aSample.run( argv );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */