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