1 /*************************************************************************
3 * $RCSfile: KeyGenerator.java,v $
7 * last change: $Author: rt $ $Date: 2005-01-31 16:30:50 $
9 * The Contents of this file are made available subject to the terms of
12 * Copyright (c) 2003 by Sun Microsystems, Inc.
13 * All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. Neither the name of Sun Microsystems, Inc. nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
34 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *************************************************************************/
41 import com
.sun
.star
.uno
.*;
42 import com
.sun
.star
.beans
.*;
43 import com
.sun
.star
.form
.*;
44 import com
.sun
.star
.lang
.*;
45 import com
.sun
.star
.sdb
.*;
46 import com
.sun
.star
.sdbc
.*;
47 import com
.sun
.star
.sdbcx
.*;
48 import com
.sun
.star
.container
.*;
49 import com
.sun
.star
.awt
.*;
51 /**************************************************************************/
52 /** base class for helpers dealing with unique column values
54 class UniqueColumnValue
56 /* ------------------------------------------------------------------ */
57 /** extracts the name of the table a form is based on.
59 <p>This method works for forms based directly on tables, and for forms based on statements, which
60 themself are based on one table.<br/>
61 Everything else (especially forms based on queries) is not yet implemented.</p>
63 protected String
extractTableName( XPropertySet xForm
) throws com
.sun
.star
.uno
.Exception
67 Integer aCommandType
= (Integer
)xForm
.getPropertyValue( "CommandType" );
68 String sCommand
= (String
)xForm
.getPropertyValue( "Command" );
70 if ( CommandType
.COMMAND
== aCommandType
.intValue() )
72 // get the connection from the form
73 XConnection xFormConn
= (XConnection
)UnoRuntime
.queryInterface( XConnection
.class,
74 xForm
.getPropertyValue( "ActiveConnection" ) );
75 // and let it create a composer for us
76 XSQLQueryComposerFactory xComposerFac
=
77 (XSQLQueryComposerFactory
)UnoRuntime
.queryInterface(
78 XSQLQueryComposerFactory
.class, xFormConn
);
79 XSQLQueryComposer xComposer
= xComposerFac
.createQueryComposer( );
81 // let this composer analyze the command
82 xComposer
.setQuery( sCommand
);
84 // and ask it for the table(s)
85 XTablesSupplier xSuppTables
= (XTablesSupplier
)UnoRuntime
.queryInterface(
86 XTablesSupplier
.class, xComposer
);
87 XNameAccess xTables
= xSuppTables
.getTables();
89 // simply take the first table name
90 String
[] aNames
= xTables
.getElementNames( );
97 /* ------------------------------------------------------------------ */
98 /** generates a statement which can be used to create a unique (in all conscience) value
100 <p>Currently, the implementation uses a very simple approach - it just determines the maximum of currently
101 existing values in the column. If your concrete data source supports a more sophisticated approach of generating
102 unique values, you probably want to adjust the <code>SELECT</code> statement below accordingly.</p>
105 a String which can be used as statement to retrieve a unique value for the given column.
106 The result set resulting from such a execution contains the value in it's first column.
108 protected String
composeUniqueyKeyStatement( XPropertySet xForm
, String sFieldName
) throws com
.sun
.star
.uno
.Exception
110 String sStatement
= new String( "SELECT MAX( " );
111 sStatement
+= sFieldName
;
112 sStatement
+= new String( ") + 1 FROM " );
113 // the table name is a property of the form
114 sStatement
+= extractTableName( xForm
);
116 // note that the implementation is imperfect (besides the problem that MAX is not a really good solution
117 // for a database with more that one client):
118 // It does not quote the field and the table name. This needs to be done if the database is intolerant
119 // against such things - the XDatabaseMetaData, obtained from the connection, would be needed then
120 // Unfortunately, there is no UNO service doing this - it would need to be implemented manually.
125 /* ------------------------------------------------------------------ */
126 /** generates a unique (in all conscience) key into the column given
128 the form which contains the column in question
130 the name of the column
132 protected int generatePrimaryKey( XPropertySet xForm
, String sFieldName
) throws com
.sun
.star
.uno
.Exception
134 // get the current connection of the form
135 XConnection xConn
= (XConnection
)UnoRuntime
.queryInterface(
136 XConnection
.class, xForm
.getPropertyValue( "ActiveConnection" ) );
137 // let it create a new statement
138 XStatement xStatement
= xConn
.createStatement();
140 // build the query string to determine a free value
141 String sStatement
= composeUniqueyKeyStatement( xForm
, sFieldName
);
144 XResultSet xResults
= xStatement
.executeQuery( sStatement
);
146 // move the result set to the first record
150 XRow xRow
= (XRow
)UnoRuntime
.queryInterface( XRow
.class, xResults
);
151 int nFreeValue
= xRow
.getInt( 1 );
153 // dispose the temporary objects
154 FLTools
.disposeComponent( xStatement
);
155 // this should get rid of the result set, too
160 /* ------------------------------------------------------------------ */
161 /** inserts a unique (in all conscience) key into the column given
163 the form which contains the column in question
165 the name of the column
167 public void insertPrimaryKey( XPropertySet xForm
, String sFieldName
) throws com
.sun
.star
.uno
.Exception
169 // check the privileges
170 Integer aConcurrency
= (Integer
)xForm
.getPropertyValue( "ResultSetConcurrency" );
171 if ( ResultSetConcurrency
.READ_ONLY
!= aConcurrency
.intValue() )
173 // get the column object
174 XColumnsSupplier xSuppCols
= (XColumnsSupplier
)UnoRuntime
.queryInterface(
175 XColumnsSupplier
.class, xForm
);
176 XNameAccess xCols
= xSuppCols
.getColumns();
177 XColumnUpdate xCol
= (XColumnUpdate
)UnoRuntime
.queryInterface(
178 XColumnUpdate
.class, xCols
.getByName( sFieldName
) );
180 xCol
.updateInt( generatePrimaryKey( xForm
, sFieldName
) );
185 /**************************************************************************/
186 /** base class for helpers dealing with unique column values
188 class KeyGeneratorForReset
extends UniqueColumnValue
implements XResetListener
190 /* ------------------------------------------------------------------ */
191 private DocumentViewHelper m_aView
;
192 private String m_sFieldName
;
194 /* ------------------------------------------------------------------ */
197 the view which shall be used to focus controls
199 the name of the field for which keys should be generated
201 public KeyGeneratorForReset( String sFieldName
, DocumentViewHelper aView
)
203 m_sFieldName
= sFieldName
;
207 /* ------------------------------------------------------------------ */
208 /** sets the focus to the first control which is no fixed text, and not the
211 public void defaultNewRecordFocus( XPropertySet xForm
) throws com
.sun
.star
.uno
.Exception
213 XIndexAccess xFormAsContainer
= (XIndexAccess
)UnoRuntime
.queryInterface(
214 XIndexAccess
.class, xForm
);
215 for ( int i
= 0; i
<xFormAsContainer
.getCount(); ++i
)
218 XPropertySet xModel
= UNO
.queryPropertySet( xFormAsContainer
.getByIndex( i
) );
220 // check if it's a valid leaf (no sub form or such)
221 XPropertySetInfo xPSI
= xModel
.getPropertySetInfo( );
222 if ( ( null == xPSI
) || !xPSI
.hasPropertyByName( "ClassId" ) )
225 // check if it's a fixed text
226 Short nClassId
= (Short
)xModel
.getPropertyValue( "ClassId" );
227 if ( FormComponentType
.FIXEDTEXT
== nClassId
.shortValue() )
230 // check if it is bound to the field we are responsible for
231 if ( !xPSI
.hasPropertyByName( "DataField" ) )
234 String sFieldDataSource
= (String
)xModel
.getPropertyValue( "DataField" );
235 if ( sFieldDataSource
.equals( m_sFieldName
) )
238 // both conditions do not apply
239 // -> set the focus into the respective control
240 XControlModel xCM
= UNO
.queryControlModel( xModel
);
241 m_aView
.grabControlFocus( xCM
);
246 /* ------------------------------------------------------------------ */
247 // XResetListener overridables
248 /* ------------------------------------------------------------------ */
249 public boolean approveReset( com
.sun
.star
.lang
.EventObject rEvent
) throws com
.sun
.star
.uno
.RuntimeException
251 // not interested in vetoing this
255 /* ------------------------------------------------------------------ */
256 public void resetted( com
.sun
.star
.lang
.EventObject aEvent
) throws com
.sun
.star
.uno
.RuntimeException
258 // check if this reset occured becase we're on a new record
259 XPropertySet xFormProps
= UNO
.queryPropertySet( aEvent
.Source
);
262 Boolean aIsNew
= (Boolean
)xFormProps
.getPropertyValue( "IsNew" );
263 if ( aIsNew
.booleanValue() )
266 // we're going to modify the record, though after that, to the user, it should look
267 // like it has not been modified
268 // So we need to ensure that we do not change the IsModified property with whatever we do
269 Object aModifiedFlag
= xFormProps
.getPropertyValue( "IsModified" );
272 insertPrimaryKey( xFormProps
, m_sFieldName
);
274 // then restore the flag
275 xFormProps
.setPropertyValue( "IsModified", aModifiedFlag
);
277 // still one thing ... would be nice to have the focus in a control which is
278 // the one which's value we just defaulted
279 defaultNewRecordFocus( xFormProps
);
282 catch( com
.sun
.star
.uno
.Exception e
)
284 System
.out
.println(e
);
288 /* ------------------------------------------------------------------ */
289 // XEventListener overridables
290 /* ------------------------------------------------------------------ */
291 public void disposing( EventObject aEvent
)
298 /**************************************************************************/
299 /** base class for helpers dealing with unique column values
301 class KeyGeneratorForUpdate
extends UniqueColumnValue
implements XRowSetApproveListener
303 /* ------------------------------------------------------------------ */
304 private String m_sFieldName
;
306 /* ------------------------------------------------------------------ */
307 public KeyGeneratorForUpdate( String sFieldName
)
309 m_sFieldName
= sFieldName
;
312 /* ------------------------------------------------------------------ */
313 // XRowSetApproveListener overridables
314 /* ------------------------------------------------------------------ */
315 public boolean approveCursorMove( com
.sun
.star
.lang
.EventObject aEvent
) throws com
.sun
.star
.uno
.RuntimeException
317 // not interested in vetoing moves
321 /* ------------------------------------------------------------------ */
322 public boolean approveRowChange( RowChangeEvent aEvent
) throws com
.sun
.star
.uno
.RuntimeException
324 if ( RowChangeAction
.INSERT
== aEvent
.Action
)
329 XPropertySet xFormProps
= UNO
.queryPropertySet( aEvent
.Source
);
330 // insert a new unique value
331 insertPrimaryKey( xFormProps
, m_sFieldName
);
333 catch( com
.sun
.star
.uno
.Exception e
)
335 System
.out
.println(e
);
342 /* ------------------------------------------------------------------ */
343 public boolean approveRowSetChange( com
.sun
.star
.lang
.EventObject aEvent
) throws com
.sun
.star
.uno
.RuntimeException
345 // not interested in vetoing executions of the row set
348 /* ------------------------------------------------------------------ */
349 // XEventListener overridables
350 /* ------------------------------------------------------------------ */
351 public void disposing( EventObject aEvent
)
357 /**************************************************************************/
358 /** allows to generate unique keys for a field of a Form
360 public class KeyGenerator
362 /* ------------------------------------------------------------------ */
363 private KeyGeneratorForReset m_aResetKeyGenerator
;
364 private KeyGeneratorForUpdate m_aUpdateKeyGenerator
;
365 private boolean m_bResetListening
;
366 private boolean m_bUpdateListening
;
368 private DocumentHelper m_aDocument
;
369 private XPropertySet m_xForm
;
371 /* ------------------------------------------------------------------ */
374 specified the form to operate on
376 specifies the field which's value should be manipulated
378 public KeyGenerator( XPropertySet xForm
, String sFieldName
,
379 XComponentContext xCtx
)
383 DocumentHelper aDocument
= DocumentHelper
.getDocumentForComponent( xForm
, xCtx
);
385 m_aResetKeyGenerator
= new KeyGeneratorForReset( sFieldName
, aDocument
.getCurrentView() );
386 m_aUpdateKeyGenerator
= new KeyGeneratorForUpdate( sFieldName
);
388 m_bResetListening
= m_bUpdateListening
= false;
391 /* ------------------------------------------------------------------ */
392 /** stops any actions on the form
394 public void stopGenerator( )
396 XReset xFormReset
= UNO
.queryReset( m_xForm
);
397 xFormReset
.removeResetListener( m_aResetKeyGenerator
);
399 XRowSetApproveBroadcaster xFormBroadcaster
= (XRowSetApproveBroadcaster
)UnoRuntime
.queryInterface(
400 XRowSetApproveBroadcaster
.class, m_xForm
);
401 xFormBroadcaster
.removeRowSetApproveListener( m_aUpdateKeyGenerator
);
403 m_bUpdateListening
= m_bResetListening
= false;
406 /* ------------------------------------------------------------------ */
407 /** activates one of our two key generators
409 public void activateKeyGenerator( boolean bGenerateOnReset
)
412 XReset xFormReset
= UNO
.queryReset( m_xForm
);
413 // for approving actions
414 XRowSetApproveBroadcaster xFormBroadcaster
= (XRowSetApproveBroadcaster
)UnoRuntime
.queryInterface(
415 XRowSetApproveBroadcaster
.class, m_xForm
);
417 if ( bGenerateOnReset
)
419 if ( !m_bResetListening
)
420 xFormReset
.addResetListener( m_aResetKeyGenerator
);
421 if ( m_bUpdateListening
)
422 xFormBroadcaster
.removeRowSetApproveListener( m_aUpdateKeyGenerator
);
424 m_bUpdateListening
= false;
425 m_bResetListening
= true;
429 if ( m_bResetListening
)
430 xFormReset
.removeResetListener( m_aResetKeyGenerator
);
431 if ( !m_bUpdateListening
)
432 xFormBroadcaster
.addRowSetApproveListener( m_aUpdateKeyGenerator
);
434 m_bResetListening
= false;
435 m_bUpdateListening
= true;