xref: /trunk/main/forms/qa/integration/forms/FormControlTest.java (revision 3309286857f19787ae62bd793a98b5af4edd2ad3)
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 package integration.forms;
24 
25 import com.sun.star.awt.XImageProducer;
26 import com.sun.star.beans.PropertyValue;
27 import com.sun.star.beans.XPropertySet;
28 import com.sun.star.container.XNameAccess;
29 import com.sun.star.form.runtime.XFormController;
30 import com.sun.star.form.XImageProducerSupplier;
31 import com.sun.star.frame.XDispatch;
32 import com.sun.star.lang.EventObject;
33 import com.sun.star.lang.XMultiServiceFactory;
34 import com.sun.star.sdb.CommandType;
35 import com.sun.star.sdb.SQLErrorEvent;
36 import com.sun.star.sdb.XSQLErrorBroadcaster;
37 import com.sun.star.sdb.XSQLErrorListener;
38 import com.sun.star.sdbc.XConnection;
39 import com.sun.star.sdbc.XDataSource;
40 import com.sun.star.sdbc.XResultSet;
41 import com.sun.star.sdbc.XResultSetUpdate;
42 import com.sun.star.uno.UnoRuntime;
43 import com.sun.star.uno.XNamingService;
44 import com.sun.star.util.URL;
45 import com.sun.star.util.XCloseable;
46 import com.sun.star.util.XURLTransformer;
47 import connectivity.tools.HsqlDatabase;
48 import connectivity.tools.sdb.Connection;
49 import java.io.FileOutputStream;
50 
51 import org.junit.After;
52 import org.junit.AfterClass;
53 import org.junit.Before;
54 import org.junit.BeforeClass;
55 import org.junit.Test;
56 import static org.junit.Assert.*;
57 import org.openoffice.test.OfficeConnection;
58 
59 
60 public class FormControlTest implements XSQLErrorListener
61 {
62     private static final OfficeConnection officeConnection = new OfficeConnection();
63     private static String s_tableName        = "CTC_form_controls";
64 
65     private HsqlDatabase            m_databaseDocument;
66     private XDataSource             m_dataSource;
67     private XPropertySet            m_dataSourceProps;
68     private XMultiServiceFactory    m_orb;
69     private DocumentHelper          m_document;
70     private FormLayer               m_formLayer;
71     private XPropertySet            m_masterForm;
72     private XFormController         m_masterFormController;
73     private String                  m_sImageURL;
74     private SQLErrorEvent           m_mostRecentErrorEvent;
75 
76     private final String            m_dataSourceName = "integration.forms.FormControlTest";
77 
78     /* ------------------------------------------------------------------ */
79 
80     @BeforeClass
beforeClass()81     public static void beforeClass() throws Exception
82     {
83         officeConnection.setUp();
84     }
85 
86     @AfterClass
afterClass()87     public static void afterClass() throws Exception
88     {
89         officeConnection.tearDown();
90     }
91 
92     /* ------------------------------------------------------------------ */
93     /// pre-test initialization
94     @Before
before()95     public void before() throws com.sun.star.uno.Exception, java.lang.Exception
96     {
97         // ensure that we have a data source to work with, and the required tables
98         if ( !ensureDataSource() || !ensureTables() )
99         {
100             fail( "could not access the required data source or table therein." );
101             return;
102         }
103 
104         // create the document which we work on
105         createSampleDocument();
106 
107         createImageFile();
108     }
109 
110     /* ------------------------------------------------------------------ */
111     @Test
checkFirstRow()112     public void checkFirstRow() throws com.sun.star.uno.Exception, java.lang.Exception
113     {
114         moveToFirst();
115 
116         // and check the content of the various controls
117         if  (  !checkRadios( (short)1, (short)0, (short)0 )
118             || !checkDoubleValue( 1,            "ID",               "Value"          )
119             || !checkDoubleValue( 42,           "f_integer",        "EffectiveValue" )
120             || !checkStringValue( "the answer", "f_text",           "Text"           )
121             || !checkDoubleValue( 0.12,         "f_decimal",        "Value"          )
122             || !checkIntValue   ( 20030922,     "f_date",           "Date"           )
123             || !checkIntValue   ( 15000000,     "f_time",           "Time"           )
124             || !checkIntValue   ( 20030923,     "f_timestamp_date", "Date"           )
125             || !checkIntValue   ( 17152300,     "f_timestamp_time", "Time"           )
126             || !checkShortValue ( (short)1,     "f_tinyint",        "State"          )
127             )
128         {
129             fail( "checking the content of one or more controls on the first row failed (see the log for details)" );
130             return;
131         }
132     }
133 
134     /* ------------------------------------------------------------------ */
135     @Test
checkInsertRow()136     public void checkInsertRow() throws com.sun.star.uno.Exception, java.lang.Exception
137     {
138         // move the cursor to the insert row
139         moveToInsertRow();
140 
141         // and check the content of the various controls
142         if  ( !verifyCleanInsertRow() )
143         {
144             fail( "checking the content of one or more controls on the insert row failed (see the log for details)" );
145             return;
146         }
147     }
148 
149     /* ------------------------------------------------------------------ */
150     /// some tests with the image control
151     @Test
checkImageControl()152     public void checkImageControl() throws com.sun.star.uno.Exception, java.lang.Exception
153     {
154         // since we did not yet insert any image, the control should not display one ...
155         moveToFirst();
156         if ( !verifyReferenceImage( new byte[0] ) )
157         {
158             fail( "image control failed to display empty image" );
159             return;
160         }
161 
162         // check if the image control is able to insert our sample image into the database
163         // insert an
164         XPropertySet xImageModel = getControlModel( "f_blob" );
165         xImageModel.setPropertyValue( "ImageURL", m_sImageURL );
166 
167         if ( !verifyReferenceImage( getSamplePictureBytes() ) )
168         {
169             fail( "image control does not display the sample image as required" );
170             return;
171         }
172 
173         // save the record
174         saveRecordByUI();
175 
176         // still needs to be the sample image
177         if ( !verifyReferenceImage( getSamplePictureBytes() ) )
178         {
179             fail( "image control does not, after saving the record, display the sample image as required" );
180             return;
181         }
182 
183         // on the next record, the image should be empty
184         moveToNext();
185         if ( !verifyReferenceImage( new byte[0] ) )
186         {
187             fail( "image control failed to display empty image, after coming from a non-empty image" );
188             return;
189         }
190 
191         // back to the record where we just inserted the image, it should be our sample image
192         moveToFirst();
193         if ( !verifyReferenceImage( getSamplePictureBytes() ) )
194         {
195             fail( "image control does not, after coming back to the record, display the sample image as required" );
196             return;
197         }
198 
199         // okay, now remove the image
200         xImageModel.setPropertyValue( "ImageURL", new String() );
201         if ( !verifyReferenceImage( new byte[0] ) )
202         {
203             fail( "image control failed to remove the image" );
204             return;
205         }
206         nextRecordByUI();
207         previousRecordByUI();
208         if ( !verifyReferenceImage( new byte[0] ) )
209         {
210             fail( "image still there after coming back, though we just removed it" );
211             return;
212         }
213     }
214 
215     /* ------------------------------------------------------------------ */
216     /** This is both a test for controls which are bound to the same column (they must reflect
217      *  each others updates), and for the immediate updates which need to happen for both check
218      *  boxes and radio buttons: They must commit their content to the underlying column as soon
219      *  as the change is made, *not* only upon explicit commit
220      */
221     @Test
checkCrossUpdates_checkBox()222     public void checkCrossUpdates_checkBox() throws com.sun.star.uno.Exception, java.lang.Exception
223     {
224         // move to the first record
225         moveToFirst();
226         if  (  !checkShortValue ( (short)1, "f_tinyint", "State" )
227             || !checkDoubleValue( 1, "f_tinyint_format", "EffectiveValue" )
228             )
229         {
230             fail( "huh? inconsistence in the test!" );
231             // we created the sample data in a way that the f_tinyint field should contain a "1" at the first
232             // record. We already asserted the proper function of the check box in checkFirstRow, so if this
233             // fails here, the script became inconsistent
234             return;
235         }
236 
237         XPropertySet checkModel = getControlModel( "f_tinyint" );
238         checkModel.setPropertyValue( "State", new Short( (short)0 ) );
239 
240         // setting the state of the check box needs to be reflected in the formatted field immediately
241         if ( !checkDoubleValue( 0, "f_tinyint_format", "EffectiveValue" ) )
242         {
243             fail( "cross-update failed: updating the check box should result in updating the same-bound formatted field (1)!" );
244             return;
245         }
246 
247         // same for the "indetermined" state of the check box
248         checkModel.setPropertyValue( "State", new Short( (short)2 ) );
249         if ( !checkNullValue( "f_tinyint_format", "EffectiveValue" ) )
250         {
251             fail( "cross-update failed: updating the check box should result in updating the same-bound formatted field (2)!" );
252             return;
253         }
254 
255         // undo the changes done so far
256         undoRecordByUI();
257         // and see if this is properly reflected in the controls
258         if  (  !checkShortValue ( (short)1, "f_tinyint", "State" )
259             || !checkDoubleValue( 1, "f_tinyint_format", "EffectiveValue" )
260             )
261         {
262             fail( "either the check box or the formatted field failed to recognize the UNDO!" );
263             return;
264         }
265 
266         // the other way round - when changing the formatted field - the change should *not*
267         // be reflected to the check box, since the formatted field needs an explicit commit
268         XPropertySet tinyFormattedModel = getControlModel( "f_tinyint_format" );
269         m_document.getCurrentView().grabControlFocus( tinyFormattedModel );
270         m_formLayer.userTextInput( tinyFormattedModel, "0" );
271         if  (  !checkShortValue ( (short)1, "f_tinyint", "State" )
272             )
273         {
274             fail( "the check box should not be updated here! (did the formatted model commit immediately?)" );
275             return;
276         }
277 
278         // set the focus to *any* other control (since we just have it at hand, we use the check box control)
279         // this should result in the formatted control being committed, and thus in the check box updating
280         m_document.getCurrentView().grabControlFocus( checkModel );
281         if  (  !checkShortValue ( (short)0, "f_tinyint", "State" )
282             )
283         {
284             fail( "formatted field did not commit (or check box did not update)" );
285             return;
286         }
287 
288         // undo the changes done so far, so we leave the document in a clean state for the next test
289         undoRecordByUI();
290     }
291 
292     /* ------------------------------------------------------------------ */
293     /** very similar to checkCrossUpdates_checkBox - does nearly the same for the radio buttons. See there for more
294      *  explanations.
295      */
296     @Test
checkCrossUpdates_radioButton()297     public void checkCrossUpdates_radioButton() throws com.sun.star.uno.Exception, java.lang.Exception
298     {
299         // move to the first record
300         moveToFirst();
301         if  (  !checkRadios( (short)1, (short)0, (short)0 )
302             || !checkStringValue( "none", "f_text_enum_text", "Text" )
303             )
304         {
305             fail( "huh? inconsistence in the test!" );
306             return;
307         }
308 
309         XPropertySet radioModel = getRadioModel( "radio_group", "normal" );
310         radioModel.setPropertyValue( "State", new Short( (short)1 ) );
311 
312         // setting the state of the radio button needs to be reflected in the formatted field immediately
313         if ( !checkStringValue( "normal", "f_text_enum_text", "Text" ) )
314         {
315             fail( "cross-update failed: updating the radio button should result in updating the same-bound text field (1)!" );
316             return;
317         }
318 
319         // same for the "indetermined" state of the check box
320         getRadioModel( "radio_group", "important" ).setPropertyValue( "State", new Short( (short)1 ) );
321         if ( !checkStringValue( "important", "f_text_enum_text", "Text" ) )
322         {
323             fail( "cross-update failed: updating the radio button should result in updating the same-bound text field (2)!" );
324             return;
325         }
326 
327         // undo the changes done so far
328         undoRecordByUI();
329         // and see if this is properly reflected in the controls
330         if  (  !checkRadios( (short)1, (short)0, (short)0 )
331             || !checkStringValue( "none", "f_text_enum_text", "Text" )
332             )
333         {
334             fail( "either the radio button or the text field failed to recognize the UNDO!" );
335             return;
336         }
337 
338         // the other way round - when changing the formatted field - the change should *not*
339         // be reflected to the check box, since the formatted field needs an explicit commit
340         XPropertySet textModel = getControlModel( "f_text_enum_text" );
341         m_document.getCurrentView().grabControlFocus( textModel );
342         m_formLayer.userTextInput( textModel, "normal" );
343         if  (  !checkRadios( (short)1, (short)0, (short)0 )
344             )
345         {
346             fail( "the radio buttons should not be updated here! (did the formatted model commit immediately?)" );
347             return;
348         }
349 
350         // set the focus to *any* other control (since we just have it at hand, we use the check box control)
351         // this should result in the formatted control being committed, and thus in the check box updating
352         m_document.getCurrentView().grabControlFocus( radioModel );
353         if  (  !checkRadios( (short)0, (short)1, (short)0 )
354             )
355         {
356             fail( "text field did not commit (or radio button did not update)" );
357             return;
358         }
359 
360         // undo the changes done so far, so we leave the document in a clean state for the next test
361         undoRecordByUI();
362     }
363 
364     /* ------------------------------------------------------------------ */
365     /** some tests with updating the table via our controls
366      */
367     @Test
checkRowUpdates()368     public void checkRowUpdates() throws com.sun.star.uno.Exception, java.lang.Exception
369     {
370         // start with inserting a new record
371         moveToInsertRow();
372         assertTrue( "insert row not in expected clean state", verifyCleanInsertRow() );
373 
374         userTextInput( "ID", "3", true );
375         userTextInput( "f_integer", "729", true );
376         userTextInput( "f_text", "test", true );
377         userTextInput( "f_decimal", "152343", true );
378         userTextInput( "f_date", "31.12.1999", true );
379         userTextInput( "f_time", "23:59:59", true );
380 
381         // move to the next row, this should automatically commit the changes we made
382         nextRecordByUI();
383         // and back to the row we just inserted
384         previousRecordByUI();
385 
386         if  (  !checkDoubleValue( 3,        "ID",        "Value" )
387             || !checkDoubleValue( 729,      "f_integer", "EffectiveValue" )
388             || !checkStringValue( "test",   "f_text",    "Text" )
389             || !checkDoubleValue( 152343,   "f_decimal", "Value" )
390             || !checkIntValue   ( 19991231, "f_date",    "Date" )
391             || !checkIntValue   ( 23595900, "f_time",    "Time" )
392             )
393         {
394             fail( "the changes we made on the insert row have not been committed" );
395             return;
396         }
397 
398         // now change the data, to see if regular updates work, too
399         userTextInput( "ID", "4", true );
400         userTextInput( "f_integer", "618", true );
401         userTextInput( "f_text", "yet another stupid, meaningless text", true );
402         userTextInput( "f_required_text", "this must not be NULL", true );
403         userTextInput( "f_decimal", "4562", true );
404         userTextInput( "f_date", "26.03.2004", true );
405         userTextInput( "f_time", "17:05:00", true );
406 
407         // move to the next row, this should automatically commit the changes we made
408         nextRecordByUI();
409         // and back to the row we just inserted
410         previousRecordByUI();
411 
412         if  (  !checkDoubleValue( 4,        "ID",        "Value" )
413             || !checkDoubleValue( 618,      "f_integer", "EffectiveValue" )
414             || !checkStringValue( "yet another stupid, meaningless text",   "f_text",    "Text" )
415             || !checkDoubleValue( 4562,     "f_decimal", "Value" )
416             || !checkIntValue   ( 20040326, "f_date",    "Date" )
417             || !checkIntValue   ( 17050000, "f_time",    "Time" )
418             )
419         {
420             fail( "the changes we made on the insert row have not been committed" );
421             return;
422         }
423 
424         m_document.getCurrentView().grabControlFocus( getControlModel( "ID" ) );
425     }
426 
427     /* ------------------------------------------------------------------ */
428     /** checks the "ConvertEmptyToNull" property behavior of an edit control
429      *
430      */
431     @Test
checkEmptyIsNull()432     public void checkEmptyIsNull() throws com.sun.star.uno.Exception, java.lang.Exception
433     {
434         // start with inserting a new record
435         moveToInsertRow();
436         assertTrue( "insert row not in expected clean state", verifyCleanInsertRow() );
437 
438         // make an input in any field, but leave the edit control which is bound to a required field
439         // empty
440         userTextInput( "ID", "5", true );
441         userTextInput( "f_text", "more text", true );
442 
443         // this should *not* fail. Even if we did not input anything into the control bound to the
444         // f_required_text column, this control's reset (done when moving to the insertion row) is
445         // expected to write an empty string into its bound column, since its EmptyIsNULL property
446         // is set to FALSE
447         // (#i92471#)
448         m_mostRecentErrorEvent = null;
449         nextRecordByUI();
450         assertTrue( "updating an incomplete record did not work as expected", m_mostRecentErrorEvent == null );
451     }
452 
453     /* ------------------------------------------------------------------ */
verifyCleanInsertRow( )454     private boolean verifyCleanInsertRow( ) throws com.sun.star.uno.Exception, java.lang.Exception
455     {
456         // and check the content of the various controls
457         return (  checkRadios( (short)0, (short)0, (short)0          )
458                && checkShortValue( (short)2,    "f_tinyint", "State" )
459                && checkStringValue( "", "f_text",  "Text"            )
460                && checkNullValue( "ID",        "Value"               )
461                && checkNullValue( "f_integer", "EffectiveValue"      )
462                && checkNullValue( "f_decimal", "Value"               )
463                );
464     }
465 
466     /* ------------------------------------------------------------------ */
467     /// post-test cleanup
468     @After
after()469     public void after() throws com.sun.star.uno.Exception, java.lang.Exception
470     {
471         // close our document
472         if ( m_document != null )
473         {
474             XCloseable closeDoc = (XCloseable)UnoRuntime.queryInterface( XCloseable.class,
475                 m_document.getDocument() );
476             closeDoc.close( true );
477         }
478     }
479 
480     //=========================================================================
481     /* ------------------------------------------------------------------ */
ensureDataSource()482     private boolean ensureDataSource() throws Exception
483     {
484         m_orb = UnoRuntime.queryInterface(XMultiServiceFactory.class, officeConnection.getComponentContext().getServiceManager());
485 
486         XNameAccess databaseContext = (XNameAccess)UnoRuntime.queryInterface( XNameAccess.class,
487             m_orb.createInstance( "com.sun.star.sdb.DatabaseContext" ) );
488         XNamingService namingService = (XNamingService)UnoRuntime.queryInterface( XNamingService.class,
489             databaseContext );
490 
491         // revoke the data source, if it previously existed
492         if ( databaseContext.hasByName( m_dataSourceName ) )
493             namingService.revokeObject( m_dataSourceName );
494 
495         // // create a new ODB file, and register it with its URL
496         m_databaseDocument = new HsqlDatabase( m_orb );
497         String documentURL = m_databaseDocument.getDocumentURL();
498         namingService.registerObject( m_dataSourceName, databaseContext.getByName( documentURL ) );
499 
500         m_dataSource = (XDataSource)UnoRuntime.queryInterface( XDataSource.class,
501             databaseContext.getByName( m_dataSourceName ) );
502         m_dataSourceProps = dbfTools.queryPropertySet( m_dataSource );
503 
504         XPropertySet dataSourceSettings = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class,
505             m_dataSourceProps.getPropertyValue( "Settings" ) );
506         dataSourceSettings.setPropertyValue( "FormsCheckRequiredFields", new Boolean( false ) );
507 
508         return m_dataSource != null;
509     }
510 
511     /* ------------------------------------------------------------------ */
512     /** retrieves the control model with the given name
513     */
getControlModel( String name )514     private XPropertySet getControlModel( String name ) throws com.sun.star.uno.Exception, java.lang.Exception
515     {
516         XNameAccess nameAccess = (XNameAccess)UnoRuntime.queryInterface( XNameAccess.class,
517             m_masterForm );
518         return (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class,
519             nameAccess.getByName( name ) );
520     }
521 
522     /* ------------------------------------------------------------------ */
createSampleDocument()523     private void createSampleDocument() throws com.sun.star.uno.Exception, java.lang.Exception
524     {
525 
526         m_document = DocumentHelper.blankTextDocument( m_orb );
527         m_formLayer = new FormLayer( m_document );
528 
529         // insert some controls
530         XPropertySet xIDField =     m_formLayer.insertControlLine( "DatabaseNumericField",  "ID",               "",       3 );
531                                     m_formLayer.insertControlLine( "DatabaseFormattedField","f_integer",        "",       11 );
532                                     m_formLayer.insertControlLine( "DatabaseTextField",     "f_text",           "",       19 );
533         XPropertySet xReqField =    m_formLayer.insertControlLine( "DatabaseTextField",     "f_required_text",  "",       27 );
534                                     m_formLayer.insertControlLine( "DatabaseNumericField",  "f_decimal",        "",       35 );
535                                     m_formLayer.insertControlLine( "DatabaseDateField",     "f_date",           "",       43 );
536         XPropertySet xTimeField =   m_formLayer.insertControlLine( "DatabaseTimeField",     "f_time",           "",       51 );
537                                     m_formLayer.insertControlLine( "DatabaseDateField",     "f_timestamp",      "_date",  59 );
538                                     m_formLayer.insertControlLine( "DatabaseTimeField",     "f_timestamp",      "_time",  67 );
539         XPropertySet xImageField =  m_formLayer.insertControlLine( "DatabaseImageControl",  "f_blob",           "",       2, 75, 40 );
540                                     m_formLayer.insertControlLine( "DatabaseTextField",     "f_text_enum",      "_text",  80, 25, 6 );
541         XPropertySet xCheckBox =    m_formLayer.insertControlLine( "DatabaseCheckBox",      "f_tinyint",        "",       80, 33, 6 );
542                                     m_formLayer.insertControlLine( "DatabaseFormattedField","f_tinyint",        "_format",80, 41, 6 );
543                                     m_formLayer.insertControlLine( "DatabaseTextField",     "dummy",            "", 150 );
544 
545         xIDField.setPropertyValue( "DecimalAccuracy", new Short( (short)0 ) );
546         xImageField.setPropertyValue( "ScaleImage", new Boolean( true) );
547         xImageField.setPropertyValue( "Tabstop", new Boolean( true ) );
548         xCheckBox.setPropertyValue( "TriState", new Boolean( true ) );
549         xCheckBox.setPropertyValue( "DefaultState", new Short( (short)2 ) );
550         xTimeField.setPropertyValue( "TimeFormat", new Short( (short)1 ) );
551         xTimeField.setPropertyValue( "TimeMax", new Integer( 23595999 ) );
552         xReqField.setPropertyValue( "ConvertEmptyToNull", new Boolean( false ) );
553 
554         // the logical form
555         m_masterForm = (XPropertySet)dbfTools.getParent( xIDField, XPropertySet.class );
556         m_masterForm.setPropertyValue( "DataSourceName", m_dataSourceProps.getPropertyValue( "Name" ) );
557         m_masterForm.setPropertyValue( "CommandType", new Integer( CommandType.TABLE ) );
558         m_masterForm.setPropertyValue( "Command", s_tableName );
559 
560         insertRadio( 3, "none", "none" );
561         insertRadio( 10, "normal", "normal" );
562         insertRadio( 17, "important", "important" );
563 
564         // switch the forms into data entry mode
565         m_document.getCurrentView( ).toggleFormDesignMode( );
566 
567         m_masterFormController = m_document.getCurrentView().getFormController( m_masterForm );
568         XSQLErrorBroadcaster errorBroadcaster = (XSQLErrorBroadcaster)UnoRuntime.queryInterface( XSQLErrorBroadcaster.class,
569             m_masterFormController );
570         errorBroadcaster.addSQLErrorListener( this );
571 
572         // set the focus to the ID control
573         m_document.getCurrentView().grabControlFocus( xIDField );
574     }
575 
576     /* ------------------------------------------------------------------ */
insertRadio( int nYPos, String label, String refValue )577     private void insertRadio( int nYPos, String label, String refValue ) throws com.sun.star.uno.Exception, java.lang.Exception
578     {
579         XPropertySet xRadio = m_formLayer.createControlAndShape( "DatabaseRadioButton", 106, nYPos, 25, 6 );
580         xRadio.setPropertyValue( "Label", label );
581         xRadio.setPropertyValue( "RefValue", refValue );
582         xRadio.setPropertyValue( "Name", new String( "radio_group" ) );
583         xRadio.setPropertyValue( "DataField", new String( "f_text_enum" ) );
584     }
585 
586     /* ------------------------------------------------------------------ */
getCreateTableStatement( )587     private String getCreateTableStatement( )
588     {
589         String sCreateTableStatement = "CREATE TABLE \"" + s_tableName + "\" (";
590         sCreateTableStatement += "\"ID\" INTEGER NOT NULL PRIMARY KEY,";
591         sCreateTableStatement += "\"f_integer\" INTEGER default NULL,";
592         sCreateTableStatement += "\"f_text\" VARCHAR(50) default NULL,";
593         sCreateTableStatement += "\"f_required_text\" VARCHAR(50) NOT NULL,";
594         sCreateTableStatement += "\"f_decimal\" DECIMAL(10,2) default NULL,";
595         sCreateTableStatement += "\"f_date\" DATE default NULL,";
596         sCreateTableStatement += "\"f_time\" TIME default NULL,";
597         sCreateTableStatement += "\"f_timestamp\" DATETIME default NULL,";
598         sCreateTableStatement += "\"f_blob\" VARBINARY,";
599         sCreateTableStatement += "\"f_text_enum\" VARCHAR(50) default NULL,";
600         sCreateTableStatement += "\"f_tinyint\" TINYINT default NULL";
601         sCreateTableStatement += ");";
602         return sCreateTableStatement;
603     }
604 
605     /* ------------------------------------------------------------------ */
getSampleDataValueString( )606     private String[] getSampleDataValueString( ) throws java.lang.Exception
607     {
608         String[] aValues =  new String[] {
609             "1,42,'the answer','foo',0.12,'2003-09-22','15:00:00','2003-09-23 17:15:23',NULL,'none',1",
610             "2,13,'the question','bar',12.43,'2003-09-24','16:18:00','2003-09-24 08:45:12',NULL,'none',0"
611         };
612         return aValues;
613     }
614 
615     /* ------------------------------------------------------------------ */
ensureTables()616     private boolean ensureTables() throws com.sun.star.uno.Exception,  java.lang.Exception
617     {
618         Connection connection = new Connection( m_dataSource.getConnection( "", "" ) );
619         assertTrue( "could not connect to the data source", connection != null );
620 
621         // drop the table, if it already exists
622         if  (  !implExecuteStatement( "DROP TABLE \"" + s_tableName + "\" IF EXISTS" )
623             || !implExecuteStatement( getCreateTableStatement() )
624             )
625         {
626             fail( "could not create the required sample table!" );
627             return false;
628         }
629 
630         String sInsertionPrefix = "INSERT INTO \"" + s_tableName + "\" VALUES (";
631         String[] aValues = getSampleDataValueString();
632         for ( int i=0; i<aValues.length; ++i )
633             if ( !implExecuteStatement( sInsertionPrefix + aValues[ i ] + ")" ) )
634             {
635                 fail( "could not create the required sample data" );
636                 return false;
637             }
638 
639         connection.refreshTables();
640 
641         // do not need the connection anymore
642         connection.close();
643 
644         return true;
645     }
646 
647     /* ------------------------------------------------------------------ */
648     /// checks the 3 radio buttons for the given states
checkRadios( short stateNone, short stateNormal, short stateImportant )649     private boolean checkRadios( short stateNone, short stateNormal, short stateImportant ) throws com.sun.star.uno.Exception, java.lang.Exception
650     {
651         if ( ((Short)getRadioModel( "radio_group", "none" ).getPropertyValue( "State" )).shortValue() != stateNone )
652         {
653             fail( "wrong value of the 'none' radio button!" );
654         }
655         else if ( ((Short)getRadioModel( "radio_group", "normal" ).getPropertyValue( "State" )).shortValue() != stateNormal )
656         {
657             fail( "wrong value of the 'normal' radio button!" );
658         }
659         else if ( ((Short)getRadioModel( "radio_group", "important" ).getPropertyValue( "State" )).shortValue() != stateImportant )
660         {
661             fail( "wrong value of the 'important' radio button!" );
662         }
663         else
664             return true;
665 
666         return false;
667     }
668 
669     /* ------------------------------------------------------------------ */
checkNullValue( String fieldName, String propertyName )670     private boolean checkNullValue( String fieldName, String propertyName ) throws com.sun.star.uno.Exception, java.lang.Exception
671     {
672         Object value = getControlModel( fieldName ).getPropertyValue( propertyName );
673         if ( !util.utils.isVoid( value ) )
674         {
675             System.out.println( "wrong value of the " + fieldName + " field!" );
676             System.out.println( "  expected: <null/>" );
677             System.out.println( "  found   : " + value.toString() );
678         }
679         else
680             return true;
681 
682         return false;
683     }
684 
685     /* ------------------------------------------------------------------ */
checkIntValue( int requiredValue, String fieldName, String propertyName )686     private boolean checkIntValue( int requiredValue, String fieldName, String propertyName ) throws com.sun.star.uno.Exception, java.lang.Exception
687     {
688         try
689         {
690             if ( fieldName.equals( "f_time" ) )
691                 // http://bugs.mysql.com/bug.php?id=5681
692                 return true;
693 
694             int currentValue = ((Integer)getControlModel( fieldName ).getPropertyValue( propertyName )).intValue();
695             if ( currentValue != requiredValue )
696             {
697                 System.out.println( "wrong value of the " + fieldName + " field!" );
698                 System.out.println( "  expected: " + String.valueOf( requiredValue ) );
699                 System.out.println( "  found   : " + String.valueOf( currentValue ) );
700             }
701             else
702                 return true;
703         }
704         catch( com.sun.star.uno.Exception e )
705         {
706             System.err.println( "caught an exception while retrieving property value '" + propertyName + "' of control model '" + fieldName + "'" );
707             throw e;
708         }
709 
710         return false;
711     }
712 
713     /* ------------------------------------------------------------------ */
checkShortValue( short requiredValue, String fieldName, String propertyName )714     private boolean checkShortValue( short requiredValue, String fieldName, String propertyName ) throws com.sun.star.uno.Exception, java.lang.Exception
715     {
716         try
717         {
718             short currentValue = ((Short)getControlModel( fieldName ).getPropertyValue( propertyName )).shortValue();
719             if ( currentValue != requiredValue )
720             {
721                 System.out.println( "wrong value of the " + fieldName + " field!" );
722                 System.out.println( "  expected: " + String.valueOf( requiredValue ) );
723                 System.out.println( "  found   : " + String.valueOf( currentValue ) );
724             }
725             else
726                 return true;
727         }
728         catch( com.sun.star.uno.Exception e )
729         {
730             System.err.println( "caught an exception while retrieving property value '" + propertyName + "' of control model '" + fieldName + "'" );
731             throw e;
732         }
733 
734         return false;
735     }
736 
737     /* ------------------------------------------------------------------ */
checkDoubleValue( double requiredValue, String fieldName, String propertyName )738     private boolean checkDoubleValue( double requiredValue, String fieldName, String propertyName ) throws com.sun.star.uno.Exception, java.lang.Exception
739     {
740         double currentValue = ((Double)getControlModel( fieldName ).getPropertyValue( propertyName )).doubleValue();
741         if ( currentValue != requiredValue )
742         {
743             System.out.println( "wrong value of the " + fieldName + " field!" );
744             System.out.println( "  expected: " + String.valueOf( requiredValue ) );
745             System.out.println( "  found   : " + String.valueOf( currentValue ) );
746         }
747         else
748             return true;
749 
750         return false;
751     }
752 
753     /* ------------------------------------------------------------------ */
checkStringValue( String requiredValue, String fieldName, String propertyName )754     private boolean checkStringValue( String requiredValue, String fieldName, String propertyName ) throws com.sun.star.uno.Exception, java.lang.Exception
755     {
756         String currentValue = (String)getControlModel( fieldName ).getPropertyValue( propertyName );
757         if ( !currentValue.equals( requiredValue ) )
758         {
759             System.out.println( "wrong value of the " + fieldName + " field!" );
760             System.out.println( "  expected: " + requiredValue );
761             System.out.println( "  found   : " + currentValue );
762         }
763         else
764             return true;
765 
766         return false;
767     }
768 
769     /* ------------------------------------------------------------------ */
getRadioModel( String name, String refValue )770     private XPropertySet getRadioModel( String name, String refValue ) throws com.sun.star.uno.Exception, java.lang.Exception
771     {
772         return m_formLayer.getRadioModelByRefValue( m_masterForm, name, refValue );
773     }
774 
775     /* ------------------------------------------------------------------ */
776     /** executes the given statement on the given connection
777     */
implExecuteStatement( String sStatement )778     protected boolean implExecuteStatement( String sStatement ) throws java.lang.Exception
779     {
780         try
781         {
782             m_databaseDocument.executeSQL( sStatement );
783         }
784         catch(com.sun.star.sdbc.SQLException e)
785         {
786             System.err.println( e );
787             return false;
788         }
789 
790         return true;
791     }
792 
793     /* ------------------------------------------------------------------ */
794     /** simulates a user's text input into a control given by model name
795      */
userTextInput( String modelName, String text, boolean withCommit )796     private void userTextInput( String modelName, String text, boolean withCommit ) throws com.sun.star.uno.Exception, java.lang.Exception
797     {
798         XPropertySet controlModel = getControlModel( modelName );
799         // the form runtime environment (namely the form controller) rely on focus events for recognizing
800         // control content changes ...
801         if ( withCommit )
802             m_document.getCurrentView().grabControlFocus( controlModel );
803 
804         m_formLayer.userTextInput( controlModel, text );
805 
806         // focus back to a dummy control model so the content of the model we just changed will
807         // be committed to the underlying database column
808         if ( withCommit )
809             m_document.getCurrentView().grabControlFocus( getControlModel( "dummy" ) );
810     }
811 
812     /* ------------------------------------------------------------------ */
moveToInsertRow()813     private void moveToInsertRow() throws com.sun.star.uno.Exception, java.lang.Exception
814     {
815         XResultSetUpdate xResultSet = (XResultSetUpdate)UnoRuntime.queryInterface( XResultSetUpdate.class, m_masterForm );
816         xResultSet.moveToInsertRow( );
817     }
818 
819     /* ------------------------------------------------------------------ */
moveToFirst()820     private void moveToFirst() throws com.sun.star.uno.Exception, java.lang.Exception
821     {
822         XResultSet xResultSet = (XResultSet)UnoRuntime.queryInterface( XResultSet.class, m_masterForm );
823         xResultSet.first( );
824     }
825 
826     /* ------------------------------------------------------------------ */
moveToNext()827     private void moveToNext() throws com.sun.star.uno.Exception, java.lang.Exception
828     {
829         XResultSet xResultSet = (XResultSet)UnoRuntime.queryInterface( XResultSet.class, m_masterForm );
830         xResultSet.next( );
831     }
832 
833     /* ------------------------------------------------------------------ */
834     /** simulates pressing a toolbox button with the given URL
835      */
executeSlot( String slotURL )836     private void executeSlot( String slotURL ) throws java.lang.Exception
837     {
838         XDispatch xDispatch = m_document.getCurrentView().getDispatcher( slotURL );
839 
840         URL[] url = new URL[] { new URL() };
841         url[0].Complete = slotURL;
842         XURLTransformer xTransformer = (XURLTransformer)UnoRuntime.queryInterface(
843                 XURLTransformer.class, m_orb.createInstance( "com.sun.star.util.URLTransformer" ) );
844         xTransformer.parseStrict( url );
845 
846         PropertyValue[] aArgs = new PropertyValue[0];
847         xDispatch.dispatch( url[0], aArgs );
848     }
849 
850     /* ------------------------------------------------------------------ */
851     /** undos the changes on the current record, by simulating pressing of the respective toolbox button
852      */
undoRecordByUI()853     private void undoRecordByUI() throws java.lang.Exception
854     {
855         executeSlot( ".uno:RecUndo" );
856     }
857 
858     /* ------------------------------------------------------------------ */
859     /** saves the current record, by simulating pressing of the respective toolbox button
860      */
saveRecordByUI()861     private void saveRecordByUI() throws java.lang.Exception
862     {
863         executeSlot( ".uno:RecSave" );
864     }
865 
866     /* ------------------------------------------------------------------ */
867     /** moves to the next record, by simulating pressing of the respective toolbox button
868      */
nextRecordByUI()869     private void nextRecordByUI() throws java.lang.Exception
870     {
871         executeSlot( ".uno:NextRecord" );
872     }
873     /* ------------------------------------------------------------------ */
874     /** moves to the previous record, by simulating pressing of the respective toolbox button
875      */
previousRecordByUI()876     private void previousRecordByUI() throws java.lang.Exception
877     {
878         executeSlot( ".uno:PrevRecord" );
879     }
880 
881     /* ------------------------------------------------------------------ */
createImageFile()882     private void createImageFile() throws java.io.IOException
883     {
884         m_sImageURL = util.utils.getOfficeTempDir( m_orb ) + "image.gif";
885 
886         FileOutputStream aFile = new FileOutputStream( m_sImageURL );
887         aFile.write( getSamplePicture() );
888         aFile.close();
889         System.out.println( "created temporary image file: " + m_sImageURL );
890 
891         // for later setting the url at the imaghe control, we need a real URL, no system path
892         m_sImageURL = util.utils.getOfficeTemp( m_orb ) + "image.gif";
893     }
894 
895     /* ------------------------------------------------------------------ */
getSamplePicture()896     private byte[] getSamplePicture()
897     {
898         byte[] aBytes = new byte[] {
899             (byte)0x47, (byte)0x49, (byte)0x46, (byte)0x38, (byte)0x39, (byte)0x61, (byte)0x0A, (byte)0x00, (byte)0x0A, (byte)0x00, (byte)0xB3, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00,
900             (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF, (byte)0x00, (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF,
901             (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
902             (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x2C, (byte)0x00, (byte)0x00,
903             (byte)0x00, (byte)0x00, (byte)0x0A, (byte)0x00, (byte)0x0A, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x20, (byte)0x10, (byte)0xC8, (byte)0x49, (byte)0x41, (byte)0xB9, (byte)0xF8, (byte)0xCA,
904             (byte)0x12, (byte)0xBA, (byte)0x2F, (byte)0x5B, (byte)0x30, (byte)0x8C, (byte)0x43, (byte)0x00, (byte)0x5A, (byte)0x22, (byte)0x41, (byte)0x94, (byte)0x27, (byte)0x37, (byte)0xA8, (byte)0x6C,
905             (byte)0x48, (byte)0xC6, (byte)0xA8, (byte)0xD7, (byte)0xB5, (byte)0x19, (byte)0x56, (byte)0xED, (byte)0x11, (byte)0x00, (byte)0x3B
906         };
907 
908         return aBytes;
909     }
910 
911     /* ------------------------------------------------------------------ */
getSamplePictureBytes()912     private byte[] getSamplePictureBytes()
913     {
914         byte[] aBytes = new byte[] {
915             (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x05, (byte)0x05, (byte)0x05, (byte)0x05,
916             (byte)0x05, (byte)0x05, (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x05,
917             (byte)0x01, (byte)0x03, (byte)0x03, (byte)0x03, (byte)0x03, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x01, (byte)0x03, (byte)0x04, (byte)0x04, (byte)0x03, (byte)0x01,
918             (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x01, (byte)0x03, (byte)0x04, (byte)0x04, (byte)0x03, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x01, (byte)0x03,
919             (byte)0x03, (byte)0x03, (byte)0x03, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00,
920             (byte)0x00, (byte)0x05, (byte)0x05, (byte)0x05, (byte)0x05, (byte)0x05, (byte)0x05, (byte)0x05, (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
921             (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00
922         };
923         return aBytes;
924     }
925 
926     /* ------------------------------------------------------------------ */
verifyReferenceImage( byte[] referenceBytes )927     private boolean verifyReferenceImage( byte[] referenceBytes ) throws com.sun.star.uno.Exception, java.lang.Exception
928     {
929         XPropertySet xImageModel = getControlModel( "f_blob" );
930 
931         // check if the image control properly says that there currently is no image on the first record
932         XImageProducerSupplier xSuppProducer = (XImageProducerSupplier)UnoRuntime.queryInterface( XImageProducerSupplier.class,
933             xImageModel );
934         XImageProducer xProducer = xSuppProducer.getImageProducer();
935 
936         ImageComparison compareImages = new ImageComparison( referenceBytes, this );
937         synchronized( this )
938         {
939             xProducer.addConsumer( compareImages );
940             xProducer.startProduction();
941 //            wait();
942         }
943         xProducer.removeConsumer( compareImages );
944 
945         return compareImages.imagesEqual( );
946     }
947 
948     /* ------------------------------------------------------------------ */
errorOccured( SQLErrorEvent _event )949     public void errorOccured( SQLErrorEvent _event )
950     {
951         // just remember for the moment
952         m_mostRecentErrorEvent = _event;
953     }
954 
955     /* ------------------------------------------------------------------ */
disposing( EventObject _event )956     public void disposing( EventObject _event )
957     {
958         // not interested in
959     }
960 }
961