Branch libreoffice-5-0-4
[LibreOffice.git] / odk / examples / DevelopersGuide / Forms / DataAwareness.java
blob5674657915f300ad3df52983a3f37482b7d15062
1 /*************************************************************************
3 * The Contents of this file are made available subject to the terms of
4 * the BSD license.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of Sun Microsystems, Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *************************************************************************/
34 import com.sun.star.beans.PropertyChangeEvent;
35 import com.sun.star.beans.XPropertyChangeListener;
36 import com.sun.star.beans.XPropertySet;
39 // __________ Imports __________
40 import com.sun.star.beans.XPropertySetInfo;
42 // base classes
43 import com.sun.star.container.XIndexContainer;
44 import com.sun.star.container.XNameAccess;
45 import com.sun.star.container.XNamed;
46 import com.sun.star.form.FormComponentType;
47 import com.sun.star.form.ListSourceType;
48 import com.sun.star.form.XGridColumnFactory;
49 import com.sun.star.form.XReset;
50 import com.sun.star.form.XResetListener;
51 import com.sun.star.form.runtime.FormFeature;
52 import com.sun.star.lang.EventObject;
53 import com.sun.star.lang.XComponent;
54 import com.sun.star.sdb.CommandType;
55 import com.sun.star.sdb.XColumnUpdate;
56 import com.sun.star.sdbc.ResultSetConcurrency;
57 import com.sun.star.sdbc.XConnection;
58 import com.sun.star.sdbc.XDataSource;
59 import com.sun.star.sdbc.XStatement;
60 import com.sun.star.sdbcx.XColumnsSupplier;
61 import com.sun.star.uno.UnoRuntime;
62 import com.sun.star.uno.XInterface;
64 /**************************************************************************/
65 /** a class for enumerating a form component tree
67 class PrintComponentTree extends ComponentTreeTraversal
69 private String m_sPrefix;
71 public PrintComponentTree()
73 m_sPrefix = "";
76 @Override
77 public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
79 // the name of the child
80 XNamed xName = UnoRuntime.queryInterface( XNamed.class, aFormComponent );
82 // if it's a form control model, check it's type
83 XPropertySet xProps = UNO.queryPropertySet( aFormComponent );
84 String sTypeName = FLTools.classifyFormComponentType( xProps );
86 String sName;
87 if ( null == xName )
88 sName = "<unnamed>";
89 else
90 sName = xName.getName();
92 // print the component's name
93 if ( 0 != sTypeName.length() )
95 System.out.println( m_sPrefix + sName + " (" + sTypeName + ")" );
97 else
99 System.out.println( m_sPrefix + sName );
102 // let the super class step down the tree
103 m_sPrefix = m_sPrefix + " ";
104 super.handle( aFormComponent );
105 m_sPrefix = m_sPrefix.substring( 0, m_sPrefix.length() - 1 );
109 /**************************************************************************/
110 /** a class revoking button models from a ButtonOperator instance
112 class RevokeButtons extends ComponentTreeTraversal
114 private ButtonOperator m_aOperator;
116 public RevokeButtons( ButtonOperator aOperator )
118 m_aOperator = aOperator;
121 @Override
122 public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
124 // check if it's a button
125 XPropertySet xProps = UNO.queryPropertySet( aFormComponent );
126 XPropertySetInfo xPI = null;
127 if ( null != xProps )
128 xPI = xProps.getPropertySetInfo();
129 if ( ( null != xPI ) && xPI.hasPropertyByName( "ClassId" ) )
131 Short nClassId = (Short)xProps.getPropertyValue( "ClassId" );
132 if ( FormComponentType.COMMANDBUTTON == nClassId.shortValue() )
134 // yes, it is
135 m_aOperator.revokeButton( xProps );
139 // let the super class step down the tree (if possible)
140 super.handle( aFormComponent );
144 /**************************************************************************/
145 public class DataAwareness extends DocumentBasedExample implements XPropertyChangeListener, XResetListener
147 /* ================================================================== */
148 private HsqlDatabase m_database;
150 private static final String s_tableNameSalesmen = "SALESMEN";
151 private static final String s_tableNameCustomers = "CUSTOMERS";
152 private static final String s_tableNameSales = "SALES";
154 private XPropertySet m_xMasterForm;
155 private ButtonOperator m_aOperator;
157 private KeyGenerator m_aSalesmanKeyGenerator;
158 private KeyGenerator m_aSalesKeyGenerator;
159 private ControlLock m_aSalesmenLocker;
160 private ControlLock m_aSalesLocker;
161 private GridFieldValidator m_aSalesNameValidator;
163 private boolean m_bDefaultSalesDate;
164 private boolean m_bProtectKeyFields;
165 private boolean m_bAllowEmptySales;
167 /* ------------------------------------------------------------------ */
168 public DataAwareness()
170 super( DocumentType.WRITER );
171 m_bDefaultSalesDate = false;
172 m_bProtectKeyFields = false;
173 m_bAllowEmptySales = false;
176 /* ==================================================================
177 = form components
178 ================================================================== */
180 /* ------------------------------------------------------------------ */
181 /** enumerates and prints all the elements in the given container, together with the container itself
183 protected void enumFormComponents( XNameAccess xContainer ) throws java.lang.Exception
185 String sObjectName;
187 XNamed xNameAcc = UnoRuntime.queryInterface( XNamed.class, xContainer );
188 if ( null == xNameAcc )
189 sObjectName = "<unnamed>";
190 else
191 sObjectName = xNameAcc.getName();
192 System.out.println( "enumerating the container named \"" + sObjectName +
193 "\"\n" );
195 PrintComponentTree aPrinter = new PrintComponentTree();
196 aPrinter.handle( xContainer );
199 /* ------------------------------------------------------------------ */
200 /** enumerates and prints all form elements in the document
202 protected void enumFormComponents( ) throws java.lang.Exception
204 enumFormComponents( m_document.getFormComponentTreeRoot() );
207 /* ==================================================================
208 = UNO callbacks
209 ================================================================== */
211 /* ------------------------------------------------------------------ */
212 // XResetListener overridables
213 /* ------------------------------------------------------------------ */
214 public boolean approveReset( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
216 // not interested in vetoing this
217 return true;
220 /* ------------------------------------------------------------------ */
221 public void resetted( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
223 // check if this reset occurred because we're on a new record
224 XPropertySet xFormProps = UNO.queryPropertySet( aEvent.Source );
227 Boolean aIsNew = (Boolean)xFormProps.getPropertyValue( "IsNew" );
228 if ( aIsNew.booleanValue() )
229 { // yepp
231 if ( !m_bDefaultSalesDate )
232 { // we're interested to do all this only if the user told us to default the sales date
233 // to "today"
234 // As date fields do this defaulting automatically, the semantics is inverted here:
235 // If we're told to default, we must do nothing, if we should not default, we must
236 // reset the value which the date field set automatically.
238 Integer aConcurrency = (Integer)xFormProps.getPropertyValue( "ResultSetConcurrency" );
239 if ( ResultSetConcurrency.READ_ONLY != aConcurrency.intValue() )
241 // we're going to modify the record, though after that, to the user, it should look
242 // like it has not been modified
243 // So we need to ensure that we do not change the IsModified property with whatever we do
244 Object aModifiedFlag = xFormProps.getPropertyValue( "IsModified" );
247 // get the columns of our master form
248 XColumnsSupplier xSuppCols = UnoRuntime.queryInterface(
249 XColumnsSupplier.class, xFormProps );
250 XNameAccess xCols = xSuppCols.getColumns();
252 // and update the date column with a NULL value
253 XColumnUpdate xDateColumn = UnoRuntime.queryInterface(
254 XColumnUpdate.class, xCols.getByName( "SALEDATE" ) );
255 xDateColumn.updateNull();
258 // then restore the flag
259 xFormProps.setPropertyValue( "IsModified", aModifiedFlag );
264 catch( com.sun.star.uno.Exception e )
266 System.out.println(e);
267 e.printStackTrace();
271 /* ------------------------------------------------------------------ */
272 // XPropertyChangeListener overridables
273 /* ------------------------------------------------------------------ */
274 public void propertyChange( PropertyChangeEvent aEvent ) throws com.sun.star.uno.RuntimeException
278 // did it come from a radio button or checkbox?
279 if ( aEvent.PropertyName.equals( "State" ) )
280 { // yep
281 Short aNewState = (Short)aEvent.NewValue;
283 XPropertySet xModel = UNO.queryPropertySet( aEvent.Source );
284 String sName = (String)xModel.getPropertyValue( "Name" );
286 Short aClassId = (Short)xModel.getPropertyValue( "ClassId" );
287 if ( FormComponentType.RADIOBUTTON == aClassId.shortValue() )
289 String sRefValue = (String)xModel.getPropertyValue( "RefValue" );
291 short nNewValue = ((Short)aEvent.NewValue).shortValue();
292 if ( sName.equals( "KeyGen" ) )
294 // it's one of the options for key generation
295 if ( sRefValue.equals( "none" ) )
296 { // no automatic generation at all
297 m_aSalesmanKeyGenerator.stopGenerator( );
298 m_aSalesKeyGenerator.stopGenerator( );
300 else
302 boolean bGenerateOnReset = true;
303 if ( sRefValue.equals( "update" ) )
304 { // generate on update
305 bGenerateOnReset = ( 0 == nNewValue );
307 else if ( sRefValue.equals( "reset" ) )
308 { // generat on reset
309 bGenerateOnReset = ( 0 != nNewValue );
311 m_aSalesmanKeyGenerator.activateKeyGenerator( bGenerateOnReset );
312 m_aSalesKeyGenerator.activateKeyGenerator( bGenerateOnReset );
316 else if ( FormComponentType.CHECKBOX == aClassId.shortValue() )
318 boolean bEnabled = ( 0 != aNewState.shortValue() );
319 if ( sName.equals( "defaultdate" ) )
321 m_bDefaultSalesDate = bEnabled;
323 else if ( sName.equals( "protectkeys" ) )
325 m_bProtectKeyFields = bEnabled;
326 m_aSalesmenLocker.enableLock( m_bProtectKeyFields );
327 m_aSalesLocker.enableLock( m_bProtectKeyFields );
329 else if ( sName.equals( "emptysales" ) )
331 m_bAllowEmptySales = bEnabled;
332 m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales );
337 catch(com.sun.star.uno.Exception e)
339 System.out.println(e);
340 e.printStackTrace();
344 /* ------------------------------------------------------------------ */
345 // XEventListener overridables
346 /* ------------------------------------------------------------------ */
347 @Override
348 public void disposing( EventObject aEvent )
350 // simply disambiguate
351 super.disposing( aEvent );
354 /* ==================================================================
355 = miscellaneous
356 ================================================================== */
358 /* ------------------------------------------------------------------ */
359 /** skips line feeds in the input stream
361 @returns
362 the first character which does not belong to a line feed
364 protected int skipLineFeeds( java.io.InputStream aInput ) throws java.io.IOException
366 // read characters, until we encounter something which is not a line feed character
367 int nChar = aInput.read( );
368 while ( ( 13 == nChar ) || ( 10 == nChar ) )
369 nChar = aInput.read( );
371 // now read everything which is behind this single character we are interested in
372 while ( 0 < aInput.available() )
373 aInput.read( );
375 return nChar;
378 /* ==================================================================
379 = table handling
380 ================================================================== */
381 /* ------------------------------------------------------------------ */
382 /** checks if a given table exists.
384 <p>The check is made using a SELECT statement, so even if the connection
385 is a n SDB-level connection, which may filter tables in it's table
386 supplier, the result may be reliable ....</p>
388 protected boolean existsInvisibleTable( XConnection xConn, String sTableName ) throws java.lang.Exception
390 String sStatement = "SELECT * FROM ";
391 sStatement += sTableName;
392 sStatement += " WHERE 0=1";
394 boolean bSuccess = false;
397 XStatement xStatement = xConn.createStatement();
398 xStatement.execute( sStatement );
399 // if we reached this point, the table probably exists
400 bSuccess = true;
402 catch(com.sun.star.sdbc.SQLException e)
405 return bSuccess;
408 /* ------------------------------------------------------------------ */
409 /** add a specified table name to the table filter of the given data source.
411 protected void makeTableVisible( XDataSource xDS, String sTableName ) throws java.lang.Exception
413 // get the table filter
414 XPropertySet xDSP = UNO.queryPropertySet( xDS );
415 String[] aCurrentFilter = (String[])xDSP.getPropertyValue( "TableFilter" );
417 // check if the table name is already part of it
418 String sAllTables = "*"; // all tables
420 for ( int i=0; i<aCurrentFilter.length; ++i )
422 String sCurrentTableFilter = aCurrentFilter[i];
424 if ( sCurrentTableFilter.equals( sTableName ) )
425 return;
426 if ( sCurrentTableFilter.equals( sAllTables ) )
427 return;
430 // if we are here, we have to add our table to the filter sequence
431 String[] aNewFilter = new String[ aCurrentFilter.length + 1 ];
432 // copy the existent filter entries
433 for ( int i=0; i<aCurrentFilter.length; ++i )
434 aNewFilter[i] = aCurrentFilter[i];
435 // add our table
436 aNewFilter[ aCurrentFilter.length ] = sTableName;
438 xDSP.setPropertyValue( "TableFilter", aNewFilter );
441 /* ------------------------------------------------------------------ */
442 /** executes the given statement on the given connection
444 protected boolean implExecuteStatement( XConnection xConn, String sStatement ) throws java.lang.Exception
448 XStatement xStatement = xConn.createStatement( );
449 xStatement.execute( sStatement );
451 catch(com.sun.star.sdbc.SQLException e)
453 System.err.println( e );
454 return false;
457 return true;
460 /* ------------------------------------------------------------------ */
461 /** creates the table with the given name, using the given statement
463 protected boolean implCreateTable( XConnection xConn, String sCreateStatement, String sTableName ) throws java.lang.Exception
465 if ( !implExecuteStatement( xConn, sCreateStatement ) )
467 System.out.println( " could not create the table " + sTableName + "." );
468 System.out.println( );
469 return false;
472 return true;
475 /* ------------------------------------------------------------------ */
476 /** creates the table SALESMEN
478 @return
479 <TRUE/> if and only if the creation succeeded
481 protected boolean createTableSalesman( XConnection xConn ) throws java.lang.Exception
483 String sCreateStatement = "CREATE TABLE " + s_tableNameSalesmen + " ";
484 sCreateStatement += "(SNR INTEGER NOT NULL, ";
485 sCreateStatement += "FIRSTNAME VARCHAR(50), ";
486 sCreateStatement += "LASTNAME VARCHAR(100), ";
487 sCreateStatement += "STREET VARCHAR(50), ";
488 sCreateStatement += "STATE VARCHAR(50), ";
489 sCreateStatement += "ZIP INTEGER, ";
490 sCreateStatement += "BIRTHDATE DATE, ";
491 sCreateStatement += "PRIMARY KEY(SNR))";
493 if ( implCreateTable( xConn, sCreateStatement, s_tableNameSalesmen) )
495 String sInsertionPrefix = "INSERT INTO " + s_tableNameSalesmen + " VALUES ";
497 implExecuteStatement( xConn, sInsertionPrefix + "(1, 'Joseph', 'Smith', 'Bond Street', 'CA', 95460, '1946-07-02')" );
498 implExecuteStatement( xConn, sInsertionPrefix + "(2, 'Frank', 'Jones', 'Lake silver', 'CA', 95460, '1963-12-24')" );
499 implExecuteStatement( xConn, sInsertionPrefix + "(3, 'Jane', 'Esperansa', '23 Hollywood driver', 'CA', 95460, '1972-04-01')" );
501 return true;
503 return false;
506 /* ------------------------------------------------------------------ */
507 /** creates the table CUSTOMERS
509 @return
510 <TRUE/> if and only if the creation succeeded
512 protected boolean createTableCustomer( XConnection xConn ) throws java.lang.Exception
514 String sCreateStatement = "CREATE TABLE " + s_tableNameCustomers + " ";
515 sCreateStatement += "(COS_NR INTEGER NOT NULL, ";
516 sCreateStatement += "LASTNAME VARCHAR(100), ";
517 sCreateStatement += "STREET VARCHAR(50), ";
518 sCreateStatement += "CITY VARCHAR(50), ";
519 sCreateStatement += "STATE VARCHAR(50), ";
520 sCreateStatement += "ZIP INTEGER, ";
521 sCreateStatement += "PRIMARY KEY(COS_NR))";
523 if ( implCreateTable( xConn, sCreateStatement, s_tableNameCustomers ) )
525 String sInsertionPrefix = "INSERT INTO " + s_tableNameCustomers + " VALUES ";
527 implExecuteStatement( xConn, sInsertionPrefix + "(100, 'Acme, Inc.', '99 Market Street', 'Groundsville', 'CA', 95199)" );
528 implExecuteStatement( xConn, sInsertionPrefix + "(101, 'Superior BugSoft', '1 Party Place', 'Mendocino', 'CA', 95460)");
529 implExecuteStatement( xConn, sInsertionPrefix + "(102, 'WeKnowAll, Inc.', '100 Coffee Lane', 'Meadows', 'CA', 93699)");
531 return true;
533 return false;
536 /* ------------------------------------------------------------------ */
537 /** creates the table SALES
539 @return
540 <TRUE/> if and only if the creation succeeded
542 protected boolean createTableSales( XConnection xConn ) throws java.lang.Exception
544 String sCreateStatement = "CREATE TABLE " + s_tableNameSales + " ";
545 sCreateStatement += "(SALENR INTEGER NOT NULL, ";
546 sCreateStatement += "COS_NR INTEGER NOT NULL, ";
547 sCreateStatement += "SNR INTEGER NOT NULL, ";
548 sCreateStatement += "NAME VARCHAR(50), ";
549 sCreateStatement += "SALEDATE DATE, ";
550 sCreateStatement += "PRICE DECIMAL(8,2), ";
551 sCreateStatement += "PRIMARY KEY(SALENR))";
553 if ( implCreateTable( xConn, sCreateStatement, s_tableNameSales ) )
555 String sInsertionPrefix = "INSERT INTO " + s_tableNameSales + " VALUES ";
557 implExecuteStatement( xConn, sInsertionPrefix + "(1, 100, 1, 'Fruits', '2005-02-12', 39.99)" );
558 implExecuteStatement( xConn, sInsertionPrefix + "(2, 101, 3, 'Beef', '2005-10-18', 15.78)" );
559 implExecuteStatement( xConn, sInsertionPrefix + "(3, 102, 3, 'Orange Juice', '2005-09-08', 25.63)" );
560 implExecuteStatement( xConn, sInsertionPrefix + "(4, 101, 2, 'Oil', '2005-03-01', 12.30)" );
562 return true;
565 return false;
568 /* ------------------------------------------------------------------ */
569 /** ensures that the tables we need for our example exist
571 protected void ensureTables() throws java.lang.Exception
573 // get the data source
574 XDataSource xDS = m_database.getDataSource();
575 XPropertySet xDSProps = UNO.queryPropertySet( xDS );
577 // connect to this data source
578 XConnection xConn = xDS.getConnection( "", "" );
579 XComponent xConnComp = UNO.queryComponent( xConn );
581 createTableSalesman( xConn );
582 createTableCustomer( xConn );
583 createTableSales( xConn );
585 // free the resources acquired by the connection
586 xConnComp.dispose();
589 /* ==================================================================
590 = sample document handling
591 ================================================================== */
593 /* ------------------------------------------------------------------ */
594 /** creates the button used for demonstrating (amonst others) event handling
595 @param nXPos
596 x-position of the to be inserted shape
597 @param nYPos
598 y-position of the to be inserted shape
599 @param nXSize
600 width of the to be inserted shape
601 @param sName
602 the name of the model in the form component hierarchy
603 @param sLabel
604 the label of the button control
605 @param sActionURL
606 the URL of the action which should be triggered by the button
607 @return
608 the model of the newly created button
610 protected XPropertySet createButton( int nXPos, int nYPos, int nXSize, String sName, String sLabel, short _formFeature ) throws java.lang.Exception
612 XPropertySet xButton = m_formLayer.createControlAndShape( "CommandButton", nXPos, nYPos, nXSize, 6 );
613 // the name for referring to it later:
614 xButton.setPropertyValue( "Name", sName );
615 // the label
616 xButton.setPropertyValue( "Label", sLabel );
617 // use the name as help text
618 xButton.setPropertyValue( "HelpText", sName );
619 // don't want buttons to be accessible by the "tab" key - this would be uncomfortable when traveling
620 // with records with "tab"
621 xButton.setPropertyValue( "Tabstop", Boolean.FALSE );
622 // similar, they should not steal the focus when clicked
623 xButton.setPropertyValue( "FocusOnClick", Boolean.FALSE );
625 m_aOperator.addButton( xButton, _formFeature );
627 return xButton;
630 /* ------------------------------------------------------------------ */
631 /** creates a column in a grid
632 @param xGridModel
633 specifies the model of the grid where the new column should be inserted
634 @param sColumnService
635 specifies the service name of the column to create (e.g. "NumericField")
636 @param sDataField
637 specifies the database field to which the column should be bound
638 @param nWidth
639 specifies the column width (in mm). If 0, no width is set.
640 @return
641 the newly created column
643 XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField, int nWidth )
644 throws com.sun.star.uno.Exception
646 // the container to insert columns into
647 XIndexContainer xColumnContainer = UNO.queryIndexContainer( aGridModel );
648 // the factory for creating column models
649 XGridColumnFactory xColumnFactory = UnoRuntime.queryInterface(
650 XGridColumnFactory.class, aGridModel );
652 // (let) create the new col
653 XInterface xNewCol = xColumnFactory.createColumn( sColumnService );
654 XPropertySet xColProps = UNO.queryPropertySet( xNewCol );
656 // some props
657 // the field the column is bound to
658 xColProps.setPropertyValue( "DataField", sDataField );
659 // the "display name" of the column
660 xColProps.setPropertyValue( "Label", sDataField );
661 // the name of the column within its parent
662 xColProps.setPropertyValue( "Name", sDataField );
664 if ( nWidth > 0 )
665 xColProps.setPropertyValue( "Width", Integer.valueOf( nWidth * 10 ) );
667 // insert
668 xColumnContainer.insertByIndex( xColumnContainer.getCount(), xNewCol );
670 // outta here
671 return xColProps;
674 /* ------------------------------------------------------------------ */
675 /** creates a column in a grid
677 XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField )
678 throws com.sun.star.uno.Exception
680 return createGridColumn( aGridModel, sColumnService, sDataField );
683 /* ------------------------------------------------------------------ */
684 /** creates our sample document
686 @Override
687 protected void prepareDocument() throws com.sun.star.uno.Exception, java.lang.Exception
689 super.prepareDocument();
691 m_database = new HsqlDatabase( m_xCtx );
693 // ensure that we have the tables needed for our example
694 ensureTables();
697 /* create some shapes */
698 XPropertySet xSNRField = m_formLayer.insertControlLine( "NumericField", "SNR", "", 3 );
699 m_formLayer.insertControlLine( "TextField", "FIRSTNAME", "", 11);
700 m_formLayer.insertControlLine( "TextField", "LASTNAME", "", 19 );
701 m_formLayer.insertControlLine( "TextField", "STREET", "", 27 );
702 m_formLayer.insertControlLine( "TextField", "STATE", "", 35 );
703 XPropertySet xZipField = m_formLayer.insertControlLine( "NumericField", "ZIP", "", 43 );
704 m_formLayer.insertControlLine( "FormattedField", "BIRTHDATE", "", 51 );
706 // for the salesman number / zip code, we don't want to have decimal places:
707 xSNRField.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) );
708 xZipField.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) );
711 /** need the form the control models belong to
712 for this, we simply obtain the parent for any of the control models we have
714 Note that this involves knowledge about the implementation: If a control shape is
715 inserted into a document, where the control model does not belong to the form component
716 hierarchy, yet, it is automatically inserted into the first form, which is created
717 if necessary.
719 m_xMasterForm = FLTools.getParent( xZipField );
721 // set the data source signature at the form
722 m_xMasterForm.setPropertyValue( "DataSourceName", m_database.getDocumentURL() );
723 m_xMasterForm.setPropertyValue( "CommandType", Integer.valueOf( CommandType.TABLE ) );
724 m_xMasterForm.setPropertyValue( "Command", "SALESMEN" );
727 // insert the buttons
728 // create our button operator, if necessary
729 m_aOperator = new ButtonOperator( m_xCtx, m_document, m_xMasterForm );
731 createButton( 2, 63, 8, "first", "<<", FormFeature.MoveToFirst );
732 createButton( 12, 63, 8, "prev", "<", FormFeature.MoveToPrevious );
733 createButton( 22, 63, 8, "next", ">", FormFeature.MoveToNext );
734 createButton( 32, 63, 8, "last", ">>", FormFeature.MoveToLast );
735 createButton( 42, 63, 8, "new", ">*", FormFeature.MoveToInsertRow );
736 createButton( 58, 63, 13, "reload", "reload", FormFeature.ReloadForm );
739 // create a sub form for the sales
741 // for this, first create a sub form and bind it to the SALES table
742 XIndexContainer xSalesForm = m_document.createSubForm( m_xMasterForm, "Sales" );
743 XPropertySet xSalesFormProps = UNO.queryPropertySet( xSalesForm );
745 xSalesFormProps.setPropertyValue( "DataSourceName", m_database.getDocumentURL() );
746 xSalesFormProps.setPropertyValue( "CommandType", Integer.valueOf( CommandType.COMMAND ) );
748 String sCommand = "SELECT * FROM ";
749 sCommand += s_tableNameSales;
750 sCommand += " WHERE " + s_tableNameSales + ".SNR = :salesmen";
751 xSalesFormProps.setPropertyValue( "Command", sCommand );
753 // the master-details connection
754 String[] aMasterFields = new String[] { "SNR" }; // the field in the master form
755 String[] aDetailFields = new String[] { "salesmen" }; // the name in the detail form
756 xSalesFormProps.setPropertyValue( "MasterFields", aMasterFields );
757 xSalesFormProps.setPropertyValue( "DetailFields", aDetailFields );
759 // the create thr grid model
760 XPropertySet xSalesGridModel = m_formLayer.createControlAndShape( "GridControl", 2, 80, 162, 40, xSalesForm );
761 xSalesGridModel.setPropertyValue( "Name", "SalesTable" );
762 XPropertySet xKeyColumn = createGridColumn( xSalesGridModel, "NumericField", "SALENR", 12 );
763 XPropertySet xCustomerColumn = createGridColumn( xSalesGridModel, "ListBox", "COS_NR", 40 );
764 XPropertySet xSalesNameColumn = createGridColumn( xSalesGridModel, "TextField", "NAME", 25 );
765 createGridColumn( xSalesGridModel, "DateField", "SALEDATE", 24 );
766 createGridColumn( xSalesGridModel, "CurrencyField", "PRICE", 16 );
768 // please note that a better solution for the SALEDATE field would have been to use
769 // a FormattedField. But we want to demonstrate some effects with DateFields here ...
771 m_aSalesNameValidator = new GridFieldValidator( m_xCtx, xSalesNameColumn );
772 m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales );
774 xKeyColumn.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) );
776 // init the list box which is for choosing the customer a sale belongs to
777 xCustomerColumn.setPropertyValue( "BoundColumn", Short.valueOf( (short)1 ) );
778 xCustomerColumn.setPropertyValue( "Label", "Customer" );
779 xCustomerColumn.setPropertyValue( "ListSourceType", ListSourceType.SQL );
781 String sListSource = "SELECT LASTNAME, COS_NR FROM ";
782 sListSource += s_tableNameCustomers;
783 String[] aListSource = new String[] { sListSource };
784 xCustomerColumn.setPropertyValue( "ListSource", aListSource );
786 // We want to demonstrate how to reset fields to NULL, we do this with the SALEDATE field
787 // above. For this, we add as reset listener to the form
788 XReset xFormReset = UNO.queryReset( xSalesForm );
789 xFormReset.addResetListener( this );
793 // the option for filtering the sales form
794 XIndexContainer xSalesFilterForm = m_document.createSiblingForm( xSalesForm, "SalesFilter" );
795 XPropertySet xSFFProps = UNO.queryPropertySet( xSalesFilterForm );
796 XPropertySet xLabel = m_formLayer.createControlAndShape( "FixedText", 2, 125, 35, 6, xSalesFilterForm );
797 xLabel.setPropertyValue( "Label", "show only sales since" );
798 xLabel.setPropertyValue( "Name", "FilterLabel" );
800 XPropertySet xFilterSelection = m_formLayer.createControlAndShape( "ListBox", 40, 125, 59, 6, xSalesFilterForm );
801 xFilterSelection.setPropertyValue( "Name", "FilterList" );
802 xFilterSelection.setPropertyValue( "LabelControl", xLabel );
803 XPropertySet xManualFilter = m_formLayer.createControlAndShape( "DateField", 104, 125, 30, 6, xSalesFilterForm );
804 xManualFilter.setPropertyValue( "Name", "ManualFilter" );
805 XPropertySet xApplyFilter = m_formLayer.createControlAndShape( "CommandButton", 139, 125, 25, 6, xSalesFilterForm );
806 xApplyFilter.setPropertyValue( "Name", "ApplyFilter" );
807 xApplyFilter.setPropertyValue( "DefaultButton", Boolean.TRUE );
808 new SalesFilter( m_document, xSalesFormProps, xFilterSelection,
809 xManualFilter, xApplyFilter );
813 // the options section
814 // for this, we need a form which is a sibling of our master form (don't want to interfere
815 // the controls which represent options only with the controls which are used for data access)
817 XIndexContainer xOptionsForm = m_document.createSiblingForm( m_xMasterForm, "Options" );
819 xLabel = m_formLayer.createControlAndShape( "GroupBox", 98, 0, 66, 62, xOptionsForm );
820 xLabel.setPropertyValue( "Name", "Options" );
821 xLabel.setPropertyValue( "Label", "Options" );
823 // radio buttons which controls how we generate unique keys
824 xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 5, 56, 25, xOptionsForm );
825 xLabel.setPropertyValue( "Label", "key generation" );
826 xLabel.setPropertyValue( "Name", "KeyGeneration" );
827 XPropertySet xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 11, 50, 6, xOptionsForm );
828 xKeyGen.setPropertyValue( "Name", "KeyGen" );
829 xKeyGen.setPropertyValue( "Label", "no automatic generation" );
830 xKeyGen.setPropertyValue( "RefValue", "none" );
831 xKeyGen.addPropertyChangeListener( "State", this );
833 xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 17, 50, 6, xOptionsForm );
834 xKeyGen.setPropertyValue( "Name", "KeyGen" );
835 xKeyGen.setPropertyValue( "Label", "before inserting a record" );
836 xKeyGen.setPropertyValue( "RefValue", "update" );
837 xKeyGen.addPropertyChangeListener( "State", this );
839 xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 23, 50, 6, xOptionsForm );
840 xKeyGen.setPropertyValue( "Name", "KeyGen" );
841 xKeyGen.setPropertyValue( "Label", "when moving to a new record" );
842 xKeyGen.setPropertyValue( "RefValue", "reset" );
843 xKeyGen.addPropertyChangeListener( "State", this );
845 // initialize listeners
846 // master form - key generation
847 m_aSalesmanKeyGenerator = new KeyGenerator( m_xMasterForm, "SNR", m_xCtx );
848 m_aSalesmanKeyGenerator.activateKeyGenerator( true );
849 // master form - control locking
850 m_aSalesmenLocker = new ControlLock( m_xMasterForm, "SNR" );
851 m_aSalesmenLocker.enableLock( m_bProtectKeyFields );
853 // details form - key generation
854 m_aSalesKeyGenerator = new KeyGenerator( xSalesFormProps, "SALENR", m_xCtx );
855 m_aSalesKeyGenerator.activateKeyGenerator( true );
857 // details form - control locking
858 m_aSalesLocker = new ControlLock( xSalesFormProps, "SALENR" );
859 m_aSalesLocker.enableLock( m_bProtectKeyFields );
861 // initially, we want to generate keys when moving to a new record
862 xKeyGen.setPropertyValue( "DefaultState", Short.valueOf( (short)1 ) );
865 // second options block
866 xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 33, 56, 25, xOptionsForm );
867 xLabel.setPropertyValue( "Name", "Misc" );
868 xLabel.setPropertyValue( "Label", "Miscellaneous" );
870 XPropertySet xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 39, 60, 6, xOptionsForm );
871 xCheck.setPropertyValue( "Name", "defaultdate" );
872 xCheck.setPropertyValue( "Label", "default sales date to \"today\"" );
873 xCheck.setPropertyValue( "HelpText", "When checked, newly entered sales records are pre-filled with today's date, else left empty." );
874 xCheck.addPropertyChangeListener( "State", this );
876 xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 45, 60, 6, xOptionsForm );
877 xCheck.setPropertyValue( "Name", "protectkeys" );
878 xCheck.setPropertyValue( "Label", "protect key fields from editing" );
879 xCheck.setPropertyValue( "HelpText", "When checked, you cannot modify the values in the table's key fields (SNR and SALENR)" );
880 xCheck.addPropertyChangeListener( "State", this );
882 xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 51, 60, 6, xOptionsForm );
883 xCheck.setPropertyValue( "Name", "emptysales" );
884 xCheck.setPropertyValue( "Label", "check for empty sales names" );
885 xCheck.setPropertyValue( "HelpText", "When checked, you cannot enter empty values into the NAME column of the 'Sales' table." );
886 xCheck.addPropertyChangeListener( "State", this );
888 // dump the form component tree
889 enumFormComponents( );
892 /* ------------------------------------------------------------------ */
893 @Override
894 protected void onFormsAlive()
896 m_aOperator.onFormsAlive();
899 /* ------------------------------------------------------------------ */
900 /** performs any cleanup before exiting the program
902 @Override
903 protected void cleanUp( ) throws java.lang.Exception
905 // remove the listeners at the buttons
906 RevokeButtons aRevoke = new RevokeButtons( m_aOperator );
907 aRevoke.handle( m_document.getFormComponentTreeRoot( ) );
909 // remove the key generator listeners from the form
910 m_aSalesmanKeyGenerator.stopGenerator( );
911 m_aSalesKeyGenerator.stopGenerator( );
913 // and the control lockers
914 m_aSalesmenLocker.enableLock( false );
915 m_aSalesLocker.enableLock( false );
917 // the validator for the grid column
918 m_aSalesNameValidator.enableColumnWatch( false );
920 // remove our own reset listener from the form
921 XNameAccess xMasterAsNames = UnoRuntime.queryInterface(
922 XNameAccess.class, m_xMasterForm );
923 XReset xFormReset = UNO.queryReset( xMasterAsNames.getByName( "Sales" ) );
924 xFormReset.removeResetListener( this );
926 super.cleanUp();
929 /* ------------------------------------------------------------------ */
930 /** class entry point
932 public static void main(String argv[]) throws java.lang.Exception
934 DataAwareness aSample = new DataAwareness();
935 aSample.run( argv );