merge the formfield patch from ooo-build
[ooovba.git] / odk / examples / DevelopersGuide / Forms / DataAwareness.java
blob7568a35546f956aec1364dd4f522d1aea1e7995d
1 /*************************************************************************
3 * $RCSfile: DataAwareness.java,v $
5 * $Revision: 1.2 $
7 * last change: $Author: rt $ $Date: 2005-01-31 16:28:50 $
9 * The Contents of this file are made available subject to the terms of
10 * the BSD license.
12 * Copyright (c) 2003 by Sun Microsystems, Inc.
13 * All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. Neither the name of Sun Microsystems, Inc. nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
34 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *************************************************************************/
40 package org.openoffice.sdk.forms;
42 import com.sun.star.beans.PropertyChangeEvent;
43 import com.sun.star.beans.XPropertyChangeListener;
44 import com.sun.star.beans.XPropertySet;
47 // __________ Imports __________
48 import com.sun.star.beans.XPropertySetInfo;
50 // base classes
51 import com.sun.star.container.XIndexContainer;
52 import com.sun.star.container.XNameAccess;
53 import com.sun.star.container.XNamed;
54 import com.sun.star.form.FormComponentType;
55 import com.sun.star.form.ListSourceType;
56 import com.sun.star.form.XGridColumnFactory;
57 import com.sun.star.form.XReset;
58 import com.sun.star.form.XResetListener;
59 import com.sun.star.form.runtime.FormFeature;
60 import com.sun.star.lang.EventObject;
61 import com.sun.star.lang.XComponent;
62 import com.sun.star.sdb.CommandType;
63 import com.sun.star.sdb.XColumnUpdate;
64 import com.sun.star.sdbc.ResultSetConcurrency;
65 import com.sun.star.sdbc.XConnection;
66 import com.sun.star.sdbc.XDataSource;
67 import com.sun.star.sdbc.XStatement;
68 import com.sun.star.sdbcx.XColumnsSupplier;
69 import com.sun.star.uno.UnoRuntime;
70 import com.sun.star.uno.XInterface;
72 /**************************************************************************/
73 /** a class for enumerating a form component tree
75 class PrintComponentTree extends ComponentTreeTraversal
77 private String m_sPrefix;
79 public PrintComponentTree()
81 m_sPrefix = new String();
84 public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
86 // the name of the child
87 XNamed xName = (XNamed)UnoRuntime.queryInterface( XNamed.class, aFormComponent );
89 // if it's a form control model, check it's type
90 XPropertySet xProps = UNO.queryPropertySet( aFormComponent );
91 String sTypeName = FLTools.classifyFormComponentType( xProps );
93 String sName;
94 if ( null == xName )
95 sName = "<unnamed>";
96 else
97 sName = xName.getName();
99 // print the component's name
100 if ( 0 != sTypeName.length() )
102 System.out.println( m_sPrefix + sName + " (" + sTypeName + ")" );
104 else
106 System.out.println( m_sPrefix + sName );
109 // let the super class step down the tree
110 m_sPrefix = m_sPrefix + " ";
111 super.handle( aFormComponent );
112 m_sPrefix = m_sPrefix.substring( 0, m_sPrefix.length() - 1 );
116 /**************************************************************************/
117 /** a class revoking button models from a ButtonOperator instance
119 class RevokeButtons extends ComponentTreeTraversal
121 private ButtonOperator m_aOperator;
123 public RevokeButtons( ButtonOperator aOperator )
125 m_aOperator = aOperator;
128 public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
130 // check if it's a button
131 XPropertySet xProps = UNO.queryPropertySet( aFormComponent );
132 XPropertySetInfo xPI = null;
133 if ( null != xProps )
134 xPI = xProps.getPropertySetInfo();
135 if ( ( null != xPI ) && xPI.hasPropertyByName( "ClassId" ) )
137 Short nClassId = (Short)xProps.getPropertyValue( "ClassId" );
138 if ( FormComponentType.COMMANDBUTTON == nClassId.shortValue() )
140 // yes, it is
141 m_aOperator.revokeButton( xProps );
145 // let the super class step down the tree (if possible)
146 super.handle( aFormComponent );
150 /**************************************************************************/
151 public class DataAwareness extends DocumentBasedExample implements XPropertyChangeListener, XResetListener
153 /* ================================================================== */
154 private HsqlDatabase m_database;
156 private static final String s_tableNameSalesmen = "SALESMEN";
157 private static final String s_tableNameCustomers = "CUSTOMERS";
158 private static final String s_tableNameSales = "SALES";
160 private XPropertySet m_xMasterForm;
161 private ButtonOperator m_aOperator;
162 private SalesFilter m_aSalesFilter;
164 private KeyGenerator m_aSalesmanKeyGenerator;
165 private KeyGenerator m_aSalesKeyGenerator;
166 private ControlLock m_aSalesmenLocker;
167 private ControlLock m_aSalesLocker;
168 private GridFieldValidator m_aSalesNameValidator;
170 private boolean m_bDefaultSalesDate;
171 private boolean m_bProtectKeyFields;
172 private boolean m_bAllowEmptySales;
174 /* ------------------------------------------------------------------ */
175 public DataAwareness()
177 super( DocumentType.WRITER );
178 m_bDefaultSalesDate = false;
179 m_bProtectKeyFields = false;
180 m_bAllowEmptySales = false;
183 /* ==================================================================
184 = form components
185 ================================================================== */
187 /* ------------------------------------------------------------------ */
188 /** enumerates and prints all the elements in the given container, together with the container itself
190 protected void enumFormComponents( XNameAccess xContainer ) throws java.lang.Exception
192 String sObjectName;
194 XNamed xNameAcc = (XNamed)UnoRuntime.queryInterface( XNamed.class, xContainer );
195 if ( null == xNameAcc )
196 sObjectName = new String( "<unnamed>" );
197 else
198 sObjectName = xNameAcc.getName();
199 System.out.println( new String( "enumerating the container named \"" ) + sObjectName +
200 new String( "\"\n" ) );
202 PrintComponentTree aPrinter = new PrintComponentTree();
203 aPrinter.handle( xContainer );
206 /* ------------------------------------------------------------------ */
207 /** enumerates and prints all form elements in the document
209 protected void enumFormComponents( ) throws java.lang.Exception
211 enumFormComponents( m_document.getFormComponentTreeRoot() );
214 /* ==================================================================
215 = UNO callbacks
216 ================================================================== */
218 /* ------------------------------------------------------------------ */
219 // XResetListener overridables
220 /* ------------------------------------------------------------------ */
221 public boolean approveReset( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
223 // not interested in vetoing this
224 return true;
227 /* ------------------------------------------------------------------ */
228 public void resetted( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
230 // check if this reset occured becase we're on a new record
231 XPropertySet xFormProps = UNO.queryPropertySet( aEvent.Source );
234 Boolean aIsNew = (Boolean)xFormProps.getPropertyValue( "IsNew" );
235 if ( aIsNew.booleanValue() )
236 { // yepp
238 if ( !m_bDefaultSalesDate )
239 { // we're interested to do all this only if the user told us to default the sales date
240 // to "today"
241 // As date fields do this defaulting automatically, the semantics is inverted here:
242 // If we're told to default, we must do nothing, if we should not default, we must
243 // reset the value which the date field set automatically.
245 Integer aConcurrency = (Integer)xFormProps.getPropertyValue( "ResultSetConcurrency" );
246 if ( ResultSetConcurrency.READ_ONLY != aConcurrency.intValue() )
248 // we're going to modify the record, though after that, to the user, it should look
249 // like it has not been modified
250 // So we need to ensure that we do not change the IsModified property with whatever we do
251 Object aModifiedFlag = xFormProps.getPropertyValue( "IsModified" );
254 // get the columns of our master form
255 XColumnsSupplier xSuppCols = (XColumnsSupplier)UnoRuntime.queryInterface(
256 XColumnsSupplier.class, xFormProps );
257 XNameAccess xCols = xSuppCols.getColumns();
259 // and update the date column with a NULL value
260 XColumnUpdate xDateColumn = (XColumnUpdate)UnoRuntime.queryInterface(
261 XColumnUpdate.class, xCols.getByName( "SALEDATE" ) );
262 xDateColumn.updateNull();
265 // then restore the flag
266 xFormProps.setPropertyValue( "IsModified", aModifiedFlag );
271 catch( com.sun.star.uno.Exception e )
273 System.out.println(e);
274 e.printStackTrace();
278 /* ------------------------------------------------------------------ */
279 // XPropertyChangeListener overridables
280 /* ------------------------------------------------------------------ */
281 public void propertyChange( PropertyChangeEvent aEvent ) throws com.sun.star.uno.RuntimeException
285 // did it come from a radio button or checkbox?
286 if ( aEvent.PropertyName.equals( "State" ) )
287 { // yep
288 Short aNewState = (Short)aEvent.NewValue;
290 XPropertySet xModel = UNO.queryPropertySet( aEvent.Source );
291 String sName = (String)xModel.getPropertyValue( "Name" );
293 Short aClassId = (Short)xModel.getPropertyValue( "ClassId" );
294 if ( FormComponentType.RADIOBUTTON == aClassId.shortValue() )
296 String sRefValue = (String)xModel.getPropertyValue( "RefValue" );
298 short nNewValue = ((Short)aEvent.NewValue).shortValue();
299 if ( sName.equals( "KeyGen" ) )
301 // it's one of the options for key generation
302 if ( sRefValue.equals( "none" ) )
303 { // no automatic generation at all
304 m_aSalesmanKeyGenerator.stopGenerator( );
305 m_aSalesKeyGenerator.stopGenerator( );
307 else
309 boolean bGenerateOnReset = true;
310 if ( sRefValue.equals( "update" ) )
311 { // generate on update
312 bGenerateOnReset = ( 0 == nNewValue );
314 else if ( sRefValue.equals( "reset" ) )
315 { // generat on reset
316 bGenerateOnReset = ( 0 != nNewValue );
318 m_aSalesmanKeyGenerator.activateKeyGenerator( bGenerateOnReset );
319 m_aSalesKeyGenerator.activateKeyGenerator( bGenerateOnReset );
323 else if ( FormComponentType.CHECKBOX == aClassId.shortValue() )
325 boolean bEnabled = ( 0 != aNewState.shortValue() );
326 if ( sName.equals( "defaultdate" ) )
328 m_bDefaultSalesDate = bEnabled;
330 else if ( sName.equals( "protectkeys" ) )
332 m_bProtectKeyFields = bEnabled;
333 m_aSalesmenLocker.enableLock( m_bProtectKeyFields );
334 m_aSalesLocker.enableLock( m_bProtectKeyFields );
336 else if ( sName.equals( "emptysales" ) )
338 m_bAllowEmptySales = bEnabled;
339 m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales );
344 catch(com.sun.star.uno.Exception e)
346 System.out.println(e);
347 e.printStackTrace();
351 /* ------------------------------------------------------------------ */
352 // XEventListener overridables
353 /* ------------------------------------------------------------------ */
354 public void disposing( EventObject aEvent )
356 // simply disambiguate
357 super.disposing( aEvent );
360 /* ==================================================================
361 = miscellaneous
362 ================================================================== */
364 /* ------------------------------------------------------------------ */
365 /** skips line feeds in the input stream
367 @returns
368 the first character which does not belong to a line feed
370 protected int skipLineFeeds( java.io.InputStream aInput ) throws java.io.IOException
372 // read characters, until we encounter something which is not a line feed character
373 int nChar = aInput.read( );
374 while ( ( 13 == nChar ) || ( 10 == nChar ) )
375 nChar = aInput.read( );
377 // now read everything which is behind this single character we are interested in
378 while ( 0 < aInput.available() )
379 aInput.read( );
381 return nChar;
384 /* ==================================================================
385 = table handling
386 ================================================================== */
387 /* ------------------------------------------------------------------ */
388 /** checks if a given table exists.
390 <p>The check is made using a SELECT statement, so even if the connection
391 is a n SDB-level connection, which may filter tables in it's table
392 supplier, the result may be reliable ....</p>
394 protected boolean existsInvisibleTable( XConnection xConn, String sTableName ) throws java.lang.Exception
396 String sStatement = "SELECT * FROM ";
397 sStatement += sTableName;
398 sStatement += " WHERE 0=1";
400 boolean bSuccess = false;
403 XStatement xStatement = xConn.createStatement();
404 xStatement.execute( sStatement );
405 // if we reached this point, the table probably exists
406 bSuccess = true;
408 catch(com.sun.star.sdbc.SQLException e)
411 return bSuccess;
414 /* ------------------------------------------------------------------ */
415 /** add a specified table name to the table filter of the given data source.
417 protected void makeTableVisible( XDataSource xDS, XConnection xConn, String sTableName ) throws java.lang.Exception
419 // get the table filter
420 XPropertySet xDSP = UNO.queryPropertySet( xDS );
421 String[] aCurrentFilter = (String[])xDSP.getPropertyValue( "TableFilter" );
423 // check if the table name is already part of it
424 String sAllTables = "*"; // all tables
426 for ( int i=0; i<aCurrentFilter.length; ++i )
428 String sCurrentTableFilter = aCurrentFilter[i];
430 if ( sCurrentTableFilter.equals( sTableName ) )
431 return;
432 if ( sCurrentTableFilter.equals( sAllTables ) )
433 return;
436 // if we are here, we have to add our table to the filter sequence
437 String[] aNewFilter = new String[ aCurrentFilter.length + 1 ];
438 // copy the existent filter entries
439 for ( int i=0; i<aCurrentFilter.length; ++i )
440 aNewFilter[i] = aCurrentFilter[i];
441 // add our table
442 aNewFilter[ aCurrentFilter.length ] = sTableName;
444 xDSP.setPropertyValue( "TableFilter", aNewFilter );
447 /* ------------------------------------------------------------------ */
448 /** executes the given statement on the given connection
450 protected boolean implExecuteStatement( XConnection xConn, String sStatement ) throws java.lang.Exception
454 XStatement xStatement = xConn.createStatement( );
455 xStatement.execute( sStatement );
457 catch(com.sun.star.sdbc.SQLException e)
459 System.err.println( e );
460 return false;
463 return true;
466 /* ------------------------------------------------------------------ */
467 /** creates the table witht the given name, using the given statement
469 protected boolean implCreateTable( XConnection xConn, String sCreateStatement, String sTableName ) throws java.lang.Exception
471 if ( !implExecuteStatement( xConn, sCreateStatement ) )
473 System.out.println( " could not create the table " + sTableName + "." );
474 System.out.println( );
475 return false;
478 return true;
481 /* ------------------------------------------------------------------ */
482 /** creates the table SALESMEN
484 @return
485 <TRUE/> if and only if the creation succeeded
487 protected boolean createTableSalesman( XConnection xConn ) throws java.lang.Exception
489 String sCreateStatement = "CREATE TABLE " + s_tableNameSalesmen + " ";
490 sCreateStatement += "(SNR INTEGER NOT NULL, ";
491 sCreateStatement += "FIRSTNAME VARCHAR(50), ";
492 sCreateStatement += "LASTNAME VARCHAR(100), ";
493 sCreateStatement += "STREET VARCHAR(50), ";
494 sCreateStatement += "STATE VARCHAR(50), ";
495 sCreateStatement += "ZIP INTEGER, ";
496 sCreateStatement += "BIRTHDATE DATE, ";
497 sCreateStatement += "PRIMARY KEY(SNR))";
499 if ( implCreateTable( xConn, sCreateStatement, s_tableNameSalesmen) )
501 String sInsertionPrefix = "INSERT INTO " + s_tableNameSalesmen + " VALUES ";
503 implExecuteStatement( xConn, sInsertionPrefix + "(1, 'Joseph', 'Smith', 'Bond Street', 'CA', 95460, '1946-07-02')" );
504 implExecuteStatement( xConn, sInsertionPrefix + "(2, 'Frank', 'Jones', 'Lake silver', 'CA', 95460, '1963-12-24')" );
505 implExecuteStatement( xConn, sInsertionPrefix + "(3, 'Jane', 'Esperansa', '23 Hollywood driver', 'CA', 95460, '1972-04-01')" );
507 return true;
509 return false;
512 /* ------------------------------------------------------------------ */
513 /** creates the table CUSTOMERS
515 @return
516 <TRUE/> if and only if the creation succeeded
518 protected boolean createTableCustomer( XConnection xConn ) throws java.lang.Exception
520 String sCreateStatement = "CREATE TABLE " + s_tableNameCustomers + " ";
521 sCreateStatement += "(COS_NR INTEGER NOT NULL, ";
522 sCreateStatement += "LASTNAME VARCHAR(100), ";
523 sCreateStatement += "STREET VARCHAR(50), ";
524 sCreateStatement += "CITY VARCHAR(50), ";
525 sCreateStatement += "STATE VARCHAR(50), ";
526 sCreateStatement += "ZIP INTEGER, ";
527 sCreateStatement += "PRIMARY KEY(COS_NR))";
529 if ( implCreateTable( xConn, sCreateStatement, s_tableNameCustomers ) )
531 String sInsertionPrefix = "INSERT INTO " + s_tableNameCustomers + " VALUES ";
533 implExecuteStatement( xConn, sInsertionPrefix + "(100, 'Acme, Inc.', '99 Market Street', 'Groundsville', 'CA', 95199)" );
534 implExecuteStatement( xConn, sInsertionPrefix + "(101, 'Superior BugSoft', '1 Party Place', 'Mendocino', 'CA', 95460)");
535 implExecuteStatement( xConn, sInsertionPrefix + "(102, 'WeKnowAll, Inc.', '100 Coffee Lane', 'Meadows', 'CA', 93699)");
537 return true;
539 return false;
542 /* ------------------------------------------------------------------ */
543 /** creates the table SALES
545 @return
546 <TRUE/> if and only if the creation succeeded
548 protected boolean createTableSales( XConnection xConn ) throws java.lang.Exception
550 String sCreateStatement = "CREATE TABLE " + s_tableNameSales + " ";
551 sCreateStatement += "(SALENR INTEGER NOT NULL, ";
552 sCreateStatement += "COS_NR INTEGER NOT NULL, ";
553 sCreateStatement += "SNR INTEGER NOT NULL, ";
554 sCreateStatement += "NAME VARCHAR(50), ";
555 sCreateStatement += "SALEDATE DATE, ";
556 sCreateStatement += "PRICE DECIMAL(8,2), ";
557 sCreateStatement += "PRIMARY KEY(SALENR))";
559 if ( implCreateTable( xConn, sCreateStatement, s_tableNameSales ) )
561 String sInsertionPrefix = "INSERT INTO " + s_tableNameSales + " VALUES ";
563 implExecuteStatement( xConn, sInsertionPrefix + "(1, 100, 1, 'Fruits', '2005-02-12', 39.99)" );
564 implExecuteStatement( xConn, sInsertionPrefix + "(2, 101, 3, 'Beef', '2005-10-18', 15.78)" );
565 implExecuteStatement( xConn, sInsertionPrefix + "(3, 102, 3, 'Orange Juice', '2005-09-08', 25.63)" );
566 implExecuteStatement( xConn, sInsertionPrefix + "(4, 101, 2, 'Oil', '2005-03-01', 12.30)" );
568 return true;
571 return false;
574 /* ------------------------------------------------------------------ */
575 /** ensures that the tables we need for our example exist
577 protected void ensureTables() throws java.lang.Exception
579 // get the data source
580 XDataSource xDS = m_database.getDataSource();
581 XPropertySet xDSProps = UNO.queryPropertySet( xDS );
583 // connect to this data source
584 XConnection xConn = xDS.getConnection( "", "" );
585 XComponent xConnComp = UNO.queryComponent( xConn );
587 createTableSalesman( xConn );
588 createTableCustomer( xConn );
589 createTableSales( xConn );
591 // free the resources acquired by the connection
592 xConnComp.dispose();
595 /* ==================================================================
596 = sample document handling
597 ================================================================== */
599 /* ------------------------------------------------------------------ */
600 /** creates the button used for demonstrating (amonst others) event handling
601 @param nXPos
602 x-position of the to be inserted shape
603 @param nYPos
604 y-position of the to be inserted shape
605 @param nXSize
606 width of the to be inserted shape
607 @param sName
608 the name of the model in the form component hierarchy
609 @param sLabel
610 the label of the button control
611 @param sActionURL
612 the URL of the action which should be triggered by the button
613 @return
614 the model of the newly created button
616 protected XPropertySet createButton( int nXPos, int nYPos, int nXSize, String sName, String sLabel, short _formFeature ) throws java.lang.Exception
618 XPropertySet xButton = m_formLayer.createControlAndShape( "CommandButton", nXPos, nYPos, nXSize, 6 );
619 // the name for referring to it later:
620 xButton.setPropertyValue( "Name", sName );
621 // the label
622 xButton.setPropertyValue( "Label", sLabel );
623 // use the name as help text
624 xButton.setPropertyValue( "HelpText", sName );
625 // don't want buttons to be accessible by the "tab" key - this would be uncomfortable when traveling
626 // with records with "tab"
627 xButton.setPropertyValue( "Tabstop", new Boolean( false ) );
628 // similar, they should not steal the focus when clicked
629 xButton.setPropertyValue( "FocusOnClick", new Boolean( false ) );
631 m_aOperator.addButton( xButton, _formFeature );
633 return xButton;
636 /* ------------------------------------------------------------------ */
637 /** creates a column in a grid
638 @param xGridModel
639 specifies the model of the grid where the new column should be inserted
640 @param sColumnService
641 specifies the service name of the column to create (e.g. "NumericField")
642 @param sDataField
643 specifies the database field to which the column should be bound
644 @param nWidth
645 specifies the column width (in mm). If 0, no width is set.
646 @return
647 the newly created column
649 XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField, int nWidth )
650 throws com.sun.star.uno.Exception
652 // the container to insert columns into
653 XIndexContainer xColumnContainer = UNO.queryIndexContainer( aGridModel );
654 // the factory for creating column models
655 XGridColumnFactory xColumnFactory = (XGridColumnFactory)UnoRuntime.queryInterface(
656 XGridColumnFactory.class, aGridModel );
658 // (let) create the new col
659 XInterface xNewCol = (XInterface)xColumnFactory.createColumn( sColumnService );
660 XPropertySet xColProps = UNO.queryPropertySet( xNewCol );
662 // some props
663 // the field the column is bound to
664 xColProps.setPropertyValue( "DataField", sDataField );
665 // the "display name" of the column
666 xColProps.setPropertyValue( "Label", sDataField );
667 // the name of the column within it's parent
668 xColProps.setPropertyValue( "Name", sDataField );
670 if ( nWidth > 0 )
671 xColProps.setPropertyValue( "Width", new Integer( nWidth * 10 ) );
673 // insert
674 xColumnContainer.insertByIndex( xColumnContainer.getCount(), xNewCol );
676 // outta here
677 return xColProps;
680 /* ------------------------------------------------------------------ */
681 /** creates a column in a grid
683 XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField )
684 throws com.sun.star.uno.Exception
686 return createGridColumn( aGridModel, sColumnService, sDataField );
689 /* ------------------------------------------------------------------ */
690 /** creates our sample document
692 protected void prepareDocument() throws com.sun.star.uno.Exception, java.lang.Exception
694 super.prepareDocument();
696 m_database = new HsqlDatabase( m_xCtx );
698 // ensure that we have the tables needed for our example
699 ensureTables();
701 // --------------------------------------------------------------
702 /* create some shapes */
703 XPropertySet xSNRField = m_formLayer.insertControlLine( "NumericField", "SNR", "", 3 );
704 m_formLayer.insertControlLine( "TextField", "FIRSTNAME", "", 11);
705 m_formLayer.insertControlLine( "TextField", "LASTNAME", "", 19 );
706 m_formLayer.insertControlLine( "TextField", "STREET", "", 27 );
707 m_formLayer.insertControlLine( "TextField", "STATE", "", 35 );
708 XPropertySet xZipField = m_formLayer.insertControlLine( "NumericField", "ZIP", "", 43 );
709 m_formLayer.insertControlLine( "FormattedField", "BIRTHDATE", "", 51 );
711 // for the salesman number / zip code, we don't want to have decimal places:
712 xSNRField.setPropertyValue( "DecimalAccuracy", new Short( (short)0 ) );
713 xZipField.setPropertyValue( "DecimalAccuracy", new Short( (short)0 ) );
715 // --------------------------------------------------------------
716 /** need the form the control models belong to
717 for this, we simply obtain the parent for any of the control models we have
719 Note that this involves knowledge about the implementation: If a control shape is
720 inserted into a document, where the control model does not belong to the form component
721 hierarchy, yet, it is automatically inserted into the first form, which is created
722 if necessary.
724 m_xMasterForm = FLTools.getParent( xZipField );
726 // set the data source signature at the form
727 m_xMasterForm.setPropertyValue( "DataSourceName", m_database.getDocumentURL() );
728 m_xMasterForm.setPropertyValue( "CommandType", new Integer( CommandType.TABLE ) );
729 m_xMasterForm.setPropertyValue( "Command", "SALESMEN" );
731 // --------------------------------------------------------------
732 // insert the buttons
733 // create our button operator, if necessary
734 m_aOperator = new ButtonOperator( m_xCtx, m_document, m_xMasterForm );
736 createButton( 2, 63, 8, "first", "<<", FormFeature.MoveToFirst );
737 createButton( 12, 63, 8, "prev", "<", FormFeature.MoveToPrevious );
738 createButton( 22, 63, 8, "next", ">", FormFeature.MoveToNext );
739 createButton( 32, 63, 8, "last", ">>", FormFeature.MoveToLast );
740 createButton( 42, 63, 8, "new", ">*", FormFeature.MoveToInsertRow );
741 createButton( 58, 63, 13, "reload", "reload", FormFeature.ReloadForm );
743 // --------------------------------------------------------------
744 // create a sub for for the sales
746 // for this, first create a sub form and bind it to the SALES table
747 XIndexContainer xSalesForm = m_document.createSubForm( m_xMasterForm, "Sales" );
748 XPropertySet xSalesFormProps = UNO.queryPropertySet( xSalesForm );
750 xSalesFormProps.setPropertyValue( "DataSourceName", m_database.getDocumentURL() );
751 xSalesFormProps.setPropertyValue( "CommandType", new Integer( CommandType.COMMAND ) );
753 String sCommand = new String( "SELECT * FROM " );
754 sCommand += s_tableNameSales;
755 sCommand += " WHERE " + s_tableNameSales + ".SNR = :salesmen";
756 xSalesFormProps.setPropertyValue( "Command", sCommand );
758 // the master-details connection
759 String[] aMasterFields = new String[] { "SNR" }; // the field in the master form
760 String[] aDetailFields = new String[] { "salesmen" }; // the name in the detail form
761 xSalesFormProps.setPropertyValue( "MasterFields", aMasterFields );
762 xSalesFormProps.setPropertyValue( "DetailFields", aDetailFields );
764 // the create thr grid model
765 XPropertySet xSalesGridModel = m_formLayer.createControlAndShape( "GridControl", 2, 80, 162, 40, xSalesForm );
766 xSalesGridModel.setPropertyValue( "Name", "SalesTable" );
767 XPropertySet xKeyColumn = createGridColumn( xSalesGridModel, "NumericField", "SALENR", 12 );
768 XPropertySet xCustomerColumn = createGridColumn( xSalesGridModel, "ListBox", "COS_NR", 40 );
769 XPropertySet xSalesNameColumn = createGridColumn( xSalesGridModel, "TextField", "NAME", 25 );
770 createGridColumn( xSalesGridModel, "DateField", "SALEDATE", 24 );
771 createGridColumn( xSalesGridModel, "CurrencyField", "PRICE", 16 );
773 // please note that a better solution for the SALEDATE field would have been to use
774 // a FormattedField. But we want to demonstrate some effects with DateFields here ...
776 m_aSalesNameValidator = new GridFieldValidator( m_xCtx, xSalesNameColumn );
777 m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales );
779 xKeyColumn.setPropertyValue( "DecimalAccuracy", new Short( (short)0 ) );
781 // init the list box which is for choosing the customer a sale belongs to
782 xCustomerColumn.setPropertyValue( "BoundColumn", new Short( (short)1 ) );
783 xCustomerColumn.setPropertyValue( "Label", "Customer" );
784 xCustomerColumn.setPropertyValue( "ListSourceType", ListSourceType.SQL );
786 String sListSource = "SELECT LASTNAME, COS_NR FROM ";
787 sListSource += s_tableNameCustomers;
788 String[] aListSource = new String[] { sListSource };
789 xCustomerColumn.setPropertyValue( "ListSource", aListSource );
791 // We want to demonstrate how to reset fields to NULL, we do this with the SALEDATE field
792 // above. For this, we add as reset listener to the form
793 XReset xFormReset = UNO.queryReset( xSalesForm );
794 xFormReset.addResetListener( this );
797 // --------------------------------------------------------------
798 // the option for filtering the sales form
799 XIndexContainer xSalesFilterForm = m_document.createSiblingForm( xSalesForm, "SalesFilter" );
800 XPropertySet xSFFProps = UNO.queryPropertySet( xSalesFilterForm );
801 XPropertySet xLabel = m_formLayer.createControlAndShape( "FixedText", 2, 125, 35, 6, xSalesFilterForm );
802 xLabel.setPropertyValue( "Label", "show only sales since" );
803 xLabel.setPropertyValue( "Name", "FilterLabel" );
805 XPropertySet xFilterSelection = m_formLayer.createControlAndShape( "ListBox", 40, 125, 59, 6, xSalesFilterForm );
806 xFilterSelection.setPropertyValue( "Name", "FilterList" );
807 xFilterSelection.setPropertyValue( "LabelControl", xLabel );
808 XPropertySet xManualFilter = m_formLayer.createControlAndShape( "DateField", 104, 125, 30, 6, xSalesFilterForm );
809 xManualFilter.setPropertyValue( "Name", "ManualFilter" );
810 XPropertySet xApplyFilter = m_formLayer.createControlAndShape( "CommandButton", 139, 125, 25, 6, xSalesFilterForm );
811 xApplyFilter.setPropertyValue( "Name", "ApplyFilter" );
812 xApplyFilter.setPropertyValue( "DefaultButton", new Boolean( true ) );
813 m_aSalesFilter = new SalesFilter( m_document, xSalesFormProps, xFilterSelection,
814 xManualFilter, xApplyFilter );
817 // --------------------------------------------------------------
818 // the options section
819 // for this, we need a form which is a sibling of our master form (don't want to interfere
820 // the controls which represent options only with the controls which are used for data access)
822 XIndexContainer xOptionsForm = m_document.createSiblingForm( m_xMasterForm, "Options" );
824 xLabel = m_formLayer.createControlAndShape( "GroupBox", 98, 0, 66, 62, xOptionsForm );
825 xLabel.setPropertyValue( "Name", "Options" );
826 xLabel.setPropertyValue( "Label", "Options" );
828 // radio buttons which controls how we generate unique keys
829 xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 5, 56, 25, xOptionsForm );
830 xLabel.setPropertyValue( "Label", "key generation" );
831 xLabel.setPropertyValue( "Name", "KeyGeneration" );
832 XPropertySet xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 11, 50, 6, xOptionsForm );
833 xKeyGen.setPropertyValue( "Name", "KeyGen" );
834 xKeyGen.setPropertyValue( "Label", "no automatic generation" );
835 xKeyGen.setPropertyValue( "RefValue", "none" );
836 xKeyGen.addPropertyChangeListener( "State", this );
838 xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 17, 50, 6, xOptionsForm );
839 xKeyGen.setPropertyValue( "Name", "KeyGen" );
840 xKeyGen.setPropertyValue( "Label", "before inserting a record" );
841 xKeyGen.setPropertyValue( "RefValue", "update" );
842 xKeyGen.addPropertyChangeListener( "State", this );
844 xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 23, 50, 6, xOptionsForm );
845 xKeyGen.setPropertyValue( "Name", "KeyGen" );
846 xKeyGen.setPropertyValue( "Label", "when moving to a new record" );
847 xKeyGen.setPropertyValue( "RefValue", "reset" );
848 xKeyGen.addPropertyChangeListener( "State", this );
850 // initialize listeners
851 // master form - key generation
852 m_aSalesmanKeyGenerator = new KeyGenerator( m_xMasterForm, "SNR", m_xCtx );
853 m_aSalesmanKeyGenerator.activateKeyGenerator( true );
854 // master form - control locking
855 m_aSalesmenLocker = new ControlLock( m_xMasterForm, "SNR" );
856 m_aSalesmenLocker.enableLock( m_bProtectKeyFields );
858 // details form - key generation
859 m_aSalesKeyGenerator = new KeyGenerator( xSalesFormProps, "SALENR", m_xCtx );
860 m_aSalesKeyGenerator.activateKeyGenerator( true );
862 // details form - control locking
863 m_aSalesLocker = new ControlLock( xSalesFormProps, "SALENR" );
864 m_aSalesLocker.enableLock( m_bProtectKeyFields );
866 // initally, we want to generate keys when moving to a new record
867 xKeyGen.setPropertyValue( "DefaultState", new Short( (short)1 ) );
869 // --------------------------------------------------------------
870 // second options block
871 xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 33, 56, 25, xOptionsForm );
872 xLabel.setPropertyValue( "Name", "Misc" );
873 xLabel.setPropertyValue( "Label", "Miscellaneous" );
875 XPropertySet xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 39, 60, 6, xOptionsForm );
876 xCheck.setPropertyValue( "Name", "defaultdate" );
877 xCheck.setPropertyValue( "Label", "default sales date to \"today\"" );
878 xCheck.setPropertyValue( "HelpText", "When checked, newly entered sales records are pre-filled with today's date, else left empty." );
879 xCheck.addPropertyChangeListener( "State", this );
881 xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 45, 60, 6, xOptionsForm );
882 xCheck.setPropertyValue( "Name", "protectkeys" );
883 xCheck.setPropertyValue( "Label", "protect key fields from editing" );
884 xCheck.setPropertyValue( "HelpText", "When checked, you cannot modify the values in the table's key fields (SNR and SALENR)" );
885 xCheck.addPropertyChangeListener( "State", this );
887 xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 51, 60, 6, xOptionsForm );
888 xCheck.setPropertyValue( "Name", "emptysales" );
889 xCheck.setPropertyValue( "Label", "check for empty sales names" );
890 xCheck.setPropertyValue( "HelpText", "When checked, you cannot enter empty values into the NAME column of the 'Sales' table." );
891 xCheck.addPropertyChangeListener( "State", this );
893 // dump the form component tree
894 enumFormComponents( );
897 /* ------------------------------------------------------------------ */
898 protected void onFormsAlive()
900 m_aOperator.onFormsAlive();
903 /* ------------------------------------------------------------------ */
904 /** performs any cleanup before exiting the program
906 protected void cleanUp( ) throws java.lang.Exception
908 // remove the listeners at the buttons
909 RevokeButtons aRevoke = new RevokeButtons( m_aOperator );
910 aRevoke.handle( m_document.getFormComponentTreeRoot( ) );
912 // remove the key generator listeners from the form
913 m_aSalesmanKeyGenerator.stopGenerator( );
914 m_aSalesKeyGenerator.stopGenerator( );
916 // and the control lockers
917 m_aSalesmenLocker.enableLock( false );
918 m_aSalesLocker.enableLock( false );
920 // the validator for the grid column
921 m_aSalesNameValidator.enableColumnWatch( false );
923 // remove our own reset listener from the form
924 XNameAccess xMasterAsNames = (XNameAccess)UnoRuntime.queryInterface(
925 XNameAccess.class, m_xMasterForm );
926 XReset xFormReset = UNO.queryReset( xMasterAsNames.getByName( "Sales" ) );
927 xFormReset.removeResetListener( this );
929 super.cleanUp();
932 /* ------------------------------------------------------------------ */
933 /** class entry point
935 public static void main(String argv[]) throws java.lang.Exception
937 DataAwareness aSample = new DataAwareness();
938 aSample.run( argv );