Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / forms / source / runtime / formoperations.cxx
blob744a11b77ac304b7cb5577873ab7585e871aebb5
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::ui::dialogs::XExecutableDialog;
111 using ::com::sun::star::beans::NamedValue;
112 using ::com::sun::star::util::XRefreshable;
113 using ::com::sun::star::awt::XControlModel;
115 namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
116 namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
118 FormOperations::FormOperations( const Reference< XComponentContext >& _rxContext )
119 :FormOperations_Base( m_aMutex )
120 ,m_xContext( _rxContext )
121 ,m_bInitializedParser( false )
122 ,m_bActiveControlModified( false )
123 ,m_bConstructed( false )
124 #ifdef DBG_UTIL
125 ,m_nMethodNestingLevel( 0 )
126 #endif
130 FormOperations::~FormOperations()
134 OUString FormOperations::getImplementationName_Static( ) throw(RuntimeException)
136 return OUString( "com.sun.star.comp.forms.FormOperations" );
139 Sequence< OUString > FormOperations::getSupportedServiceNames_Static( ) throw(RuntimeException)
141 Sequence< OUString > aNames { "com.sun.star.form.runtime.FormOperations" };
142 return aNames;
145 void SAL_CALL FormOperations::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException, std::exception)
147 if ( m_bConstructed )
148 throw AlreadyInitializedException();
150 if ( _arguments.getLength() == 1 )
152 Reference< XFormController > xController;
153 Reference< XForm > xForm;
154 if ( _arguments[0] >>= xController )
155 createWithFormController( xController );
156 else if ( _arguments[0] >>= xForm )
157 createWithForm( xForm );
158 else
159 throw IllegalArgumentException( OUString(), *this, 1 );
160 return;
163 throw IllegalArgumentException( OUString(), *this, 0 );
166 OUString SAL_CALL FormOperations::getImplementationName( ) throw (RuntimeException, std::exception)
168 return getImplementationName_Static();
171 sal_Bool SAL_CALL FormOperations::supportsService( const OUString& ServiceName ) throw (RuntimeException, std::exception)
173 return cppu::supportsService(this, ServiceName);
176 Sequence< OUString > SAL_CALL FormOperations::getSupportedServiceNames( ) throw (RuntimeException, std::exception)
178 return getSupportedServiceNames_Static();
181 Reference< XRowSet > SAL_CALL FormOperations::getCursor() throw (RuntimeException, std::exception)
183 MethodGuard aGuard( *this );
184 return m_xCursor;
187 Reference< XResultSetUpdate > SAL_CALL FormOperations::getUpdateCursor() throw (RuntimeException, std::exception)
189 MethodGuard aGuard( *this );
190 return m_xUpdateCursor;
194 Reference< XFormController > SAL_CALL FormOperations::getController() throw (RuntimeException, std::exception)
196 MethodGuard aGuard( *this );
197 return m_xController;
201 Reference< XFeatureInvalidation > SAL_CALL FormOperations::getFeatureInvalidation() throw (RuntimeException, std::exception)
203 MethodGuard aGuard( *this );
204 return m_xFeatureInvalidation;
208 void SAL_CALL FormOperations::setFeatureInvalidation( const Reference< XFeatureInvalidation > & _rxFeatureInvalidation ) throw (RuntimeException, std::exception)
210 MethodGuard aGuard( *this );
211 m_xFeatureInvalidation = _rxFeatureInvalidation;
215 FeatureState SAL_CALL FormOperations::getState( ::sal_Int16 _nFeature ) throw (RuntimeException, std::exception)
217 MethodGuard aGuard( *this );
219 FeatureState aState;
220 aState.Enabled = false;
224 // some checks for basic pre-requisites
225 if ( !m_xLoadableForm.is()
226 || !m_xLoadableForm->isLoaded()
227 || !m_xCursorProperties.is()
230 return aState;
233 switch ( _nFeature )
235 case FormFeature::MoveToFirst:
236 case FormFeature::MoveToPrevious:
237 aState.Enabled = impl_canMoveLeft_throw( );
238 break;
240 case FormFeature::MoveToNext:
241 aState.Enabled = impl_canMoveRight_throw();
242 break;
244 case FormFeature::MoveToLast:
245 aState.Enabled = impl_getRowCount_throw() && ( !m_xCursor->isLast() || impl_isInsertionRow_throw() );
246 break;
248 case FormFeature::DeleteRecord:
249 // already deleted ?
250 if ( m_xCursor->rowDeleted() )
251 aState.Enabled = false;
252 else
254 // allowed to delete the row ?
255 aState.Enabled = !impl_isInsertionRow_throw() && ::dbtools::canDelete( m_xCursorProperties );
257 break;
259 case FormFeature::MoveToInsertRow:
260 // if we are inserting we can move to the next row if the current record or control is modified
261 aState.Enabled = impl_isInsertionRow_throw()
262 ? impl_isModifiedRow_throw() || m_bActiveControlModified
263 : ::dbtools::canInsert( m_xCursorProperties );
264 break;
266 case FormFeature::ReloadForm:
268 // there must be an active connection
269 Reference< XRowSet > xCursorRowSet( m_xCursor, UNO_QUERY );
270 aState.Enabled = ::dbtools::getConnection( xCursorRowSet ).is();
272 // and an active command
273 OUString sActiveCommand;
274 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sActiveCommand;
275 aState.Enabled = aState.Enabled && !sActiveCommand.isEmpty();
277 break;
279 case FormFeature::RefreshCurrentControl:
281 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
282 aState.Enabled = xControlModelRefresh.is();
284 break;
286 case FormFeature::SaveRecordChanges:
287 case FormFeature::UndoRecordChanges:
288 aState.Enabled = impl_isModifiedRow_throw() || m_bActiveControlModified;
289 break;
291 case FormFeature::RemoveFilterAndSort:
292 if ( impl_isParseable_throw() && impl_hasFilterOrOrder_throw() )
293 aState.Enabled = !impl_isInsertOnlyForm_throw();
294 break;
296 case FormFeature::SortAscending:
297 case FormFeature::SortDescending:
298 case FormFeature::AutoFilter:
299 if ( m_xController.is() && impl_isParseable_throw() )
301 bool bIsDeleted = m_xCursor->rowDeleted();
303 if ( !bIsDeleted && !impl_isInsertOnlyForm_throw() )
305 Reference< XPropertySet > xBoundField = impl_getCurrentBoundField_nothrow( );
306 if ( xBoundField.is() )
307 xBoundField->getPropertyValue( PROPERTY_SEARCHABLE ) >>= aState.Enabled;
310 break;
312 case FormFeature::InteractiveSort:
313 case FormFeature::InteractiveFilter:
314 if ( impl_isParseable_throw() )
315 aState.Enabled = !impl_isInsertOnlyForm_throw();
316 break;
318 case FormFeature::ToggleApplyFilter:
320 OUString sFilter;
321 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
322 if ( !sFilter.isEmpty() )
324 aState.State = m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER );
325 aState.Enabled = !impl_isInsertOnlyForm_throw();
327 else
328 aState.State <<= false;
330 break;
332 case FormFeature::MoveAbsolute:
334 sal_Int32 nPosition = m_xCursor->getRow();
335 bool bIsNew = impl_isInsertionRow_throw();
336 sal_Int32 nCount = impl_getRowCount_throw();
337 bool bFinalCount = impl_isRowCountFinal_throw();
339 if ( ( nPosition >= 0 ) || bIsNew )
341 if ( bFinalCount )
343 // special case: there are no records at all, and we
344 // can't insert records -> disabled
345 if ( !nCount && !::dbtools::canInsert( m_xCursorProperties ) )
347 aState.Enabled = false;
349 else
351 if ( bIsNew )
352 nPosition = ++nCount;
353 aState.State <<= (sal_Int32)nPosition;
354 aState.Enabled = true;
357 else
359 aState.State <<= (sal_Int32)nPosition;
360 aState.Enabled = true;
364 break;
366 case FormFeature::TotalRecords:
368 bool bIsNew = impl_isInsertionRow_throw();
369 sal_Int32 nCount = impl_getRowCount_throw();
370 bool bFinalCount = impl_isRowCountFinal_throw();
372 if ( bIsNew )
373 ++nCount;
375 OUString sValue = OUString::number( nCount );
376 if ( !bFinalCount )
377 sValue += " *";
379 aState.State <<= sValue;
380 aState.Enabled = true;
382 break;
384 default:
385 OSL_FAIL( "FormOperations::getState: unknown feature id!" );
386 break;
389 catch( const Exception& )
391 OSL_FAIL( "FormOperations::getState: caught an exception!" );
394 return aState;
398 sal_Bool SAL_CALL FormOperations::isEnabled( ::sal_Int16 _nFeature ) throw (RuntimeException, std::exception)
400 MethodGuard aGuard( *this );
402 FeatureState aState( getState( _nFeature ) );
403 return aState.Enabled;
407 namespace
409 bool lcl_needConfirmCommit( sal_Int32 _nFeature )
411 return ( ( _nFeature == FormFeature::ReloadForm )
412 || ( _nFeature == FormFeature::RemoveFilterAndSort )
413 || ( _nFeature == FormFeature::ToggleApplyFilter )
414 || ( _nFeature == FormFeature::SortAscending )
415 || ( _nFeature == FormFeature::SortDescending )
416 || ( _nFeature == FormFeature::AutoFilter )
417 || ( _nFeature == FormFeature::InteractiveSort )
418 || ( _nFeature == FormFeature::InteractiveFilter )
421 bool lcl_requiresArguments( sal_Int32 _nFeature )
423 return ( _nFeature == FormFeature::MoveAbsolute );
425 bool lcl_isExecutableFeature( sal_Int32 _nFeature )
427 return ( _nFeature != FormFeature::TotalRecords );
430 template < typename TYPE >
431 TYPE lcl_safeGetPropertyValue_throw( const Reference< XPropertySet >& _rxProperties, const OUString& _rPropertyName, TYPE Default )
433 TYPE value( Default );
434 OSL_PRECOND( _rxProperties.is(), "FormOperations::<foo>: no cursor (already disposed?)!" );
435 if ( _rxProperties.is() )
436 OSL_VERIFY( _rxProperties->getPropertyValue( _rPropertyName ) >>= value );
437 return value;
440 // returns false if parent should *abort* (user pressed cancel)
441 bool checkConfirmation(bool &needConfirmation, bool &shouldCommit)
443 if(needConfirmation)
445 // TODO: shouldn't this be done with an interaction handler?
446 ScopedVclPtrInstance< QueryBox > aQuery( nullptr, WB_YES_NO_CANCEL | WB_DEF_YES, FRM_RES_STRING( RID_STR_QUERY_SAVE_MODIFIED_ROW ) );
447 switch ( aQuery->Execute() )
449 case RET_NO:
450 shouldCommit = false;
451 SAL_FALLTHROUGH; // don't ask again!
452 case RET_YES:
453 needConfirmation = false;
454 return true;
455 case RET_CANCEL:
456 return false;
459 return true;
462 bool commit1Form(const Reference< XFormController >& xCntrl, bool &needConfirmation, bool &shouldCommit)
464 Reference< XFormOperations > xFrmOps(xCntrl->getFormOperations());
465 if (!xFrmOps->commitCurrentControl())
466 return false;
468 if(xFrmOps->isModifiedRow())
470 if(!checkConfirmation(needConfirmation, shouldCommit))
471 return false;
472 sal_Bool bTmp;
473 if (shouldCommit && !xFrmOps->commitCurrentRecord(bTmp))
474 return false;
476 return true;
479 bool commitFormAndSubforms(const Reference< XFormController >& xCntrl, bool needConfirmation)
481 bool shouldCommit(true);
482 assert(xCntrl.is());
483 Reference< XIndexAccess > xSubForms(xCntrl, UNO_QUERY);
484 assert(xSubForms.is());
485 if(xSubForms.is())
487 const sal_Int32 cnt = xSubForms->getCount();
488 for(int i=0; i < cnt; ++i)
490 Reference< XFormController > xSubForm(xSubForms->getByIndex(i), UNO_QUERY);
491 assert(xSubForm.is());
492 if (xSubForm.is())
494 if (!commit1Form(xSubForm, needConfirmation, shouldCommit))
495 return false;
500 if(!commit1Form(xCntrl, needConfirmation, shouldCommit))
501 return false;
503 return true;
506 bool commit1Form(const Reference< XForm >& xFrm, bool &needConfirmation, bool &shouldCommit)
508 Reference< XPropertySet > xProps(xFrm, UNO_QUERY_THROW);
509 // nothing to do if the record is not modified
510 if(!lcl_safeGetPropertyValue_throw( xProps, PROPERTY_ISMODIFIED, false ))
511 return true;
513 if(!checkConfirmation(needConfirmation, shouldCommit))
514 return false;
515 if(shouldCommit)
517 Reference< XResultSetUpdate > xUpd(xFrm, UNO_QUERY_THROW);
518 // insert respectively update the row
519 if ( lcl_safeGetPropertyValue_throw( xProps, PROPERTY_ISNEW, false ) )
520 xUpd->insertRow();
521 else
522 xUpd->updateRow();
524 return true;
527 bool commitFormAndSubforms(const Reference< XForm >& xFrm, bool needConfirmation)
529 // No control... do what we can with the models
530 bool shouldCommit(true);
531 Reference< XIndexAccess > xFormComps(xFrm, UNO_QUERY_THROW);
532 assert( xFormComps.is() );
534 const sal_Int32 cnt = xFormComps->getCount();
535 for(int i=0; i < cnt; ++i)
537 Reference< XForm > xSubForm(xFormComps->getByIndex(i), UNO_QUERY);
538 if(xSubForm.is())
540 if(!commit1Form(xSubForm, needConfirmation, shouldCommit))
541 return false;
545 if(!commit1Form(xFrm, needConfirmation, shouldCommit))
546 return false;
548 return true;
552 void SAL_CALL FormOperations::execute( ::sal_Int16 _nFeature ) throw (RuntimeException, IllegalArgumentException, SQLException, WrappedTargetException, std::exception)
554 SolarMutexGuard aSolarGuard;
555 MethodGuard aGuard( *this );
557 if ( ( _nFeature != FormFeature::DeleteRecord ) && ( _nFeature != FormFeature::UndoRecordChanges ) )
561 if(m_xController.is())
563 if(!commitFormAndSubforms(m_xController, lcl_needConfirmCommit( _nFeature )))
564 return;
566 else if(m_xCursor.is())
568 Reference< XForm > xForm(m_xCursor, UNO_QUERY);
569 assert(xForm.is());
570 if(!commitFormAndSubforms(xForm, lcl_needConfirmCommit( _nFeature )))
571 return;
573 else
575 SAL_WARN( "forms.runtime", "No cursor, but trying to execute form operation " << _nFeature );
581 switch ( _nFeature )
583 case FormFeature::MoveToFirst:
584 m_xCursor->first();
585 break;
587 case FormFeature::MoveToNext:
588 impl_moveRight_throw( );
589 break;
591 case FormFeature::MoveToPrevious:
592 impl_moveLeft_throw( );
593 break;
595 case FormFeature::MoveToLast:
598 // TODO: re-implement this .....
599 // run in an own thread if ...
600 // ... the data source is thread safe ...
601 sal_Bool bAllowOwnThread = sal_False;
602 if ( ::comphelper::hasProperty( PROPERTY_THREADSAFE, m_xCursorProperties ) )
603 m_xCursorProperties->getPropertyValue( PROPERTY_THREADSAFE ) >>= bAllowOwnThread;
605 // ... the record count is unknown
606 sal_Bool bNeedOwnThread sal_False;
607 if ( ::comphelper::hasProperty( PROPERTY_ROWCOUNTFINAL, m_xCursorProperties ) )
608 m_xCursorProperties->getPropertyValue( PROPERTY_ROWCOUNTFINAL ) >>= bNeedOwnThread;
610 if ( bNeedOwnThread && bAllowOwnThread )
612 else
614 m_xCursor->last();
616 break;
618 case FormFeature::ReloadForm:
619 if ( m_xLoadableForm.is() )
621 WaitObject aWO( nullptr );
622 m_xLoadableForm->reload();
624 // refresh all controls in the form (and sub forms) which can be refreshed
625 // #i90914#
626 ::comphelper::IndexAccessIterator aIter( m_xLoadableForm );
627 Reference< XInterface > xElement( aIter.Next() );
628 while ( xElement.is() )
630 Reference< XRefreshable > xRefresh( xElement, UNO_QUERY );
631 if ( xRefresh.is() )
632 xRefresh->refresh();
633 xElement = aIter.Next();
636 break;
638 case FormFeature::RefreshCurrentControl:
640 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
641 OSL_ENSURE( xControlModelRefresh.is(), "FormOperations::execute: how did you reach this?" );
642 if ( xControlModelRefresh.is() )
643 xControlModelRefresh->refresh();
645 break;
647 case FormFeature::DeleteRecord:
649 sal_uInt32 nCount = impl_getRowCount_throw();
651 // next position
652 bool bLeft = m_xCursor->isLast() && ( nCount > 1 );
653 bool bRight= !m_xCursor->isLast();
654 bool bSuccess = false;
657 // ask for confirmation
658 Reference< XConfirmDeleteListener > xConfirmDelete( m_xController, UNO_QUERY );
660 if ( xConfirmDelete.is() )
662 RowChangeEvent aEvent;
663 aEvent.Source.set( m_xCursor, UNO_QUERY );
664 aEvent.Action = RowChangeAction::DELETE;
665 aEvent.Rows = 1;
666 bSuccess = xConfirmDelete->confirmDelete( aEvent );
669 // delete it
670 if ( bSuccess )
671 m_xUpdateCursor->deleteRow();
673 catch( const Exception& )
675 bSuccess = false;
678 if ( bSuccess )
680 if ( bLeft || bRight )
681 m_xCursor->relative( bRight ? 1 : -1 );
682 else
684 bool bCanInsert = ::dbtools::canInsert( m_xCursorProperties );
685 // is it possible to insert another record?
686 if ( bCanInsert )
687 m_xUpdateCursor->moveToInsertRow();
688 else
689 // move record to update status
690 m_xCursor->first();
694 break;
696 case FormFeature::SaveRecordChanges:
697 case FormFeature::UndoRecordChanges:
699 bool bInserting = impl_isInsertionRow_throw();
701 if ( FormFeature::UndoRecordChanges == _nFeature )
703 if ( !bInserting )
704 m_xUpdateCursor->cancelRowUpdates();
706 // reset all controls for this form
707 impl_resetAllControls_nothrow( );
709 if ( bInserting ) // back to insertion mode for this form
710 m_xUpdateCursor->moveToInsertRow();
712 else
714 if ( bInserting )
716 m_xUpdateCursor->insertRow();
717 m_xCursor->last();
719 else
720 m_xUpdateCursor->updateRow();
723 break;
725 case FormFeature::MoveToInsertRow:
726 // move to the last row before moving to the insert row
727 m_xCursor->last();
728 m_xUpdateCursor->moveToInsertRow();
729 break;
731 case FormFeature::RemoveFilterAndSort:
733 // simultaneously reset Filter and Order property
734 Reference< XMultiPropertySet > xProperties( m_xCursorProperties, UNO_QUERY );
735 OSL_ENSURE( xProperties.is(), "FormOperations::execute: no multi property access!" );
736 if ( xProperties.is() )
738 Sequence< OUString > aNames( 2 );
739 aNames[0] = PROPERTY_FILTER;
740 aNames[1] = PROPERTY_SORT;
742 Sequence< Any> aValues( 2 );
743 aValues[0] <<= OUString();
744 aValues[1] <<= OUString();
746 WaitObject aWO( nullptr );
747 xProperties->setPropertyValues( aNames, aValues );
749 if ( m_xLoadableForm.is() )
750 m_xLoadableForm->reload();
753 break;
755 case FormFeature::ToggleApplyFilter:
756 if ( impl_commitCurrentControl_throw() && impl_commitCurrentRecord_throw() )
758 // simply toggle the value
759 bool bApplied = false;
760 m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
761 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( !bApplied ) );
763 // and reload
764 WaitObject aWO( nullptr );
765 m_xLoadableForm->reload();
767 break;
769 case FormFeature::SortAscending:
770 impl_executeAutoSort_throw( true );
771 break;
773 case FormFeature::SortDescending:
774 impl_executeAutoSort_throw( false );
775 break;
777 case FormFeature::AutoFilter:
778 impl_executeAutoFilter_throw();
779 break;
781 case FormFeature::InteractiveSort:
782 impl_executeFilterOrSort_throw( false );
783 break;
785 case FormFeature::InteractiveFilter:
786 impl_executeFilterOrSort_throw( true );
787 break;
789 default:
791 sal_uInt16 nErrorResourceId = RID_STR_FEATURE_UNKNOWN;
792 if ( lcl_requiresArguments( _nFeature ) )
793 nErrorResourceId = RID_STR_FEATURE_REQUIRES_PARAMETERS;
794 else if ( !lcl_isExecutableFeature( _nFeature ) )
795 nErrorResourceId = RID_STR_FEATURE_NOT_EXECUTABLE;
796 throw IllegalArgumentException( FRM_RES_STRING( nErrorResourceId ), *this, 1 );
798 } // switch
800 catch( const RuntimeException& ) { throw; }
801 catch( const SQLException& ) { throw; }
802 catch( const Exception& )
804 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
807 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
811 void SAL_CALL FormOperations::executeWithArguments( ::sal_Int16 _nFeature, const Sequence< NamedValue >& _rArguments ) throw (RuntimeException, IllegalArgumentException, SQLException, WrappedTargetException, std::exception)
813 if ( !lcl_requiresArguments( _nFeature ) )
815 execute( _nFeature );
816 return;
819 SolarMutexGuard aSolarGuard;
820 MethodGuard aGuard( *this );
822 // at the moment we have only one feature which supports execution parameters
823 if ( !lcl_isExecutableFeature( _nFeature ) )
824 throw IllegalArgumentException( FRM_RES_STRING( RID_STR_FEATURE_NOT_EXECUTABLE ), *this, 1 );
826 switch ( _nFeature )
828 case FormFeature::MoveAbsolute:
830 sal_Int32 nPosition = -1;
832 ::comphelper::NamedValueCollection aArguments( _rArguments );
833 aArguments.get_ensureType( "Position", nPosition );
835 if ( nPosition < 1 )
836 nPosition = 1;
840 // commit before doing anything else
841 if ( m_xController.is() && !impl_commitCurrentControl_throw() )
842 return;
843 if ( !impl_commitCurrentRecord_throw() )
844 return;
846 sal_Int32 nCount = impl_getRowCount_throw();
847 bool bFinalCount = impl_isRowCountFinal_throw();
849 if ( bFinalCount && ( (sal_Int32)nPosition > nCount ) )
850 nPosition = nCount;
852 m_xCursor->absolute( nPosition );
854 catch( const RuntimeException& ) { throw; }
855 catch( const SQLException& ) { throw; }
856 catch( const Exception& )
858 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
861 break;
862 default:
863 throw IllegalArgumentException( FRM_RES_STRING( RID_STR_FEATURE_UNKNOWN ), *this, 1 );
864 } // switch
868 sal_Bool SAL_CALL FormOperations::commitCurrentRecord( sal_Bool& _out_rRecordInserted ) throw (RuntimeException, SQLException, std::exception)
870 MethodGuard aGuard( *this );
871 _out_rRecordInserted = false;
873 return impl_commitCurrentRecord_throw( &_out_rRecordInserted );
877 bool FormOperations::impl_commitCurrentRecord_throw( sal_Bool* _pRecordInserted ) const
879 #ifdef DBG_UTIL
880 DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentRecord_throw: to be called within a MethodGuard'ed section only!" );
881 #endif
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 = 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 #ifdef DBG_UTIL
915 DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentControl_throw: to be called within a MethodGuard'ed section only!" );
916 #endif
917 OSL_PRECOND( m_xController.is(), "FormOperations::commitCurrentControl: no controller!" );
918 if ( !m_xController.is() )
919 return false;
921 bool bSuccess = false;
924 Reference< XControl > xCurrentControl( m_xController->getCurrentControl() );
926 // check whether the control is locked
927 Reference< XBoundControl > xCheckLock( xCurrentControl, UNO_QUERY );
928 bool bControlIsLocked = xCheckLock.is() && xCheckLock->getLock();
930 // commit if necessary
931 bSuccess = true;
932 if ( xCurrentControl.is() && !bControlIsLocked )
934 // both the control and its model can be committable, so try both
935 Reference< XBoundComponent > xBound( xCurrentControl, UNO_QUERY );
936 if ( !xBound.is() )
937 xBound.set(xCurrentControl->getModel(), css::uno::UNO_QUERY);
938 // and now really commit
939 if ( xBound.is() )
940 bSuccess = xBound->commit();
944 catch( const RuntimeException& ) { throw; }
945 catch( const SQLException& ) { throw; }
946 catch( const Exception& )
948 DBG_UNHANDLED_EXCEPTION();
949 bSuccess = false;
952 return bSuccess;
956 sal_Bool SAL_CALL FormOperations::isInsertionRow() throw (RuntimeException, WrappedTargetException, std::exception)
958 bool bIs = false;
961 bIs = impl_isInsertionRow_throw();
963 catch( const RuntimeException& ) { throw; }
964 catch( const Exception& )
966 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
968 return bIs;
972 sal_Bool SAL_CALL FormOperations::isModifiedRow() throw (RuntimeException, WrappedTargetException, std::exception)
974 bool bIs = false;
977 bIs = impl_isModifiedRow_throw();
979 catch( const RuntimeException& ) { throw; }
980 catch( const Exception& )
982 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
984 return bIs;
988 void SAL_CALL FormOperations::cursorMoved( const EventObject& /*_Event*/ ) throw (RuntimeException, std::exception)
990 MethodGuard aGuard( *this );
991 m_bActiveControlModified = false;
993 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
997 void SAL_CALL FormOperations::rowChanged( const EventObject& /*_Event*/ ) throw (RuntimeException, std::exception)
999 // not interested in
1003 void SAL_CALL FormOperations::rowSetChanged( const EventObject& /*_Event*/ ) throw (RuntimeException, std::exception)
1005 // not interested in
1009 void SAL_CALL FormOperations::modified( const EventObject& /*_Source*/ ) throw( RuntimeException, std::exception )
1011 MethodGuard aGuard( *this );
1013 OSL_ENSURE( m_xCursor.is(), "FormOperations::modified: already disposed!" );
1014 if ( !m_bActiveControlModified )
1016 m_bActiveControlModified = true;
1017 impl_invalidateModifyDependentFeatures_nothrow( aGuard );
1022 void SAL_CALL FormOperations::propertyChange( const PropertyChangeEvent& _rEvent ) throw (RuntimeException, std::exception)
1024 MethodGuard aGuard( *this );
1026 if ( m_xCursor.is() && ( m_xCursor == _rEvent.Source ) )
1028 if ( ( _rEvent.PropertyName == PROPERTY_ISMODIFIED )
1029 || ( _rEvent.PropertyName == PROPERTY_ISNEW )
1032 bool bIs = false;
1033 if ( ( _rEvent.NewValue >>= bIs ) && !bIs )
1034 m_bActiveControlModified = false;
1036 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
1039 if ( m_xParser.is() && ( m_xCursor == _rEvent.Source ) )
1043 OUString sNewValue;
1044 _rEvent.NewValue >>= sNewValue;
1045 if ( _rEvent.PropertyName == PROPERTY_ACTIVECOMMAND )
1047 m_xParser->setElementaryQuery( sNewValue );
1049 else if ( _rEvent.PropertyName == PROPERTY_FILTER )
1051 if ( m_xParser->getFilter() != sNewValue )
1052 m_xParser->setFilter( sNewValue );
1054 else if ( _rEvent.PropertyName == PROPERTY_SORT )
1056 _rEvent.NewValue >>= sNewValue;
1057 if ( m_xParser->getOrder() != sNewValue )
1058 m_xParser->setOrder( sNewValue );
1061 catch( const Exception& )
1063 OSL_FAIL( "FormOperations::propertyChange: caught an exception while updating the parser!" );
1065 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
1070 void SAL_CALL FormOperations::disposing( const EventObject& /*_Source*/ ) throw (RuntimeException, std::exception)
1072 // TODO: should we react on this? Or is this the responsibility of our owner to dispose us?
1076 void SAL_CALL FormOperations::disposing()
1078 ::osl::MutexGuard aGuard( m_aMutex );
1080 impl_disposeParser_nothrow();
1084 // revoke various listeners
1085 if ( m_xCursor.is() )
1086 m_xCursor->removeRowSetListener( this );
1088 if ( m_xCursorProperties.is() )
1090 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISMODIFIED,this );
1091 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISNEW, this );
1094 Reference< XModifyBroadcaster > xBroadcaster( m_xController, UNO_QUERY );
1095 if ( xBroadcaster.is() )
1096 xBroadcaster->removeModifyListener( this );
1098 catch( const Exception& )
1100 DBG_UNHANDLED_EXCEPTION();
1103 m_xController.clear();
1104 m_xCursor.clear();
1105 m_xUpdateCursor.clear();
1106 m_xCursorProperties.clear();
1107 m_xLoadableForm.clear();
1108 m_xFeatureInvalidation.clear();
1110 m_bActiveControlModified = true;
1114 void FormOperations::impl_checkDisposed_throw() const
1116 if ( impl_isDisposed_nothrow() )
1117 throw DisposedException( OUString(), *const_cast< FormOperations* >( this ) );
1121 void FormOperations::impl_initFromController_throw()
1123 OSL_PRECOND( m_xController.is(), "FormOperations::impl_initFromController_throw: invalid controller!" );
1124 m_xCursor.set(m_xController->getModel(), css::uno::UNO_QUERY);
1125 if ( !m_xCursor.is() )
1126 throw IllegalArgumentException( OUString(), *this, 0 );
1128 impl_initFromForm_throw();
1130 Reference< XModifyBroadcaster > xBroadcaster( m_xController, UNO_QUERY );
1131 if ( xBroadcaster.is() )
1132 xBroadcaster->addModifyListener( this );
1136 void FormOperations::impl_initFromForm_throw()
1138 OSL_PRECOND( m_xCursor.is(), "FormOperations::impl_initFromForm_throw: invalid form!" );
1139 m_xCursorProperties.set(m_xCursor, css::uno::UNO_QUERY);
1140 m_xUpdateCursor.set(m_xCursor, css::uno::UNO_QUERY);
1141 m_xLoadableForm.set(m_xCursor, css::uno::UNO_QUERY);
1143 if ( !m_xCursor.is() || !m_xCursorProperties.is() || !m_xLoadableForm.is() )
1144 throw IllegalArgumentException( OUString(), *this, 0 );
1146 m_xCursor->addRowSetListener( this );
1147 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISMODIFIED,this );
1148 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISNEW, this );
1152 void FormOperations::createWithFormController( const Reference< XFormController >& _rxController )
1154 m_xController = _rxController;
1155 if ( !m_xController.is() )
1156 throw IllegalArgumentException( OUString(), *this, 0 );
1158 impl_initFromController_throw();
1160 m_bConstructed = true;
1164 void FormOperations::createWithForm( const Reference< XForm >& _rxForm )
1166 m_xCursor.set(_rxForm, css::uno::UNO_QUERY);
1167 if ( !m_xCursor.is() )
1168 throw IllegalArgumentException( OUString(), *this, 0 );
1170 impl_initFromForm_throw();
1172 m_bConstructed = true;
1176 void FormOperations::impl_invalidateAllSupportedFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1178 if ( !m_xFeatureInvalidation.is() )
1179 // nobody's interested in ...
1180 return;
1182 Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1183 _rClearForCallback.clear();
1184 xInvalidation->invalidateAllFeatures();
1188 void FormOperations::impl_invalidateModifyDependentFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1190 if ( !m_xFeatureInvalidation.is() )
1191 // nobody's interested in ...
1192 return;
1194 static Sequence< sal_Int16 > s_aModifyDependentFeatures;
1195 if ( s_aModifyDependentFeatures.getLength() == 0 )
1197 sal_Int16 pModifyDependentFeatures[] =
1199 FormFeature::MoveToNext,
1200 FormFeature::MoveToInsertRow,
1201 FormFeature::SaveRecordChanges,
1202 FormFeature::UndoRecordChanges
1204 size_t nFeatureCount = SAL_N_ELEMENTS( pModifyDependentFeatures );
1205 s_aModifyDependentFeatures = Sequence< sal_Int16 >( pModifyDependentFeatures, nFeatureCount );
1208 Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1209 _rClearForCallback.clear();
1211 xInvalidation->invalidateFeatures( s_aModifyDependentFeatures );
1215 void FormOperations::impl_ensureInitializedParser_nothrow()
1217 OSL_PRECOND( m_xCursorProperties.is(), "FormOperations::impl_ensureInitializedParser_nothrow: we're disposed!" );
1218 if ( m_bInitializedParser )
1219 return;
1223 bool bUseEscapeProcessing = false;
1224 m_xCursorProperties->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bUseEscapeProcessing;
1225 if ( bUseEscapeProcessing )
1227 Reference< XMultiServiceFactory > xFactory( ::dbtools::getConnection( m_xCursor ), UNO_QUERY );
1228 if ( xFactory.is() )
1230 m_xParser.set( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"), UNO_QUERY );
1231 OSL_ENSURE( m_xParser.is(), "FormOperations::impl_ensureInitializedParser_nothrow: factory did not create a parser for us!" );
1235 if ( m_xParser.is() )
1237 if ( m_xLoadableForm.is() && m_xLoadableForm->isLoaded() )
1239 OUString sStatement;
1240 OUString sFilter;
1241 OUString sSort;
1243 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sStatement;
1244 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
1245 m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sSort;
1247 m_xParser->setElementaryQuery( sStatement );
1248 m_xParser->setFilter ( sFilter );
1249 m_xParser->setOrder ( sSort );
1252 // start listening at the order/sort properties at the form, so
1253 // we can keep our parser in sync
1254 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1255 m_xCursorProperties->addPropertyChangeListener( PROPERTY_FILTER, this );
1256 m_xCursorProperties->addPropertyChangeListener( PROPERTY_SORT, this );
1259 catch( const Exception& )
1261 OSL_FAIL( "FormOperations::impl_ensureInitializedParser_nothrow: caught an exception!" );
1264 m_bInitializedParser = true;
1268 void FormOperations::impl_disposeParser_nothrow()
1272 // if we have a parser (and a cursor), then we're listening at the cursor's
1273 // properties to keep the parser in sync with the cursor
1274 if ( m_xParser.is() && m_xCursorProperties.is() )
1276 m_xCursorProperties->removePropertyChangeListener( PROPERTY_FILTER, this );
1277 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1278 m_xCursorProperties->removePropertyChangeListener( PROPERTY_SORT, this );
1281 Reference< XComponent > xParserComp( m_xParser, UNO_QUERY );
1282 if ( xParserComp.is() )
1283 xParserComp->dispose();
1284 m_xParser.clear();
1286 m_bInitializedParser = false;
1288 catch( const Exception& )
1290 OSL_FAIL( "FormOperations::impl_disposeParser_nothrow: caught an exception!" );
1295 bool FormOperations::impl_canMoveLeft_throw( ) const
1297 if ( !impl_hasCursor_nothrow() )
1298 return false;
1300 return impl_getRowCount_throw() && ( !m_xCursor->isFirst() || impl_isInsertionRow_throw() );
1304 bool FormOperations::impl_canMoveRight_throw( ) const
1306 if ( !impl_hasCursor_nothrow() )
1307 return false;
1309 bool bIsNew = impl_isInsertionRow_throw();
1311 if ( impl_getRowCount_throw() && !m_xCursor->isLast() && !bIsNew )
1312 return true;
1314 if ( ::dbtools::canInsert( m_xCursorProperties ) )
1315 if ( !bIsNew || impl_isModifiedRow_throw() )
1316 return true;
1318 if ( bIsNew && m_bActiveControlModified )
1319 return true;
1321 return false;
1325 bool FormOperations::impl_isInsertionRow_throw() const
1327 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISNEW, false );
1331 sal_Int32 FormOperations::impl_getRowCount_throw() const
1333 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNT, (sal_Int32)0 );
1336 bool FormOperations::impl_isRowCountFinal_throw() const
1338 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNTFINAL, false );
1342 bool FormOperations::impl_isModifiedRow_throw() const
1344 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISMODIFIED, false );
1348 bool FormOperations::impl_isParseable_throw() const
1350 const_cast< FormOperations* >( this )->impl_ensureInitializedParser_nothrow();
1351 return m_xParser.is() && !m_xParser->getQuery().isEmpty();
1355 bool FormOperations::impl_hasFilterOrOrder_throw() const
1357 return impl_isParseable_throw() && ( !m_xParser->getFilter().isEmpty() || !m_xParser->getOrder().isEmpty() );
1361 bool FormOperations::impl_isInsertOnlyForm_throw() const
1363 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_INSERTONLY, true );
1367 Reference< XControlModel > FormOperations::impl_getCurrentControlModel_throw() const
1369 Reference< XControl > xControl( m_xController->getCurrentControl() );
1371 // special handling for grid controls
1372 Reference< XGrid > xGrid( xControl, UNO_QUERY );
1373 Reference< XControlModel > xControlModel;
1375 if ( xGrid.is() )
1377 Reference< XIndexAccess > xColumns( xControl->getModel(), UNO_QUERY_THROW );
1378 sal_Int16 nCurrentPos = xGrid->getCurrentColumnPosition();
1379 nCurrentPos = impl_gridView2ModelPos_nothrow( xColumns, nCurrentPos );
1381 if ( nCurrentPos != (sal_Int16)-1 )
1382 xColumns->getByIndex( nCurrentPos ) >>= xControlModel;
1384 else if ( xControl.is() )
1386 xControlModel = xControl->getModel();
1388 return xControlModel;
1392 Reference< XPropertySet > FormOperations::impl_getCurrentBoundField_nothrow( ) const
1394 OSL_PRECOND( m_xController.is(), "FormOperations::impl_getCurrentBoundField_nothrow: no controller -> no control!" );
1395 if ( !m_xController.is() )
1396 return nullptr;
1398 Reference< XPropertySet > xField;
1401 Reference< XPropertySet > xControlModel( impl_getCurrentControlModel_throw(), UNO_QUERY );
1403 if ( xControlModel.is() && ::comphelper::hasProperty( PROPERTY_BOUNDFIELD, xControlModel ) )
1404 xControlModel->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xField;
1407 catch( const Exception& )
1409 DBG_UNHANDLED_EXCEPTION();
1412 return xField;
1416 sal_Int16 FormOperations::impl_gridView2ModelPos_nothrow( const Reference< XIndexAccess >& _rxColumns, sal_Int16 _nViewPos )
1418 OSL_PRECOND( _rxColumns.is(), "FormOperations::impl_gridView2ModelPos_nothrow: invalid columns container!" );
1421 // loop through all columns
1422 sal_Int16 col = 0;
1423 Reference< XPropertySet > xCol;
1424 bool bHidden( false );
1425 for ( col = 0; col < _rxColumns->getCount(); ++col )
1427 _rxColumns->getByIndex( col ) >>= xCol;
1428 OSL_VERIFY( xCol->getPropertyValue( PROPERTY_HIDDEN ) >>= bHidden );
1429 if ( bHidden )
1430 continue;
1432 // for every visible col : if nViewPos is greater zero, decrement it, else we
1433 // have found the model position
1434 if ( !_nViewPos )
1435 break;
1436 else
1437 --_nViewPos;
1439 if ( col < _rxColumns->getCount() )
1440 return col;
1442 catch( const Exception& )
1444 DBG_UNHANDLED_EXCEPTION();
1446 return (sal_Int16)-1;
1450 void FormOperations::impl_moveLeft_throw( ) const
1452 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveLeft_throw: no cursor!" );
1453 if ( !impl_hasCursor_nothrow() )
1454 return;
1456 sal_Bool bRecordInserted = false;
1457 bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1459 if ( !bSuccess )
1460 return;
1462 if ( bRecordInserted )
1464 // retrieve the bookmark of the new record and move to the record preceding this bookmark
1465 Reference< XRowLocate > xLocate( m_xCursor, UNO_QUERY );
1466 OSL_ENSURE( xLocate.is(), "FormOperations::impl_moveLeft_throw: no XRowLocate!" );
1467 if ( xLocate.is() )
1468 xLocate->moveRelativeToBookmark( xLocate->getBookmark(), -1 );
1470 else
1472 if ( impl_isInsertionRow_throw() )
1474 // we assume that the inserted record is now the last record in the
1475 // result set
1476 m_xCursor->last();
1478 else
1479 m_xCursor->previous();
1484 void FormOperations::impl_moveRight_throw( ) const
1486 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveRight_throw: no cursor!" );
1487 if ( !impl_hasCursor_nothrow() )
1488 return;
1490 sal_Bool bRecordInserted = false;
1491 bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1493 if ( !bSuccess )
1494 return;
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();
1511 void FormOperations::impl_resetAllControls_nothrow() const
1513 Reference< XIndexAccess > xContainer( m_xCursor, UNO_QUERY );
1514 if ( !xContainer.is() )
1515 return;
1519 Reference< XReset > xReset;
1520 sal_Int32 nCount( xContainer->getCount() );
1521 for ( sal_Int32 i = 0; i < nCount; ++i )
1523 if ( xContainer->getByIndex( i ) >>= xReset )
1525 // no resets on sub forms
1526 Reference< XForm > xAsForm( xReset, UNO_QUERY );
1527 if ( !xAsForm.is() )
1528 xReset->reset();
1532 catch( const Exception& )
1534 DBG_UNHANDLED_EXCEPTION();
1539 void FormOperations::impl_executeAutoSort_throw( bool _bUp ) const
1541 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoSort_throw: need a controller for this!" );
1542 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoSort_throw: need a cursor for this!" );
1543 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoSort_throw: need a parseable statement for this!" );
1544 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1545 return;
1549 Reference< XControl > xControl = m_xController->getCurrentControl();
1550 if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1551 return;
1553 Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1554 if ( !xBoundField.is() )
1555 return;
1557 OUString sOriginalSort;
1558 m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sOriginalSort;
1560 // automatic sort by field is expected to always resets the previous sort order
1561 m_xParser->setOrder( OUString() );
1563 impl_appendOrderByColumn_throw aAction(this, xBoundField, _bUp);
1564 impl_doActionInSQLContext_throw(aAction, RID_STR_COULD_NOT_SET_ORDER );
1566 WaitObject aWO( nullptr );
1569 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1570 m_xLoadableForm->reload();
1572 catch( const Exception& )
1574 OSL_FAIL( "FormOperations::impl_executeAutoSort_throw: caught an exception while setting the parser properties!" );
1578 if ( !m_xLoadableForm->isLoaded() )
1579 { // something went wrong -> restore the original state
1582 m_xParser->setOrder( sOriginalSort );
1583 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1584 m_xLoadableForm->reload();
1586 catch( const Exception& )
1588 OSL_FAIL( "FormOperations::impl_executeAutoSort_throw: could not reset the form to its original state!" );
1593 catch( const RuntimeException& ) { throw; }
1594 catch( const SQLException& ) { throw; }
1595 catch( const Exception& )
1597 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1602 void FormOperations::impl_executeAutoFilter_throw( ) const
1604 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoFilter_throw: need a controller for this!" );
1605 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoFilter_throw: need a cursor for this!" );
1606 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoFilter_throw: need a parseable statement for this!" );
1607 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1608 return;
1612 Reference< XControl > xControl = m_xController->getCurrentControl();
1613 if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1614 return;
1616 Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1617 if ( !xBoundField.is() )
1618 return;
1620 OUString sOriginalFilter;
1621 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
1622 bool bApplied = true;
1623 m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
1625 // if we have a filter, but it's not applied, then we have to overwrite it, else append one
1626 if ( !bApplied )
1627 m_xParser->setFilter( OUString() );
1629 impl_appendFilterByColumn_throw aAction(this, xBoundField);
1630 impl_doActionInSQLContext_throw( aAction, RID_STR_COULD_NOT_SET_FILTER );
1632 WaitObject aWO( nullptr );
1635 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1636 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( true ) );
1638 m_xLoadableForm->reload();
1640 catch( const Exception& )
1642 OSL_FAIL( "FormOperations::impl_executeAutoFilter_throw: caught an exception while setting the parser properties!" );
1646 if ( !m_xLoadableForm->isLoaded() )
1647 { // something went wrong -> restore the original state
1650 m_xParser->setOrder( sOriginalFilter );
1651 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( bApplied ) );
1652 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1653 m_xLoadableForm->reload();
1655 catch( const Exception& )
1657 OSL_FAIL( "FormOperations::impl_executeAutoFilter_throw: could not reset the form to its original state!" );
1662 catch( const RuntimeException& ) { throw; }
1663 catch( const SQLException& ) { throw; }
1664 catch( const Exception& )
1666 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1671 void FormOperations::impl_executeFilterOrSort_throw( bool _bFilter ) const
1673 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeFilterOrSort_throw: need a controller for this!" );
1674 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeFilterOrSort_throw: need a cursor for this!" );
1675 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeFilterOrSort_throw: need a parseable statement for this!" );
1676 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1677 return;
1679 if ( !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1680 return;
1683 Reference< XExecutableDialog> xDialog;
1684 if ( _bFilter )
1686 xDialog = css::sdb::FilterDialog::createWithQuery(m_xContext, m_xParser, m_xCursor,
1687 Reference<css::awt::XWindow>());
1689 else
1691 xDialog = css::sdb::OrderDialog::createWithQuery(m_xContext, m_xParser, m_xCursorProperties);
1695 if ( RET_OK == xDialog->execute() )
1697 WaitObject aWO( nullptr );
1698 if ( _bFilter )
1699 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1700 else
1701 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1702 m_xLoadableForm->reload();
1706 catch( const RuntimeException& ) { throw; }
1707 catch( const SQLException& ) { throw; }
1708 catch( const Exception& )
1710 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1715 template < typename FunctObj >
1716 void FormOperations::impl_doActionInSQLContext_throw( FunctObj f, sal_uInt16 _nErrorResourceId ) const
1720 f();
1722 #if HAVE_FEATURE_DBCONNECTIVITY
1723 catch( const SQLException& e )
1725 (void)e;
1726 if ( !_nErrorResourceId )
1727 // no information to prepend
1728 throw;
1730 SQLExceptionInfo aInfo( ::cppu::getCaughtException() );
1731 OUString sAdditionalError( FRM_RES_STRING( _nErrorResourceId ) );
1732 aInfo.prepend( sAdditionalError );
1733 aInfo.doThrow();
1735 #endif
1736 catch( const RuntimeException& ) { throw; }
1737 catch( const Exception& )
1739 OUString sAdditionalError( FRM_RES_STRING( _nErrorResourceId ) );
1740 throw WrappedTargetException( sAdditionalError, *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1745 } // namespace frm
1748 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* SAL_CALL
1749 com_sun_star_comp_forms_FormOperations_get_implementation(css::uno::XComponentContext* context,
1750 css::uno::Sequence<css::uno::Any> const &)
1752 return cppu::acquire(new frm::FormOperations(context));
1755 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */