Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / odk / examples / DevelopersGuide / Forms / DataAwareness.java
blob123360c4e9422b4474aee4c350733bb6295cfd27
1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * The Contents of this file are made available subject to the terms of
5 * the BSD license.
7 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of Sun Microsystems, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
31 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
32 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *************************************************************************/
35 import com.sun.star.beans.PropertyChangeEvent;
36 import com.sun.star.beans.XPropertyChangeListener;
37 import com.sun.star.beans.XPropertySet;
40 // __________ Imports __________
41 import com.sun.star.beans.XPropertySetInfo;
43 // base classes
44 import com.sun.star.container.XIndexContainer;
45 import com.sun.star.container.XNameAccess;
46 import com.sun.star.container.XNamed;
47 import com.sun.star.form.FormComponentType;
48 import com.sun.star.form.ListSourceType;
49 import com.sun.star.form.XGridColumnFactory;
50 import com.sun.star.form.XReset;
51 import com.sun.star.form.XResetListener;
52 import com.sun.star.form.runtime.FormFeature;
53 import com.sun.star.lang.EventObject;
54 import com.sun.star.lang.XComponent;
55 import com.sun.star.sdb.CommandType;
56 import com.sun.star.sdb.XColumnUpdate;
57 import com.sun.star.sdbc.ResultSetConcurrency;
58 import com.sun.star.sdbc.XConnection;
59 import com.sun.star.sdbc.XDataSource;
60 import com.sun.star.sdbc.XStatement;
61 import com.sun.star.sdbcx.XColumnsSupplier;
62 import com.sun.star.uno.UnoRuntime;
63 import com.sun.star.uno.XInterface;
65 /**************************************************************************/
66 /** a class for enumerating a form component tree
68 class PrintComponentTree extends ComponentTreeTraversal
70 private String m_sPrefix;
72 public PrintComponentTree()
74 m_sPrefix = "";
77 @Override
78 public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
80 // the name of the child
81 XNamed xName = UnoRuntime.queryInterface( XNamed.class, aFormComponent );
83 // if it's a form control model, check it's type
84 XPropertySet xProps = UNO.queryPropertySet( aFormComponent );
85 String sTypeName = FLTools.classifyFormComponentType( xProps );
87 String sName;
88 if ( null == xName )
89 sName = "<unnamed>";
90 else
91 sName = xName.getName();
93 // print the component's name
94 if ( 0 != sTypeName.length() )
96 System.out.println( m_sPrefix + sName + " (" + sTypeName + ")" );
98 else
100 System.out.println( m_sPrefix + sName );
103 // let the super class step down the tree
104 m_sPrefix = m_sPrefix + " ";
105 super.handle( aFormComponent );
106 m_sPrefix = m_sPrefix.substring( 0, m_sPrefix.length() - 1 );
110 /**************************************************************************/
111 /** a class revoking button models from a ButtonOperator instance
113 class RevokeButtons extends ComponentTreeTraversal
115 private ButtonOperator m_aOperator;
117 public RevokeButtons( ButtonOperator aOperator )
119 m_aOperator = aOperator;
122 @Override
123 public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
125 // check if it's a button
126 XPropertySet xProps = UNO.queryPropertySet( aFormComponent );
127 XPropertySetInfo xPI = null;
128 if ( null != xProps )
129 xPI = xProps.getPropertySetInfo();
130 if ( ( null != xPI ) && xPI.hasPropertyByName( "ClassId" ) )
132 Short nClassId = (Short)xProps.getPropertyValue( "ClassId" );
133 if ( FormComponentType.COMMANDBUTTON == nClassId.shortValue() )
135 // yes, it is
136 m_aOperator.revokeButton( xProps );
140 // let the super class step down the tree (if possible)
141 super.handle( aFormComponent );
145 /**************************************************************************/
146 public class DataAwareness extends DocumentBasedExample implements XPropertyChangeListener, XResetListener
148 /* ================================================================== */
149 private HsqlDatabase m_database;
151 private static final String s_tableNameSalesmen = "SALESMEN";
152 private static final String s_tableNameCustomers = "CUSTOMERS";
153 private static final String s_tableNameSales = "SALES";
155 private XPropertySet m_xMasterForm;
156 private ButtonOperator m_aOperator;
158 private KeyGenerator m_aSalesmanKeyGenerator;
159 private KeyGenerator m_aSalesKeyGenerator;
160 private ControlLock m_aSalesmenLocker;
161 private ControlLock m_aSalesLocker;
162 private GridFieldValidator m_aSalesNameValidator;
164 private boolean m_bDefaultSalesDate;
165 private boolean m_bProtectKeyFields;
166 private boolean m_bAllowEmptySales;
168 /* ------------------------------------------------------------------ */
169 public DataAwareness()
171 super( DocumentType.WRITER );
172 m_bDefaultSalesDate = false;
173 m_bProtectKeyFields = false;
174 m_bAllowEmptySales = false;
177 /* ==================================================================
178 = form components
179 ================================================================== */
181 /* ------------------------------------------------------------------ */
182 /** enumerates and prints all the elements in the given container, together with the container itself
184 protected void enumFormComponents( XNameAccess xContainer ) throws java.lang.Exception
186 String sObjectName;
188 XNamed xNameAcc = UnoRuntime.queryInterface( XNamed.class, xContainer );
189 if ( null == xNameAcc )
190 sObjectName = "<unnamed>";
191 else
192 sObjectName = xNameAcc.getName();
193 System.out.println( "enumerating the container named \"" + sObjectName +
194 "\"\n" );
196 PrintComponentTree aPrinter = new PrintComponentTree();
197 aPrinter.handle( xContainer );
200 /* ------------------------------------------------------------------ */
201 /** enumerates and prints all form elements in the document
203 protected void enumFormComponents( ) throws java.lang.Exception
205 enumFormComponents( m_document.getFormComponentTreeRoot() );
208 /* ==================================================================
209 = UNO callbacks
210 ================================================================== */
212 /* ------------------------------------------------------------------ */
213 // XResetListener overridables
214 /* ------------------------------------------------------------------ */
215 public boolean approveReset( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
217 // not interested in vetoing this
218 return true;
221 /* ------------------------------------------------------------------ */
222 public void resetted( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
224 // check if this reset occurred because we're on a new record
225 XPropertySet xFormProps = UNO.queryPropertySet( aEvent.Source );
228 Boolean aIsNew = (Boolean)xFormProps.getPropertyValue( "IsNew" );
229 if ( aIsNew.booleanValue() )
230 { // yepp
232 if ( !m_bDefaultSalesDate )
233 { // we're interested to do all this only if the user told us to default the sales date
234 // to "today"
235 // As date fields do this defaulting automatically, the semantics is inverted here:
236 // If we're told to default, we must do nothing, if we should not default, we must
237 // reset the value which the date field set automatically.
239 Integer aConcurrency = (Integer)xFormProps.getPropertyValue( "ResultSetConcurrency" );
240 if ( ResultSetConcurrency.READ_ONLY != aConcurrency.intValue() )
242 // we're going to modify the record, though after that, to the user, it should look
243 // like it has not been modified
244 // So we need to ensure that we do not change the IsModified property with whatever we do
245 Object aModifiedFlag = xFormProps.getPropertyValue( "IsModified" );
248 // get the columns of our master form
249 XColumnsSupplier xSuppCols = UnoRuntime.queryInterface(
250 XColumnsSupplier.class, xFormProps );
251 XNameAccess xCols = xSuppCols.getColumns();
253 // and update the date column with a NULL value
254 XColumnUpdate xDateColumn = UnoRuntime.queryInterface(
255 XColumnUpdate.class, xCols.getByName( "SALEDATE" ) );
256 xDateColumn.updateNull();
259 // then restore the flag
260 xFormProps.setPropertyValue( "IsModified", aModifiedFlag );
265 catch( com.sun.star.uno.Exception e )
267 System.out.println(e);
268 e.printStackTrace();
272 /* ------------------------------------------------------------------ */
273 // XPropertyChangeListener overridables
274 /* ------------------------------------------------------------------ */
275 public void propertyChange( PropertyChangeEvent aEvent ) throws com.sun.star.uno.RuntimeException
279 // did it come from a radio button or checkbox?
280 if ( aEvent.PropertyName.equals( "State" ) )
281 { // yep
282 Short aNewState = (Short)aEvent.NewValue;
284 XPropertySet xModel = UNO.queryPropertySet( aEvent.Source );
285 String sName = (String)xModel.getPropertyValue( "Name" );
287 Short aClassId = (Short)xModel.getPropertyValue( "ClassId" );
288 if ( FormComponentType.RADIOBUTTON == aClassId.shortValue() )
290 String sRefValue = (String)xModel.getPropertyValue( "RefValue" );
292 short nNewValue = ((Short)aEvent.NewValue).shortValue();
293 if ( sName.equals( "KeyGen" ) )
295 // it's one of the options for key generation
296 if ( sRefValue.equals( "none" ) )
297 { // no automatic generation at all
298 m_aSalesmanKeyGenerator.stopGenerator( );
299 m_aSalesKeyGenerator.stopGenerator( );
301 else
303 boolean bGenerateOnReset = true;
304 if ( sRefValue.equals( "update" ) )
305 { // generate on update
306 bGenerateOnReset = ( 0 == nNewValue );
308 else if ( sRefValue.equals( "reset" ) )
309 { // generate on reset
310 bGenerateOnReset = ( 0 != nNewValue );
312 m_aSalesmanKeyGenerator.activateKeyGenerator( bGenerateOnReset );
313 m_aSalesKeyGenerator.activateKeyGenerator( bGenerateOnReset );
317 else if ( FormComponentType.CHECKBOX == aClassId.shortValue() )
319 boolean bEnabled = ( 0 != aNewState.shortValue() );
320 if ( sName.equals( "defaultdate" ) )
322 m_bDefaultSalesDate = bEnabled;
324 else if ( sName.equals( "protectkeys" ) )
326 m_bProtectKeyFields = bEnabled;
327 m_aSalesmenLocker.enableLock( m_bProtectKeyFields );
328 m_aSalesLocker.enableLock( m_bProtectKeyFields );
330 else if ( sName.equals( "emptysales" ) )
332 m_bAllowEmptySales = bEnabled;
333 m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales );
338 catch(com.sun.star.uno.Exception e)
340 System.out.println(e);
341 e.printStackTrace();
345 /* ------------------------------------------------------------------ */
346 // XEventListener overridables
347 /* ------------------------------------------------------------------ */
348 @Override
349 public void disposing( EventObject aEvent )
351 // simply disambiguate
352 super.disposing( aEvent );
355 /* ==================================================================
356 = miscellaneous
357 ================================================================== */
359 /* ------------------------------------------------------------------ */
360 /** skips line feeds in the input stream
362 @returns
363 the first character which does not belong to a line feed
365 protected int skipLineFeeds( java.io.InputStream aInput ) throws java.io.IOException
367 // read characters, until we encounter something which is not a line feed character
368 int nChar = aInput.read( );
369 while ( ( 13 == nChar ) || ( 10 == nChar ) )
370 nChar = aInput.read( );
372 // now read everything which is behind this single character we are interested in
373 while ( 0 < aInput.available() )
374 aInput.read( );
376 return nChar;
379 /* ==================================================================
380 = table handling
381 ================================================================== */
382 /* ------------------------------------------------------------------ */
383 /** checks if a given table exists.
385 <p>The check is made using a SELECT statement, so even if the connection
386 is a n SDB-level connection, which may filter tables in its table
387 supplier, the result may be reliable ....</p>
389 protected boolean existsInvisibleTable( XConnection xConn, String sTableName ) throws java.lang.Exception
391 String sStatement = "SELECT * FROM ";
392 sStatement += sTableName;
393 sStatement += " WHERE 0=1";
395 boolean bSuccess = false;
398 XStatement xStatement = xConn.createStatement();
399 xStatement.execute( sStatement );
400 // if we reached this point, the table probably exists
401 bSuccess = true;
403 catch(com.sun.star.sdbc.SQLException e)
406 return bSuccess;
409 /* ------------------------------------------------------------------ */
410 /** add a specified table name to the table filter of the given data source.
412 protected void makeTableVisible( XDataSource xDS, String sTableName ) throws java.lang.Exception
414 // get the table filter
415 XPropertySet xDSP = UNO.queryPropertySet( xDS );
416 String[] aCurrentFilter = (String[])xDSP.getPropertyValue( "TableFilter" );
418 // check if the table name is already part of it
419 String sAllTables = "*"; // all tables
421 for ( int i=0; i<aCurrentFilter.length; ++i )
423 String sCurrentTableFilter = aCurrentFilter[i];
425 if ( sCurrentTableFilter.equals( sTableName ) )
426 return;
427 if ( sCurrentTableFilter.equals( sAllTables ) )
428 return;
431 // if we are here, we have to add our table to the filter sequence
432 String[] aNewFilter = new String[ aCurrentFilter.length + 1 ];
433 // copy the existent filter entries
434 for ( int i=0; i<aCurrentFilter.length; ++i )
435 aNewFilter[i] = aCurrentFilter[i];
436 // add our table
437 aNewFilter[ aCurrentFilter.length ] = sTableName;
439 xDSP.setPropertyValue( "TableFilter", aNewFilter );
442 /* ------------------------------------------------------------------ */
443 /** executes the given statement on the given connection
445 protected boolean implExecuteStatement( XConnection xConn, String sStatement ) throws java.lang.Exception
449 XStatement xStatement = xConn.createStatement( );
450 xStatement.execute( sStatement );
452 catch(com.sun.star.sdbc.SQLException e)
454 System.err.println( e );
455 return false;
458 return true;
461 /* ------------------------------------------------------------------ */
462 /** creates the table with the given name, using the given statement
464 protected boolean implCreateTable( XConnection xConn, String sCreateStatement, String sTableName ) throws java.lang.Exception
466 if ( !implExecuteStatement( xConn, sCreateStatement ) )
468 System.out.println( " could not create the table " + sTableName + "." );
469 System.out.println( );
470 return false;
473 return true;
476 /* ------------------------------------------------------------------ */
477 /** creates the table SALESMEN
479 @return
480 <TRUE/> if and only if the creation succeeded
482 protected boolean createTableSalesman( XConnection xConn ) throws java.lang.Exception
484 String sCreateStatement = "CREATE TABLE " + s_tableNameSalesmen + " ";
485 sCreateStatement += "(SNR INTEGER NOT NULL, ";
486 sCreateStatement += "FIRSTNAME VARCHAR(50), ";
487 sCreateStatement += "LASTNAME VARCHAR(100), ";
488 sCreateStatement += "STREET VARCHAR(50), ";
489 sCreateStatement += "STATE VARCHAR(50), ";
490 sCreateStatement += "ZIP INTEGER, ";
491 sCreateStatement += "BIRTHDATE DATE, ";
492 sCreateStatement += "PRIMARY KEY(SNR))";
494 if ( implCreateTable( xConn, sCreateStatement, s_tableNameSalesmen) )
496 String sInsertionPrefix = "INSERT INTO " + s_tableNameSalesmen + " VALUES ";
498 implExecuteStatement( xConn, sInsertionPrefix + "(1, 'Joseph', 'Smith', 'Bond Street', 'CA', 95460, '1946-07-02')" );
499 implExecuteStatement( xConn, sInsertionPrefix + "(2, 'Frank', 'Jones', 'Lake silver', 'CA', 95460, '1963-12-24')" );
500 implExecuteStatement( xConn, sInsertionPrefix + "(3, 'Jane', 'Esperansa', '23 Hollywood driver', 'CA', 95460, '1972-04-01')" );
502 return true;
504 return false;
507 /* ------------------------------------------------------------------ */
508 /** creates the table CUSTOMERS
510 @return
511 <TRUE/> if and only if the creation succeeded
513 protected boolean createTableCustomer( XConnection xConn ) throws java.lang.Exception
515 String sCreateStatement = "CREATE TABLE " + s_tableNameCustomers + " ";
516 sCreateStatement += "(COS_NR INTEGER NOT NULL, ";
517 sCreateStatement += "LASTNAME VARCHAR(100), ";
518 sCreateStatement += "STREET VARCHAR(50), ";
519 sCreateStatement += "CITY VARCHAR(50), ";
520 sCreateStatement += "STATE VARCHAR(50), ";
521 sCreateStatement += "ZIP INTEGER, ";
522 sCreateStatement += "PRIMARY KEY(COS_NR))";
524 if ( implCreateTable( xConn, sCreateStatement, s_tableNameCustomers ) )
526 String sInsertionPrefix = "INSERT INTO " + s_tableNameCustomers + " VALUES ";
528 implExecuteStatement( xConn, sInsertionPrefix + "(100, 'Acme, Inc.', '99 Market Street', 'Groundsville', 'CA', 95199)" );
529 implExecuteStatement( xConn, sInsertionPrefix + "(101, 'Superior BugSoft', '1 Party Place', 'Mendocino', 'CA', 95460)");
530 implExecuteStatement( xConn, sInsertionPrefix + "(102, 'WeKnowAll, Inc.', '100 Coffee Lane', 'Meadows', 'CA', 93699)");
532 return true;
534 return false;
537 /* ------------------------------------------------------------------ */
538 /** creates the table SALES
540 @return
541 <TRUE/> if and only if the creation succeeded
543 protected boolean createTableSales( XConnection xConn ) throws java.lang.Exception
545 String sCreateStatement = "CREATE TABLE " + s_tableNameSales + " ";
546 sCreateStatement += "(SALENR INTEGER NOT NULL, ";
547 sCreateStatement += "COS_NR INTEGER NOT NULL, ";
548 sCreateStatement += "SNR INTEGER NOT NULL, ";
549 sCreateStatement += "NAME VARCHAR(50), ";
550 sCreateStatement += "SALEDATE DATE, ";
551 sCreateStatement += "PRICE DECIMAL(8,2), ";
552 sCreateStatement += "PRIMARY KEY(SALENR))";
554 if ( implCreateTable( xConn, sCreateStatement, s_tableNameSales ) )
556 String sInsertionPrefix = "INSERT INTO " + s_tableNameSales + " VALUES ";
558 implExecuteStatement( xConn, sInsertionPrefix + "(1, 100, 1, 'Fruits', '2005-02-12', 39.99)" );
559 implExecuteStatement( xConn, sInsertionPrefix + "(2, 101, 3, 'Beef', '2005-10-18', 15.78)" );
560 implExecuteStatement( xConn, sInsertionPrefix + "(3, 102, 3, 'Orange Juice', '2005-09-08', 25.63)" );
561 implExecuteStatement( xConn, sInsertionPrefix + "(4, 101, 2, 'Oil', '2005-03-01', 12.30)" );
563 return true;
566 return false;
569 /* ------------------------------------------------------------------ */
570 /** ensures that the tables we need for our example exist
572 protected void ensureTables() throws java.lang.Exception
574 // get the data source
575 XDataSource xDS = m_database.getDataSource();
576 XPropertySet xDSProps = UNO.queryPropertySet( xDS );
578 // connect to this data source
579 XConnection xConn = xDS.getConnection( "", "" );
580 XComponent xConnComp = UNO.queryComponent( xConn );
582 createTableSalesman( xConn );
583 createTableCustomer( xConn );
584 createTableSales( xConn );
586 // free the resources acquired by the connection
587 xConnComp.dispose();
590 /* ==================================================================
591 = sample document handling
592 ================================================================== */
594 /* ------------------------------------------------------------------ */
595 /** creates the button used for demonstrating (amongst others) event handling
596 @param nXPos
597 x-position of the to be inserted shape
598 @param nYPos
599 y-position of the to be inserted shape
600 @param nXSize
601 width of the to be inserted shape
602 @param sName
603 the name of the model in the form component hierarchy
604 @param sLabel
605 the label of the button control
606 @param sActionURL
607 the URL of the action which should be triggered by the button
608 @return
609 the model of the newly created button
611 protected XPropertySet createButton( int nXPos, int nYPos, int nXSize, String sName, String sLabel, short _formFeature ) throws java.lang.Exception
613 XPropertySet xButton = m_formLayer.createControlAndShape( "CommandButton", nXPos, nYPos, nXSize, 6 );
614 // the name for referring to it later:
615 xButton.setPropertyValue( "Name", sName );
616 // the label
617 xButton.setPropertyValue( "Label", sLabel );
618 // use the name as help text
619 xButton.setPropertyValue( "HelpText", sName );
620 // don't want buttons to be accessible by the "tab" key - this would be uncomfortable when traveling
621 // with records with "tab"
622 xButton.setPropertyValue( "Tabstop", Boolean.FALSE );
623 // similar, they should not steal the focus when clicked
624 xButton.setPropertyValue( "FocusOnClick", Boolean.FALSE );
626 m_aOperator.addButton( xButton, _formFeature );
628 return xButton;
631 /* ------------------------------------------------------------------ */
632 /** creates a column in a grid
633 @param xGridModel
634 specifies the model of the grid where the new column should be inserted
635 @param sColumnService
636 specifies the service name of the column to create (e.g. "NumericField")
637 @param sDataField
638 specifies the database field to which the column should be bound
639 @param nWidth
640 specifies the column width (in mm). If 0, no width is set.
641 @return
642 the newly created column
644 XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField, int nWidth )
645 throws com.sun.star.uno.Exception
647 // the container to insert columns into
648 XIndexContainer xColumnContainer = UNO.queryIndexContainer( aGridModel );
649 // the factory for creating column models
650 XGridColumnFactory xColumnFactory = UnoRuntime.queryInterface(
651 XGridColumnFactory.class, aGridModel );
653 // (let) create the new col
654 XInterface xNewCol = xColumnFactory.createColumn( sColumnService );
655 XPropertySet xColProps = UNO.queryPropertySet( xNewCol );
657 // some props
658 // the field the column is bound to
659 xColProps.setPropertyValue( "DataField", sDataField );
660 // the "display name" of the column
661 xColProps.setPropertyValue( "Label", sDataField );
662 // the name of the column within its parent
663 xColProps.setPropertyValue( "Name", sDataField );
665 if ( nWidth > 0 )
666 xColProps.setPropertyValue( "Width", Integer.valueOf( nWidth * 10 ) );
668 // insert
669 xColumnContainer.insertByIndex( xColumnContainer.getCount(), xNewCol );
671 // outta here
672 return xColProps;
675 /* ------------------------------------------------------------------ */
676 /** creates a column in a grid
678 XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField )
679 throws com.sun.star.uno.Exception
681 return createGridColumn( aGridModel, sColumnService, sDataField );
684 /* ------------------------------------------------------------------ */
685 /** creates our sample document
687 @Override
688 protected void prepareDocument() throws com.sun.star.uno.Exception, java.lang.Exception
690 super.prepareDocument();
692 m_database = new HsqlDatabase( m_xCtx );
694 // ensure that we have the tables needed for our example
695 ensureTables();
698 /* create some shapes */
699 XPropertySet xSNRField = m_formLayer.insertControlLine( "NumericField", "SNR", "", 3 );
700 m_formLayer.insertControlLine( "TextField", "FIRSTNAME", "", 11);
701 m_formLayer.insertControlLine( "TextField", "LASTNAME", "", 19 );
702 m_formLayer.insertControlLine( "TextField", "STREET", "", 27 );
703 m_formLayer.insertControlLine( "TextField", "STATE", "", 35 );
704 XPropertySet xZipField = m_formLayer.insertControlLine( "NumericField", "ZIP", "", 43 );
705 m_formLayer.insertControlLine( "FormattedField", "BIRTHDATE", "", 51 );
707 // for the salesman number / zip code, we don't want to have decimal places:
708 xSNRField.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) );
709 xZipField.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) );
712 /** need the form the control models belong to
713 for this, we simply obtain the parent for any of the control models we have
715 Note that this involves knowledge about the implementation: If a control shape is
716 inserted into a document, where the control model does not belong to the form component
717 hierarchy, yet, it is automatically inserted into the first form, which is created
718 if necessary.
720 m_xMasterForm = FLTools.getParent( xZipField );
722 // set the data source signature at the form
723 m_xMasterForm.setPropertyValue( "DataSourceName", m_database.getDocumentURL() );
724 m_xMasterForm.setPropertyValue( "CommandType", Integer.valueOf( CommandType.TABLE ) );
725 m_xMasterForm.setPropertyValue( "Command", "SALESMEN" );
728 // insert the buttons
729 // create our button operator, if necessary
730 m_aOperator = new ButtonOperator( m_xCtx, m_document, m_xMasterForm );
732 createButton( 2, 63, 8, "first", "<<", FormFeature.MoveToFirst );
733 createButton( 12, 63, 8, "prev", "<", FormFeature.MoveToPrevious );
734 createButton( 22, 63, 8, "next", ">", FormFeature.MoveToNext );
735 createButton( 32, 63, 8, "last", ">>", FormFeature.MoveToLast );
736 createButton( 42, 63, 8, "new", ">*", FormFeature.MoveToInsertRow );
737 createButton( 58, 63, 13, "reload", "reload", FormFeature.ReloadForm );
740 // create a sub form for the sales
742 // for this, first create a sub form and bind it to the SALES table
743 XIndexContainer xSalesForm = m_document.createSubForm( m_xMasterForm, "Sales" );
744 XPropertySet xSalesFormProps = UNO.queryPropertySet( xSalesForm );
746 xSalesFormProps.setPropertyValue( "DataSourceName", m_database.getDocumentURL() );
747 xSalesFormProps.setPropertyValue( "CommandType", Integer.valueOf( CommandType.COMMAND ) );
749 String sCommand = "SELECT * FROM ";
750 sCommand += s_tableNameSales;
751 sCommand += " WHERE " + s_tableNameSales + ".SNR = :salesmen";
752 xSalesFormProps.setPropertyValue( "Command", sCommand );
754 // the master-details connection
755 String[] aMasterFields = new String[] { "SNR" }; // the field in the master form
756 String[] aDetailFields = new String[] { "salesmen" }; // the name in the detail form
757 xSalesFormProps.setPropertyValue( "MasterFields", aMasterFields );
758 xSalesFormProps.setPropertyValue( "DetailFields", aDetailFields );
760 // the create thr grid model
761 XPropertySet xSalesGridModel = m_formLayer.createControlAndShape( "GridControl", 2, 80, 162, 40, xSalesForm );
762 xSalesGridModel.setPropertyValue( "Name", "SalesTable" );
763 XPropertySet xKeyColumn = createGridColumn( xSalesGridModel, "NumericField", "SALENR", 12 );
764 XPropertySet xCustomerColumn = createGridColumn( xSalesGridModel, "ListBox", "COS_NR", 40 );
765 XPropertySet xSalesNameColumn = createGridColumn( xSalesGridModel, "TextField", "NAME", 25 );
766 createGridColumn( xSalesGridModel, "DateField", "SALEDATE", 24 );
767 createGridColumn( xSalesGridModel, "CurrencyField", "PRICE", 16 );
769 // please note that a better solution for the SALEDATE field would have been to use
770 // a FormattedField. But we want to demonstrate some effects with DateFields here ...
772 m_aSalesNameValidator = new GridFieldValidator( m_xCtx, xSalesNameColumn );
773 m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales );
775 xKeyColumn.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) );
777 // init the list box which is for choosing the customer a sale belongs to
778 xCustomerColumn.setPropertyValue( "BoundColumn", Short.valueOf( (short)1 ) );
779 xCustomerColumn.setPropertyValue( "Label", "Customer" );
780 xCustomerColumn.setPropertyValue( "ListSourceType", ListSourceType.SQL );
782 String sListSource = "SELECT LASTNAME, COS_NR FROM ";
783 sListSource += s_tableNameCustomers;
784 String[] aListSource = new String[] { sListSource };
785 xCustomerColumn.setPropertyValue( "ListSource", aListSource );
787 // We want to demonstrate how to reset fields to NULL, we do this with the SALEDATE field
788 // above. For this, we add as reset listener to the form
789 XReset xFormReset = UNO.queryReset( xSalesForm );
790 xFormReset.addResetListener( this );
794 // the option for filtering the sales form
795 XIndexContainer xSalesFilterForm = m_document.createSiblingForm( xSalesForm, "SalesFilter" );
796 XPropertySet xSFFProps = UNO.queryPropertySet( xSalesFilterForm );
797 XPropertySet xLabel = m_formLayer.createControlAndShape( "FixedText", 2, 125, 35, 6, xSalesFilterForm );
798 xLabel.setPropertyValue( "Label", "show only sales since" );
799 xLabel.setPropertyValue( "Name", "FilterLabel" );
801 XPropertySet xFilterSelection = m_formLayer.createControlAndShape( "ListBox", 40, 125, 59, 6, xSalesFilterForm );
802 xFilterSelection.setPropertyValue( "Name", "FilterList" );
803 xFilterSelection.setPropertyValue( "LabelControl", xLabel );
804 XPropertySet xManualFilter = m_formLayer.createControlAndShape( "DateField", 104, 125, 30, 6, xSalesFilterForm );
805 xManualFilter.setPropertyValue( "Name", "ManualFilter" );
806 XPropertySet xApplyFilter = m_formLayer.createControlAndShape( "CommandButton", 139, 125, 25, 6, xSalesFilterForm );
807 xApplyFilter.setPropertyValue( "Name", "ApplyFilter" );
808 xApplyFilter.setPropertyValue( "DefaultButton", Boolean.TRUE );
809 new SalesFilter( m_document, xSalesFormProps, xFilterSelection,
810 xManualFilter, xApplyFilter );
814 // the options section
815 // for this, we need a form which is a sibling of our master form (don't want to interfere
816 // the controls which represent options only with the controls which are used for data access)
818 XIndexContainer xOptionsForm = m_document.createSiblingForm( m_xMasterForm, "Options" );
820 xLabel = m_formLayer.createControlAndShape( "GroupBox", 98, 0, 66, 62, xOptionsForm );
821 xLabel.setPropertyValue( "Name", "Options" );
822 xLabel.setPropertyValue( "Label", "Options" );
824 // radio buttons which controls how we generate unique keys
825 xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 5, 56, 25, xOptionsForm );
826 xLabel.setPropertyValue( "Label", "key generation" );
827 xLabel.setPropertyValue( "Name", "KeyGeneration" );
828 XPropertySet xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 11, 50, 6, xOptionsForm );
829 xKeyGen.setPropertyValue( "Name", "KeyGen" );
830 xKeyGen.setPropertyValue( "Label", "no automatic generation" );
831 xKeyGen.setPropertyValue( "RefValue", "none" );
832 xKeyGen.addPropertyChangeListener( "State", this );
834 xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 17, 50, 6, xOptionsForm );
835 xKeyGen.setPropertyValue( "Name", "KeyGen" );
836 xKeyGen.setPropertyValue( "Label", "before inserting a record" );
837 xKeyGen.setPropertyValue( "RefValue", "update" );
838 xKeyGen.addPropertyChangeListener( "State", this );
840 xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 23, 50, 6, xOptionsForm );
841 xKeyGen.setPropertyValue( "Name", "KeyGen" );
842 xKeyGen.setPropertyValue( "Label", "when moving to a new record" );
843 xKeyGen.setPropertyValue( "RefValue", "reset" );
844 xKeyGen.addPropertyChangeListener( "State", this );
846 // initialize listeners
847 // master form - key generation
848 m_aSalesmanKeyGenerator = new KeyGenerator( m_xMasterForm, "SNR", m_xCtx );
849 m_aSalesmanKeyGenerator.activateKeyGenerator( true );
850 // master form - control locking
851 m_aSalesmenLocker = new ControlLock( m_xMasterForm, "SNR" );
852 m_aSalesmenLocker.enableLock( m_bProtectKeyFields );
854 // details form - key generation
855 m_aSalesKeyGenerator = new KeyGenerator( xSalesFormProps, "SALENR", m_xCtx );
856 m_aSalesKeyGenerator.activateKeyGenerator( true );
858 // details form - control locking
859 m_aSalesLocker = new ControlLock( xSalesFormProps, "SALENR" );
860 m_aSalesLocker.enableLock( m_bProtectKeyFields );
862 // initially, we want to generate keys when moving to a new record
863 xKeyGen.setPropertyValue( "DefaultState", Short.valueOf( (short)1 ) );
866 // second options block
867 xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 33, 56, 25, xOptionsForm );
868 xLabel.setPropertyValue( "Name", "Misc" );
869 xLabel.setPropertyValue( "Label", "Miscellaneous" );
871 XPropertySet xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 39, 60, 6, xOptionsForm );
872 xCheck.setPropertyValue( "Name", "defaultdate" );
873 xCheck.setPropertyValue( "Label", "default sales date to \"today\"" );
874 xCheck.setPropertyValue( "HelpText", "When checked, newly entered sales records are pre-filled with today's date, else left empty." );
875 xCheck.addPropertyChangeListener( "State", this );
877 xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 45, 60, 6, xOptionsForm );
878 xCheck.setPropertyValue( "Name", "protectkeys" );
879 xCheck.setPropertyValue( "Label", "protect key fields from editing" );
880 xCheck.setPropertyValue( "HelpText", "When checked, you cannot modify the values in the table's key fields (SNR and SALENR)" );
881 xCheck.addPropertyChangeListener( "State", this );
883 xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 51, 60, 6, xOptionsForm );
884 xCheck.setPropertyValue( "Name", "emptysales" );
885 xCheck.setPropertyValue( "Label", "check for empty sales names" );
886 xCheck.setPropertyValue( "HelpText", "When checked, you cannot enter empty values into the NAME column of the 'Sales' table." );
887 xCheck.addPropertyChangeListener( "State", this );
889 // dump the form component tree
890 enumFormComponents( );
893 /* ------------------------------------------------------------------ */
894 @Override
895 protected void onFormsAlive()
897 m_aOperator.onFormsAlive();
900 /* ------------------------------------------------------------------ */
901 /** performs any cleanup before exiting the program
903 @Override
904 protected void cleanUp( ) throws java.lang.Exception
906 // remove the listeners at the buttons
907 RevokeButtons aRevoke = new RevokeButtons( m_aOperator );
908 aRevoke.handle( m_document.getFormComponentTreeRoot( ) );
910 // remove the key generator listeners from the form
911 m_aSalesmanKeyGenerator.stopGenerator( );
912 m_aSalesKeyGenerator.stopGenerator( );
914 // and the control lockers
915 m_aSalesmenLocker.enableLock( false );
916 m_aSalesLocker.enableLock( false );
918 // the validator for the grid column
919 m_aSalesNameValidator.enableColumnWatch( false );
921 // remove our own reset listener from the form
922 XNameAccess xMasterAsNames = UnoRuntime.queryInterface(
923 XNameAccess.class, m_xMasterForm );
924 XReset xFormReset = UNO.queryReset( xMasterAsNames.getByName( "Sales" ) );
925 xFormReset.removeResetListener( this );
927 super.cleanUp();
930 /* ------------------------------------------------------------------ */
931 /** class entry point
933 public static void main(String argv[]) throws java.lang.Exception
935 DataAwareness aSample = new DataAwareness();
936 aSample.run( argv );
940 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */