1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_forms.hxx"
30 
31 #include "formoperations.hxx"
32 #include "frm_strings.hxx"
33 #include "frm_resource.hxx"
34 #include "frm_resource.hrc"
35 #include "frm_module.hxx"
36 
37 /** === begin UNO includes === **/
38 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
39 #include <com/sun/star/util/XModifyBroadcaster.hpp>
40 #include <com/sun/star/form/runtime/FormFeature.hpp>
41 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
42 #include <com/sun/star/lang/DisposedException.hpp>
43 #include <com/sun/star/awt/XControl.hpp>
44 #include <com/sun/star/form/XGrid.hpp>
45 #include <com/sun/star/form/XBoundControl.hpp>
46 #include <com/sun/star/form/XBoundComponent.hpp>
47 #include <com/sun/star/sdbcx/XRowLocate.hpp>
48 #include <com/sun/star/form/XConfirmDeleteListener.hpp>
49 #include <com/sun/star/sdb/RowChangeEvent.hpp>
50 #include <com/sun/star/sdb/RowChangeAction.hpp>
51 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
52 #include <com/sun/star/sdbc/DataType.hpp>
53 #include <com/sun/star/form/XReset.hpp>
54 #include <com/sun/star/beans/XMultiPropertySet.hpp>
55 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
56 #include <com/sun/star/util/XRefreshable.hpp>
57 /** === end UNO includes === **/
58 
59 #include <connectivity/dbtools.hxx>
60 #include <connectivity/dbexception.hxx>
61 #include <vcl/svapp.hxx>
62 #include <vcl/stdtext.hxx>
63 #include <vcl/msgbox.hxx>
64 #include <vcl/waitobj.hxx>
65 #include <tools/diagnose_ex.h>
66 #include <comphelper/container.hxx>
67 #include <comphelper/property.hxx>
68 #include <comphelper/namedvaluecollection.hxx>
69 #include <cppuhelper/exc_hlp.hxx>
70 #include <vos/mutex.hxx>
71 
72 //--------------------------------------------------------------------------
73 extern "C" void SAL_CALL createRegistryInfo_FormOperations()
74 {
75 	static ::frm::OMultiInstanceAutoRegistration< ::frm::FormOperations > aAutoRegistration;
76 }
77 
78 //........................................................................
79 namespace frm
80 {
81 //........................................................................
82 
83     using ::dbtools::SQLExceptionInfo;
84 	/** === begin UNO using === **/
85     using ::com::sun::star::uno::Reference;
86     using ::com::sun::star::uno::XComponentContext;
87     using ::com::sun::star::uno::RuntimeException;
88     using ::com::sun::star::uno::Sequence;
89     using ::com::sun::star::uno::Exception;
90     using ::com::sun::star::uno::Any;
91     using ::com::sun::star::uno::XInterface;
92     using ::com::sun::star::sdbc::XRowSet;
93     using ::com::sun::star::sdbc::XResultSetUpdate;
94     using ::com::sun::star::form::runtime::XFormController;
95     using ::com::sun::star::form::runtime::XFeatureInvalidation;
96     using ::com::sun::star::form::runtime::FeatureState;
97     using ::com::sun::star::lang::IllegalArgumentException;
98     using ::com::sun::star::sdbc::SQLException;
99     using namespace ::com::sun::star::sdbc;
100     using ::com::sun::star::form::XForm;
101     using ::com::sun::star::ucb::AlreadyInitializedException;
102     using ::com::sun::star::util::XModifyBroadcaster;
103     using ::com::sun::star::uno::UNO_QUERY;
104     using ::com::sun::star::lang::EventObject;
105     using ::com::sun::star::beans::PropertyChangeEvent;
106     using ::com::sun::star::lang::XMultiServiceFactory;
107     using ::com::sun::star::lang::DisposedException;
108     using ::com::sun::star::beans::XPropertySet;
109     using ::com::sun::star::awt::XControl;
110     using ::com::sun::star::form::XGrid;
111     using ::com::sun::star::container::XIndexAccess;
112     using ::com::sun::star::uno::UNO_QUERY_THROW;
113     using ::com::sun::star::form::XBoundControl;
114     using ::com::sun::star::form::XBoundComponent;
115     using ::com::sun::star::sdbcx::XRowLocate;
116     using ::com::sun::star::form::XConfirmDeleteListener;
117     using ::com::sun::star::sdb::RowChangeEvent;
118     using namespace ::com::sun::star::sdb;
119     using ::com::sun::star::form::XReset;
120     using ::com::sun::star::beans::XMultiPropertySet;
121     using ::com::sun::star::uno::makeAny;
122     using ::com::sun::star::lang::WrappedTargetException;
123     using ::com::sun::star::beans::PropertyValue;
124     using ::com::sun::star::ui::dialogs::XExecutableDialog;
125     using ::com::sun::star::beans::NamedValue;
126 
127     using ::com::sun::star::util::XRefreshable;
128     using ::com::sun::star::awt::XControlModel;
129 	/** === end UNO using === **/
130     namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
131     namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
132 
133 	//====================================================================
134 	//= FormOperations
135 	//====================================================================
136 	//--------------------------------------------------------------------
137     FormOperations::FormOperations( const Reference< XMultiServiceFactory >& _rxContext )
138         :FormOperations_Base( m_aMutex )
139         ,m_aContext( _rxContext )
140         ,m_bInitializedParser( false )
141         ,m_bActiveControlModified( false )
142         ,m_bConstructed( false )
143     #ifdef DBG_UTIL
144         ,m_nMethodNestingLevel( false )
145     #endif
146     {
147     }
148 
149 	//--------------------------------------------------------------------
150     FormOperations::~FormOperations()
151     {
152     }
153 
154     //--------------------------------------------------------------------
155     ::rtl::OUString FormOperations::getImplementationName_Static(  ) throw(RuntimeException)
156     {
157         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.forms.FormOperations" ) );
158     }
159 
160     //--------------------------------------------------------------------
161     Sequence< ::rtl::OUString > FormOperations::getSupportedServiceNames_Static(  ) throw(RuntimeException)
162     {
163         Sequence< ::rtl::OUString > aNames(1);
164         aNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.runtime.FormOperations" ) );
165         return aNames;
166     }
167 
168     //--------------------------------------------------------------------
169     Reference< XInterface > SAL_CALL FormOperations::Create(const Reference< XMultiServiceFactory >& _rxFactory )
170     {
171         return *new FormOperations( _rxFactory );
172     }
173 
174     //--------------------------------------------------------------------
175     void SAL_CALL FormOperations::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException)
176     {
177         if ( m_bConstructed )
178             throw AlreadyInitializedException();
179 
180         if ( _arguments.getLength() == 1 )
181         {
182             Reference< XFormController > xController;
183             Reference< XForm > xForm;
184             if ( _arguments[0] >>= xController )
185                 createWithFormController( xController );
186             else if ( _arguments[0] >>= xForm )
187                 createWithForm( xForm );
188             else
189                 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
190             return;
191         }
192 
193         throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
194     }
195 
196     //--------------------------------------------------------------------
197     ::rtl::OUString SAL_CALL FormOperations::getImplementationName(  ) throw (RuntimeException)
198     {
199         return getImplementationName_Static();
200     }
201 
202     //--------------------------------------------------------------------
203     ::sal_Bool SAL_CALL FormOperations::supportsService( const ::rtl::OUString& _ServiceName ) throw (RuntimeException)
204     {
205         Sequence< ::rtl::OUString > aSupportedServiceNames( getSupportedServiceNames() );
206         const ::rtl::OUString* pBegin = aSupportedServiceNames.getConstArray();
207         const ::rtl::OUString* pEnd = aSupportedServiceNames.getConstArray() + aSupportedServiceNames.getLength();
208         return ::std::find( pBegin, pEnd, _ServiceName ) != pEnd;
209     }
210 
211     //--------------------------------------------------------------------
212     Sequence< ::rtl::OUString > SAL_CALL FormOperations::getSupportedServiceNames(  ) throw (RuntimeException)
213     {
214         return getSupportedServiceNames_Static();
215     }
216 
217     //--------------------------------------------------------------------
218     Reference< XRowSet > SAL_CALL FormOperations::getCursor() throw (RuntimeException)
219     {
220         MethodGuard aGuard( *this );
221         return m_xCursor;
222     }
223 
224     //--------------------------------------------------------------------
225     Reference< XResultSetUpdate > SAL_CALL FormOperations::getUpdateCursor() throw (RuntimeException)
226     {
227         MethodGuard aGuard( *this );
228         return m_xUpdateCursor;
229     }
230 
231     //--------------------------------------------------------------------
232     Reference< XFormController > SAL_CALL FormOperations::getController() throw (RuntimeException)
233     {
234         MethodGuard aGuard( *this );
235         return m_xController;
236     }
237 
238     //--------------------------------------------------------------------
239     Reference< XFeatureInvalidation > SAL_CALL FormOperations::getFeatureInvalidation() throw (RuntimeException)
240     {
241         MethodGuard aGuard( *this );
242         return m_xFeatureInvalidation;
243     }
244 
245     //--------------------------------------------------------------------
246     void SAL_CALL FormOperations::setFeatureInvalidation( const Reference< XFeatureInvalidation > & _rxFeatureInvalidation ) throw (RuntimeException)
247     {
248         MethodGuard aGuard( *this );
249         m_xFeatureInvalidation = _rxFeatureInvalidation;
250     }
251 
252     //--------------------------------------------------------------------
253     FeatureState SAL_CALL FormOperations::getState( ::sal_Int16 _nFeature ) throw (RuntimeException)
254     {
255         MethodGuard aGuard( *this );
256 
257         FeatureState aState;
258         aState.Enabled = sal_False;
259 
260         try
261         {
262             // some checks for basic pre-requisites
263             if	(	!m_xLoadableForm.is()
264                 ||  !m_xLoadableForm->isLoaded()
265 		        ||	!m_xCursorProperties.is()
266 		        )
267             {
268                 return aState;
269             }
270 
271             switch ( _nFeature )
272             {
273             case FormFeature::MoveToFirst:
274             case FormFeature::MoveToPrevious:
275                 aState.Enabled = impl_canMoveLeft_throw( );
276                 break;
277 
278 			case FormFeature::MoveToNext:
279 				aState.Enabled = impl_canMoveRight_throw();
280                 break;
281 
282             case FormFeature::MoveToLast:
283 				aState.Enabled = impl_getRowCount_throw() && ( !m_xCursor->isLast() || impl_isInsertionRow_throw() );
284                 break;
285 
286             case FormFeature::DeleteRecord:
287 				// already deleted ?
288 				if ( m_xCursor->rowDeleted() )
289                     aState.Enabled = sal_False;
290                 else
291 				{
292 					// allowed to delete the row ?
293                     aState.Enabled = !impl_isInsertionRow_throw() && ::dbtools::canDelete( m_xCursorProperties );
294 				}
295                 break;
296 
297             case FormFeature::MoveToInsertRow:
298 				// if we are inserting we can move to the next row if the current record or control is modified
299 				aState.Enabled =    impl_isInsertionRow_throw()
300                                 ?   impl_isModifiedRow_throw() || m_bActiveControlModified
301                                 :   ::dbtools::canInsert( m_xCursorProperties );
302                 break;
303 
304             case FormFeature::ReloadForm:
305             {
306                 // there must be an active connection
307                 Reference< XRowSet > xCursorRowSet( m_xCursor, UNO_QUERY );
308                 aState.Enabled = ::dbtools::getConnection( xCursorRowSet ).is();
309 
310                 // and an active command
311                 ::rtl::OUString sActiveCommand;
312                 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sActiveCommand;
313                 aState.Enabled &= sActiveCommand.getLength() > 0;
314             }
315             break;
316 
317             case FormFeature::RefreshCurrentControl:
318             {
319                 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
320                 aState.Enabled = xControlModelRefresh.is();
321             }
322             break;
323 
324 			case FormFeature::SaveRecordChanges:
325 			case FormFeature::UndoRecordChanges:
326 				aState.Enabled = impl_isModifiedRow_throw() || m_bActiveControlModified;
327                 break;
328 
329 			case FormFeature::RemoveFilterAndSort:
330 				if ( impl_isParseable_throw() && impl_hasFilterOrOrder_throw() )
331                     aState.Enabled = !impl_isInsertOnlyForm_throw();
332 				break;
333 
334             case FormFeature::SortAscending:
335 			case FormFeature::SortDescending:
336 			case FormFeature::AutoFilter:
337 				if ( m_xController.is() && impl_isParseable_throw() )
338 				{
339 					sal_Bool bIsDeleted = m_xCursor->rowDeleted();
340 
341 					if ( !bIsDeleted && !impl_isInsertOnlyForm_throw() )
342 					{
343 						Reference< XPropertySet > xBoundField = impl_getCurrentBoundField_nothrow( );
344 						if ( xBoundField.is() )
345                             xBoundField->getPropertyValue( PROPERTY_SEARCHABLE ) >>= aState.Enabled;
346 					}
347 				}
348                 break;
349 
350 			case FormFeature::InteractiveSort:
351             case FormFeature::InteractiveFilter:
352 				if ( impl_isParseable_throw() )
353                     aState.Enabled = !impl_isInsertOnlyForm_throw();
354                 break;
355 
356 			case FormFeature::ToggleApplyFilter:
357 			{
358 				::rtl::OUString sFilter;
359                 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
360 				if ( sFilter.getLength() )
361 				{
362                     aState.State = m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER );
363                     aState.Enabled = !impl_isInsertOnlyForm_throw();
364 				}
365                 else
366                     aState.State <<= (sal_Bool)sal_False;
367 			}
368             break;
369 
370 			case FormFeature::MoveAbsolute:
371 			{
372 				sal_Int32 nPosition   = m_xCursor->getRow();
373 				sal_Bool  bIsNew      = impl_isInsertionRow_throw();
374                 sal_Int32 nCount      = impl_getRowCount_throw();
375 				sal_Bool  bFinalCount = impl_isRowCountFinal_throw();
376 
377                 if ( ( nPosition >= 0 ) || bIsNew )
378 				{
379 					if ( bFinalCount )
380 					{
381                         // special case: there are no records at all, and we
382                         // can't insert records -> disabled
383 						if ( !nCount && !::dbtools::canInsert( m_xCursorProperties ) )
384 						{
385 							aState.Enabled = sal_False;
386 						}
387 						else
388 						{
389 							if ( bIsNew )
390 								nPosition = ++nCount;
391                             aState.State <<= (sal_Int32)nPosition;
392 							aState.Enabled = sal_True;
393 						}
394 					}
395 					else
396 					{
397                         aState.State <<= (sal_Int32)nPosition;
398 						aState.Enabled = sal_True;
399 					}
400 				}
401 			}
402             break;
403 
404 			case FormFeature::TotalRecords:
405 			{
406 				sal_Bool  bIsNew      = impl_isInsertionRow_throw();
407                 sal_Int32 nCount      = impl_getRowCount_throw();
408 				sal_Bool  bFinalCount = impl_isRowCountFinal_throw();
409 
410 				if ( bIsNew )
411 					++nCount;
412 
413                 ::rtl::OUString sValue = ::rtl::OUString::valueOf( sal_Int32( nCount ) );
414 				if ( !bFinalCount )
415                     sValue += ::rtl::OUString::createFromAscii( " *" );
416 
417                 aState.State <<= sValue;
418                 aState.Enabled = sal_True;
419 			}
420             break;
421 
422             default:
423                 OSL_ENSURE( sal_False, "FormOperations::getState: unknown feature id!" );
424                 break;
425             }
426         }
427         catch( const Exception& )
428         {
429             OSL_ENSURE( sal_False, "FormOperations::getState: caught an exception!" );
430         }
431 
432         return aState;
433     }
434 
435     //--------------------------------------------------------------------
436     ::sal_Bool SAL_CALL FormOperations::isEnabled( ::sal_Int16 _nFeature ) throw (RuntimeException)
437     {
438         MethodGuard aGuard( *this );
439 
440         FeatureState aState( getState( _nFeature ) );
441         return aState.Enabled;
442     }
443 
444     //--------------------------------------------------------------------
445     namespace
446     {
447         static bool lcl_needConfirmCommit( sal_Int32 _nFeature )
448         {
449             return ( ( _nFeature == FormFeature::ReloadForm )
450                   || ( _nFeature == FormFeature::RemoveFilterAndSort )
451                   || ( _nFeature == FormFeature::ToggleApplyFilter )
452                   || ( _nFeature == FormFeature::SortAscending )
453                   || ( _nFeature == FormFeature::SortDescending )
454                   || ( _nFeature == FormFeature::AutoFilter )
455                   || ( _nFeature == FormFeature::InteractiveSort )
456                   || ( _nFeature == FormFeature::InteractiveFilter )
457                    );
458         }
459         static bool lcl_requiresArguments( sal_Int32 _nFeature )
460         {
461             return ( _nFeature == FormFeature::MoveAbsolute );
462         }
463         static bool lcl_isExecutableFeature( sal_Int32 _nFeature )
464         {
465             return ( _nFeature != FormFeature::TotalRecords );
466         }
467     }
468 
469     //--------------------------------------------------------------------
470     void SAL_CALL FormOperations::execute( ::sal_Int16 _nFeature ) throw (RuntimeException, IllegalArgumentException, SQLException, WrappedTargetException)
471     {
472         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
473         MethodGuard aGuard( *this );
474 
475         if ( ( _nFeature != FormFeature::DeleteRecord ) && ( _nFeature != FormFeature::UndoRecordChanges ) )
476         {
477             // if we have a controller, commit the current control
478             if ( m_xController.is() )
479                 if ( !impl_commitCurrentControl_throw() )
480                     return;
481 
482             // commit the current record
483             bool bCommitCurrentRecord = true;
484             // (but before, let the user confirm if necessary)
485             if ( impl_isModifiedRow_throw() )
486             {
487                 if ( lcl_needConfirmCommit( _nFeature ) )
488                 {
489                     // TODO: shouldn't this be done with an interaction handler?
490 				    QueryBox aQuery( NULL, WB_YES_NO_CANCEL | WB_DEF_YES, FRM_RES_STRING( RID_STR_QUERY_SAVE_MODIFIED_ROW ) );
491                     switch ( aQuery.Execute() )
492                     {
493                     case RET_NO: bCommitCurrentRecord = false; break;
494                     case RET_CANCEL: return;
495                     }
496                 }
497             }
498 
499             if ( bCommitCurrentRecord && !impl_commitCurrentRecord_throw() )
500                 return;
501         }
502 
503         try
504         {
505             switch ( _nFeature )
506             {
507 	        case FormFeature::MoveToFirst:
508                 m_xCursor->first();
509 		        break;
510 
511             case FormFeature::MoveToNext:
512                 impl_moveRight_throw( );
513                 break;
514 
515             case FormFeature::MoveToPrevious:
516     		    impl_moveLeft_throw( );
517 		        break;
518 
519 	        case FormFeature::MoveToLast:
520 	        {
521 /*
522                 // TODO: re-implement this .....
523 		        // run in an own thread if ...
524 		        // ... the data source is thread safe ...
525 		        sal_Bool bAllowOwnThread = sal_False;
526                 if ( ::comphelper::hasProperty( PROPERTY_THREADSAFE, m_xCursorProperties ) )
527                     m_xCursorProperties->getPropertyValue( PROPERTY_THREADSAFE ) >>= bAllowOwnThread;
528 
529                 // ... the record count is unknown
530 		        sal_Bool bNeedOwnThread sal_False;
531                 if ( ::comphelper::hasProperty( PROPERTY_ROWCOUNTFINAL, m_xCursorProperties ) )
532                     m_xCursorProperties->getPropertyValue( PROPERTY_ROWCOUNTFINAL ) >>= bNeedOwnThread;
533 
534 		        if ( bNeedOwnThread && bAllowOwnThread )
535 			        ;
536 		        else
537 */
538 			        m_xCursor->last();
539 	        }
540 	        break;
541 
542 	        case FormFeature::ReloadForm:
543                 if ( m_xLoadableForm.is() )
544                 {
545     			    WaitObject aWO( NULL );
546                     m_xLoadableForm->reload();
547 
548                     // refresh all controls in the form (and sub forms) which can be refreshed
549                     // #i90914# / 2008-07-02 / frank.schoenheit@sun.com
550                     ::comphelper::IndexAccessIterator aIter( m_xLoadableForm );
551                     Reference< XInterface > xElement( aIter.Next() );
552                     while ( xElement.is() )
553                     {
554                         Reference< XRefreshable > xRefresh( xElement, UNO_QUERY );
555                         if ( xRefresh.is() )
556                             xRefresh->refresh();
557                         xElement = aIter.Next();
558                     }
559                 }
560 	            break;
561 
562             case FormFeature::RefreshCurrentControl:
563             {
564                 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
565                 OSL_ENSURE( xControlModelRefresh.is(), "FormOperations::execute: how did you reach this?" );
566                 if ( xControlModelRefresh.is() )
567                     xControlModelRefresh->refresh();
568             }
569             break;
570 
571             case FormFeature::DeleteRecord:
572 	        {
573                 sal_uInt32 nCount = impl_getRowCount_throw();
574 
575 		        // next position
576 		        sal_Bool bLeft = m_xCursor->isLast() && ( nCount > 1 );
577 		        sal_Bool bRight= !m_xCursor->isLast();
578 		        sal_Bool bSuccess = sal_False;
579 		        try
580 		        {
581 			        // ask for confirmation
582                     Reference< XConfirmDeleteListener > xConfirmDelete( m_xController, UNO_QUERY );
583 
584                     if ( xConfirmDelete.is() )
585 			        {
586 				        RowChangeEvent aEvent;
587 				        aEvent.Source = Reference< XInterface >( m_xCursor, UNO_QUERY );
588 				        aEvent.Action = RowChangeAction::DELETE;
589 				        aEvent.Rows = 1;
590 				        bSuccess = xConfirmDelete->confirmDelete( aEvent );
591 			        }
592 
593 			        // delete it
594 			        if ( bSuccess )
595 				        m_xUpdateCursor->deleteRow();
596 		        }
597 		        catch( const Exception& )
598 		        {
599 			        bSuccess = sal_False;
600 		        }
601 
602 		        if ( bSuccess )
603 		        {
604 			        if ( bLeft || bRight )
605 				        m_xCursor->relative( bRight ? 1 : -1 );
606 			        else
607 			        {
608 				        sal_Bool bCanInsert = ::dbtools::canInsert( m_xCursorProperties );
609 				        // is it possible to insert another record?
610 					    if ( bCanInsert )
611 						    m_xUpdateCursor->moveToInsertRow();
612 					    else
613 						    // move record to update stati
614 						    m_xCursor->first();
615 			        }
616 		        }
617             }
618             break;
619 
620 	        case FormFeature::SaveRecordChanges:
621             case FormFeature::UndoRecordChanges:
622             {
623 			    sal_Bool bInserting = impl_isInsertionRow_throw();
624 
625                 if ( FormFeature::UndoRecordChanges == _nFeature )
626                 {
627     			    if ( !bInserting )
628 	    			    m_xUpdateCursor->cancelRowUpdates();
629 
630                     // reset all controls for this form
631                     impl_resetAllControls_nothrow( );
632 
633 			        if ( bInserting )   // back to insertion mode for this form
634 				        m_xUpdateCursor->moveToInsertRow();
635                 }
636                 else
637                 {
638 			        if  ( bInserting )
639                     {
640 				        m_xUpdateCursor->insertRow();
641                         m_xCursor->last();
642                     }
643 			        else
644 				        m_xUpdateCursor->updateRow();
645                 }
646             }
647             break;
648 
649             case FormFeature::MoveToInsertRow:
650 		        // move to the last row before moving to the insert row
651 		        // 21.01.2002 - 96480 - fs@openoffice.org
652                 m_xCursor->last();
653 		        m_xUpdateCursor->moveToInsertRow();
654     	        break;
655 
656             case FormFeature::RemoveFilterAndSort:
657             {
658 				// simultaneously reset Filter and Order property
659                 Reference< XMultiPropertySet > xProperties( m_xCursorProperties, UNO_QUERY );
660                 OSL_ENSURE( xProperties.is(), "FormOperations::execute: no multi property access!" );
661 				if ( xProperties.is() )
662 				{
663 					Sequence< ::rtl::OUString > aNames( 2 );
664                     aNames[0] = PROPERTY_FILTER;
665                     aNames[1] = PROPERTY_SORT;
666 
667 					Sequence< Any> aValues( 2 );
668                     aValues[0] <<= ::rtl::OUString();
669                     aValues[1] <<= ::rtl::OUString();
670 
671 					WaitObject aWO( NULL );
672 					xProperties->setPropertyValues( aNames, aValues );
673 
674                     if ( m_xLoadableForm.is() )
675 					    m_xLoadableForm->reload();
676 				}
677             }
678             break;
679 
680             case FormFeature::ToggleApplyFilter:
681                 if ( impl_commitCurrentControl_throw() && impl_commitCurrentRecord_throw() )
682 			    {
683                     // simply toggle the value
684 				    sal_Bool bApplied = sal_False;
685                     m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
686 				    m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( (sal_Bool)!bApplied ) );
687 
688                     // and reload
689 				    WaitObject aWO( NULL );
690 				    m_xLoadableForm->reload();
691 			    }
692                 break;
693 
694             case FormFeature::SortAscending:
695                 impl_executeAutoSort_throw( true );
696                 break;
697 
698             case FormFeature::SortDescending:
699                 impl_executeAutoSort_throw( false );
700                 break;
701 
702             case FormFeature::AutoFilter:
703                 impl_executeAutoFilter_throw();
704                 break;
705 
706             case FormFeature::InteractiveSort:
707                 impl_executeFilterOrSort_throw( false );
708 		        break;
709 
710             case FormFeature::InteractiveFilter:
711                 impl_executeFilterOrSort_throw( true );
712                 break;
713 
714             default:
715             {
716                 sal_uInt16 nErrorResourceId = RID_STR_FEATURE_UNKNOWN;
717                 if ( lcl_requiresArguments( _nFeature ) )
718                     nErrorResourceId = RID_STR_FEATURE_REQUIRES_PARAMETERS;
719                 else if ( !lcl_isExecutableFeature( _nFeature ) )
720                     nErrorResourceId = RID_STR_FEATURE_NOT_EXECUTABLE;
721                 throw IllegalArgumentException( FRM_RES_STRING( nErrorResourceId ), *this, 1 );
722             }
723             }   // switch
724         }
725         catch( const RuntimeException& ) { throw; }
726         catch( const SQLException& ) { throw; }
727         catch( const IllegalArgumentException& ) { throw; }
728         catch( const Exception& )
729         {
730             throw WrappedTargetException( ::rtl::OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
731         }
732 
733         impl_invalidateAllSupportedFeatures_nothrow( aGuard );
734     }
735 
736     //--------------------------------------------------------------------
737     void SAL_CALL FormOperations::executeWithArguments( ::sal_Int16 _nFeature, const Sequence< NamedValue >& _rArguments ) throw (RuntimeException, IllegalArgumentException, SQLException, WrappedTargetException)
738     {
739         if ( !lcl_requiresArguments( _nFeature ) )
740         {
741             execute( _nFeature );
742             return;
743         }
744 
745         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
746         MethodGuard aGuard( *this );
747 
748         // at the moment we have only one feature which supports execution parameters
749         if ( !lcl_isExecutableFeature( _nFeature ) )
750             throw IllegalArgumentException( FRM_RES_STRING( RID_STR_FEATURE_NOT_EXECUTABLE ), *this, 1 );
751 
752         switch ( _nFeature )
753         {
754         case FormFeature::MoveAbsolute:
755         {
756             sal_Int32 nPosition = -1;
757 
758             ::comphelper::NamedValueCollection aArguments( _rArguments );
759             aArguments.get_ensureType( "Position", nPosition );
760 
761             if ( nPosition < 1 )
762                 nPosition = 1;
763 
764             try
765             {
766                 // commit before doing anything else
767                 if ( m_xController.is() && !impl_commitCurrentControl_throw() )
768                     return;
769 			    if ( !impl_commitCurrentRecord_throw() )
770                     return;
771 
772                 sal_Int32 nCount      = impl_getRowCount_throw();
773 				sal_Bool  bFinalCount = impl_isRowCountFinal_throw();
774 
775 				if ( bFinalCount && ( (sal_Int32)nPosition > nCount ) )
776 					nPosition = nCount;
777 
778                 m_xCursor->absolute( nPosition );
779             }
780             catch( const RuntimeException& ) { throw; }
781             catch( const SQLException& ) { throw; }
782             catch( const Exception& )
783             {
784                 throw WrappedTargetException( ::rtl::OUString(), *this, ::cppu::getCaughtException() );
785             }
786         }
787         break;
788         default:
789             throw IllegalArgumentException( FRM_RES_STRING( RID_STR_FEATURE_UNKNOWN ), *this, 1 );
790         }   // switch
791     }
792 
793     //--------------------------------------------------------------------
794     ::sal_Bool SAL_CALL FormOperations::commitCurrentRecord( ::sal_Bool& _out_rRecordInserted ) throw (RuntimeException, SQLException)
795     {
796         MethodGuard aGuard( *this );
797         _out_rRecordInserted = sal_False;
798 
799         return impl_commitCurrentRecord_throw( &_out_rRecordInserted );
800     }
801 
802     //--------------------------------------------------------------------
803     bool FormOperations::impl_commitCurrentRecord_throw( ::sal_Bool* _pRecordInserted ) const
804     {
805         DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentRecord_throw: to be called within a MethodGuard'ed section only!" );
806 
807         if ( !impl_hasCursor_nothrow() )
808 		    return false;
809 
810         // nothing to do if the record is not modified
811 	    sal_Bool bResult = !impl_isModifiedRow_throw();
812 	    if ( !bResult )
813 	    {
814             // insert respectively update the row
815             if ( impl_isInsertionRow_throw() )
816             {
817 				m_xUpdateCursor->insertRow();
818                 if ( _pRecordInserted )
819                     *_pRecordInserted = sal_True;
820             }
821 			else
822 				m_xUpdateCursor->updateRow();
823 			bResult = true;
824 	    }
825 	    return bResult;
826     }
827 
828     //--------------------------------------------------------------------
829     ::sal_Bool SAL_CALL FormOperations::commitCurrentControl() throw (RuntimeException, SQLException)
830     {
831         MethodGuard aGuard( *this );
832         return impl_commitCurrentControl_throw();
833     }
834 
835     //--------------------------------------------------------------------
836     bool FormOperations::impl_commitCurrentControl_throw() const
837     {
838         DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentRecord_throw: to be called within a MethodGuard'ed section only!" );
839         OSL_PRECOND( m_xController.is(), "FormOperations::commitCurrentControl: no controller!" );
840         if ( !m_xController.is() )
841             return false;
842 
843 	    bool bSuccess = false;
844         try
845         {
846             Reference< XControl > xCurrentControl( m_xController->getCurrentControl() );
847 
848             // check whether the control is locked
849             Reference< XBoundControl > xCheckLock( xCurrentControl, UNO_QUERY );
850 	        sal_Bool bControlIsLocked = xCheckLock.is() && xCheckLock->getLock();
851 
852             // commit if necessary
853             bSuccess = true;
854 	        if ( xCurrentControl.is() && !bControlIsLocked )
855 	        {
856 		        // both the control and it's model can be committable, so try both
857 		        Reference< XBoundComponent > xBound( xCurrentControl, UNO_QUERY );
858 		        if ( !xBound.is() )
859 			        xBound = xBound.query( xCurrentControl->getModel() );
860                 // and now really commit
861                 if ( xBound.is() )
862 			        bSuccess = xBound->commit();
863 	        }
864 
865         }
866         catch( const RuntimeException& ) { throw; }
867         catch( const SQLException& ) { throw; }
868         catch( const Exception& )
869         {
870         	DBG_UNHANDLED_EXCEPTION();
871             bSuccess = false;
872         }
873 
874 	    return bSuccess;
875     }
876 
877     //--------------------------------------------------------------------
878     ::sal_Bool SAL_CALL FormOperations::isInsertionRow() throw (RuntimeException, WrappedTargetException)
879     {
880         sal_Bool bIs = sal_False;
881         try
882         {
883             bIs = impl_isInsertionRow_throw();
884         }
885         catch( const RuntimeException& ) { throw; }
886         catch( const Exception& )
887         {
888             throw WrappedTargetException( ::rtl::OUString(), *this, ::cppu::getCaughtException() );
889         }
890         return bIs;
891     }
892 
893     //--------------------------------------------------------------------
894     ::sal_Bool SAL_CALL FormOperations::isModifiedRow() throw (RuntimeException, WrappedTargetException)
895     {
896         sal_Bool bIs = sal_False;
897         try
898         {
899             bIs = impl_isModifiedRow_throw();
900         }
901         catch( const RuntimeException& ) { throw; }
902         catch( const Exception& )
903         {
904             throw WrappedTargetException( ::rtl::OUString(), *this, ::cppu::getCaughtException() );
905         }
906         return bIs;
907     }
908 
909     //--------------------------------------------------------------------
910     void SAL_CALL FormOperations::cursorMoved( const EventObject& /*_Event*/ ) throw (RuntimeException)
911     {
912         MethodGuard aGuard( *this );
913 	    m_bActiveControlModified = sal_False;
914 
915         impl_invalidateAllSupportedFeatures_nothrow( aGuard );
916     }
917 
918     //--------------------------------------------------------------------
919     void SAL_CALL FormOperations::rowChanged( const EventObject& /*_Event*/ ) throw (RuntimeException)
920     {
921         // not interested in
922     }
923 
924     //--------------------------------------------------------------------
925     void SAL_CALL FormOperations::rowSetChanged( const EventObject& /*_Event*/ ) throw (RuntimeException)
926     {
927         // not interested in
928     }
929 
930     //--------------------------------------------------------------------
931     void SAL_CALL FormOperations::modified( const EventObject& /*_Source*/ ) throw( RuntimeException )
932     {
933         MethodGuard aGuard( *this );
934 
935         OSL_ENSURE( m_xCursor.is(), "FormOperations::modified: already disposed!" );
936 	    if ( !m_bActiveControlModified )
937 	    {
938 		    m_bActiveControlModified = sal_True;
939             impl_invalidateModifyDependentFeatures_nothrow( aGuard );
940 	    }
941     }
942 
943     //--------------------------------------------------------------------
944     void SAL_CALL FormOperations::propertyChange( const PropertyChangeEvent& _rEvent ) throw (RuntimeException)
945     {
946         MethodGuard aGuard( *this );
947 
948         if ( m_xCursor.is() && ( m_xCursor == _rEvent.Source ) )
949         {
950             sal_Bool bIs = sal_False;
951         	if  ( ( _rEvent.PropertyName == PROPERTY_ISMODIFIED )
952                || ( _rEvent.PropertyName == PROPERTY_ISNEW )
953                 )
954 	        {
955 		        if ( ( _rEvent.NewValue >>= bIs ) && !bIs )
956 			        m_bActiveControlModified = sal_False;
957 	        }
958             impl_invalidateAllSupportedFeatures_nothrow( aGuard );
959         }
960 
961         if ( m_xParser.is() && ( m_xCursor == _rEvent.Source ) )
962 	    {
963 		    try
964 		    {
965                 ::rtl::OUString sNewValue;
966                 _rEvent.NewValue >>= sNewValue;
967 			    if ( _rEvent.PropertyName == PROPERTY_ACTIVECOMMAND )
968                 {
969 				    m_xParser->setElementaryQuery( sNewValue );
970                 }
971 			    else if ( _rEvent.PropertyName == PROPERTY_FILTER )
972 			    {
973 				    if ( m_xParser->getFilter() != sNewValue )
974 					    m_xParser->setFilter( sNewValue );
975 			    }
976 			    else if ( _rEvent.PropertyName == PROPERTY_SORT )
977 			    {
978                     _rEvent.NewValue >>= sNewValue;
979 				    if ( m_xParser->getOrder() != sNewValue )
980 					    m_xParser->setOrder( sNewValue );
981 			    }
982 		    }
983 		    catch( Exception& )
984 		    {
985 			    OSL_ENSURE( sal_False, "FormOperations::propertyChange: caught an exception while updating the parser!" );
986 		    }
987             impl_invalidateAllSupportedFeatures_nothrow( aGuard );
988 	    }
989     }
990 
991     //--------------------------------------------------------------------
992     void SAL_CALL FormOperations::disposing( const EventObject& /*_Source*/ ) throw (RuntimeException)
993     {
994         // TODO: should we react on this? Or is this the responsibility of our owner to dispose us?
995     }
996 
997     //--------------------------------------------------------------------
998     void SAL_CALL FormOperations::disposing()
999     {
1000         ::osl::MutexGuard aGuard( m_aMutex );
1001 
1002         impl_disposeParser_nothrow();
1003 
1004         try
1005         {
1006             // revoke various listeners
1007             if ( m_xCursor.is() )
1008                 m_xCursor->removeRowSetListener( this );
1009 
1010 		    if ( m_xCursorProperties.is() )
1011 		    {
1012 			    m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISMODIFIED,this );
1013 			    m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISNEW, this );
1014 		    }
1015 
1016             Reference< XModifyBroadcaster > xBroadcaster( m_xController, UNO_QUERY );
1017 		    if ( xBroadcaster.is() )
1018 			    xBroadcaster->removeModifyListener( this );
1019         }
1020         catch( const Exception& )
1021         {
1022         	DBG_UNHANDLED_EXCEPTION();
1023         }
1024 
1025         m_xController.clear();
1026         m_xCursor.clear();
1027         m_xUpdateCursor.clear();
1028         m_xCursorProperties.clear();
1029         m_xLoadableForm.clear();
1030         m_xFeatureInvalidation.clear();
1031 
1032         m_bActiveControlModified = true;
1033     }
1034 
1035     //--------------------------------------------------------------------
1036     void FormOperations::impl_checkDisposed_throw() const
1037     {
1038         if ( impl_isDisposed_nothrow() )
1039             throw DisposedException( ::rtl::OUString(), *const_cast< FormOperations* >( this ) );
1040     }
1041 
1042     //--------------------------------------------------------------------
1043     void FormOperations::impl_initFromController_throw()
1044     {
1045         OSL_PRECOND( m_xController.is(), "FormOperations::impl_initFromController_throw: invalid controller!" );
1046         m_xCursor = m_xCursor.query( m_xController->getModel() );
1047         if ( !m_xCursor.is() )
1048             throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
1049 
1050         impl_initFromForm_throw();
1051 
1052         Reference< XModifyBroadcaster > xBroadcaster( m_xController, UNO_QUERY );
1053 		if ( xBroadcaster.is() )
1054 			xBroadcaster->addModifyListener( this );
1055     }
1056 
1057     //--------------------------------------------------------------------
1058     void FormOperations::impl_initFromForm_throw()
1059     {
1060         OSL_PRECOND( m_xCursor.is(), "FormOperations::impl_initFromForm_throw: invalid form!" );
1061         m_xCursorProperties = m_xCursorProperties.query ( m_xCursor );
1062         m_xUpdateCursor     = m_xUpdateCursor.query     ( m_xCursor );
1063         m_xLoadableForm     = m_xLoadableForm.query     ( m_xCursor );
1064 
1065         if ( !m_xCursor.is() || !m_xCursorProperties.is() || !m_xLoadableForm.is() )
1066             throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
1067 
1068         m_xCursor->addRowSetListener( this );
1069 		m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISMODIFIED,this );
1070 		m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISNEW, this );
1071     }
1072 
1073     //--------------------------------------------------------------------
1074     void FormOperations::createWithFormController( const Reference< XFormController >& _rxController )
1075     {
1076         m_xController = _rxController;
1077         if ( !m_xController.is() )
1078             throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
1079 
1080         impl_initFromController_throw();
1081 
1082         m_bConstructed = true;
1083     }
1084 
1085     //--------------------------------------------------------------------
1086     void FormOperations::createWithForm( const Reference< XForm >& _rxForm )
1087     {
1088         m_xCursor = m_xCursor.query( _rxForm );
1089         if ( !m_xCursor.is() )
1090             throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
1091 
1092         impl_initFromForm_throw();
1093 
1094         m_bConstructed = true;
1095     }
1096 
1097     //------------------------------------------------------------------------------
1098     void FormOperations::impl_invalidateAllSupportedFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1099     {
1100         if ( !m_xFeatureInvalidation.is() )
1101             // nobody's interested in ...
1102             return;
1103 
1104         Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1105         _rClearForCallback.clear();
1106         xInvalidation->invalidateAllFeatures();
1107     }
1108 
1109     //------------------------------------------------------------------------------
1110     void FormOperations::impl_invalidateModifyDependentFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1111     {
1112         if ( !m_xFeatureInvalidation.is() )
1113             // nobody's interested in ...
1114             return;
1115 
1116         static Sequence< sal_Int16 > s_aModifyDependentFeatures;
1117         if ( s_aModifyDependentFeatures.getLength() == 0 )
1118         {
1119             sal_Int16 pModifyDependentFeatures[] =
1120             {
1121 	            FormFeature::MoveToNext,
1122 	            FormFeature::MoveToInsertRow,
1123 	            FormFeature::SaveRecordChanges,
1124 	            FormFeature::UndoRecordChanges
1125             };
1126             size_t nFeatureCount = sizeof( pModifyDependentFeatures ) / sizeof( pModifyDependentFeatures[ 0 ] );
1127             s_aModifyDependentFeatures = Sequence< sal_Int16 >( pModifyDependentFeatures, nFeatureCount );
1128         }
1129 
1130         Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1131         _rClearForCallback.clear();
1132 
1133         xInvalidation->invalidateFeatures( s_aModifyDependentFeatures );
1134     }
1135 
1136     //--------------------------------------------------------------------
1137     void FormOperations::impl_ensureInitializedParser_nothrow()
1138     {
1139         OSL_PRECOND( m_xCursorProperties.is(), "FormOperations::impl_ensureInitializedParser_nothrow: we're disposed!" );
1140         if ( m_bInitializedParser )
1141             return;
1142 
1143         try
1144         {
1145             sal_Bool bUseEscapeProcessing = sal_False;
1146             m_xCursorProperties->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bUseEscapeProcessing;
1147             if ( bUseEscapeProcessing )
1148             {
1149                 Reference< XMultiServiceFactory > xFactory( ::dbtools::getConnection( m_xCursor ), UNO_QUERY );
1150 	            if ( xFactory.is() )
1151                 {
1152 		            m_xParser.set( xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.SingleSelectQueryComposer" ) ) ), UNO_QUERY );
1153                     OSL_ENSURE( m_xParser.is(), "FormOperations::impl_ensureInitializedParser_nothrow: factory did not create a parser for us!" );
1154                 }
1155             }
1156 
1157 		    if ( m_xParser.is() )
1158 		    {
1159 			    if ( m_xLoadableForm.is() && m_xLoadableForm->isLoaded() )
1160 			    {
1161 				    ::rtl::OUString sStatement;
1162 				    ::rtl::OUString sFilter;
1163 				    ::rtl::OUString sSort;
1164 
1165                     m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND   ) >>= sStatement;
1166 				    m_xCursorProperties->getPropertyValue( PROPERTY_FILTER          ) >>= sFilter;
1167 				    m_xCursorProperties->getPropertyValue( PROPERTY_SORT            ) >>= sSort;
1168 
1169 					m_xParser->setElementaryQuery( sStatement );
1170 					m_xParser->setFilter         ( sFilter    );
1171 					m_xParser->setOrder          ( sSort      );
1172 			    }
1173 
1174                 // start listening at the order/sort properties at the form, so
1175                 // we can keep our parser in sync
1176 				m_xCursorProperties->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1177 				m_xCursorProperties->addPropertyChangeListener( PROPERTY_FILTER, this );
1178 				m_xCursorProperties->addPropertyChangeListener( PROPERTY_SORT, this );
1179 		    }
1180         }
1181         catch( const Exception& )
1182         {
1183 	        OSL_ENSURE( sal_False, "FormOperations::impl_ensureInitializedParser_nothrow: caught an exception!" );
1184         }
1185 
1186         m_bInitializedParser = true;
1187     }
1188 
1189     //--------------------------------------------------------------------
1190     void FormOperations::impl_disposeParser_nothrow()
1191     {
1192         try
1193         {
1194             // if we have a parser (and a cursor), then we're listening at the cursor's
1195             // properties to keep the parser in sync with the cursor
1196 		    if ( m_xParser.is() && m_xCursorProperties.is() )
1197 		    {
1198 			    m_xCursorProperties->removePropertyChangeListener( PROPERTY_FILTER, this );
1199 			    m_xCursorProperties->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1200 			    m_xCursorProperties->removePropertyChangeListener( PROPERTY_SORT, this );
1201 		    }
1202 
1203             Reference< XComponent > xParserComp( m_xParser, UNO_QUERY );
1204             if ( xParserComp.is() )
1205                 xParserComp->dispose();
1206             m_xParser.clear();
1207 
1208             m_bInitializedParser = false;
1209         }
1210         catch( const Exception& )
1211         {
1212             OSL_ENSURE( sal_False, "FormOperations::impl_disposeParser_nothrow: caught an exception!" );
1213         }
1214     }
1215 
1216     //--------------------------------------------------------------------
1217     bool FormOperations::impl_canMoveLeft_throw( ) const
1218     {
1219         if ( !impl_hasCursor_nothrow() )
1220             return false;
1221 
1222         return impl_getRowCount_throw() && ( !m_xCursor->isFirst() || impl_isInsertionRow_throw() );
1223     }
1224 
1225     //--------------------------------------------------------------------
1226     bool FormOperations::impl_canMoveRight_throw( ) const
1227     {
1228         if ( !impl_hasCursor_nothrow() )
1229             return false;
1230 
1231         bool bIsNew = impl_isInsertionRow_throw();
1232 
1233         if ( impl_getRowCount_throw() && !m_xCursor->isLast() && !bIsNew )
1234             return true;
1235 
1236         if ( ::dbtools::canInsert( m_xCursorProperties ) )
1237             if ( !bIsNew || impl_isModifiedRow_throw() )
1238                 return true;
1239 
1240         if ( bIsNew && m_bActiveControlModified )
1241             return true;
1242 
1243         return false;
1244     }
1245 
1246     //--------------------------------------------------------------------
1247     namespace
1248     {
1249         template < typename TYPE >
1250         TYPE lcl_safeGetPropertyValue_throw( const Reference< XPropertySet >& _rxProperties, const ::rtl::OUString& _rPropertyName, TYPE _Default )
1251         {
1252             TYPE value( _Default );
1253             OSL_PRECOND( _rxProperties.is(), "FormOperations::<foo>: no cursor (already disposed?)!" );
1254             if ( _rxProperties.is() )
1255                 OSL_VERIFY( _rxProperties->getPropertyValue( _rPropertyName ) >>= value );
1256             return value;
1257         }
1258     }
1259 
1260     //--------------------------------------------------------------------
1261     bool FormOperations::impl_isInsertionRow_throw() const
1262     {
1263         return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISNEW, false );
1264     }
1265 
1266     //--------------------------------------------------------------------
1267     sal_Int32 FormOperations::impl_getRowCount_throw() const
1268     {
1269         return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNT, (sal_Int32)0 );
1270     }
1271     //--------------------------------------------------------------------
1272     bool FormOperations::impl_isRowCountFinal_throw() const
1273     {
1274         return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNTFINAL, false );
1275     }
1276 
1277     //--------------------------------------------------------------------
1278     bool FormOperations::impl_isModifiedRow_throw() const
1279     {
1280         return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISMODIFIED, false );
1281     }
1282 
1283     //--------------------------------------------------------------------
1284     bool FormOperations::impl_isParseable_throw() const
1285     {
1286         const_cast< FormOperations* >( this )->impl_ensureInitializedParser_nothrow();
1287         return m_xParser.is() && m_xParser->getQuery().getLength();
1288     }
1289 
1290     //--------------------------------------------------------------------
1291 	bool FormOperations::impl_hasFilterOrOrder_throw() const
1292     {
1293         return impl_isParseable_throw() && ( m_xParser->getFilter().getLength() || m_xParser->getOrder().getLength() );
1294     }
1295 
1296     //--------------------------------------------------------------------
1297     bool FormOperations::impl_isInsertOnlyForm_throw() const
1298     {
1299         return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_INSERTONLY, true );
1300     }
1301 
1302     //------------------------------------------------------------------------------
1303     Reference< XControlModel > FormOperations::impl_getCurrentControlModel_throw() const
1304     {
1305         Reference< XControl > xControl( m_xController->getCurrentControl() );
1306 
1307         // special handling for grid controls
1308         Reference< XGrid > xGrid( xControl, UNO_QUERY );
1309         Reference< XControlModel > xControlModel;
1310 
1311         if ( xGrid.is() )
1312         {
1313 	        Reference< XIndexAccess > xColumns( xControl->getModel(), UNO_QUERY_THROW );
1314 	        sal_Int16 nCurrentPos = xGrid->getCurrentColumnPosition();
1315 	        nCurrentPos = impl_gridView2ModelPos_nothrow( xColumns, nCurrentPos );
1316 
1317             if ( nCurrentPos != (sal_Int16)-1 )
1318 		        xColumns->getByIndex( nCurrentPos ) >>= xControlModel;
1319         }
1320         else if ( xControl.is() )
1321         {
1322 	        xControlModel = xControl->getModel();
1323         }
1324         return xControlModel;
1325     }
1326 
1327     //------------------------------------------------------------------------------
1328     Reference< XPropertySet > FormOperations::impl_getCurrentBoundField_nothrow( ) const
1329     {
1330         OSL_PRECOND( m_xController.is(), "FormOperations::impl_getCurrentBoundField_nothrow: no controller -> no control!" );
1331         if ( !m_xController.is() )
1332             return NULL;
1333 
1334         Reference< XPropertySet > xField;
1335         try
1336         {
1337             Reference< XPropertySet > xControlModel( impl_getCurrentControlModel_throw(), UNO_QUERY );
1338 
1339 	        if ( xControlModel.is() && ::comphelper::hasProperty( PROPERTY_BOUNDFIELD, xControlModel ) )
1340 		        xControlModel->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xField;
1341 
1342         }
1343         catch( const Exception& )
1344         {
1345         	DBG_UNHANDLED_EXCEPTION();
1346         }
1347 
1348 	    return xField;
1349     }
1350 
1351     //------------------------------------------------------------------------------
1352     sal_Int16 FormOperations::impl_gridView2ModelPos_nothrow( const Reference< XIndexAccess >& _rxColumns, sal_Int16 _nViewPos ) const
1353     {
1354         OSL_PRECOND( _rxColumns.is(), "FormOperations::impl_gridView2ModelPos_nothrow: invalid columns container!" );
1355         try
1356         {
1357             // loop through all columns
1358             sal_Int16 col = 0;
1359             Reference< XPropertySet > xCol;
1360             bool bHidden( false );
1361             for ( col = 0; col < _rxColumns->getCount(); ++col )
1362             {
1363                 _rxColumns->getByIndex( col ) >>= xCol;
1364                 OSL_VERIFY( xCol->getPropertyValue( PROPERTY_HIDDEN ) >>= bHidden );
1365                 if ( bHidden )
1366                     continue;
1367 
1368                 // for every visible col : if nViewPos is greater zero, decrement it, else we
1369                 // have found the model position
1370                 if ( !_nViewPos )
1371                     break;
1372                 else
1373                     --_nViewPos;
1374             }
1375             if ( col < _rxColumns->getCount() )
1376                 return col;
1377         }
1378         catch( const Exception& )
1379         {
1380             DBG_UNHANDLED_EXCEPTION();
1381         }
1382         return (sal_Int16)-1;
1383     }
1384 
1385     //------------------------------------------------------------------------------
1386     bool FormOperations::impl_moveLeft_throw( ) const
1387     {
1388         OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveLeft_throw: no cursor!" );
1389 	    if ( !impl_hasCursor_nothrow() )
1390 		    return false;
1391 
1392 	    sal_Bool bRecordInserted = sal_False;
1393 	    sal_Bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1394 
1395 	    if ( !bSuccess )
1396             return false;
1397 
1398 		if ( bRecordInserted )
1399 		{
1400 			// retrieve the bookmark of the new record and move to the record preceding this bookmark
1401 			Reference< XRowLocate > xLocate( m_xCursor, UNO_QUERY );
1402             OSL_ENSURE( xLocate.is(), "FormOperations::impl_moveLeft_throw: no XRowLocate!" );
1403             if ( xLocate.is() )
1404                 xLocate->moveRelativeToBookmark( xLocate->getBookmark(), -1 );
1405 		}
1406 		else
1407         {
1408             if ( impl_isInsertionRow_throw() )
1409 			{
1410 				// we assume that the inserted record is now the last record in the
1411 				// result set
1412 				m_xCursor->last();
1413 			}
1414 			else
1415 				m_xCursor->previous();
1416         }
1417 
1418         return true;
1419     }
1420 
1421     //--------------------------------------------------------------------
1422     bool FormOperations::impl_moveRight_throw( ) const
1423     {
1424         OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveRight_throw: no cursor!" );
1425 	    if ( !impl_hasCursor_nothrow() )
1426 		    return false;
1427 
1428 	    sal_Bool bRecordInserted = sal_False;
1429 	    sal_Bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1430 
1431         if ( !bSuccess )
1432             return false;
1433 
1434 		if ( bRecordInserted )
1435 		{
1436 			// go to insert row
1437 			m_xUpdateCursor->moveToInsertRow();
1438 		}
1439 		else
1440 		{
1441 			if ( m_xCursor->isLast() )
1442 				m_xUpdateCursor->moveToInsertRow();
1443 			else
1444 				m_xCursor->next();
1445 		}
1446 
1447 	    return true;
1448     }
1449 
1450     //--------------------------------------------------------------------
1451     void FormOperations::impl_resetAllControls_nothrow() const
1452     {
1453 	    Reference< XIndexAccess > xContainer( m_xCursor, UNO_QUERY );
1454 		if ( !xContainer.is() )
1455             return;
1456 
1457         try
1458         {
1459             Reference< XReset > xReset;
1460             sal_Int32 nCount( xContainer->getCount() );
1461 		    for ( sal_Int32 i = 0; i < nCount; ++i )
1462 		    {
1463 			    if ( xContainer->getByIndex( i ) >>= xReset )
1464 			    {
1465                     // no resets on sub forms
1466 				    Reference< XForm > xAsForm( xReset, UNO_QUERY );
1467 				    if ( !xAsForm.is() )
1468 					    xReset->reset();
1469 			    }
1470 		    }
1471         }
1472         catch( const Exception& )
1473         {
1474         	DBG_UNHANDLED_EXCEPTION();
1475         }
1476     }
1477 
1478     //------------------------------------------------------------------------------
1479     void FormOperations::impl_executeAutoSort_throw( bool _bUp ) const
1480     {
1481         OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoSort_throw: need a controller for this!" );
1482         OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoSort_throw: need a cursor for this!" );
1483         OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoSort_throw: need a parseable statement for this!" );
1484         if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1485             return;
1486 
1487         try
1488         {
1489 		    Reference< XControl > xControl = m_xController->getCurrentControl();
1490             if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1491                 return;
1492 
1493             Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1494 			if ( !xBoundField.is() )
1495                 return;
1496 
1497             ::rtl::OUString sOriginalSort;
1498 			m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sOriginalSort;
1499 
1500 			// automatic sort by field is expected to always resets the previous sort order
1501     		m_xParser->setOrder( ::rtl::OUString() );
1502 
1503             param_appendOrderByColumn aParam;
1504             aParam.xField = xBoundField;
1505             aParam.bUp = _bUp;
1506 			impl_doActionInSQLContext_throw(
1507                 (Action)&FormOperations::impl_appendOrderByColumn_throw,
1508                 static_cast< const void* >( &aParam ),
1509                 (sal_uInt16)RID_STR_COULD_NOT_SET_ORDER
1510             );
1511 
1512 			WaitObject aWO( NULL );
1513 			try
1514 			{
1515 				m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1516 				m_xLoadableForm->reload();
1517 			}
1518 			catch( const Exception& )
1519 			{
1520                 OSL_ENSURE( sal_False, "FormOperations::impl_executeAutoSort_throw: caught an exception while setting the parser properties!" );
1521 			}
1522 
1523 
1524 			if ( !m_xLoadableForm->isLoaded() )
1525 			{	// something went wrong -> restore the original state
1526 				try
1527 				{
1528 					m_xParser->setOrder( sOriginalSort );
1529 					m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1530 					m_xLoadableForm->reload();
1531 				}
1532 				catch( const Exception& )
1533 				{
1534                     OSL_ENSURE( sal_False, "FormOperations::impl_executeAutoSort_throw: could not reset the form to it's original state!" );
1535 				}
1536 
1537 			}
1538         }
1539         catch( const RuntimeException& ) { throw; }
1540         catch( const SQLException& ) { throw; }
1541         catch( const Exception& )
1542         {
1543             throw WrappedTargetException( ::rtl::OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1544         }
1545     }
1546 
1547     //------------------------------------------------------------------------------
1548     void FormOperations::impl_executeAutoFilter_throw( ) const
1549     {
1550         OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoFilter_throw: need a controller for this!" );
1551         OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoFilter_throw: need a cursor for this!" );
1552         OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoFilter_throw: need a parseable statement for this!" );
1553         if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1554             return;
1555 
1556         try
1557         {
1558 		    Reference< XControl > xControl = m_xController->getCurrentControl();
1559             if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1560                 return;
1561 
1562             Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1563 		    if ( !xBoundField.is() )
1564                 return;
1565 
1566 		    ::rtl::OUString sOriginalFilter;
1567             m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
1568 		    sal_Bool bApplied = sal_True;
1569             m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
1570 
1571 		    // if we have a filter, but it's not applied, then we have to overwrite it, else append one
1572 		    if ( !bApplied )
1573                 m_xParser->setFilter( ::rtl::OUString() );
1574 
1575             param_appendFilterByColumn aParam;
1576             aParam.xField = xBoundField;
1577 		    impl_doActionInSQLContext_throw(
1578                 (Action)&FormOperations::impl_appendFilterByColumn_throw,
1579                 static_cast< const void* >( &aParam ),
1580                 (sal_uInt16)RID_STR_COULD_NOT_SET_FILTER
1581             );
1582 
1583             WaitObject aWO( NULL );
1584 		    try
1585 		    {
1586 			    m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1587 			    m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( (sal_Bool)sal_True ) );
1588 
1589 			    m_xLoadableForm->reload();
1590 		    }
1591 		    catch( const Exception& )
1592 		    {
1593                 OSL_ENSURE( sal_False, "FormOperations::impl_executeAutoFilter_throw: caught an exception while setting the parser properties!" );
1594 		    }
1595 
1596 
1597 		    if ( !m_xLoadableForm->isLoaded() )
1598 		    {	// something went wrong -> restore the original state
1599 			    try
1600 			    {
1601 				    m_xParser->setOrder( sOriginalFilter );
1602 				    m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( (sal_Bool)bApplied ) );
1603 				    m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1604 				    m_xLoadableForm->reload();
1605 			    }
1606 			    catch( const Exception& )
1607 			    {
1608                     OSL_ENSURE( sal_False, "FormOperations::impl_executeAutoFilter_throw: could not reset the form to it's original state!" );
1609 			    }
1610 
1611 		    }
1612         }
1613         catch( const RuntimeException& ) { throw; }
1614         catch( const SQLException& ) { throw; }
1615         catch( const Exception& )
1616         {
1617             throw WrappedTargetException( ::rtl::OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1618         }
1619     }
1620 
1621     //--------------------------------------------------------------------
1622     void FormOperations::impl_executeFilterOrSort_throw( bool _bFilter ) const
1623     {
1624         OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeFilterOrSort_throw: need a controller for this!" );
1625         OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeFilterOrSort_throw: need a cursor for this!" );
1626         OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeFilterOrSort_throw: need a parseable statement for this!" );
1627         if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1628             return;
1629 
1630         if ( !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1631             return;
1632 		try
1633 		{
1634 			PropertyValue aFirst;
1635 			aFirst.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "QueryComposer" ) );
1636 			aFirst.Value <<= m_xParser;
1637 
1638 			PropertyValue aSecond;
1639 			aSecond.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RowSet" ) );
1640 			aSecond.Value <<= m_xCursorProperties;
1641 
1642 			Sequence<Any> aInit(2);
1643 			aInit[0] <<= aFirst;
1644 			aInit[1] <<= aSecond;
1645 
1646             ::rtl::OUString sDialogServiceName;
1647             if ( _bFilter )
1648                 sDialogServiceName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.FilterDialog" ) );
1649             else
1650                 sDialogServiceName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.OrderDialog" ) );
1651 
1652             Reference< XExecutableDialog> xDialog;
1653             m_aContext.createComponentWithArguments( sDialogServiceName, aInit, xDialog );
1654 
1655 			if ( !xDialog.is() )
1656             {
1657     		    ShowServiceNotAvailableError( NULL, sDialogServiceName, sal_True );
1658                 return;
1659             }
1660 
1661             if ( RET_OK == xDialog->execute() )
1662             {
1663         		WaitObject aWO( NULL );
1664                 if ( _bFilter )
1665                     m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1666                 else
1667                     m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1668 		    	m_xLoadableForm->reload();
1669             }
1670 
1671 		}
1672         catch( const RuntimeException& ) { throw; }
1673         catch( const SQLException& ) { throw; }
1674 		catch( const Exception& )
1675 		{
1676             throw WrappedTargetException( ::rtl::OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1677 		}
1678     }
1679 
1680     //------------------------------------------------------------------------------
1681     void FormOperations::impl_appendOrderByColumn_throw( const void* _pActionParam ) const
1682     {
1683         const param_appendOrderByColumn* pParam = static_cast< const param_appendOrderByColumn* >( _pActionParam );
1684         m_xParser->appendOrderByColumn( pParam->xField, pParam->bUp );
1685     }
1686 
1687     //------------------------------------------------------------------------------
1688     void FormOperations::impl_appendFilterByColumn_throw( const void* _pActionParam ) const
1689     {
1690         const param_appendFilterByColumn* pParam = static_cast< const param_appendFilterByColumn* >( _pActionParam );
1691         sal_Int32 nOp = SQLFilterOperator::EQUAL;
1692         if ( pParam->xField.is() )
1693         {
1694             sal_Int32 nType = 0;
1695             pParam->xField->getPropertyValue(PROPERTY_FIELDTYPE) >>= nType;
1696             switch(nType)
1697             {
1698                 case DataType::VARCHAR:
1699 	            case DataType::CHAR:
1700 	            case DataType::LONGVARCHAR:
1701                     nOp = SQLFilterOperator::LIKE;
1702                     break;
1703                 default:
1704                     nOp = SQLFilterOperator::EQUAL;
1705             }
1706         }
1707         m_xParser->appendFilterByColumn( pParam->xField, sal_True,nOp );
1708     }
1709 
1710     //------------------------------------------------------------------------------
1711     void FormOperations::impl_doActionInSQLContext_throw( Action _pAction, const void* _pParam, sal_uInt16 _nErrorResourceId ) const
1712     {
1713 	    try
1714 	    {
1715 		    (this->*_pAction)( _pParam );
1716 	    }
1717 	    catch( const SQLException& e )
1718 	    {
1719             (void)e;
1720             if ( !_nErrorResourceId )
1721                 // no information to prepend
1722                 throw;
1723 
1724             SQLExceptionInfo aInfo( ::cppu::getCaughtException() );
1725             ::rtl::OUString sAdditionalError( FRM_RES_STRING( _nErrorResourceId ) );
1726             aInfo.prepend( sAdditionalError );
1727             aInfo.doThrow();
1728 	    }
1729         catch( const RuntimeException& ) { throw; }
1730 	    catch( const Exception& )
1731 	    {
1732             ::rtl::OUString sAdditionalError( FRM_RES_STRING( _nErrorResourceId ) );
1733             throw WrappedTargetException( sAdditionalError, *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1734 	    }
1735     }
1736 
1737 //........................................................................
1738 } // namespace frm
1739 //........................................................................
1740