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 60 public PrintComponentTree() 61 { 62 m_sPrefix = new String(); 63 } 64 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 104 public RevokeButtons( ButtonOperator aOperator ) 105 { 106 m_aOperator = aOperator; 107 } 108 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 /* ------------------------------------------------------------------ */ 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 */ 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 */ 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 /* ------------------------------------------------------------------ */ 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 /* ------------------------------------------------------------------ */ 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 /* ------------------------------------------------------------------ */ 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 /* ------------------------------------------------------------------ */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 /* ------------------------------------------------------------------ */ 879 protected void onFormsAlive() 880 { 881 m_aOperator.onFormsAlive(); 882 } 883 884 /* ------------------------------------------------------------------ */ 885 /** performs any cleanup before exiting the program 886 */ 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 */ 916 public static void main(String argv[]) throws java.lang.Exception 917 { 918 DataAwareness aSample = new DataAwareness(); 919 aSample.run( argv ); 920 } 921 } 922