Bump version to 5.0-43
[LibreOffice.git] / forms / source / runtime / formoperations.cxx
blob2ccb2df5005fde430d0fbe3d5137b54569396f73
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include "formoperations.hxx"
23 #include "frm_strings.hxx"
24 #include "frm_resource.hxx"
25 #include "frm_resource.hrc"
26 #include "services.hxx"
28 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
29 #include <com/sun/star/util/XModifyBroadcaster.hpp>
30 #include <com/sun/star/form/runtime/FormFeature.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/lang/DisposedException.hpp>
33 #include <com/sun/star/awt/XControl.hpp>
34 #include <com/sun/star/form/XGrid.hpp>
35 #include <com/sun/star/form/XBoundControl.hpp>
36 #include <com/sun/star/form/XBoundComponent.hpp>
37 #include <com/sun/star/sdbcx/XRowLocate.hpp>
38 #include <com/sun/star/form/XConfirmDeleteListener.hpp>
39 #include <com/sun/star/sdb/RowChangeEvent.hpp>
40 #include <com/sun/star/sdb/RowChangeAction.hpp>
41 #include <com/sun/star/sdb/OrderDialog.hpp>
42 #include <com/sun/star/sdb/FilterDialog.hpp>
43 #include <com/sun/star/sdbc/DataType.hpp>
44 #include <com/sun/star/form/XReset.hpp>
45 #include <com/sun/star/beans/XMultiPropertySet.hpp>
46 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
47 #include <com/sun/star/util/XRefreshable.hpp>
49 #include <connectivity/dbtools.hxx>
50 #include <connectivity/dbexception.hxx>
51 #include <vcl/svapp.hxx>
52 #include <vcl/stdtext.hxx>
53 #include <vcl/msgbox.hxx>
54 #include <vcl/waitobj.hxx>
55 #include <tools/diagnose_ex.h>
56 #include <comphelper/container.hxx>
57 #include <comphelper/property.hxx>
58 #include <comphelper/namedvaluecollection.hxx>
59 #include <comphelper/processfactory.hxx>
60 #include <cppuhelper/exc_hlp.hxx>
61 #include <cppuhelper/supportsservice.hxx>
62 #include <osl/mutex.hxx>
63 #include <sal/macros.h>
66 namespace frm
70 using ::dbtools::SQLExceptionInfo;
71 using ::com::sun::star::uno::Reference;
72 using ::com::sun::star::uno::XComponentContext;
73 using ::com::sun::star::uno::RuntimeException;
74 using ::com::sun::star::uno::Sequence;
75 using ::com::sun::star::uno::Exception;
76 using ::com::sun::star::uno::Any;
77 using ::com::sun::star::uno::XInterface;
78 using ::com::sun::star::sdbc::XRowSet;
79 using ::com::sun::star::sdbc::XResultSetUpdate;
80 using ::com::sun::star::form::runtime::XFormController;
81 using ::com::sun::star::form::runtime::XFormOperations;
82 using ::com::sun::star::form::runtime::XFeatureInvalidation;
83 using ::com::sun::star::form::runtime::FeatureState;
84 using ::com::sun::star::lang::IllegalArgumentException;
85 using ::com::sun::star::sdbc::SQLException;
86 using namespace ::com::sun::star::sdbc;
87 using ::com::sun::star::form::XForm;
88 using ::com::sun::star::ucb::AlreadyInitializedException;
89 using ::com::sun::star::util::XModifyBroadcaster;
90 using ::com::sun::star::uno::UNO_QUERY;
91 using ::com::sun::star::lang::EventObject;
92 using ::com::sun::star::beans::PropertyChangeEvent;
93 using ::com::sun::star::lang::XMultiServiceFactory;
94 using ::com::sun::star::lang::DisposedException;
95 using ::com::sun::star::beans::XPropertySet;
96 using ::com::sun::star::awt::XControl;
97 using ::com::sun::star::form::XGrid;
98 using ::com::sun::star::container::XIndexAccess;
99 using ::com::sun::star::uno::UNO_QUERY_THROW;
100 using ::com::sun::star::form::XBoundControl;
101 using ::com::sun::star::form::XBoundComponent;
102 using ::com::sun::star::sdbcx::XRowLocate;
103 using ::com::sun::star::form::XConfirmDeleteListener;
104 using ::com::sun::star::sdb::RowChangeEvent;
105 using namespace ::com::sun::star::sdb;
106 using ::com::sun::star::form::XReset;
107 using ::com::sun::star::beans::XMultiPropertySet;
108 using ::com::sun::star::uno::makeAny;
109 using ::com::sun::star::lang::WrappedTargetException;
110 using ::com::sun::star::beans::PropertyValue;
111 using ::com::sun::star::ui::dialogs::XExecutableDialog;
112 using ::com::sun::star::beans::NamedValue;
113 using ::com::sun::star::util::XRefreshable;
114 using ::com::sun::star::awt::XControlModel;
116 namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
117 namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
119 FormOperations::FormOperations( const Reference< XComponentContext >& _rxContext )
120 :FormOperations_Base( m_aMutex )
121 ,m_xContext( _rxContext )
122 ,m_bInitializedParser( false )
123 ,m_bActiveControlModified( false )
124 ,m_bConstructed( false )
125 #ifdef DBG_UTIL
126 ,m_nMethodNestingLevel( 0 )
127 #endif
131 FormOperations::~FormOperations()
135 OUString FormOperations::getImplementationName_Static( ) throw(RuntimeException)
137 return OUString( "com.sun.star.comp.forms.FormOperations" );
140 Sequence< OUString > FormOperations::getSupportedServiceNames_Static( ) throw(RuntimeException)
142 Sequence< OUString > aNames(1);
143 aNames[0] = "com.sun.star.form.runtime.FormOperations";
144 return aNames;
147 void SAL_CALL FormOperations::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException, std::exception)
149 if ( m_bConstructed )
150 throw AlreadyInitializedException();
152 if ( _arguments.getLength() == 1 )
154 Reference< XFormController > xController;
155 Reference< XForm > xForm;
156 if ( _arguments[0] >>= xController )
157 createWithFormController( xController );
158 else if ( _arguments[0] >>= xForm )
159 createWithForm( xForm );
160 else
161 throw IllegalArgumentException( OUString(), *this, 1 );
162 return;
165 throw IllegalArgumentException( OUString(), *this, 0 );
168 OUString SAL_CALL FormOperations::getImplementationName( ) throw (RuntimeException, std::exception)
170 return getImplementationName_Static();
173 sal_Bool SAL_CALL FormOperations::supportsService( const OUString& _ServiceName ) throw (RuntimeException, std::exception)
175 return cppu::supportsService(this, _ServiceName);
178 Sequence< OUString > SAL_CALL FormOperations::getSupportedServiceNames( ) throw (RuntimeException, std::exception)
180 return getSupportedServiceNames_Static();
183 Reference< XRowSet > SAL_CALL FormOperations::getCursor() throw (RuntimeException, std::exception)
185 MethodGuard aGuard( *this );
186 return m_xCursor;
189 Reference< XResultSetUpdate > SAL_CALL FormOperations::getUpdateCursor() throw (RuntimeException, std::exception)
191 MethodGuard aGuard( *this );
192 return m_xUpdateCursor;
196 Reference< XFormController > SAL_CALL FormOperations::getController() throw (RuntimeException, std::exception)
198 MethodGuard aGuard( *this );
199 return m_xController;
203 Reference< XFeatureInvalidation > SAL_CALL FormOperations::getFeatureInvalidation() throw (RuntimeException, std::exception)
205 MethodGuard aGuard( *this );
206 return m_xFeatureInvalidation;
210 void SAL_CALL FormOperations::setFeatureInvalidation( const Reference< XFeatureInvalidation > & _rxFeatureInvalidation ) throw (RuntimeException, std::exception)
212 MethodGuard aGuard( *this );
213 m_xFeatureInvalidation = _rxFeatureInvalidation;
217 FeatureState SAL_CALL FormOperations::getState( ::sal_Int16 _nFeature ) throw (RuntimeException, std::exception)
219 MethodGuard aGuard( *this );
221 FeatureState aState;
222 aState.Enabled = sal_False;
226 // some checks for basic pre-requisites
227 if ( !m_xLoadableForm.is()
228 || !m_xLoadableForm->isLoaded()
229 || !m_xCursorProperties.is()
232 return aState;
235 switch ( _nFeature )
237 case FormFeature::MoveToFirst:
238 case FormFeature::MoveToPrevious:
239 aState.Enabled = impl_canMoveLeft_throw( );
240 break;
242 case FormFeature::MoveToNext:
243 aState.Enabled = impl_canMoveRight_throw();
244 break;
246 case FormFeature::MoveToLast:
247 aState.Enabled = impl_getRowCount_throw() && ( !m_xCursor->isLast() || impl_isInsertionRow_throw() );
248 break;
250 case FormFeature::DeleteRecord:
251 // already deleted ?
252 if ( m_xCursor->rowDeleted() )
253 aState.Enabled = sal_False;
254 else
256 // allowed to delete the row ?
257 aState.Enabled = !impl_isInsertionRow_throw() && ::dbtools::canDelete( m_xCursorProperties );
259 break;
261 case FormFeature::MoveToInsertRow:
262 // if we are inserting we can move to the next row if the current record or control is modified
263 aState.Enabled = impl_isInsertionRow_throw()
264 ? impl_isModifiedRow_throw() || m_bActiveControlModified
265 : ::dbtools::canInsert( m_xCursorProperties );
266 break;
268 case FormFeature::ReloadForm:
270 // there must be an active connection
271 Reference< XRowSet > xCursorRowSet( m_xCursor, UNO_QUERY );
272 aState.Enabled = ::dbtools::getConnection( xCursorRowSet ).is();
274 // and an active command
275 OUString sActiveCommand;
276 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sActiveCommand;
277 aState.Enabled = aState.Enabled && !sActiveCommand.isEmpty();
279 break;
281 case FormFeature::RefreshCurrentControl:
283 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
284 aState.Enabled = xControlModelRefresh.is();
286 break;
288 case FormFeature::SaveRecordChanges:
289 case FormFeature::UndoRecordChanges:
290 aState.Enabled = impl_isModifiedRow_throw() || m_bActiveControlModified;
291 break;
293 case FormFeature::RemoveFilterAndSort:
294 if ( impl_isParseable_throw() && impl_hasFilterOrOrder_throw() )
295 aState.Enabled = !impl_isInsertOnlyForm_throw();
296 break;
298 case FormFeature::SortAscending:
299 case FormFeature::SortDescending:
300 case FormFeature::AutoFilter:
301 if ( m_xController.is() && impl_isParseable_throw() )
303 bool bIsDeleted = m_xCursor->rowDeleted();
305 if ( !bIsDeleted && !impl_isInsertOnlyForm_throw() )
307 Reference< XPropertySet > xBoundField = impl_getCurrentBoundField_nothrow( );
308 if ( xBoundField.is() )
309 xBoundField->getPropertyValue( PROPERTY_SEARCHABLE ) >>= aState.Enabled;
312 break;
314 case FormFeature::InteractiveSort:
315 case FormFeature::InteractiveFilter:
316 if ( impl_isParseable_throw() )
317 aState.Enabled = !impl_isInsertOnlyForm_throw();
318 break;
320 case FormFeature::ToggleApplyFilter:
322 OUString sFilter;
323 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
324 if ( !sFilter.isEmpty() )
326 aState.State = m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER );
327 aState.Enabled = !impl_isInsertOnlyForm_throw();
329 else
330 aState.State <<= false;
332 break;
334 case FormFeature::MoveAbsolute:
336 sal_Int32 nPosition = m_xCursor->getRow();
337 bool bIsNew = impl_isInsertionRow_throw();
338 sal_Int32 nCount = impl_getRowCount_throw();
339 bool bFinalCount = impl_isRowCountFinal_throw();
341 if ( ( nPosition >= 0 ) || bIsNew )
343 if ( bFinalCount )
345 // special case: there are no records at all, and we
346 // can't insert records -> disabled
347 if ( !nCount && !::dbtools::canInsert( m_xCursorProperties ) )
349 aState.Enabled = sal_False;
351 else
353 if ( bIsNew )
354 nPosition = ++nCount;
355 aState.State <<= (sal_Int32)nPosition;
356 aState.Enabled = sal_True;
359 else
361 aState.State <<= (sal_Int32)nPosition;
362 aState.Enabled = sal_True;
366 break;
368 case FormFeature::TotalRecords:
370 bool bIsNew = impl_isInsertionRow_throw();
371 sal_Int32 nCount = impl_getRowCount_throw();
372 bool bFinalCount = impl_isRowCountFinal_throw();
374 if ( bIsNew )
375 ++nCount;
377 OUString sValue = OUString::number( nCount );
378 if ( !bFinalCount )
379 sValue += " *";
381 aState.State <<= sValue;
382 aState.Enabled = sal_True;
384 break;
386 default:
387 OSL_FAIL( "FormOperations::getState: unknown feature id!" );
388 break;
391 catch( const Exception& )
393 OSL_FAIL( "FormOperations::getState: caught an exception!" );
396 return aState;
400 sal_Bool SAL_CALL FormOperations::isEnabled( ::sal_Int16 _nFeature ) throw (RuntimeException, std::exception)
402 MethodGuard aGuard( *this );
404 FeatureState aState( getState( _nFeature ) );
405 return aState.Enabled;
409 namespace
411 static bool lcl_needConfirmCommit( sal_Int32 _nFeature )
413 return ( ( _nFeature == FormFeature::ReloadForm )
414 || ( _nFeature == FormFeature::RemoveFilterAndSort )
415 || ( _nFeature == FormFeature::ToggleApplyFilter )
416 || ( _nFeature == FormFeature::SortAscending )
417 || ( _nFeature == FormFeature::SortDescending )
418 || ( _nFeature == FormFeature::AutoFilter )
419 || ( _nFeature == FormFeature::InteractiveSort )
420 || ( _nFeature == FormFeature::InteractiveFilter )
423 static bool lcl_requiresArguments( sal_Int32 _nFeature )
425 return ( _nFeature == FormFeature::MoveAbsolute );
427 static bool lcl_isExecutableFeature( sal_Int32 _nFeature )
429 return ( _nFeature != FormFeature::TotalRecords );
432 template < typename TYPE >
433 TYPE lcl_safeGetPropertyValue_throw( const Reference< XPropertySet >& _rxProperties, const OUString& _rPropertyName, TYPE _Default )
435 TYPE value( _Default );
436 OSL_PRECOND( _rxProperties.is(), "FormOperations::<foo>: no cursor (already disposed?)!" );
437 if ( _rxProperties.is() )
438 OSL_VERIFY( _rxProperties->getPropertyValue( _rPropertyName ) >>= value );
439 return value;
442 // returns false if parent should *abort* (user pressed cancel)
443 bool checkConfirmation(bool &needConfirmation, bool &shouldCommit)
445 if(needConfirmation)
447 // TODO: shouldn't this be done with an interaction handler?
448 ScopedVclPtrInstance< QueryBox > aQuery( nullptr, WB_YES_NO_CANCEL | WB_DEF_YES, FRM_RES_STRING( RID_STR_QUERY_SAVE_MODIFIED_ROW ) );
449 switch ( aQuery->Execute() )
451 case RET_NO:
452 shouldCommit = false;
453 // no break on purpose: don't ask again!
454 case RET_YES:
455 needConfirmation = false;
456 return true;
457 case RET_CANCEL:
458 return false;
461 return true;
464 bool commit1Form(Reference< XFormController > xCntrl, bool &needConfirmation, bool &shouldCommit)
466 Reference< XFormOperations > xFrmOps(xCntrl->getFormOperations());
467 if (!xFrmOps->commitCurrentControl())
468 return false;
470 if(xFrmOps->isModifiedRow())
472 if(!checkConfirmation(needConfirmation, shouldCommit))
473 return false;
474 sal_Bool bTmp;
475 if (shouldCommit && !xFrmOps->commitCurrentRecord(bTmp))
476 return false;
478 return true;
481 bool commitFormAndSubforms(Reference< XFormController > xCntrl, bool needConfirmation)
483 bool shouldCommit(true);
484 assert(xCntrl.is());
485 Reference< XIndexAccess > xSubForms(xCntrl, UNO_QUERY);
486 assert(xSubForms.is());
487 if(xSubForms.is())
489 const sal_Int32 cnt = xSubForms->getCount();
490 for(int i=0; i < cnt; ++i)
492 Reference< XFormController > xSubForm(xSubForms->getByIndex(i), UNO_QUERY);
493 assert(xSubForm.is());
494 if (xSubForm.is())
496 if (!commit1Form(xSubForm, needConfirmation, shouldCommit))
497 return false;
502 if(!commit1Form(xCntrl, needConfirmation, shouldCommit))
503 return false;
505 return true;
508 bool commit1Form(Reference< XForm > xFrm, bool &needConfirmation, bool &shouldCommit)
510 Reference< XPropertySet > xProps(xFrm, UNO_QUERY_THROW);
511 // nothing to do if the record is not modified
512 if(!lcl_safeGetPropertyValue_throw( xProps, PROPERTY_ISMODIFIED, false ))
513 return true;
515 if(!checkConfirmation(needConfirmation, shouldCommit))
516 return false;
517 if(shouldCommit)
519 Reference< XResultSetUpdate > xUpd(xFrm, UNO_QUERY_THROW);
520 // insert respectively update the row
521 if ( lcl_safeGetPropertyValue_throw( xProps, PROPERTY_ISNEW, false ) )
522 xUpd->insertRow();
523 else
524 xUpd->updateRow();
526 return true;
529 bool commitFormAndSubforms(Reference< XForm > xFrm, bool needConfirmation)
531 // No control... do what we can with the models
532 bool shouldCommit(true);
533 Reference< XIndexAccess > xFormComps(xFrm, UNO_QUERY_THROW);
534 assert( xFormComps.is() );
536 const sal_Int32 cnt = xFormComps->getCount();
537 for(int i=0; i < cnt; ++i)
539 Reference< XForm > xSubForm(xFormComps->getByIndex(i), UNO_QUERY);
540 if(xSubForm.is())
542 if(!commit1Form(xSubForm, needConfirmation, shouldCommit))
543 return false;
547 if(!commit1Form(xFrm, needConfirmation, shouldCommit))
548 return false;
550 return true;
554 void SAL_CALL FormOperations::execute( ::sal_Int16 _nFeature ) throw (RuntimeException, IllegalArgumentException, SQLException, WrappedTargetException, std::exception)
556 SolarMutexGuard aSolarGuard;
557 MethodGuard aGuard( *this );
559 if ( ( _nFeature != FormFeature::DeleteRecord ) && ( _nFeature != FormFeature::UndoRecordChanges ) )
563 if(m_xController.is())
565 if(!commitFormAndSubforms(m_xController, lcl_needConfirmCommit( _nFeature )))
566 return;
568 else if(m_xCursor.is())
570 Reference< XForm > xForm(m_xCursor, UNO_QUERY);
571 assert(xForm.is());
572 if(!commitFormAndSubforms(xForm, lcl_needConfirmCommit( _nFeature )))
573 return;
575 else
577 SAL_WARN( "forms.runtime", "No cursor, but trying to execute form operation " << _nFeature );
583 switch ( _nFeature )
585 case FormFeature::MoveToFirst:
586 m_xCursor->first();
587 break;
589 case FormFeature::MoveToNext:
590 impl_moveRight_throw( );
591 break;
593 case FormFeature::MoveToPrevious:
594 impl_moveLeft_throw( );
595 break;
597 case FormFeature::MoveToLast:
600 // TODO: re-implement this .....
601 // run in an own thread if ...
602 // ... the data source is thread safe ...
603 sal_Bool bAllowOwnThread = sal_False;
604 if ( ::comphelper::hasProperty( PROPERTY_THREADSAFE, m_xCursorProperties ) )
605 m_xCursorProperties->getPropertyValue( PROPERTY_THREADSAFE ) >>= bAllowOwnThread;
607 // ... the record count is unknown
608 sal_Bool bNeedOwnThread sal_False;
609 if ( ::comphelper::hasProperty( PROPERTY_ROWCOUNTFINAL, m_xCursorProperties ) )
610 m_xCursorProperties->getPropertyValue( PROPERTY_ROWCOUNTFINAL ) >>= bNeedOwnThread;
612 if ( bNeedOwnThread && bAllowOwnThread )
614 else
616 m_xCursor->last();
618 break;
620 case FormFeature::ReloadForm:
621 if ( m_xLoadableForm.is() )
623 WaitObject aWO( NULL );
624 m_xLoadableForm->reload();
626 // refresh all controls in the form (and sub forms) which can be refreshed
627 // #i90914#
628 ::comphelper::IndexAccessIterator aIter( m_xLoadableForm );
629 Reference< XInterface > xElement( aIter.Next() );
630 while ( xElement.is() )
632 Reference< XRefreshable > xRefresh( xElement, UNO_QUERY );
633 if ( xRefresh.is() )
634 xRefresh->refresh();
635 xElement = aIter.Next();
638 break;
640 case FormFeature::RefreshCurrentControl:
642 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
643 OSL_ENSURE( xControlModelRefresh.is(), "FormOperations::execute: how did you reach this?" );
644 if ( xControlModelRefresh.is() )
645 xControlModelRefresh->refresh();
647 break;
649 case FormFeature::DeleteRecord:
651 sal_uInt32 nCount = impl_getRowCount_throw();
653 // next position
654 bool bLeft = m_xCursor->isLast() && ( nCount > 1 );
655 bool bRight= !m_xCursor->isLast();
656 bool bSuccess = false;
659 // ask for confirmation
660 Reference< XConfirmDeleteListener > xConfirmDelete( m_xController, UNO_QUERY );
662 if ( xConfirmDelete.is() )
664 RowChangeEvent aEvent;
665 aEvent.Source = Reference< XInterface >( m_xCursor, UNO_QUERY );
666 aEvent.Action = RowChangeAction::DELETE;
667 aEvent.Rows = 1;
668 bSuccess = xConfirmDelete->confirmDelete( aEvent );
671 // delete it
672 if ( bSuccess )
673 m_xUpdateCursor->deleteRow();
675 catch( const Exception& )
677 bSuccess = false;
680 if ( bSuccess )
682 if ( bLeft || bRight )
683 m_xCursor->relative( bRight ? 1 : -1 );
684 else
686 bool bCanInsert = ::dbtools::canInsert( m_xCursorProperties );
687 // is it possible to insert another record?
688 if ( bCanInsert )
689 m_xUpdateCursor->moveToInsertRow();
690 else
691 // move record to update status
692 m_xCursor->first();
696 break;
698 case FormFeature::SaveRecordChanges:
699 case FormFeature::UndoRecordChanges:
701 bool bInserting = impl_isInsertionRow_throw();
703 if ( FormFeature::UndoRecordChanges == _nFeature )
705 if ( !bInserting )
706 m_xUpdateCursor->cancelRowUpdates();
708 // reset all controls for this form
709 impl_resetAllControls_nothrow( );
711 if ( bInserting ) // back to insertion mode for this form
712 m_xUpdateCursor->moveToInsertRow();
714 else
716 if ( bInserting )
718 m_xUpdateCursor->insertRow();
719 m_xCursor->last();
721 else
722 m_xUpdateCursor->updateRow();
725 break;
727 case FormFeature::MoveToInsertRow:
728 // move to the last row before moving to the insert row
729 m_xCursor->last();
730 m_xUpdateCursor->moveToInsertRow();
731 break;
733 case FormFeature::RemoveFilterAndSort:
735 // simultaneously reset Filter and Order property
736 Reference< XMultiPropertySet > xProperties( m_xCursorProperties, UNO_QUERY );
737 OSL_ENSURE( xProperties.is(), "FormOperations::execute: no multi property access!" );
738 if ( xProperties.is() )
740 Sequence< OUString > aNames( 2 );
741 aNames[0] = PROPERTY_FILTER;
742 aNames[1] = PROPERTY_SORT;
744 Sequence< Any> aValues( 2 );
745 aValues[0] <<= OUString();
746 aValues[1] <<= OUString();
748 WaitObject aWO( NULL );
749 xProperties->setPropertyValues( aNames, aValues );
751 if ( m_xLoadableForm.is() )
752 m_xLoadableForm->reload();
755 break;
757 case FormFeature::ToggleApplyFilter:
758 if ( impl_commitCurrentControl_throw() && impl_commitCurrentRecord_throw() )
760 // simply toggle the value
761 bool bApplied = false;
762 m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
763 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( !bApplied ) );
765 // and reload
766 WaitObject aWO( NULL );
767 m_xLoadableForm->reload();
769 break;
771 case FormFeature::SortAscending:
772 impl_executeAutoSort_throw( true );
773 break;
775 case FormFeature::SortDescending:
776 impl_executeAutoSort_throw( false );
777 break;
779 case FormFeature::AutoFilter:
780 impl_executeAutoFilter_throw();
781 break;
783 case FormFeature::InteractiveSort:
784 impl_executeFilterOrSort_throw( false );
785 break;
787 case FormFeature::InteractiveFilter:
788 impl_executeFilterOrSort_throw( true );
789 break;
791 default:
793 sal_uInt16 nErrorResourceId = RID_STR_FEATURE_UNKNOWN;
794 if ( lcl_requiresArguments( _nFeature ) )
795 nErrorResourceId = RID_STR_FEATURE_REQUIRES_PARAMETERS;
796 else if ( !lcl_isExecutableFeature( _nFeature ) )
797 nErrorResourceId = RID_STR_FEATURE_NOT_EXECUTABLE;
798 throw IllegalArgumentException( FRM_RES_STRING( nErrorResourceId ), *this, 1 );
800 } // switch
802 catch( const RuntimeException& ) { throw; }
803 catch( const SQLException& ) { throw; }
804 catch( const Exception& )
806 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
809 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
813 void SAL_CALL FormOperations::executeWithArguments( ::sal_Int16 _nFeature, const Sequence< NamedValue >& _rArguments ) throw (RuntimeException, IllegalArgumentException, SQLException, WrappedTargetException, std::exception)
815 if ( !lcl_requiresArguments( _nFeature ) )
817 execute( _nFeature );
818 return;
821 SolarMutexGuard aSolarGuard;
822 MethodGuard aGuard( *this );
824 // at the moment we have only one feature which supports execution parameters
825 if ( !lcl_isExecutableFeature( _nFeature ) )
826 throw IllegalArgumentException( FRM_RES_STRING( RID_STR_FEATURE_NOT_EXECUTABLE ), *this, 1 );
828 switch ( _nFeature )
830 case FormFeature::MoveAbsolute:
832 sal_Int32 nPosition = -1;
834 ::comphelper::NamedValueCollection aArguments( _rArguments );
835 aArguments.get_ensureType( "Position", nPosition );
837 if ( nPosition < 1 )
838 nPosition = 1;
842 // commit before doing anything else
843 if ( m_xController.is() && !impl_commitCurrentControl_throw() )
844 return;
845 if ( !impl_commitCurrentRecord_throw() )
846 return;
848 sal_Int32 nCount = impl_getRowCount_throw();
849 bool bFinalCount = impl_isRowCountFinal_throw();
851 if ( bFinalCount && ( (sal_Int32)nPosition > nCount ) )
852 nPosition = nCount;
854 m_xCursor->absolute( nPosition );
856 catch( const RuntimeException& ) { throw; }
857 catch( const SQLException& ) { throw; }
858 catch( const Exception& )
860 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
863 break;
864 default:
865 throw IllegalArgumentException( FRM_RES_STRING( RID_STR_FEATURE_UNKNOWN ), *this, 1 );
866 } // switch
870 sal_Bool SAL_CALL FormOperations::commitCurrentRecord( sal_Bool& _out_rRecordInserted ) throw (RuntimeException, SQLException, std::exception)
872 MethodGuard aGuard( *this );
873 _out_rRecordInserted = sal_False;
875 return impl_commitCurrentRecord_throw( &_out_rRecordInserted );
879 bool FormOperations::impl_commitCurrentRecord_throw( sal_Bool* _pRecordInserted ) const
881 DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentRecord_throw: to be called within a MethodGuard'ed section only!" );
883 if ( !impl_hasCursor_nothrow() )
884 return false;
886 // nothing to do if the record is not modified
887 bool bResult = !impl_isModifiedRow_throw();
888 if ( !bResult )
890 // insert respectively update the row
891 if ( impl_isInsertionRow_throw() )
893 m_xUpdateCursor->insertRow();
894 if ( _pRecordInserted )
895 *_pRecordInserted = sal_True;
897 else
898 m_xUpdateCursor->updateRow();
899 bResult = true;
901 return bResult;
905 sal_Bool SAL_CALL FormOperations::commitCurrentControl() throw (RuntimeException, SQLException, std::exception)
907 MethodGuard aGuard( *this );
908 return impl_commitCurrentControl_throw();
912 bool FormOperations::impl_commitCurrentControl_throw() const
914 DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentControl_throw: to be called within a MethodGuard'ed section only!" );
915 OSL_PRECOND( m_xController.is(), "FormOperations::commitCurrentControl: no controller!" );
916 if ( !m_xController.is() )
917 return false;
919 bool bSuccess = false;
922 Reference< XControl > xCurrentControl( m_xController->getCurrentControl() );
924 // check whether the control is locked
925 Reference< XBoundControl > xCheckLock( xCurrentControl, UNO_QUERY );
926 bool bControlIsLocked = xCheckLock.is() && xCheckLock->getLock();
928 // commit if necessary
929 bSuccess = true;
930 if ( xCurrentControl.is() && !bControlIsLocked )
932 // both the control and its model can be committable, so try both
933 Reference< XBoundComponent > xBound( xCurrentControl, UNO_QUERY );
934 if ( !xBound.is() )
935 xBound.set(xCurrentControl->getModel(), css::uno::UNO_QUERY);
936 // and now really commit
937 if ( xBound.is() )
938 bSuccess = xBound->commit();
942 catch( const RuntimeException& ) { throw; }
943 catch( const SQLException& ) { throw; }
944 catch( const Exception& )
946 DBG_UNHANDLED_EXCEPTION();
947 bSuccess = false;
950 return bSuccess;
954 sal_Bool SAL_CALL FormOperations::isInsertionRow() throw (RuntimeException, WrappedTargetException, std::exception)
956 bool bIs = false;
959 bIs = impl_isInsertionRow_throw();
961 catch( const RuntimeException& ) { throw; }
962 catch( const Exception& )
964 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
966 return bIs;
970 sal_Bool SAL_CALL FormOperations::isModifiedRow() throw (RuntimeException, WrappedTargetException, std::exception)
972 bool bIs = false;
975 bIs = impl_isModifiedRow_throw();
977 catch( const RuntimeException& ) { throw; }
978 catch( const Exception& )
980 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
982 return bIs;
986 void SAL_CALL FormOperations::cursorMoved( const EventObject& /*_Event*/ ) throw (RuntimeException, std::exception)
988 MethodGuard aGuard( *this );
989 m_bActiveControlModified = false;
991 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
995 void SAL_CALL FormOperations::rowChanged( const EventObject& /*_Event*/ ) throw (RuntimeException, std::exception)
997 // not interested in
1001 void SAL_CALL FormOperations::rowSetChanged( const EventObject& /*_Event*/ ) throw (RuntimeException, std::exception)
1003 // not interested in
1007 void SAL_CALL FormOperations::modified( const EventObject& /*_Source*/ ) throw( RuntimeException, std::exception )
1009 MethodGuard aGuard( *this );
1011 OSL_ENSURE( m_xCursor.is(), "FormOperations::modified: already disposed!" );
1012 if ( !m_bActiveControlModified )
1014 m_bActiveControlModified = true;
1015 impl_invalidateModifyDependentFeatures_nothrow( aGuard );
1020 void SAL_CALL FormOperations::propertyChange( const PropertyChangeEvent& _rEvent ) throw (RuntimeException, std::exception)
1022 MethodGuard aGuard( *this );
1024 if ( m_xCursor.is() && ( m_xCursor == _rEvent.Source ) )
1026 if ( ( _rEvent.PropertyName == PROPERTY_ISMODIFIED )
1027 || ( _rEvent.PropertyName == PROPERTY_ISNEW )
1030 bool bIs = false;
1031 if ( ( _rEvent.NewValue >>= bIs ) && !bIs )
1032 m_bActiveControlModified = false;
1034 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
1037 if ( m_xParser.is() && ( m_xCursor == _rEvent.Source ) )
1041 OUString sNewValue;
1042 _rEvent.NewValue >>= sNewValue;
1043 if ( _rEvent.PropertyName == PROPERTY_ACTIVECOMMAND )
1045 m_xParser->setElementaryQuery( sNewValue );
1047 else if ( _rEvent.PropertyName == PROPERTY_FILTER )
1049 if ( m_xParser->getFilter() != sNewValue )
1050 m_xParser->setFilter( sNewValue );
1052 else if ( _rEvent.PropertyName == PROPERTY_SORT )
1054 _rEvent.NewValue >>= sNewValue;
1055 if ( m_xParser->getOrder() != sNewValue )
1056 m_xParser->setOrder( sNewValue );
1059 catch( const Exception& )
1061 OSL_FAIL( "FormOperations::propertyChange: caught an exception while updating the parser!" );
1063 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
1068 void SAL_CALL FormOperations::disposing( const EventObject& /*_Source*/ ) throw (RuntimeException, std::exception)
1070 // TODO: should we react on this? Or is this the responsibility of our owner to dispose us?
1074 void SAL_CALL FormOperations::disposing()
1076 ::osl::MutexGuard aGuard( m_aMutex );
1078 impl_disposeParser_nothrow();
1082 // revoke various listeners
1083 if ( m_xCursor.is() )
1084 m_xCursor->removeRowSetListener( this );
1086 if ( m_xCursorProperties.is() )
1088 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISMODIFIED,this );
1089 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISNEW, this );
1092 Reference< XModifyBroadcaster > xBroadcaster( m_xController, UNO_QUERY );
1093 if ( xBroadcaster.is() )
1094 xBroadcaster->removeModifyListener( this );
1096 catch( const Exception& )
1098 DBG_UNHANDLED_EXCEPTION();
1101 m_xController.clear();
1102 m_xCursor.clear();
1103 m_xUpdateCursor.clear();
1104 m_xCursorProperties.clear();
1105 m_xLoadableForm.clear();
1106 m_xFeatureInvalidation.clear();
1108 m_bActiveControlModified = true;
1112 void FormOperations::impl_checkDisposed_throw() const
1114 if ( impl_isDisposed_nothrow() )
1115 throw DisposedException( OUString(), *const_cast< FormOperations* >( this ) );
1119 void FormOperations::impl_initFromController_throw()
1121 OSL_PRECOND( m_xController.is(), "FormOperations::impl_initFromController_throw: invalid controller!" );
1122 m_xCursor.set(m_xController->getModel(), css::uno::UNO_QUERY);
1123 if ( !m_xCursor.is() )
1124 throw IllegalArgumentException( OUString(), *this, 0 );
1126 impl_initFromForm_throw();
1128 Reference< XModifyBroadcaster > xBroadcaster( m_xController, UNO_QUERY );
1129 if ( xBroadcaster.is() )
1130 xBroadcaster->addModifyListener( this );
1134 void FormOperations::impl_initFromForm_throw()
1136 OSL_PRECOND( m_xCursor.is(), "FormOperations::impl_initFromForm_throw: invalid form!" );
1137 m_xCursorProperties.set(m_xCursor, css::uno::UNO_QUERY);
1138 m_xUpdateCursor.set(m_xCursor, css::uno::UNO_QUERY);
1139 m_xLoadableForm.set(m_xCursor, css::uno::UNO_QUERY);
1141 if ( !m_xCursor.is() || !m_xCursorProperties.is() || !m_xLoadableForm.is() )
1142 throw IllegalArgumentException( OUString(), *this, 0 );
1144 m_xCursor->addRowSetListener( this );
1145 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISMODIFIED,this );
1146 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISNEW, this );
1150 void FormOperations::createWithFormController( const Reference< XFormController >& _rxController )
1152 m_xController = _rxController;
1153 if ( !m_xController.is() )
1154 throw IllegalArgumentException( OUString(), *this, 0 );
1156 impl_initFromController_throw();
1158 m_bConstructed = true;
1162 void FormOperations::createWithForm( const Reference< XForm >& _rxForm )
1164 m_xCursor.set(_rxForm, css::uno::UNO_QUERY);
1165 if ( !m_xCursor.is() )
1166 throw IllegalArgumentException( OUString(), *this, 0 );
1168 impl_initFromForm_throw();
1170 m_bConstructed = true;
1174 void FormOperations::impl_invalidateAllSupportedFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1176 if ( !m_xFeatureInvalidation.is() )
1177 // nobody's interested in ...
1178 return;
1180 Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1181 _rClearForCallback.clear();
1182 xInvalidation->invalidateAllFeatures();
1186 void FormOperations::impl_invalidateModifyDependentFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1188 if ( !m_xFeatureInvalidation.is() )
1189 // nobody's interested in ...
1190 return;
1192 static Sequence< sal_Int16 > s_aModifyDependentFeatures;
1193 if ( s_aModifyDependentFeatures.getLength() == 0 )
1195 sal_Int16 pModifyDependentFeatures[] =
1197 FormFeature::MoveToNext,
1198 FormFeature::MoveToInsertRow,
1199 FormFeature::SaveRecordChanges,
1200 FormFeature::UndoRecordChanges
1202 size_t nFeatureCount = SAL_N_ELEMENTS( pModifyDependentFeatures );
1203 s_aModifyDependentFeatures = Sequence< sal_Int16 >( pModifyDependentFeatures, nFeatureCount );
1206 Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1207 _rClearForCallback.clear();
1209 xInvalidation->invalidateFeatures( s_aModifyDependentFeatures );
1213 void FormOperations::impl_ensureInitializedParser_nothrow()
1215 OSL_PRECOND( m_xCursorProperties.is(), "FormOperations::impl_ensureInitializedParser_nothrow: we're disposed!" );
1216 if ( m_bInitializedParser )
1217 return;
1221 bool bUseEscapeProcessing = false;
1222 m_xCursorProperties->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bUseEscapeProcessing;
1223 if ( bUseEscapeProcessing )
1225 Reference< XMultiServiceFactory > xFactory( ::dbtools::getConnection( m_xCursor ), UNO_QUERY );
1226 if ( xFactory.is() )
1228 m_xParser.set( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"), UNO_QUERY );
1229 OSL_ENSURE( m_xParser.is(), "FormOperations::impl_ensureInitializedParser_nothrow: factory did not create a parser for us!" );
1233 if ( m_xParser.is() )
1235 if ( m_xLoadableForm.is() && m_xLoadableForm->isLoaded() )
1237 OUString sStatement;
1238 OUString sFilter;
1239 OUString sSort;
1241 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sStatement;
1242 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
1243 m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sSort;
1245 m_xParser->setElementaryQuery( sStatement );
1246 m_xParser->setFilter ( sFilter );
1247 m_xParser->setOrder ( sSort );
1250 // start listening at the order/sort properties at the form, so
1251 // we can keep our parser in sync
1252 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1253 m_xCursorProperties->addPropertyChangeListener( PROPERTY_FILTER, this );
1254 m_xCursorProperties->addPropertyChangeListener( PROPERTY_SORT, this );
1257 catch( const Exception& )
1259 OSL_FAIL( "FormOperations::impl_ensureInitializedParser_nothrow: caught an exception!" );
1262 m_bInitializedParser = true;
1266 void FormOperations::impl_disposeParser_nothrow()
1270 // if we have a parser (and a cursor), then we're listening at the cursor's
1271 // properties to keep the parser in sync with the cursor
1272 if ( m_xParser.is() && m_xCursorProperties.is() )
1274 m_xCursorProperties->removePropertyChangeListener( PROPERTY_FILTER, this );
1275 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1276 m_xCursorProperties->removePropertyChangeListener( PROPERTY_SORT, this );
1279 Reference< XComponent > xParserComp( m_xParser, UNO_QUERY );
1280 if ( xParserComp.is() )
1281 xParserComp->dispose();
1282 m_xParser.clear();
1284 m_bInitializedParser = false;
1286 catch( const Exception& )
1288 OSL_FAIL( "FormOperations::impl_disposeParser_nothrow: caught an exception!" );
1293 bool FormOperations::impl_canMoveLeft_throw( ) const
1295 if ( !impl_hasCursor_nothrow() )
1296 return false;
1298 return impl_getRowCount_throw() && ( !m_xCursor->isFirst() || impl_isInsertionRow_throw() );
1302 bool FormOperations::impl_canMoveRight_throw( ) const
1304 if ( !impl_hasCursor_nothrow() )
1305 return false;
1307 bool bIsNew = impl_isInsertionRow_throw();
1309 if ( impl_getRowCount_throw() && !m_xCursor->isLast() && !bIsNew )
1310 return true;
1312 if ( ::dbtools::canInsert( m_xCursorProperties ) )
1313 if ( !bIsNew || impl_isModifiedRow_throw() )
1314 return true;
1316 if ( bIsNew && m_bActiveControlModified )
1317 return true;
1319 return false;
1323 bool FormOperations::impl_isInsertionRow_throw() const
1325 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISNEW, false );
1329 sal_Int32 FormOperations::impl_getRowCount_throw() const
1331 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNT, (sal_Int32)0 );
1334 bool FormOperations::impl_isRowCountFinal_throw() const
1336 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNTFINAL, false );
1340 bool FormOperations::impl_isModifiedRow_throw() const
1342 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISMODIFIED, false );
1346 bool FormOperations::impl_isParseable_throw() const
1348 const_cast< FormOperations* >( this )->impl_ensureInitializedParser_nothrow();
1349 return m_xParser.is() && !m_xParser->getQuery().isEmpty();
1353 bool FormOperations::impl_hasFilterOrOrder_throw() const
1355 return impl_isParseable_throw() && ( !m_xParser->getFilter().isEmpty() || !m_xParser->getOrder().isEmpty() );
1359 bool FormOperations::impl_isInsertOnlyForm_throw() const
1361 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_INSERTONLY, true );
1365 Reference< XControlModel > FormOperations::impl_getCurrentControlModel_throw() const
1367 Reference< XControl > xControl( m_xController->getCurrentControl() );
1369 // special handling for grid controls
1370 Reference< XGrid > xGrid( xControl, UNO_QUERY );
1371 Reference< XControlModel > xControlModel;
1373 if ( xGrid.is() )
1375 Reference< XIndexAccess > xColumns( xControl->getModel(), UNO_QUERY_THROW );
1376 sal_Int16 nCurrentPos = xGrid->getCurrentColumnPosition();
1377 nCurrentPos = impl_gridView2ModelPos_nothrow( xColumns, nCurrentPos );
1379 if ( nCurrentPos != (sal_Int16)-1 )
1380 xColumns->getByIndex( nCurrentPos ) >>= xControlModel;
1382 else if ( xControl.is() )
1384 xControlModel = xControl->getModel();
1386 return xControlModel;
1390 Reference< XPropertySet > FormOperations::impl_getCurrentBoundField_nothrow( ) const
1392 OSL_PRECOND( m_xController.is(), "FormOperations::impl_getCurrentBoundField_nothrow: no controller -> no control!" );
1393 if ( !m_xController.is() )
1394 return NULL;
1396 Reference< XPropertySet > xField;
1399 Reference< XPropertySet > xControlModel( impl_getCurrentControlModel_throw(), UNO_QUERY );
1401 if ( xControlModel.is() && ::comphelper::hasProperty( PROPERTY_BOUNDFIELD, xControlModel ) )
1402 xControlModel->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xField;
1405 catch( const Exception& )
1407 DBG_UNHANDLED_EXCEPTION();
1410 return xField;
1414 sal_Int16 FormOperations::impl_gridView2ModelPos_nothrow( const Reference< XIndexAccess >& _rxColumns, sal_Int16 _nViewPos )
1416 OSL_PRECOND( _rxColumns.is(), "FormOperations::impl_gridView2ModelPos_nothrow: invalid columns container!" );
1419 // loop through all columns
1420 sal_Int16 col = 0;
1421 Reference< XPropertySet > xCol;
1422 bool bHidden( false );
1423 for ( col = 0; col < _rxColumns->getCount(); ++col )
1425 _rxColumns->getByIndex( col ) >>= xCol;
1426 OSL_VERIFY( xCol->getPropertyValue( PROPERTY_HIDDEN ) >>= bHidden );
1427 if ( bHidden )
1428 continue;
1430 // for every visible col : if nViewPos is greater zero, decrement it, else we
1431 // have found the model position
1432 if ( !_nViewPos )
1433 break;
1434 else
1435 --_nViewPos;
1437 if ( col < _rxColumns->getCount() )
1438 return col;
1440 catch( const Exception& )
1442 DBG_UNHANDLED_EXCEPTION();
1444 return (sal_Int16)-1;
1448 bool FormOperations::impl_moveLeft_throw( ) const
1450 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveLeft_throw: no cursor!" );
1451 if ( !impl_hasCursor_nothrow() )
1452 return false;
1454 sal_Bool bRecordInserted = sal_False;
1455 bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1457 if ( !bSuccess )
1458 return false;
1460 if ( bRecordInserted )
1462 // retrieve the bookmark of the new record and move to the record preceding this bookmark
1463 Reference< XRowLocate > xLocate( m_xCursor, UNO_QUERY );
1464 OSL_ENSURE( xLocate.is(), "FormOperations::impl_moveLeft_throw: no XRowLocate!" );
1465 if ( xLocate.is() )
1466 xLocate->moveRelativeToBookmark( xLocate->getBookmark(), -1 );
1468 else
1470 if ( impl_isInsertionRow_throw() )
1472 // we assume that the inserted record is now the last record in the
1473 // result set
1474 m_xCursor->last();
1476 else
1477 m_xCursor->previous();
1480 return true;
1484 bool FormOperations::impl_moveRight_throw( ) const
1486 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveRight_throw: no cursor!" );
1487 if ( !impl_hasCursor_nothrow() )
1488 return false;
1490 sal_Bool bRecordInserted = sal_False;
1491 bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1493 if ( !bSuccess )
1494 return false;
1496 if ( bRecordInserted )
1498 // go to insert row
1499 m_xUpdateCursor->moveToInsertRow();
1501 else
1503 if ( m_xCursor->isLast() )
1504 m_xUpdateCursor->moveToInsertRow();
1505 else
1506 (void)m_xCursor->next();
1509 return true;
1513 void FormOperations::impl_resetAllControls_nothrow() const
1515 Reference< XIndexAccess > xContainer( m_xCursor, UNO_QUERY );
1516 if ( !xContainer.is() )
1517 return;
1521 Reference< XReset > xReset;
1522 sal_Int32 nCount( xContainer->getCount() );
1523 for ( sal_Int32 i = 0; i < nCount; ++i )
1525 if ( xContainer->getByIndex( i ) >>= xReset )
1527 // no resets on sub forms
1528 Reference< XForm > xAsForm( xReset, UNO_QUERY );
1529 if ( !xAsForm.is() )
1530 xReset->reset();
1534 catch( const Exception& )
1536 DBG_UNHANDLED_EXCEPTION();
1541 void FormOperations::impl_executeAutoSort_throw( bool _bUp ) const
1543 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoSort_throw: need a controller for this!" );
1544 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoSort_throw: need a cursor for this!" );
1545 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoSort_throw: need a parseable statement for this!" );
1546 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1547 return;
1551 Reference< XControl > xControl = m_xController->getCurrentControl();
1552 if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1553 return;
1555 Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1556 if ( !xBoundField.is() )
1557 return;
1559 OUString sOriginalSort;
1560 m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sOriginalSort;
1562 // automatic sort by field is expected to always resets the previous sort order
1563 m_xParser->setOrder( OUString() );
1565 impl_appendOrderByColumn_throw aAction(this, xBoundField, _bUp);
1566 impl_doActionInSQLContext_throw(aAction, RID_STR_COULD_NOT_SET_ORDER );
1568 WaitObject aWO( NULL );
1571 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1572 m_xLoadableForm->reload();
1574 catch( const Exception& )
1576 OSL_FAIL( "FormOperations::impl_executeAutoSort_throw: caught an exception while setting the parser properties!" );
1580 if ( !m_xLoadableForm->isLoaded() )
1581 { // something went wrong -> restore the original state
1584 m_xParser->setOrder( sOriginalSort );
1585 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1586 m_xLoadableForm->reload();
1588 catch( const Exception& )
1590 OSL_FAIL( "FormOperations::impl_executeAutoSort_throw: could not reset the form to it's original state!" );
1595 catch( const RuntimeException& ) { throw; }
1596 catch( const SQLException& ) { throw; }
1597 catch( const Exception& )
1599 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1604 void FormOperations::impl_executeAutoFilter_throw( ) const
1606 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoFilter_throw: need a controller for this!" );
1607 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoFilter_throw: need a cursor for this!" );
1608 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoFilter_throw: need a parseable statement for this!" );
1609 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1610 return;
1614 Reference< XControl > xControl = m_xController->getCurrentControl();
1615 if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1616 return;
1618 Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1619 if ( !xBoundField.is() )
1620 return;
1622 OUString sOriginalFilter;
1623 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
1624 bool bApplied = true;
1625 m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
1627 // if we have a filter, but it's not applied, then we have to overwrite it, else append one
1628 if ( !bApplied )
1629 m_xParser->setFilter( OUString() );
1631 impl_appendFilterByColumn_throw aAction(this, xBoundField);
1632 impl_doActionInSQLContext_throw( aAction, RID_STR_COULD_NOT_SET_FILTER );
1634 WaitObject aWO( NULL );
1637 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1638 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( true ) );
1640 m_xLoadableForm->reload();
1642 catch( const Exception& )
1644 OSL_FAIL( "FormOperations::impl_executeAutoFilter_throw: caught an exception while setting the parser properties!" );
1648 if ( !m_xLoadableForm->isLoaded() )
1649 { // something went wrong -> restore the original state
1652 m_xParser->setOrder( sOriginalFilter );
1653 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( bApplied ) );
1654 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1655 m_xLoadableForm->reload();
1657 catch( const Exception& )
1659 OSL_FAIL( "FormOperations::impl_executeAutoFilter_throw: could not reset the form to it's original state!" );
1664 catch( const RuntimeException& ) { throw; }
1665 catch( const SQLException& ) { throw; }
1666 catch( const Exception& )
1668 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1673 void FormOperations::impl_executeFilterOrSort_throw( bool _bFilter ) const
1675 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeFilterOrSort_throw: need a controller for this!" );
1676 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeFilterOrSort_throw: need a cursor for this!" );
1677 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeFilterOrSort_throw: need a parseable statement for this!" );
1678 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1679 return;
1681 if ( !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1682 return;
1685 Reference< XExecutableDialog> xDialog;
1686 if ( _bFilter )
1688 xDialog = com::sun::star::sdb::FilterDialog::createWithQuery(m_xContext, m_xParser, m_xCursor,
1689 Reference<com::sun::star::awt::XWindow>());
1691 else
1693 xDialog = com::sun::star::sdb::OrderDialog::createWithQuery(m_xContext, m_xParser, m_xCursorProperties);
1697 if ( RET_OK == xDialog->execute() )
1699 WaitObject aWO( NULL );
1700 if ( _bFilter )
1701 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1702 else
1703 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1704 m_xLoadableForm->reload();
1708 catch( const RuntimeException& ) { throw; }
1709 catch( const SQLException& ) { throw; }
1710 catch( const Exception& )
1712 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1717 template < typename FunctObj >
1718 void FormOperations::impl_doActionInSQLContext_throw( FunctObj f, sal_uInt16 _nErrorResourceId ) const
1722 f();
1724 #if HAVE_FEATURE_DBCONNECTIVITY
1725 catch( const SQLException& e )
1727 (void)e;
1728 if ( !_nErrorResourceId )
1729 // no information to prepend
1730 throw;
1732 SQLExceptionInfo aInfo( ::cppu::getCaughtException() );
1733 OUString sAdditionalError( FRM_RES_STRING( _nErrorResourceId ) );
1734 aInfo.prepend( sAdditionalError );
1735 aInfo.doThrow();
1737 #endif
1738 catch( const RuntimeException& ) { throw; }
1739 catch( const Exception& )
1741 OUString sAdditionalError( FRM_RES_STRING( _nErrorResourceId ) );
1742 throw WrappedTargetException( sAdditionalError, *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1747 } // namespace frm
1750 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* SAL_CALL
1751 com_sun_star_comp_forms_FormOperations_get_implementation(css::uno::XComponentContext* context,
1752 css::uno::Sequence<css::uno::Any> const &)
1754 return cppu::acquire(new frm::FormOperations(context));
1757 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */