xref: /AOO41X/main/odk/examples/DevelopersGuide/Forms/DataAwareness.java (revision 34dd1e2512dbacb6a9a7e4c7f17b9296daa8eff3)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 import com.sun.star.beans.PropertyChangeEvent;
24 import com.sun.star.beans.XPropertyChangeListener;
25 import com.sun.star.beans.XPropertySet;
26 
27 
28 // __________ Imports __________
29 import com.sun.star.beans.XPropertySetInfo;
30 
31 // base classes
32 import com.sun.star.container.XIndexContainer;
33 import com.sun.star.container.XNameAccess;
34 import com.sun.star.container.XNamed;
35 import com.sun.star.form.FormComponentType;
36 import com.sun.star.form.ListSourceType;
37 import com.sun.star.form.XGridColumnFactory;
38 import com.sun.star.form.XReset;
39 import com.sun.star.form.XResetListener;
40 import com.sun.star.form.runtime.FormFeature;
41 import com.sun.star.lang.EventObject;
42 import com.sun.star.lang.XComponent;
43 import com.sun.star.sdb.CommandType;
44 import com.sun.star.sdb.XColumnUpdate;
45 import com.sun.star.sdbc.ResultSetConcurrency;
46 import com.sun.star.sdbc.XConnection;
47 import com.sun.star.sdbc.XDataSource;
48 import com.sun.star.sdbc.XStatement;
49 import com.sun.star.sdbcx.XColumnsSupplier;
50 import com.sun.star.uno.UnoRuntime;
51 import com.sun.star.uno.XInterface;
52 
53 /**************************************************************************/
54 /** a class for enumerating a form component tree
55 */
56 class PrintComponentTree extends ComponentTreeTraversal
57 {
58     private String m_sPrefix;
59 
PrintComponentTree()60     public PrintComponentTree()
61     {
62         m_sPrefix = new String();
63     }
64 
handle( Object aFormComponent )65     public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
66     {
67         // the name of the child
68         XNamed xName = (XNamed)UnoRuntime.queryInterface( XNamed.class, aFormComponent );
69 
70         // if it's a form control model, check it's type
71         XPropertySet xProps = UNO.queryPropertySet( aFormComponent );
72         String sTypeName = FLTools.classifyFormComponentType( xProps );
73 
74         String sName;
75         if ( null == xName )
76             sName = "<unnamed>";
77         else
78             sName = xName.getName();
79 
80         // print the component's name
81         if ( 0 != sTypeName.length() )
82         {
83             System.out.println( m_sPrefix + sName + " (" + sTypeName + ")" );
84         }
85         else
86         {
87             System.out.println( m_sPrefix + sName );
88         }
89 
90         // let the super class step down the tree
91         m_sPrefix = m_sPrefix + " ";
92         super.handle( aFormComponent );
93         m_sPrefix = m_sPrefix.substring( 0, m_sPrefix.length() - 1 );
94     }
95 };
96 
97 /**************************************************************************/
98 /** a class revoking button models from a ButtonOperator instance
99 */
100 class RevokeButtons extends ComponentTreeTraversal
101 {
102     private ButtonOperator m_aOperator;
103 
RevokeButtons( ButtonOperator aOperator )104     public RevokeButtons( ButtonOperator aOperator )
105     {
106         m_aOperator = aOperator;
107     }
108 
handle( Object aFormComponent )109     public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
110     {
111         // check if it's a button
112         XPropertySet xProps = UNO.queryPropertySet( aFormComponent );
113         XPropertySetInfo xPI = null;
114         if ( null != xProps )
115             xPI = xProps.getPropertySetInfo();
116         if ( ( null != xPI ) && xPI.hasPropertyByName( "ClassId" ) )
117         {
118             Short nClassId = (Short)xProps.getPropertyValue( "ClassId" );
119             if ( FormComponentType.COMMANDBUTTON == nClassId.shortValue() )
120             {
121                 // yes, it is
122                 m_aOperator.revokeButton( xProps );
123             }
124         }
125 
126         // let the super class step down the tree (if possible)
127         super.handle( aFormComponent );
128     }
129 }
130 
131 /**************************************************************************/
132 public class DataAwareness extends DocumentBasedExample implements XPropertyChangeListener, XResetListener
133 {
134     /* ================================================================== */
135     private HsqlDatabase            m_database;
136 
137     private static final String     s_tableNameSalesmen = "SALESMEN";
138     private static final String     s_tableNameCustomers = "CUSTOMERS";
139     private static final String     s_tableNameSales = "SALES";
140 
141     private XPropertySet            m_xMasterForm;
142     private ButtonOperator          m_aOperator;
143     private SalesFilter             m_aSalesFilter;
144 
145     private KeyGenerator            m_aSalesmanKeyGenerator;
146     private KeyGenerator            m_aSalesKeyGenerator;
147     private ControlLock             m_aSalesmenLocker;
148     private ControlLock             m_aSalesLocker;
149     private GridFieldValidator      m_aSalesNameValidator;
150 
151     private boolean                 m_bDefaultSalesDate;
152     private boolean                 m_bProtectKeyFields;
153     private boolean                 m_bAllowEmptySales;
154 
155     /* ------------------------------------------------------------------ */
DataAwareness()156     public DataAwareness()
157     {
158         super( DocumentType.WRITER );
159         m_bDefaultSalesDate = false;
160         m_bProtectKeyFields = false;
161         m_bAllowEmptySales = false;
162     }
163 
164     /* ==================================================================
165        = form components
166        ================================================================== */
167 
168     /* ------------------------------------------------------------------ */
169     /** enumerates and prints all the elements in the given container, together with the container itself
170     */
enumFormComponents( XNameAccess xContainer )171     protected void enumFormComponents( XNameAccess xContainer ) throws java.lang.Exception
172     {
173         String sObjectName;
174 
175         XNamed xNameAcc = (XNamed)UnoRuntime.queryInterface( XNamed.class, xContainer );
176         if ( null == xNameAcc )
177             sObjectName = new String( "<unnamed>" );
178         else
179             sObjectName = xNameAcc.getName();
180         System.out.println( new String( "enumerating the container named \"" ) + sObjectName +
181             new String( "\"\n" ) );
182 
183         PrintComponentTree aPrinter = new PrintComponentTree();
184         aPrinter.handle( xContainer );
185     }
186 
187     /* ------------------------------------------------------------------ */
188     /** enumerates and prints all form elements in the document
189     */
enumFormComponents( )190     protected void enumFormComponents( ) throws java.lang.Exception
191     {
192         enumFormComponents( m_document.getFormComponentTreeRoot() );
193     }
194 
195     /* ==================================================================
196        = UNO callbacks
197        ================================================================== */
198 
199     /* ------------------------------------------------------------------ */
200     // XResetListener overridables
201     /* ------------------------------------------------------------------ */
approveReset( EventObject aEvent )202     public boolean approveReset( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
203     {
204         // not interested in vetoing this
205         return true;
206     }
207 
208     /* ------------------------------------------------------------------ */
resetted( EventObject aEvent )209     public void resetted( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
210     {
211         // check if this reset occured becase we're on a new record
212         XPropertySet xFormProps = UNO.queryPropertySet(  aEvent.Source );
213         try
214         {
215             Boolean aIsNew = (Boolean)xFormProps.getPropertyValue( "IsNew" );
216             if ( aIsNew.booleanValue() )
217             {   // yepp
218 
219                 if ( !m_bDefaultSalesDate )
220                 {   // we're interested to do all this only if the user told us to default the sales date
221                     // to "today"
222                     // As date fields do this defaulting automatically, the semantics is inverted here:
223                     // If we're told to default, we must do nothing, if we should not default, we must
224                     // reset the value which the date field set automatically.
225 
226                     Integer aConcurrency = (Integer)xFormProps.getPropertyValue( "ResultSetConcurrency" );
227                     if ( ResultSetConcurrency.READ_ONLY != aConcurrency.intValue() )
228                     {
229                         // we're going to modify the record, though after that, to the user, it should look
230                         // like it has not been modified
231                         // So we need to ensure that we do not change the IsModified property with whatever we do
232                         Object aModifiedFlag = xFormProps.getPropertyValue( "IsModified" );
233 
234 
235                         // get the columns of our master form
236                         XColumnsSupplier xSuppCols = (XColumnsSupplier)UnoRuntime.queryInterface(
237                             XColumnsSupplier.class, xFormProps );
238                         XNameAccess xCols = xSuppCols.getColumns();
239 
240                         // and update the date column with a NULL value
241                         XColumnUpdate xDateColumn = (XColumnUpdate)UnoRuntime.queryInterface(
242                             XColumnUpdate.class, xCols.getByName( "SALEDATE" ) );
243                         xDateColumn.updateNull();
244 
245 
246                         // then restore the flag
247                         xFormProps.setPropertyValue( "IsModified", aModifiedFlag );
248                     }
249                 }
250             }
251         }
252         catch( com.sun.star.uno.Exception e )
253         {
254             System.out.println(e);
255             e.printStackTrace();
256         }
257     }
258 
259     /* ------------------------------------------------------------------ */
260     // XPropertyChangeListener overridables
261     /* ------------------------------------------------------------------ */
propertyChange( PropertyChangeEvent aEvent )262     public void propertyChange( PropertyChangeEvent aEvent ) throws com.sun.star.uno.RuntimeException
263     {
264         try
265         {
266             // did it come from a radio button or checkbox?
267             if ( aEvent.PropertyName.equals( "State" ) )
268             {   // yep
269                 Short aNewState = (Short)aEvent.NewValue;
270 
271                 XPropertySet xModel = UNO.queryPropertySet( aEvent.Source );
272                 String sName = (String)xModel.getPropertyValue( "Name" );
273 
274                 Short aClassId = (Short)xModel.getPropertyValue( "ClassId" );
275                 if ( FormComponentType.RADIOBUTTON == aClassId.shortValue() )
276                 {
277                     String sRefValue = (String)xModel.getPropertyValue( "RefValue" );
278 
279                     short nNewValue = ((Short)aEvent.NewValue).shortValue();
280                     if ( sName.equals( "KeyGen" ) )
281                     {
282                         // it's one of the options for key generation
283                         if ( sRefValue.equals( "none" ) )
284                         {   // no automatic generation at all
285                             m_aSalesmanKeyGenerator.stopGenerator( );
286                             m_aSalesKeyGenerator.stopGenerator( );
287                         }
288                         else
289                         {
290                             boolean bGenerateOnReset = true;
291                             if ( sRefValue.equals( "update" ) )
292                             {   // generate on update
293                                 bGenerateOnReset = ( 0 == nNewValue );
294                             }
295                             else if ( sRefValue.equals( "reset" ) )
296                             {   // generat on reset
297                                 bGenerateOnReset = ( 0 != nNewValue );
298                             }
299                             m_aSalesmanKeyGenerator.activateKeyGenerator( bGenerateOnReset );
300                             m_aSalesKeyGenerator.activateKeyGenerator( bGenerateOnReset );
301                         }
302                     }
303                 }
304                 else if ( FormComponentType.CHECKBOX == aClassId.shortValue() )
305                 {
306                     boolean bEnabled = ( 0 != aNewState.shortValue() );
307                     if ( sName.equals( "defaultdate" ) )
308                     {
309                         m_bDefaultSalesDate = bEnabled;
310                     }
311                     else if ( sName.equals( "protectkeys" ) )
312                     {
313                         m_bProtectKeyFields = bEnabled;
314                         m_aSalesmenLocker.enableLock( m_bProtectKeyFields );
315                         m_aSalesLocker.enableLock( m_bProtectKeyFields );
316                     }
317                     else if ( sName.equals( "emptysales" ) )
318                     {
319                         m_bAllowEmptySales = bEnabled;
320                         m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales );
321                     }
322                 }
323             }
324         }
325         catch(com.sun.star.uno.Exception e)
326         {
327             System.out.println(e);
328             e.printStackTrace();
329         }
330     }
331 
332     /* ------------------------------------------------------------------ */
333     // XEventListener overridables
334     /* ------------------------------------------------------------------ */
disposing( EventObject aEvent )335     public void disposing( EventObject aEvent )
336     {
337         // simply disambiguate
338         super.disposing( aEvent );
339     }
340 
341     /* ==================================================================
342        = miscellaneous
343        ================================================================== */
344 
345     /* ------------------------------------------------------------------ */
346     /** skips line feeds in the input stream
347 
348         @returns
349             the first character which does not belong to a line feed
350     */
skipLineFeeds( java.io.InputStream aInput )351     protected int skipLineFeeds( java.io.InputStream aInput ) throws java.io.IOException
352     {
353         // read characters, until we encounter something which is not a line feed character
354         int nChar = aInput.read( );
355         while ( ( 13 == nChar ) || ( 10 == nChar ) )
356             nChar = aInput.read( );
357 
358         // now read everything which is behind this single character we are interested in
359         while ( 0 < aInput.available() )
360             aInput.read( );
361 
362         return nChar;
363     }
364 
365     /* ==================================================================
366        = table handling
367        ================================================================== */
368     /* ------------------------------------------------------------------ */
369     /** checks if a given table exists.
370 
371         <p>The check is made using a SELECT statement, so even if the connection
372         is a n SDB-level connection, which may filter tables in it's table
373         supplier, the result may be reliable ....</p>
374     */
existsInvisibleTable( XConnection xConn, String sTableName )375     protected boolean existsInvisibleTable( XConnection xConn, String sTableName ) throws java.lang.Exception
376     {
377         String sStatement = "SELECT * FROM ";
378         sStatement += sTableName;
379         sStatement += " WHERE 0=1";
380 
381         boolean bSuccess = false;
382         try
383         {
384             XStatement xStatement = xConn.createStatement();
385             xStatement.execute( sStatement );
386             // if we reached this point, the table probably exists
387             bSuccess = true;
388         }
389         catch(com.sun.star.sdbc.SQLException e)
390         {
391         }
392         return bSuccess;
393     }
394 
395     /* ------------------------------------------------------------------ */
396     /** add a specified table name to the table filter of the given data source.
397     */
makeTableVisible( XDataSource xDS, XConnection xConn, String sTableName )398     protected void makeTableVisible( XDataSource xDS, XConnection xConn, String sTableName ) throws java.lang.Exception
399     {
400         // get the table filter
401         XPropertySet xDSP = UNO.queryPropertySet( xDS );
402         String[] aCurrentFilter = (String[])xDSP.getPropertyValue( "TableFilter" );
403 
404         // check if the table name is already part of it
405         String sAllTables = "*";                                                // all tables
406 
407         for ( int i=0; i<aCurrentFilter.length; ++i )
408         {
409             String sCurrentTableFilter = aCurrentFilter[i];
410 
411             if ( sCurrentTableFilter.equals( sTableName ) )
412                 return;
413             if ( sCurrentTableFilter.equals( sAllTables ) )
414                 return;
415         }
416 
417         // if we are here, we have to add our table to the filter sequence
418         String[] aNewFilter = new String[ aCurrentFilter.length + 1 ];
419         // copy the existent filter entries
420         for ( int i=0; i<aCurrentFilter.length; ++i )
421             aNewFilter[i] = aCurrentFilter[i];
422         // add our table
423         aNewFilter[ aCurrentFilter.length ] = sTableName;
424 
425         xDSP.setPropertyValue( "TableFilter", aNewFilter );
426     }
427 
428     /* ------------------------------------------------------------------ */
429     /** executes the given statement on the given connection
430     */
implExecuteStatement( XConnection xConn, String sStatement )431     protected boolean implExecuteStatement( XConnection xConn, String sStatement ) throws java.lang.Exception
432     {
433         try
434         {
435             XStatement xStatement = xConn.createStatement( );
436             xStatement.execute( sStatement );
437         }
438         catch(com.sun.star.sdbc.SQLException e)
439         {
440             System.err.println( e );
441             return false;
442         }
443 
444         return true;
445     }
446 
447     /* ------------------------------------------------------------------ */
448     /** creates the table witht the given name, using the given statement
449     */
implCreateTable( XConnection xConn, String sCreateStatement, String sTableName )450     protected boolean implCreateTable( XConnection xConn, String sCreateStatement, String sTableName ) throws java.lang.Exception
451     {
452         if ( !implExecuteStatement( xConn, sCreateStatement ) )
453         {
454             System.out.println( "  could not create the table " + sTableName + "." );
455             System.out.println( );
456             return false;
457         }
458 
459         return true;
460     }
461 
462     /* ------------------------------------------------------------------ */
463     /** creates the table SALESMEN
464 
465         @return
466             <TRUE/> if and only if the creation succeeded
467     */
createTableSalesman( XConnection xConn )468     protected boolean createTableSalesman( XConnection xConn ) throws java.lang.Exception
469     {
470         String sCreateStatement = "CREATE TABLE " + s_tableNameSalesmen + " ";
471         sCreateStatement += "(SNR INTEGER NOT NULL, ";
472         sCreateStatement += "FIRSTNAME VARCHAR(50), ";
473         sCreateStatement += "LASTNAME VARCHAR(100), ";
474         sCreateStatement += "STREET VARCHAR(50), ";
475         sCreateStatement += "STATE VARCHAR(50), ";
476         sCreateStatement += "ZIP INTEGER, ";
477         sCreateStatement += "BIRTHDATE DATE, ";
478         sCreateStatement += "PRIMARY KEY(SNR))";
479 
480         if ( implCreateTable( xConn, sCreateStatement, s_tableNameSalesmen) )
481         {
482             String sInsertionPrefix = "INSERT INTO " + s_tableNameSalesmen + " VALUES ";
483 
484             implExecuteStatement( xConn, sInsertionPrefix + "(1, 'Joseph', 'Smith', 'Bond Street', 'CA', 95460, '1946-07-02')" );
485             implExecuteStatement( xConn, sInsertionPrefix + "(2, 'Frank', 'Jones', 'Lake silver', 'CA', 95460, '1963-12-24')" );
486             implExecuteStatement( xConn, sInsertionPrefix + "(3, 'Jane', 'Esperansa', '23 Hollywood driver', 'CA', 95460, '1972-04-01')" );
487 
488             return true;
489         }
490         return false;
491     }
492 
493     /* ------------------------------------------------------------------ */
494     /** creates the table CUSTOMERS
495 
496         @return
497             <TRUE/> if and only if the creation succeeded
498     */
createTableCustomer( XConnection xConn )499     protected boolean createTableCustomer( XConnection xConn ) throws java.lang.Exception
500     {
501         String sCreateStatement = "CREATE TABLE " + s_tableNameCustomers + " ";
502         sCreateStatement += "(COS_NR INTEGER NOT NULL, ";
503         sCreateStatement += "LASTNAME VARCHAR(100), ";
504         sCreateStatement += "STREET VARCHAR(50), ";
505         sCreateStatement += "CITY VARCHAR(50), ";
506         sCreateStatement += "STATE VARCHAR(50), ";
507         sCreateStatement += "ZIP INTEGER, ";
508         sCreateStatement += "PRIMARY KEY(COS_NR))";
509 
510         if ( implCreateTable( xConn, sCreateStatement, s_tableNameCustomers ) )
511         {
512             String sInsertionPrefix = "INSERT INTO " + s_tableNameCustomers + " VALUES ";
513 
514             implExecuteStatement( xConn, sInsertionPrefix + "(100, 'Acme, Inc.', '99 Market Street', 'Groundsville', 'CA', 95199)" );
515             implExecuteStatement( xConn, sInsertionPrefix + "(101, 'Superior BugSoft', '1 Party Place', 'Mendocino', 'CA', 95460)");
516             implExecuteStatement( xConn, sInsertionPrefix + "(102, 'WeKnowAll, Inc.', '100 Coffee Lane', 'Meadows', 'CA', 93699)");
517 
518             return true;
519         }
520         return false;
521     }
522 
523     /* ------------------------------------------------------------------ */
524     /** creates the table SALES
525 
526         @return
527             <TRUE/> if and only if the creation succeeded
528     */
createTableSales( XConnection xConn )529     protected boolean createTableSales( XConnection xConn ) throws java.lang.Exception
530     {
531         String sCreateStatement = "CREATE TABLE " + s_tableNameSales + " ";
532         sCreateStatement += "(SALENR INTEGER NOT NULL, ";
533         sCreateStatement += "COS_NR INTEGER NOT NULL, ";
534         sCreateStatement += "SNR INTEGER NOT NULL, ";
535         sCreateStatement += "NAME VARCHAR(50), ";
536         sCreateStatement += "SALEDATE DATE, ";
537         sCreateStatement += "PRICE DECIMAL(8,2), ";
538         sCreateStatement += "PRIMARY KEY(SALENR))";
539 
540         if ( implCreateTable( xConn, sCreateStatement, s_tableNameSales ) )
541         {
542             String sInsertionPrefix = "INSERT INTO " + s_tableNameSales + " VALUES ";
543 
544             implExecuteStatement( xConn, sInsertionPrefix + "(1, 100, 1, 'Fruits', '2005-02-12', 39.99)" );
545             implExecuteStatement( xConn, sInsertionPrefix + "(2, 101, 3, 'Beef', '2005-10-18', 15.78)" );
546             implExecuteStatement( xConn, sInsertionPrefix + "(3, 102, 3, 'Orange Juice', '2005-09-08', 25.63)" );
547             implExecuteStatement( xConn, sInsertionPrefix + "(4, 101, 2, 'Oil', '2005-03-01', 12.30)" );
548 
549             return true;
550         }
551 
552         return false;
553     }
554 
555     /* ------------------------------------------------------------------ */
556     /** ensures that the tables we need for our example exist
557     */
ensureTables()558     protected void ensureTables() throws java.lang.Exception
559     {
560         // get the data source
561         XDataSource xDS = m_database.getDataSource();
562         XPropertySet xDSProps = UNO.queryPropertySet( xDS );
563 
564         // connect to this data source
565         XConnection xConn = xDS.getConnection( "", "" );
566         XComponent xConnComp = UNO.queryComponent( xConn );
567 
568         createTableSalesman( xConn );
569         createTableCustomer( xConn );
570         createTableSales( xConn );
571 
572         // free the resources acquired by the connection
573         xConnComp.dispose();
574     }
575 
576     /* ==================================================================
577        = sample document handling
578        ================================================================== */
579 
580     /* ------------------------------------------------------------------ */
581     /** creates the button used for demonstrating (amonst others) event handling
582         @param nXPos
583             x-position of the to be inserted shape
584         @param nYPos
585             y-position of the to be inserted shape
586         @param nXSize
587             width of the to be inserted shape
588         @param sName
589             the name of the model in the form component hierarchy
590         @param sLabel
591             the label of the button control
592         @param sActionURL
593             the URL of the action which should be triggered by the button
594         @return
595             the model of the newly created button
596     */
createButton( int nXPos, int nYPos, int nXSize, String sName, String sLabel, short _formFeature )597     protected XPropertySet createButton( int nXPos, int nYPos, int nXSize, String sName, String sLabel, short _formFeature ) throws java.lang.Exception
598     {
599         XPropertySet xButton = m_formLayer.createControlAndShape( "CommandButton", nXPos, nYPos, nXSize, 6 );
600         // the name for referring to it later:
601         xButton.setPropertyValue( "Name", sName );
602         // the label
603         xButton.setPropertyValue( "Label", sLabel );
604         // use the name as help text
605         xButton.setPropertyValue( "HelpText", sName );
606         // don't want buttons to be accessible by the "tab" key - this would be uncomfortable when traveling
607         // with records with "tab"
608         xButton.setPropertyValue( "Tabstop", new Boolean( false ) );
609         // similar, they should not steal the focus when clicked
610         xButton.setPropertyValue( "FocusOnClick", new Boolean( false ) );
611 
612         m_aOperator.addButton( xButton, _formFeature );
613 
614         return xButton;
615     }
616 
617     /* ------------------------------------------------------------------ */
618     /** creates a column in a grid
619         @param xGridModel
620             specifies the model of the grid where the new column should be inserted
621         @param sColumnService
622             specifies the service name of the column to create (e.g. "NumericField")
623         @param sDataField
624             specifies the database field to which the column should be bound
625         @param nWidth
626             specifies the column width (in mm). If 0, no width is set.
627         @return
628             the newly created column
629     */
createGridColumn( Object aGridModel, String sColumnService, String sDataField, int nWidth )630     XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField, int nWidth )
631         throws com.sun.star.uno.Exception
632     {
633         // the container to insert columns into
634         XIndexContainer xColumnContainer = UNO.queryIndexContainer( aGridModel );
635         // the factory for creating column models
636         XGridColumnFactory xColumnFactory = (XGridColumnFactory)UnoRuntime.queryInterface(
637             XGridColumnFactory.class, aGridModel );
638 
639         // (let) create the new col
640         XInterface xNewCol = (XInterface)xColumnFactory.createColumn( sColumnService );
641         XPropertySet xColProps = UNO.queryPropertySet( xNewCol );
642 
643         // some props
644         // the field the column is bound to
645         xColProps.setPropertyValue( "DataField", sDataField );
646         // the "display name" of the column
647         xColProps.setPropertyValue( "Label", sDataField );
648         // the name of the column within it's parent
649         xColProps.setPropertyValue( "Name", sDataField );
650 
651         if ( nWidth > 0 )
652             xColProps.setPropertyValue( "Width", new Integer( nWidth * 10 ) );
653 
654         // insert
655         xColumnContainer.insertByIndex( xColumnContainer.getCount(), xNewCol );
656 
657         // outta here
658         return xColProps;
659     }
660 
661     /* ------------------------------------------------------------------ */
662     /** creates a column in a grid
663     */
createGridColumn( Object aGridModel, String sColumnService, String sDataField )664     XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField )
665         throws com.sun.star.uno.Exception
666     {
667         return createGridColumn( aGridModel, sColumnService, sDataField );
668     }
669 
670     /* ------------------------------------------------------------------ */
671     /** creates our sample document
672     */
prepareDocument()673     protected void prepareDocument() throws com.sun.star.uno.Exception, java.lang.Exception
674     {
675         super.prepareDocument();
676 
677         m_database = new HsqlDatabase( m_xCtx );
678 
679         // ensure that we have the tables needed for our example
680         ensureTables();
681 
682         // --------------------------------------------------------------
683         /* create some shapes */
684         XPropertySet xSNRField =    m_formLayer.insertControlLine( "NumericField", "SNR", "", 3 );
685                                     m_formLayer.insertControlLine( "TextField", "FIRSTNAME", "", 11);
686                                     m_formLayer.insertControlLine( "TextField", "LASTNAME", "", 19 );
687                                     m_formLayer.insertControlLine( "TextField", "STREET", "", 27 );
688                                     m_formLayer.insertControlLine( "TextField", "STATE", "", 35 );
689         XPropertySet xZipField =    m_formLayer.insertControlLine( "NumericField", "ZIP", "", 43 );
690                                     m_formLayer.insertControlLine( "FormattedField", "BIRTHDATE", "", 51 );
691 
692         // for the salesman number / zip code, we don't want to have decimal places:
693         xSNRField.setPropertyValue( "DecimalAccuracy", new Short( (short)0 ) );
694         xZipField.setPropertyValue( "DecimalAccuracy", new Short( (short)0 ) );
695 
696         // --------------------------------------------------------------
697         /** need the form the control models belong to
698             for this, we simply obtain the parent for any of the control models we have
699 
700             Note that this involves knowledge about the implementation: If a control shape is
701             inserted into a document, where the control model does not belong to the form component
702             hierarchy, yet, it is automatically inserted into the first form, which is created
703             if necessary.
704         */
705         m_xMasterForm = FLTools.getParent( xZipField );
706 
707         // set the data source signature at the form
708         m_xMasterForm.setPropertyValue( "DataSourceName", m_database.getDocumentURL() );
709         m_xMasterForm.setPropertyValue( "CommandType", new Integer( CommandType.TABLE ) );
710         m_xMasterForm.setPropertyValue( "Command", "SALESMEN" );
711 
712         // --------------------------------------------------------------
713         // insert the buttons
714         // create our button operator, if necessary
715         m_aOperator = new ButtonOperator( m_xCtx, m_document, m_xMasterForm );
716 
717         createButton( 2, 63, 8, "first", "<<", FormFeature.MoveToFirst );
718         createButton( 12, 63, 8, "prev", "<", FormFeature.MoveToPrevious );
719         createButton( 22, 63, 8, "next", ">", FormFeature.MoveToNext );
720         createButton( 32, 63, 8, "last", ">>", FormFeature.MoveToLast );
721         createButton( 42, 63, 8, "new", ">*", FormFeature.MoveToInsertRow );
722         createButton( 58, 63, 13, "reload", "reload", FormFeature.ReloadForm );
723 
724         // --------------------------------------------------------------
725         // create a sub for for the sales
726 
727         // for this, first create a sub form and bind it to the SALES table
728         XIndexContainer xSalesForm = m_document.createSubForm( m_xMasterForm, "Sales" );
729         XPropertySet xSalesFormProps = UNO.queryPropertySet( xSalesForm );
730 
731         xSalesFormProps.setPropertyValue( "DataSourceName", m_database.getDocumentURL() );
732         xSalesFormProps.setPropertyValue( "CommandType", new Integer( CommandType.COMMAND ) );
733 
734         String sCommand = new String( "SELECT * FROM " );
735         sCommand += s_tableNameSales;
736         sCommand += " WHERE " + s_tableNameSales + ".SNR = :salesmen";
737         xSalesFormProps.setPropertyValue( "Command", sCommand );
738 
739         // the master-details connection
740         String[] aMasterFields = new String[] { "SNR" };        // the field in the master form
741         String[] aDetailFields = new String[] { "salesmen" };   // the name in the detail form
742         xSalesFormProps.setPropertyValue( "MasterFields", aMasterFields );
743         xSalesFormProps.setPropertyValue( "DetailFields", aDetailFields );
744 
745         // the create thr grid model
746         XPropertySet xSalesGridModel = m_formLayer.createControlAndShape( "GridControl", 2, 80, 162, 40, xSalesForm );
747         xSalesGridModel.setPropertyValue( "Name", "SalesTable" );
748         XPropertySet xKeyColumn      =  createGridColumn( xSalesGridModel, "NumericField", "SALENR", 12 );
749         XPropertySet xCustomerColumn =  createGridColumn( xSalesGridModel, "ListBox", "COS_NR", 40 );
750         XPropertySet xSalesNameColumn = createGridColumn( xSalesGridModel, "TextField", "NAME", 25 );
751                                         createGridColumn( xSalesGridModel, "DateField", "SALEDATE", 24 );
752                                         createGridColumn( xSalesGridModel, "CurrencyField", "PRICE", 16 );
753 
754             // please note that a better solution for the SALEDATE field would have been to use
755             // a FormattedField. But we want to demonstrate some effects with DateFields here ...
756 
757         m_aSalesNameValidator = new GridFieldValidator( m_xCtx, xSalesNameColumn );
758         m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales );
759 
760         xKeyColumn.setPropertyValue( "DecimalAccuracy", new Short( (short)0 ) );
761 
762         // init the list box which is for choosing the customer a sale belongs to
763         xCustomerColumn.setPropertyValue( "BoundColumn", new Short( (short)1 ) );
764         xCustomerColumn.setPropertyValue( "Label", "Customer" );
765         xCustomerColumn.setPropertyValue( "ListSourceType", ListSourceType.SQL );
766 
767         String sListSource = "SELECT LASTNAME, COS_NR FROM ";
768         sListSource += s_tableNameCustomers;
769         String[] aListSource = new String[] { sListSource };
770         xCustomerColumn.setPropertyValue( "ListSource", aListSource );
771 
772         // We want to demonstrate how to reset fields to NULL, we do this with the SALEDATE field
773         // above. For this, we add as reset listener to the form
774         XReset xFormReset = UNO.queryReset( xSalesForm );
775         xFormReset.addResetListener( this );
776 
777 
778         // --------------------------------------------------------------
779         // the option for filtering the sales form
780         XIndexContainer xSalesFilterForm = m_document.createSiblingForm( xSalesForm, "SalesFilter" );
781         XPropertySet xSFFProps = UNO.queryPropertySet( xSalesFilterForm );
782         XPropertySet xLabel = m_formLayer.createControlAndShape( "FixedText", 2, 125, 35, 6, xSalesFilterForm );
783         xLabel.setPropertyValue( "Label", "show only sales since" );
784         xLabel.setPropertyValue( "Name", "FilterLabel" );
785 
786         XPropertySet xFilterSelection = m_formLayer.createControlAndShape( "ListBox", 40, 125, 59, 6, xSalesFilterForm );
787         xFilterSelection.setPropertyValue( "Name", "FilterList" );
788         xFilterSelection.setPropertyValue( "LabelControl", xLabel );
789         XPropertySet xManualFilter = m_formLayer.createControlAndShape( "DateField", 104, 125, 30, 6, xSalesFilterForm );
790         xManualFilter.setPropertyValue( "Name", "ManualFilter" );
791         XPropertySet xApplyFilter = m_formLayer.createControlAndShape( "CommandButton", 139, 125, 25, 6, xSalesFilterForm );
792         xApplyFilter.setPropertyValue( "Name", "ApplyFilter" );
793         xApplyFilter.setPropertyValue( "DefaultButton", new Boolean( true ) );
794         m_aSalesFilter = new SalesFilter( m_document, xSalesFormProps, xFilterSelection,
795             xManualFilter, xApplyFilter );
796 
797 
798         // --------------------------------------------------------------
799         // the options section
800         // for this, we need a form which is a sibling of our master form (don't want to interfere
801         // the controls which represent options only with the controls which are used for data access)
802 
803         XIndexContainer xOptionsForm = m_document.createSiblingForm( m_xMasterForm, "Options" );
804 
805         xLabel = m_formLayer.createControlAndShape( "GroupBox", 98, 0, 66, 62, xOptionsForm );
806         xLabel.setPropertyValue( "Name", "Options" );
807         xLabel.setPropertyValue( "Label", "Options" );
808 
809         // radio buttons which controls how we generate unique keys
810         xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 5, 56, 25, xOptionsForm );
811         xLabel.setPropertyValue( "Label", "key generation" );
812         xLabel.setPropertyValue( "Name", "KeyGeneration" );
813         XPropertySet xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 11, 50, 6, xOptionsForm );
814         xKeyGen.setPropertyValue( "Name", "KeyGen" );
815         xKeyGen.setPropertyValue( "Label", "no automatic generation" );
816         xKeyGen.setPropertyValue( "RefValue", "none" );
817         xKeyGen.addPropertyChangeListener( "State", this );
818 
819         xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 17, 50, 6, xOptionsForm );
820         xKeyGen.setPropertyValue( "Name", "KeyGen" );
821         xKeyGen.setPropertyValue( "Label", "before inserting a record" );
822         xKeyGen.setPropertyValue( "RefValue", "update" );
823         xKeyGen.addPropertyChangeListener( "State", this );
824 
825         xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 23, 50, 6, xOptionsForm );
826         xKeyGen.setPropertyValue( "Name", "KeyGen" );
827         xKeyGen.setPropertyValue( "Label", "when moving to a new record" );
828         xKeyGen.setPropertyValue( "RefValue", "reset" );
829         xKeyGen.addPropertyChangeListener( "State", this );
830 
831         // initialize listeners
832         // master form - key generation
833         m_aSalesmanKeyGenerator = new KeyGenerator( m_xMasterForm, "SNR", m_xCtx );
834         m_aSalesmanKeyGenerator.activateKeyGenerator( true );
835         // master form - control locking
836         m_aSalesmenLocker = new ControlLock( m_xMasterForm, "SNR" );
837         m_aSalesmenLocker.enableLock( m_bProtectKeyFields );
838 
839         // details form - key generation
840         m_aSalesKeyGenerator = new KeyGenerator( xSalesFormProps, "SALENR", m_xCtx );
841         m_aSalesKeyGenerator.activateKeyGenerator( true );
842 
843         // details form - control locking
844         m_aSalesLocker = new ControlLock( xSalesFormProps, "SALENR" );
845         m_aSalesLocker.enableLock( m_bProtectKeyFields );
846 
847         // initally, we want to generate keys when moving to a new record
848         xKeyGen.setPropertyValue( "DefaultState", new Short( (short)1 ) );
849 
850         // --------------------------------------------------------------
851         // second options block
852         xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 33, 56, 25, xOptionsForm  );
853         xLabel.setPropertyValue( "Name", "Misc" );
854         xLabel.setPropertyValue( "Label", "Miscellaneous" );
855 
856         XPropertySet xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 39, 60, 6, xOptionsForm  );
857         xCheck.setPropertyValue( "Name", "defaultdate" );
858         xCheck.setPropertyValue( "Label", "default sales date to \"today\"" );
859         xCheck.setPropertyValue( "HelpText", "When checked, newly entered sales records are pre-filled with today's date, else left empty." );
860         xCheck.addPropertyChangeListener( "State", this );
861 
862         xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 45, 60, 6, xOptionsForm  );
863         xCheck.setPropertyValue( "Name", "protectkeys" );
864         xCheck.setPropertyValue( "Label", "protect key fields from editing" );
865         xCheck.setPropertyValue( "HelpText", "When checked, you cannot modify the values in the table's key fields (SNR and SALENR)" );
866         xCheck.addPropertyChangeListener( "State", this );
867 
868         xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 51, 60, 6, xOptionsForm  );
869         xCheck.setPropertyValue( "Name", "emptysales" );
870         xCheck.setPropertyValue( "Label", "check for empty sales names" );
871         xCheck.setPropertyValue( "HelpText", "When checked, you cannot enter empty values into the NAME column of the 'Sales' table." );
872         xCheck.addPropertyChangeListener( "State", this );
873 
874         // dump the form component tree
875         enumFormComponents( );
876     }
877 
878     /* ------------------------------------------------------------------ */
onFormsAlive()879     protected void onFormsAlive()
880     {
881         m_aOperator.onFormsAlive();
882     }
883 
884     /* ------------------------------------------------------------------ */
885     /** performs any cleanup before exiting the program
886     */
cleanUp( )887     protected void cleanUp( ) throws java.lang.Exception
888     {
889         // remove the listeners at the buttons
890         RevokeButtons aRevoke = new RevokeButtons( m_aOperator );
891         aRevoke.handle( m_document.getFormComponentTreeRoot( ) );
892 
893         // remove the key generator listeners from the form
894         m_aSalesmanKeyGenerator.stopGenerator( );
895         m_aSalesKeyGenerator.stopGenerator( );
896 
897         // and the control lockers
898         m_aSalesmenLocker.enableLock( false );
899         m_aSalesLocker.enableLock( false );
900 
901         // the validator for the grid column
902         m_aSalesNameValidator.enableColumnWatch( false );
903 
904         // remove our own reset listener from the form
905         XNameAccess xMasterAsNames = (XNameAccess)UnoRuntime.queryInterface(
906             XNameAccess.class, m_xMasterForm );
907         XReset xFormReset = UNO.queryReset( xMasterAsNames.getByName( "Sales" ) );
908         xFormReset.removeResetListener( this );
909 
910         super.cleanUp();
911     }
912 
913     /* ------------------------------------------------------------------ */
914     /** class entry point
915     */
main(String argv[])916     public static void main(String argv[]) throws java.lang.Exception
917     {
918         DataAwareness aSample = new DataAwareness();
919         aSample.run( argv );
920     }
921 }
922