1 /*************************************************************************
3 * The Contents of this file are made available subject to the terms of
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
33 *************************************************************************/
35 import com
.sun
.star
.uno
.*;
36 import com
.sun
.star
.beans
.*;
37 import com
.sun
.star
.form
.*;
38 import com
.sun
.star
.lang
.*;
39 import com
.sun
.star
.sdb
.*;
40 import com
.sun
.star
.sdbc
.*;
41 import com
.sun
.star
.sdbcx
.*;
42 import com
.sun
.star
.container
.*;
43 import com
.sun
.star
.awt
.*;
45 /**************************************************************************/
46 /** base class for helpers dealing with unique column values
48 class UniqueColumnValue
50 /* ------------------------------------------------------------------ */
51 /** extracts the name of the table a form is based on.
53 <p>This method works for forms based directly on tables, and for forms based on statements, which
54 themself are based on one table.<br/>
55 Everything else (especially forms based on queries) is not yet implemented.</p>
57 private String
extractTableName( XPropertySet xForm
) throws com
.sun
.star
.uno
.Exception
61 Integer aCommandType
= (Integer
)xForm
.getPropertyValue( "CommandType" );
62 String sCommand
= (String
)xForm
.getPropertyValue( "Command" );
64 if ( CommandType
.COMMAND
== aCommandType
.intValue() )
66 // get the connection from the form
67 XConnection xFormConn
= UnoRuntime
.queryInterface( XConnection
.class,
68 xForm
.getPropertyValue( "ActiveConnection" ) );
69 // and let it create a composer for us
70 XSQLQueryComposerFactory xComposerFac
=
71 UnoRuntime
.queryInterface(
72 XSQLQueryComposerFactory
.class, xFormConn
);
73 XSQLQueryComposer xComposer
= xComposerFac
.createQueryComposer( );
75 // let this composer analyze the command
76 xComposer
.setQuery( sCommand
);
78 // and ask it for the table(s)
79 XTablesSupplier xSuppTables
= UnoRuntime
.queryInterface(
80 XTablesSupplier
.class, xComposer
);
81 XNameAccess xTables
= xSuppTables
.getTables();
83 // simply take the first table name
84 String
[] aNames
= xTables
.getElementNames( );
91 /* ------------------------------------------------------------------ */
92 /** generates a statement which can be used to create a unique (in all conscience) value
94 <p>Currently, the implementation uses a very simple approach - it just determines the maximum of currently
95 existing values in the column. If your concrete data source supports a more sophisticated approach of generating
96 unique values, you probably want to adjust the <code>SELECT</code> statement below accordingly.</p>
99 a String which can be used as statement to retrieve a unique value for the given column.
100 The result set resulting from such a execution contains the value in it's first column.
102 private String
composeUniqueyKeyStatement( XPropertySet xForm
, String sFieldName
) throws com
.sun
.star
.uno
.Exception
104 String sStatement
= "SELECT MAX( ";
105 sStatement
+= sFieldName
;
106 sStatement
+= ") + 1 FROM ";
107 // the table name is a property of the form
108 sStatement
+= extractTableName( xForm
);
110 // note that the implementation is imperfect (besides the problem that MAX is not a really good solution
111 // for a database with more that one client):
112 // It does not quote the field and the table name. This needs to be done if the database is intolerant
113 // against such things - the XDatabaseMetaData, obtained from the connection, would be needed then
114 // Unfortunately, there is no UNO service doing this - it would need to be implemented manually.
119 /* ------------------------------------------------------------------ */
120 /** generates a unique (in all conscience) key into the column given
122 the form which contains the column in question
124 the name of the column
126 private int generatePrimaryKey( XPropertySet xForm
, String sFieldName
) throws com
.sun
.star
.uno
.Exception
128 // get the current connection of the form
129 XConnection xConn
= UnoRuntime
.queryInterface(
130 XConnection
.class, xForm
.getPropertyValue( "ActiveConnection" ) );
131 // let it create a new statement
132 XStatement xStatement
= xConn
.createStatement();
134 // build the query string to determine a free value
135 String sStatement
= composeUniqueyKeyStatement( xForm
, sFieldName
);
138 XResultSet xResults
= xStatement
.executeQuery( sStatement
);
140 // move the result set to the first record
144 XRow xRow
= UnoRuntime
.queryInterface( XRow
.class, xResults
);
145 int nFreeValue
= xRow
.getInt( 1 );
147 // dispose the temporary objects
148 FLTools
.disposeComponent( xStatement
);
149 // this should get rid of the result set, too
154 /* ------------------------------------------------------------------ */
155 /** inserts a unique (in all conscience) key into the column given
157 the form which contains the column in question
159 the name of the column
161 public void insertPrimaryKey( XPropertySet xForm
, String sFieldName
) throws com
.sun
.star
.uno
.Exception
163 // check the privileges
164 Integer aConcurrency
= (Integer
)xForm
.getPropertyValue( "ResultSetConcurrency" );
165 if ( ResultSetConcurrency
.READ_ONLY
!= aConcurrency
.intValue() )
167 // get the column object
168 XColumnsSupplier xSuppCols
= UnoRuntime
.queryInterface(
169 XColumnsSupplier
.class, xForm
);
170 XNameAccess xCols
= xSuppCols
.getColumns();
171 XColumnUpdate xCol
= UnoRuntime
.queryInterface(
172 XColumnUpdate
.class, xCols
.getByName( sFieldName
) );
174 xCol
.updateInt( generatePrimaryKey( xForm
, sFieldName
) );
179 /**************************************************************************/
180 /** base class for helpers dealing with unique column values
182 class KeyGeneratorForReset
extends UniqueColumnValue
implements XResetListener
184 /* ------------------------------------------------------------------ */
185 private DocumentViewHelper m_aView
;
186 private String m_sFieldName
;
188 /* ------------------------------------------------------------------ */
191 the view which shall be used to focus controls
193 the name of the field for which keys should be generated
195 public KeyGeneratorForReset( String sFieldName
, DocumentViewHelper aView
)
197 m_sFieldName
= sFieldName
;
201 /* ------------------------------------------------------------------ */
202 /** sets the focus to the first control which is no fixed text, and not the
205 private void defaultNewRecordFocus( XPropertySet xForm
) throws com
.sun
.star
.uno
.Exception
207 XIndexAccess xFormAsContainer
= UnoRuntime
.queryInterface(
208 XIndexAccess
.class, xForm
);
209 for ( int i
= 0; i
<xFormAsContainer
.getCount(); ++i
)
212 XPropertySet xModel
= UNO
.queryPropertySet( xFormAsContainer
.getByIndex( i
) );
214 // check if it's a valid leaf (no sub form or such)
215 XPropertySetInfo xPSI
= xModel
.getPropertySetInfo( );
216 if ( ( null == xPSI
) || !xPSI
.hasPropertyByName( "ClassId" ) )
219 // check if it's a fixed text
220 Short nClassId
= (Short
)xModel
.getPropertyValue( "ClassId" );
221 if ( FormComponentType
.FIXEDTEXT
== nClassId
.shortValue() )
224 // check if it is bound to the field we are responsible for
225 if ( !xPSI
.hasPropertyByName( "DataField" ) )
228 String sFieldDataSource
= (String
)xModel
.getPropertyValue( "DataField" );
229 if ( sFieldDataSource
.equals( m_sFieldName
) )
232 // both conditions do not apply
233 // -> set the focus into the respective control
234 XControlModel xCM
= UNO
.queryControlModel( xModel
);
235 m_aView
.grabControlFocus( xCM
);
240 /* ------------------------------------------------------------------ */
241 // XResetListener overridables
242 /* ------------------------------------------------------------------ */
243 public boolean approveReset( com
.sun
.star
.lang
.EventObject rEvent
) throws com
.sun
.star
.uno
.RuntimeException
245 // not interested in vetoing this
249 /* ------------------------------------------------------------------ */
250 public void resetted( com
.sun
.star
.lang
.EventObject aEvent
) throws com
.sun
.star
.uno
.RuntimeException
252 // check if this reset occurred because we're on a new record
253 XPropertySet xFormProps
= UNO
.queryPropertySet( aEvent
.Source
);
256 Boolean aIsNew
= (Boolean
)xFormProps
.getPropertyValue( "IsNew" );
257 if ( aIsNew
.booleanValue() )
260 // we're going to modify the record, though after that, to the user, it should look
261 // like it has not been modified
262 // So we need to ensure that we do not change the IsModified property with whatever we do
263 Object aModifiedFlag
= xFormProps
.getPropertyValue( "IsModified" );
266 insertPrimaryKey( xFormProps
, m_sFieldName
);
268 // then restore the flag
269 xFormProps
.setPropertyValue( "IsModified", aModifiedFlag
);
271 // still one thing ... would be nice to have the focus in a control which is
272 // the one which's value we just defaulted
273 defaultNewRecordFocus( xFormProps
);
276 catch( com
.sun
.star
.uno
.Exception e
)
278 System
.out
.println(e
);
282 /* ------------------------------------------------------------------ */
283 // XEventListener overridables
284 /* ------------------------------------------------------------------ */
285 public void disposing( EventObject aEvent
)
292 /**************************************************************************/
293 /** base class for helpers dealing with unique column values
295 class KeyGeneratorForUpdate
extends UniqueColumnValue
implements XRowSetApproveListener
297 /* ------------------------------------------------------------------ */
298 private String m_sFieldName
;
300 /* ------------------------------------------------------------------ */
301 public KeyGeneratorForUpdate( String sFieldName
)
303 m_sFieldName
= sFieldName
;
306 /* ------------------------------------------------------------------ */
307 // XRowSetApproveListener overridables
308 /* ------------------------------------------------------------------ */
309 public boolean approveCursorMove( com
.sun
.star
.lang
.EventObject aEvent
) throws com
.sun
.star
.uno
.RuntimeException
311 // not interested in vetoing moves
315 /* ------------------------------------------------------------------ */
316 public boolean approveRowChange( RowChangeEvent aEvent
) throws com
.sun
.star
.uno
.RuntimeException
318 if ( RowChangeAction
.INSERT
== aEvent
.Action
)
323 XPropertySet xFormProps
= UNO
.queryPropertySet( aEvent
.Source
);
324 // insert a new unique value
325 insertPrimaryKey( xFormProps
, m_sFieldName
);
327 catch( com
.sun
.star
.uno
.Exception e
)
329 System
.out
.println(e
);
336 /* ------------------------------------------------------------------ */
337 public boolean approveRowSetChange( com
.sun
.star
.lang
.EventObject aEvent
) throws com
.sun
.star
.uno
.RuntimeException
339 // not interested in vetoing executions of the row set
342 /* ------------------------------------------------------------------ */
343 // XEventListener overridables
344 /* ------------------------------------------------------------------ */
345 public void disposing( EventObject aEvent
)
351 /**************************************************************************/
352 /** allows to generate unique keys for a field of a Form
354 public class KeyGenerator
356 /* ------------------------------------------------------------------ */
357 private KeyGeneratorForReset m_aResetKeyGenerator
;
358 private KeyGeneratorForUpdate m_aUpdateKeyGenerator
;
359 private boolean m_bResetListening
;
360 private boolean m_bUpdateListening
;
362 private XPropertySet m_xForm
;
364 /* ------------------------------------------------------------------ */
367 specified the form to operate on
369 specifies the field which's value should be manipulated
371 public KeyGenerator( XPropertySet xForm
, String sFieldName
,
372 XComponentContext xCtx
)
376 DocumentHelper aDocument
= DocumentHelper
.getDocumentForComponent( xForm
, xCtx
);
378 m_aResetKeyGenerator
= new KeyGeneratorForReset( sFieldName
, aDocument
.getCurrentView() );
379 m_aUpdateKeyGenerator
= new KeyGeneratorForUpdate( sFieldName
);
381 m_bResetListening
= m_bUpdateListening
= false;
384 /* ------------------------------------------------------------------ */
385 /** stops any actions on the form
387 public void stopGenerator( )
389 XReset xFormReset
= UNO
.queryReset( m_xForm
);
390 xFormReset
.removeResetListener( m_aResetKeyGenerator
);
392 XRowSetApproveBroadcaster xFormBroadcaster
= UnoRuntime
.queryInterface(
393 XRowSetApproveBroadcaster
.class, m_xForm
);
394 xFormBroadcaster
.removeRowSetApproveListener( m_aUpdateKeyGenerator
);
396 m_bUpdateListening
= m_bResetListening
= false;
399 /* ------------------------------------------------------------------ */
400 /** activates one of our two key generators
402 public void activateKeyGenerator( boolean bGenerateOnReset
)
405 XReset xFormReset
= UNO
.queryReset( m_xForm
);
406 // for approving actions
407 XRowSetApproveBroadcaster xFormBroadcaster
= UnoRuntime
.queryInterface(
408 XRowSetApproveBroadcaster
.class, m_xForm
);
410 if ( bGenerateOnReset
)
412 if ( !m_bResetListening
)
413 xFormReset
.addResetListener( m_aResetKeyGenerator
);
414 if ( m_bUpdateListening
)
415 xFormBroadcaster
.removeRowSetApproveListener( m_aUpdateKeyGenerator
);
417 m_bUpdateListening
= false;
418 m_bResetListening
= true;
422 if ( m_bResetListening
)
423 xFormReset
.removeResetListener( m_aResetKeyGenerator
);
424 if ( !m_bUpdateListening
)
425 xFormBroadcaster
.addRowSetApproveListener( m_aUpdateKeyGenerator
);
427 m_bResetListening
= false;
428 m_bUpdateListening
= true;