LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / forms / source / runtime / formoperations.cxx
blobe7c7d135f61aaeddc5e2b1556efaa6cb7752c07d
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>
21 #include <config_fuzzers.h>
23 #include "formoperations.hxx"
24 #include <frm_strings.hxx>
25 #include <frm_resource.hxx>
26 #include <strings.hrc>
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/SQLException.hpp>
44 #include <com/sun/star/sdbc/XConnection.hpp>
45 #include <com/sun/star/form/XReset.hpp>
46 #include <com/sun/star/beans/XMultiPropertySet.hpp>
47 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
48 #include <com/sun/star/util/XRefreshable.hpp>
50 #include <connectivity/dbtools.hxx>
51 #include <connectivity/dbexception.hxx>
52 #include <vcl/svapp.hxx>
53 #include <vcl/stdtext.hxx>
54 #include <vcl/weld.hxx>
55 #include <tools/diagnose_ex.h>
56 #include <comphelper/container.hxx>
57 #include <comphelper/property.hxx>
58 #include <comphelper/namedvaluecollection.hxx>
59 #include <cppuhelper/exc_hlp.hxx>
60 #include <cppuhelper/supportsservice.hxx>
61 #include <osl/mutex.hxx>
62 #include <sal/log.hxx>
63 #include <tools/debug.hxx>
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 void SAL_CALL FormOperations::initialize( const Sequence< Any >& _arguments )
136 if ( m_bConstructed )
137 throw AlreadyInitializedException();
139 if ( _arguments.getLength() == 1 )
141 Reference< XFormController > xController;
142 Reference< XForm > xForm;
143 if ( _arguments[0] >>= xController )
144 createWithFormController( xController );
145 else if ( _arguments[0] >>= xForm )
146 createWithForm( xForm );
147 else
148 throw IllegalArgumentException( OUString(), *this, 1 );
149 return;
152 throw IllegalArgumentException( OUString(), *this, 0 );
155 OUString SAL_CALL FormOperations::getImplementationName( )
157 return "com.sun.star.comp.forms.FormOperations";
160 sal_Bool SAL_CALL FormOperations::supportsService( const OUString& ServiceName )
162 return cppu::supportsService(this, ServiceName);
165 Sequence< OUString > SAL_CALL FormOperations::getSupportedServiceNames( )
167 return { "com.sun.star.form.runtime.FormOperations" };
170 Reference< XRowSet > SAL_CALL FormOperations::getCursor()
172 MethodGuard aGuard( *this );
173 return m_xCursor;
176 Reference< XResultSetUpdate > SAL_CALL FormOperations::getUpdateCursor()
178 MethodGuard aGuard( *this );
179 return m_xUpdateCursor;
183 Reference< XFormController > SAL_CALL FormOperations::getController()
185 MethodGuard aGuard( *this );
186 return m_xController;
190 Reference< XFeatureInvalidation > SAL_CALL FormOperations::getFeatureInvalidation()
192 MethodGuard aGuard( *this );
193 return m_xFeatureInvalidation;
197 void SAL_CALL FormOperations::setFeatureInvalidation( const Reference< XFeatureInvalidation > & _rxFeatureInvalidation )
199 MethodGuard aGuard( *this );
200 m_xFeatureInvalidation = _rxFeatureInvalidation;
204 FeatureState SAL_CALL FormOperations::getState( ::sal_Int16 _nFeature )
206 MethodGuard aGuard( *this );
208 FeatureState aState;
209 aState.Enabled = false;
213 // some checks for basic pre-requisites
214 if ( !m_xLoadableForm.is()
215 || !m_xLoadableForm->isLoaded()
216 || !m_xCursorProperties.is()
219 return aState;
222 switch ( _nFeature )
224 case FormFeature::MoveToFirst:
225 case FormFeature::MoveToPrevious:
226 aState.Enabled = impl_canMoveLeft_throw( );
227 break;
229 case FormFeature::MoveToNext:
230 aState.Enabled = impl_canMoveRight_throw();
231 break;
233 case FormFeature::MoveToLast:
234 aState.Enabled = impl_getRowCount_throw() && ( !m_xCursor->isLast() || impl_isInsertionRow_throw() );
235 break;
237 case FormFeature::DeleteRecord:
238 // already deleted ?
239 if ( m_xCursor->rowDeleted() )
240 aState.Enabled = false;
241 else
243 // allowed to delete the row ?
244 aState.Enabled = !impl_isInsertionRow_throw() && ::dbtools::canDelete( m_xCursorProperties );
246 break;
248 case FormFeature::MoveToInsertRow:
249 // if we are inserting we can move to the next row if the current record or control is modified
250 aState.Enabled = impl_isInsertionRow_throw()
251 ? impl_isModifiedRow_throw() || m_bActiveControlModified
252 : ::dbtools::canInsert( m_xCursorProperties );
253 break;
255 case FormFeature::ReloadForm:
257 // there must be an active connection
258 aState.Enabled = ::dbtools::getConnection( m_xCursor ).is();
260 // and an active command
261 OUString sActiveCommand;
262 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sActiveCommand;
263 aState.Enabled = aState.Enabled && !sActiveCommand.isEmpty();
265 break;
267 case FormFeature::RefreshCurrentControl:
269 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
270 aState.Enabled = xControlModelRefresh.is();
272 break;
274 case FormFeature::SaveRecordChanges:
275 case FormFeature::UndoRecordChanges:
276 aState.Enabled = impl_isModifiedRow_throw() || m_bActiveControlModified;
277 break;
279 case FormFeature::RemoveFilterAndSort:
280 if ( impl_isParseable_throw() && impl_hasFilterOrOrder_throw() )
281 aState.Enabled = !impl_isInsertOnlyForm_throw();
282 break;
284 case FormFeature::SortAscending:
285 case FormFeature::SortDescending:
286 case FormFeature::AutoFilter:
287 if ( m_xController.is() && impl_isParseable_throw() )
289 bool bIsDeleted = m_xCursor->rowDeleted();
291 if ( !bIsDeleted && !impl_isInsertOnlyForm_throw() )
293 Reference< XPropertySet > xBoundField = impl_getCurrentBoundField_nothrow( );
294 if ( xBoundField.is() )
295 xBoundField->getPropertyValue( PROPERTY_SEARCHABLE ) >>= aState.Enabled;
298 break;
300 case FormFeature::InteractiveSort:
301 case FormFeature::InteractiveFilter:
302 if ( impl_isParseable_throw() )
303 aState.Enabled = !impl_isInsertOnlyForm_throw();
304 break;
306 case FormFeature::ToggleApplyFilter:
308 OUString sFilter;
309 OUString sHaving;
310 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
311 m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sHaving;
312 if ( ! (sFilter.isEmpty() && sHaving.isEmpty()) )
314 aState.State = m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER );
315 aState.Enabled = !impl_isInsertOnlyForm_throw();
317 else
318 aState.State <<= false;
320 break;
322 case FormFeature::MoveAbsolute:
324 sal_Int32 nPosition = m_xCursor->getRow();
325 bool bIsNew = impl_isInsertionRow_throw();
326 sal_Int32 nCount = impl_getRowCount_throw();
327 bool bFinalCount = impl_isRowCountFinal_throw();
329 if ( ( nPosition >= 0 ) || bIsNew )
331 if ( bFinalCount )
333 // special case: there are no records at all, and we
334 // can't insert records -> disabled
335 if ( !nCount && !::dbtools::canInsert( m_xCursorProperties ) )
337 aState.Enabled = false;
339 else
341 if ( bIsNew )
342 nPosition = ++nCount;
343 aState.State <<= nPosition;
344 aState.Enabled = true;
347 else
349 aState.State <<= nPosition;
350 aState.Enabled = true;
354 break;
356 case FormFeature::TotalRecords:
358 bool bIsNew = impl_isInsertionRow_throw();
359 sal_Int32 nCount = impl_getRowCount_throw();
360 bool bFinalCount = impl_isRowCountFinal_throw();
362 if ( bIsNew )
363 ++nCount;
365 OUString sValue = OUString::number( nCount );
366 if ( !bFinalCount )
367 sValue += " *";
369 aState.State <<= sValue;
370 aState.Enabled = true;
372 break;
374 default:
375 OSL_FAIL( "FormOperations::getState: unknown feature id!" );
376 break;
379 catch( const Exception& )
381 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::getState" );
384 return aState;
388 sal_Bool SAL_CALL FormOperations::isEnabled( ::sal_Int16 _nFeature )
390 MethodGuard aGuard( *this );
392 FeatureState aState( getState( _nFeature ) );
393 return aState.Enabled;
397 namespace
399 bool lcl_needConfirmCommit( sal_Int32 _nFeature )
401 return ( ( _nFeature == FormFeature::ReloadForm )
402 || ( _nFeature == FormFeature::RemoveFilterAndSort )
403 || ( _nFeature == FormFeature::ToggleApplyFilter )
404 || ( _nFeature == FormFeature::SortAscending )
405 || ( _nFeature == FormFeature::SortDescending )
406 || ( _nFeature == FormFeature::AutoFilter )
407 || ( _nFeature == FormFeature::InteractiveSort )
408 || ( _nFeature == FormFeature::InteractiveFilter )
411 bool lcl_requiresArguments( sal_Int32 _nFeature )
413 return ( _nFeature == FormFeature::MoveAbsolute );
415 bool lcl_isExecutableFeature( sal_Int32 _nFeature )
417 return ( _nFeature != FormFeature::TotalRecords );
420 template < typename TYPE >
421 TYPE lcl_safeGetPropertyValue_throw( const Reference< XPropertySet >& _rxProperties, const OUString& _rPropertyName, TYPE Default )
423 TYPE value( Default );
424 OSL_PRECOND( _rxProperties.is(), "FormOperations::<foo>: no cursor (already disposed?)!" );
425 if ( _rxProperties.is() )
426 OSL_VERIFY( _rxProperties->getPropertyValue( _rPropertyName ) >>= value );
427 return value;
430 // returns false if parent should *abort* (user pressed cancel)
431 bool checkConfirmation(bool &needConfirmation, bool &shouldCommit)
433 if(needConfirmation)
435 // TODO: shouldn't this be done with an interaction handler?
436 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
437 VclMessageType::Question, VclButtonsType::YesNo,
438 ResourceManager::loadString(RID_STR_QUERY_SAVE_MODIFIED_ROW)));
439 xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
440 xQueryBox->set_default_response(RET_YES);
442 switch (xQueryBox->run())
444 case RET_NO:
445 shouldCommit = false;
446 [[fallthrough]]; // don't ask again!
447 case RET_YES:
448 needConfirmation = false;
449 return true;
450 case RET_CANCEL:
451 return false;
454 return true;
457 bool commit1Form(const Reference< XFormController >& xCntrl, bool &needConfirmation, bool &shouldCommit)
459 Reference< XFormOperations > xFrmOps(xCntrl->getFormOperations());
460 if (!xFrmOps->commitCurrentControl())
461 return false;
463 if(xFrmOps->isModifiedRow())
465 if(!checkConfirmation(needConfirmation, shouldCommit))
466 return false;
467 sal_Bool bTmp;
468 if (shouldCommit && !xFrmOps->commitCurrentRecord(bTmp))
469 return false;
471 return true;
474 bool commitFormAndSubforms(const Reference< XFormController >& xCntrl, bool needConfirmation)
476 bool shouldCommit(true);
477 assert(xCntrl.is());
478 if(xCntrl.is())
480 const sal_Int32 cnt = xCntrl->getCount();
481 for(int i=0; i < cnt; ++i)
483 Reference< XFormController > xSubForm(xCntrl->getByIndex(i), UNO_QUERY);
484 assert(xSubForm.is());
485 if (xSubForm.is())
487 if (!commit1Form(xSubForm, needConfirmation, shouldCommit))
488 return false;
493 return commit1Form(xCntrl, needConfirmation, shouldCommit);
496 bool commit1Form(const Reference< XForm >& xFrm, bool &needConfirmation, bool &shouldCommit)
498 Reference< XPropertySet > xProps(xFrm, UNO_QUERY_THROW);
499 // nothing to do if the record is not modified
500 if(!lcl_safeGetPropertyValue_throw( xProps, PROPERTY_ISMODIFIED, false ))
501 return true;
503 if(!checkConfirmation(needConfirmation, shouldCommit))
504 return false;
505 if(shouldCommit)
507 Reference< XResultSetUpdate > xUpd(xFrm, UNO_QUERY_THROW);
508 // insert respectively update the row
509 if ( lcl_safeGetPropertyValue_throw( xProps, PROPERTY_ISNEW, false ) )
510 xUpd->insertRow();
511 else
512 xUpd->updateRow();
514 return true;
517 bool commitFormAndSubforms(const Reference< XForm >& xFrm, bool needConfirmation)
519 // No control... do what we can with the models
520 bool shouldCommit(true);
521 Reference< XIndexAccess > xFormComps(xFrm, UNO_QUERY_THROW);
523 const sal_Int32 cnt = xFormComps->getCount();
524 for(int i=0; i < cnt; ++i)
526 Reference< XForm > xSubForm(xFormComps->getByIndex(i), UNO_QUERY);
527 if(xSubForm.is())
529 if(!commit1Form(xSubForm, needConfirmation, shouldCommit))
530 return false;
534 return commit1Form(xFrm, needConfirmation, shouldCommit);
538 void SAL_CALL FormOperations::execute( ::sal_Int16 _nFeature )
540 SolarMutexGuard aSolarGuard;
541 MethodGuard aGuard( *this );
543 if ( ( _nFeature != FormFeature::DeleteRecord ) && ( _nFeature != FormFeature::UndoRecordChanges ) )
547 if(m_xController.is())
549 if(!commitFormAndSubforms(m_xController, lcl_needConfirmCommit( _nFeature )))
550 return;
552 else if(m_xCursor.is())
554 Reference< XForm > xForm(m_xCursor, UNO_QUERY);
555 assert(xForm.is());
556 if(!commitFormAndSubforms(xForm, lcl_needConfirmCommit( _nFeature )))
557 return;
559 else
561 SAL_WARN( "forms.runtime", "No cursor, but trying to execute form operation " << _nFeature );
567 switch ( _nFeature )
569 case FormFeature::MoveToFirst:
570 m_xCursor->first();
571 break;
573 case FormFeature::MoveToNext:
574 impl_moveRight_throw( );
575 break;
577 case FormFeature::MoveToPrevious:
578 impl_moveLeft_throw( );
579 break;
581 case FormFeature::MoveToLast:
584 // TODO: re-implement this...
585 // run in an own thread if...
586 // ... the data source is thread safe...
587 sal_Bool bAllowOwnThread = sal_False;
588 if ( ::comphelper::hasProperty( PROPERTY_THREADSAFE, m_xCursorProperties ) )
589 m_xCursorProperties->getPropertyValue( PROPERTY_THREADSAFE ) >>= bAllowOwnThread;
591 // ... the record count is unknown
592 sal_Bool bNeedOwnThread sal_False;
593 if ( ::comphelper::hasProperty( PROPERTY_ROWCOUNTFINAL, m_xCursorProperties ) )
594 m_xCursorProperties->getPropertyValue( PROPERTY_ROWCOUNTFINAL ) >>= bNeedOwnThread;
596 if ( bNeedOwnThread && bAllowOwnThread )
598 else
600 m_xCursor->last();
602 break;
604 case FormFeature::ReloadForm:
605 if ( m_xLoadableForm.is() )
607 weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
608 m_xLoadableForm->reload();
610 // refresh all controls in the form (and sub forms) which can be refreshed
611 // #i90914#
612 ::comphelper::IndexAccessIterator aIter( m_xLoadableForm );
613 Reference< XInterface > xElement( aIter.Next() );
614 while ( xElement.is() )
616 Reference< XRefreshable > xRefresh( xElement, UNO_QUERY );
617 if ( xRefresh.is() )
618 xRefresh->refresh();
619 xElement = aIter.Next();
622 break;
624 case FormFeature::RefreshCurrentControl:
626 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
627 OSL_ENSURE( xControlModelRefresh.is(), "FormOperations::execute: how did you reach this?" );
628 if ( xControlModelRefresh.is() )
629 xControlModelRefresh->refresh();
631 break;
633 case FormFeature::DeleteRecord:
635 sal_uInt32 nCount = impl_getRowCount_throw();
637 // next position
638 bool bLeft = m_xCursor->isLast() && ( nCount > 1 );
639 bool bRight= !m_xCursor->isLast();
640 bool bSuccess = false;
643 // ask for confirmation
644 Reference< XConfirmDeleteListener > xConfirmDelete( m_xController, UNO_QUERY );
646 if ( xConfirmDelete.is() )
648 RowChangeEvent aEvent;
649 aEvent.Source.set( m_xCursor, UNO_QUERY );
650 aEvent.Action = RowChangeAction::DELETE;
651 aEvent.Rows = 1;
652 bSuccess = xConfirmDelete->confirmDelete( aEvent );
655 // delete it
656 if ( bSuccess )
657 m_xUpdateCursor->deleteRow();
659 catch( const Exception& )
661 bSuccess = false;
664 if ( bSuccess )
666 if ( bLeft || bRight )
667 m_xCursor->relative( bRight ? 1 : -1 );
668 else
670 bool bCanInsert = ::dbtools::canInsert( m_xCursorProperties );
671 // is it possible to insert another record?
672 if ( bCanInsert )
673 m_xUpdateCursor->moveToInsertRow();
674 else
675 // move record to update status
676 m_xCursor->first();
680 break;
682 case FormFeature::SaveRecordChanges:
683 case FormFeature::UndoRecordChanges:
685 bool bInserting = impl_isInsertionRow_throw();
687 if ( FormFeature::UndoRecordChanges == _nFeature )
689 if ( !bInserting )
690 m_xUpdateCursor->cancelRowUpdates();
692 // reset all controls for this form
693 impl_resetAllControls_nothrow( );
695 if ( bInserting ) // back to insertion mode for this form
696 m_xUpdateCursor->moveToInsertRow();
698 else
700 if ( bInserting )
702 m_xUpdateCursor->insertRow();
703 m_xCursor->last();
705 else
706 m_xUpdateCursor->updateRow();
709 break;
711 case FormFeature::MoveToInsertRow:
712 // move to the last row before moving to the insert row
713 m_xCursor->last();
714 m_xUpdateCursor->moveToInsertRow();
715 break;
717 case FormFeature::RemoveFilterAndSort:
719 // simultaneously reset Filter and Order property
720 Reference< XMultiPropertySet > xProperties( m_xCursorProperties, UNO_QUERY );
721 OSL_ENSURE( xProperties.is(), "FormOperations::execute: no multi property access!" );
722 if ( xProperties.is() )
724 Sequence< OUString > aNames{ PROPERTY_FILTER, PROPERTY_HAVINGCLAUSE,
725 PROPERTY_SORT };
727 Sequence< Any> aValues{ Any(OUString()), Any(OUString()), Any(OUString()) };
729 weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
730 xProperties->setPropertyValues( aNames, aValues );
732 if ( m_xLoadableForm.is() )
733 m_xLoadableForm->reload();
736 break;
738 case FormFeature::ToggleApplyFilter:
739 if ( impl_commitCurrentControl_throw() && impl_commitCurrentRecord_throw() )
741 // simply toggle the value
742 bool bApplied = false;
743 m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
744 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( !bApplied ) );
746 // and reload
747 weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
748 m_xLoadableForm->reload();
750 break;
752 case FormFeature::SortAscending:
753 impl_executeAutoSort_throw( true );
754 break;
756 case FormFeature::SortDescending:
757 impl_executeAutoSort_throw( false );
758 break;
760 case FormFeature::AutoFilter:
761 impl_executeAutoFilter_throw();
762 break;
764 case FormFeature::InteractiveSort:
765 impl_executeFilterOrSort_throw( false );
766 break;
768 case FormFeature::InteractiveFilter:
769 impl_executeFilterOrSort_throw( true );
770 break;
772 default:
774 TranslateId pErrorResourceId = RID_STR_FEATURE_UNKNOWN;
775 if ( lcl_requiresArguments( _nFeature ) )
776 pErrorResourceId = RID_STR_FEATURE_REQUIRES_PARAMETERS;
777 else if ( !lcl_isExecutableFeature( _nFeature ) )
778 pErrorResourceId = RID_STR_FEATURE_NOT_EXECUTABLE;
779 throw IllegalArgumentException( ResourceManager::loadString(pErrorResourceId), *this, 1 );
781 } // switch
783 catch( const RuntimeException& ) { throw; }
784 catch( const SQLException& ) { throw; }
785 catch( const Exception& )
787 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
790 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
794 void SAL_CALL FormOperations::executeWithArguments( ::sal_Int16 _nFeature, const Sequence< NamedValue >& _rArguments )
796 if ( !lcl_requiresArguments( _nFeature ) )
798 execute( _nFeature );
799 return;
802 SolarMutexGuard aSolarGuard;
803 MethodGuard aGuard( *this );
805 // at the moment we have only one feature which supports execution parameters
806 if ( !lcl_isExecutableFeature( _nFeature ) )
807 throw IllegalArgumentException( ResourceManager::loadString(RID_STR_FEATURE_NOT_EXECUTABLE), *this, 1 );
809 switch ( _nFeature )
811 case FormFeature::MoveAbsolute:
813 sal_Int32 nPosition = -1;
815 ::comphelper::NamedValueCollection aArguments( _rArguments );
816 aArguments.get_ensureType( "Position", nPosition );
818 if ( nPosition < 1 )
819 nPosition = 1;
823 // commit before doing anything else
824 if ( m_xController.is() && !impl_commitCurrentControl_throw() )
825 return;
826 if ( !impl_commitCurrentRecord_throw() )
827 return;
829 sal_Int32 nCount = impl_getRowCount_throw();
830 bool bFinalCount = impl_isRowCountFinal_throw();
832 if ( bFinalCount && ( nPosition > nCount ) )
833 nPosition = nCount;
835 m_xCursor->absolute( nPosition );
837 catch( const RuntimeException& ) { throw; }
838 catch( const SQLException& ) { throw; }
839 catch( const Exception& )
841 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
844 break;
845 default:
846 throw IllegalArgumentException( ResourceManager::loadString(RID_STR_FEATURE_UNKNOWN), *this, 1 );
847 } // switch
851 sal_Bool SAL_CALL FormOperations::commitCurrentRecord( sal_Bool& _out_rRecordInserted )
853 MethodGuard aGuard( *this );
854 _out_rRecordInserted = false;
856 return impl_commitCurrentRecord_throw( &_out_rRecordInserted );
860 bool FormOperations::impl_commitCurrentRecord_throw( sal_Bool* _pRecordInserted ) const
862 #ifdef DBG_UTIL
863 DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentRecord_throw: to be called within a MethodGuard'ed section only!" );
864 #endif
866 if ( !impl_hasCursor_nothrow() )
867 return false;
869 // nothing to do if the record is not modified
870 bool bResult = !impl_isModifiedRow_throw();
871 if ( !bResult )
873 // insert respectively update the row
874 if ( impl_isInsertionRow_throw() )
876 m_xUpdateCursor->insertRow();
877 if ( _pRecordInserted )
878 *_pRecordInserted = true;
880 else
881 m_xUpdateCursor->updateRow();
882 bResult = true;
884 return bResult;
888 sal_Bool SAL_CALL FormOperations::commitCurrentControl()
890 MethodGuard aGuard( *this );
891 return impl_commitCurrentControl_throw();
895 bool FormOperations::impl_commitCurrentControl_throw() const
897 #ifdef DBG_UTIL
898 DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentControl_throw: to be called within a MethodGuard'ed section only!" );
899 #endif
900 OSL_PRECOND( m_xController.is(), "FormOperations::commitCurrentControl: no controller!" );
901 if ( !m_xController.is() )
902 return false;
904 bool bSuccess = false;
907 Reference< XControl > xCurrentControl( m_xController->getCurrentControl() );
909 // check whether the control is locked
910 Reference< XBoundControl > xCheckLock( xCurrentControl, UNO_QUERY );
911 bool bControlIsLocked = xCheckLock.is() && xCheckLock->getLock();
913 // commit if necessary
914 bSuccess = true;
915 if ( xCurrentControl.is() && !bControlIsLocked )
917 // both the control and its model can be committable, so try both
918 Reference< XBoundComponent > xBound( xCurrentControl, UNO_QUERY );
919 if ( !xBound.is() )
920 xBound.set(xCurrentControl->getModel(), css::uno::UNO_QUERY);
921 // and now really commit
922 if ( xBound.is() )
923 bSuccess = xBound->commit();
927 catch( const RuntimeException& ) { throw; }
928 catch( const SQLException& ) { throw; }
929 catch( const Exception& )
931 DBG_UNHANDLED_EXCEPTION("forms.runtime");
932 bSuccess = false;
935 return bSuccess;
939 sal_Bool SAL_CALL FormOperations::isInsertionRow()
941 bool bIs = false;
944 bIs = impl_isInsertionRow_throw();
946 catch( const RuntimeException& ) { throw; }
947 catch( const Exception& )
949 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
951 return bIs;
955 sal_Bool SAL_CALL FormOperations::isModifiedRow()
957 bool bIs = false;
960 bIs = impl_isModifiedRow_throw();
962 catch( const RuntimeException& ) { throw; }
963 catch( const Exception& )
965 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
967 return bIs;
971 void SAL_CALL FormOperations::cursorMoved( const EventObject& /*_Event*/ )
973 MethodGuard aGuard( *this );
974 m_bActiveControlModified = false;
976 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
980 void SAL_CALL FormOperations::rowChanged( const EventObject& /*_Event*/ )
982 // not interested in
986 void SAL_CALL FormOperations::rowSetChanged( const EventObject& /*_Event*/ )
988 // not interested in
992 void SAL_CALL FormOperations::modified( const EventObject& /*_Source*/ )
994 MethodGuard aGuard( *this );
996 OSL_ENSURE( m_xCursor.is(), "FormOperations::modified: already disposed!" );
997 if ( !m_bActiveControlModified )
999 m_bActiveControlModified = true;
1000 impl_invalidateModifyDependentFeatures_nothrow( aGuard );
1005 void SAL_CALL FormOperations::propertyChange( const PropertyChangeEvent& _rEvent )
1007 MethodGuard aGuard( *this );
1009 if ( m_xCursor.is() && ( m_xCursor == _rEvent.Source ) )
1011 if ( ( _rEvent.PropertyName == PROPERTY_ISMODIFIED )
1012 || ( _rEvent.PropertyName == PROPERTY_ISNEW )
1015 bool bIs = false;
1016 if ( ( _rEvent.NewValue >>= bIs ) && !bIs )
1017 m_bActiveControlModified = false;
1019 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
1022 if ( !(m_xParser.is() && ( m_xCursor == _rEvent.Source )) )
1023 return;
1027 OUString sNewValue;
1028 _rEvent.NewValue >>= sNewValue;
1029 if ( _rEvent.PropertyName == PROPERTY_ACTIVECOMMAND )
1031 m_xParser->setElementaryQuery( sNewValue );
1033 else if ( _rEvent.PropertyName == PROPERTY_FILTER )
1035 if ( m_xParser->getFilter() != sNewValue )
1036 m_xParser->setFilter( sNewValue );
1038 else if ( _rEvent.PropertyName == PROPERTY_HAVINGCLAUSE )
1040 if ( m_xParser->getHavingClause() != sNewValue )
1041 m_xParser->setHavingClause( sNewValue );
1043 else if ( _rEvent.PropertyName == PROPERTY_SORT )
1045 _rEvent.NewValue >>= sNewValue;
1046 if ( m_xParser->getOrder() != sNewValue )
1047 m_xParser->setOrder( sNewValue );
1050 catch( const Exception& )
1052 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::propertyChange: caught an exception while updating the parser!" );
1054 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
1058 void SAL_CALL FormOperations::disposing( const EventObject& /*_Source*/ )
1060 // TODO: should we react on this? Or is this the responsibility of our owner to dispose us?
1064 void SAL_CALL FormOperations::disposing()
1066 ::osl::MutexGuard aGuard( m_aMutex );
1068 impl_disposeParser_nothrow();
1072 // revoke various listeners
1073 if ( m_xCursor.is() )
1074 m_xCursor->removeRowSetListener( this );
1076 if ( m_xCursorProperties.is() )
1078 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISMODIFIED,this );
1079 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISNEW, this );
1082 if ( m_xController.is() )
1083 m_xController->removeModifyListener( this );
1085 catch( const Exception& )
1087 DBG_UNHANDLED_EXCEPTION("forms.runtime");
1090 m_xController.clear();
1091 m_xCursor.clear();
1092 m_xUpdateCursor.clear();
1093 m_xCursorProperties.clear();
1094 m_xLoadableForm.clear();
1095 m_xFeatureInvalidation.clear();
1097 m_bActiveControlModified = true;
1101 void FormOperations::impl_checkDisposed_throw() const
1103 if ( !m_xCursor.is() )
1104 throw DisposedException( OUString(), *const_cast< FormOperations* >( this ) );
1108 void FormOperations::impl_initFromController_throw()
1110 OSL_PRECOND( m_xController.is(), "FormOperations::impl_initFromController_throw: invalid controller!" );
1111 m_xCursor.set(m_xController->getModel(), css::uno::UNO_QUERY);
1112 if ( !m_xCursor.is() )
1113 throw IllegalArgumentException( OUString(), *this, 0 );
1115 impl_initFromForm_throw();
1117 if ( m_xController.is() )
1118 m_xController->addModifyListener( this );
1122 void FormOperations::impl_initFromForm_throw()
1124 OSL_PRECOND( m_xCursor.is(), "FormOperations::impl_initFromForm_throw: invalid form!" );
1125 m_xCursorProperties.set(m_xCursor, css::uno::UNO_QUERY);
1126 m_xUpdateCursor.set(m_xCursor, css::uno::UNO_QUERY);
1127 m_xLoadableForm.set(m_xCursor, css::uno::UNO_QUERY);
1129 if ( !m_xCursor.is() || !m_xCursorProperties.is() || !m_xLoadableForm.is() )
1130 throw IllegalArgumentException( OUString(), *this, 0 );
1132 m_xCursor->addRowSetListener( this );
1133 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISMODIFIED,this );
1134 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISNEW, this );
1138 void FormOperations::createWithFormController( const Reference< XFormController >& _rxController )
1140 m_xController = _rxController;
1141 if ( !m_xController.is() )
1142 throw IllegalArgumentException( OUString(), *this, 0 );
1144 impl_initFromController_throw();
1146 m_bConstructed = true;
1150 void FormOperations::createWithForm( const Reference< XForm >& _rxForm )
1152 m_xCursor.set(_rxForm, css::uno::UNO_QUERY);
1153 if ( !m_xCursor.is() )
1154 throw IllegalArgumentException( OUString(), *this, 0 );
1156 impl_initFromForm_throw();
1158 m_bConstructed = true;
1162 void FormOperations::impl_invalidateAllSupportedFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1164 if ( !m_xFeatureInvalidation.is() )
1165 // nobody's interested in ...
1166 return;
1168 Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1169 _rClearForCallback.clear();
1170 xInvalidation->invalidateAllFeatures();
1174 void FormOperations::impl_invalidateModifyDependentFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1176 if ( !m_xFeatureInvalidation.is() )
1177 // nobody's interested in ...
1178 return;
1180 static Sequence< sal_Int16 > const s_aModifyDependentFeatures
1182 FormFeature::MoveToNext,
1183 FormFeature::MoveToInsertRow,
1184 FormFeature::SaveRecordChanges,
1185 FormFeature::UndoRecordChanges
1188 Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1189 _rClearForCallback.clear();
1191 xInvalidation->invalidateFeatures( s_aModifyDependentFeatures );
1195 void FormOperations::impl_ensureInitializedParser_nothrow()
1197 OSL_PRECOND( m_xCursorProperties.is(), "FormOperations::impl_ensureInitializedParser_nothrow: we're disposed!" );
1198 if ( m_bInitializedParser )
1199 return;
1203 bool bUseEscapeProcessing = false;
1204 m_xCursorProperties->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bUseEscapeProcessing;
1205 if ( bUseEscapeProcessing )
1207 Reference< XMultiServiceFactory > xFactory( ::dbtools::getConnection( m_xCursor ), UNO_QUERY );
1208 if ( xFactory.is() )
1210 m_xParser.set( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"), UNO_QUERY );
1211 OSL_ENSURE( m_xParser.is(), "FormOperations::impl_ensureInitializedParser_nothrow: factory did not create a parser for us!" );
1215 if ( m_xParser.is() )
1217 if ( m_xLoadableForm.is() && m_xLoadableForm->isLoaded() )
1219 OUString sStatement;
1220 OUString sFilter;
1221 OUString sHaving;
1222 OUString sSort;
1224 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sStatement;
1225 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
1226 m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sHaving;
1227 m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sSort;
1229 m_xParser->setElementaryQuery( sStatement );
1230 m_xParser->setFilter ( sFilter );
1231 m_xParser->setHavingClause ( sHaving );
1232 m_xParser->setOrder ( sSort );
1235 // start listening at the order/sort properties at the form, so
1236 // we can keep our parser in sync
1237 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1238 m_xCursorProperties->addPropertyChangeListener( PROPERTY_FILTER, this );
1239 m_xCursorProperties->addPropertyChangeListener( PROPERTY_HAVINGCLAUSE, this );
1240 m_xCursorProperties->addPropertyChangeListener( PROPERTY_SORT, this );
1243 catch( const Exception& )
1245 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_ensureInitializedParser_nothrow" );
1248 m_bInitializedParser = true;
1252 void FormOperations::impl_disposeParser_nothrow()
1256 // if we have a parser (and a cursor), then we're listening at the cursor's
1257 // properties to keep the parser in sync with the cursor
1258 if ( m_xParser.is() && m_xCursorProperties.is() )
1260 m_xCursorProperties->removePropertyChangeListener( PROPERTY_FILTER, this );
1261 m_xCursorProperties->removePropertyChangeListener( PROPERTY_HAVINGCLAUSE, this );
1262 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1263 m_xCursorProperties->removePropertyChangeListener( PROPERTY_SORT, this );
1266 Reference< XComponent > xParserComp( m_xParser, UNO_QUERY );
1267 if ( xParserComp.is() )
1268 xParserComp->dispose();
1269 m_xParser.clear();
1271 m_bInitializedParser = false;
1273 catch( const Exception& )
1275 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_disposeParser_nothrow" );
1280 bool FormOperations::impl_canMoveLeft_throw( ) const
1282 if ( !impl_hasCursor_nothrow() )
1283 return false;
1285 return impl_getRowCount_throw() && ( !m_xCursor->isFirst() || impl_isInsertionRow_throw() );
1289 bool FormOperations::impl_canMoveRight_throw( ) const
1291 if ( !impl_hasCursor_nothrow() )
1292 return false;
1294 bool bIsNew = impl_isInsertionRow_throw();
1296 if ( impl_getRowCount_throw() && !m_xCursor->isLast() && !bIsNew )
1297 return true;
1299 if ( ::dbtools::canInsert( m_xCursorProperties ) )
1300 if ( !bIsNew || impl_isModifiedRow_throw() )
1301 return true;
1303 if ( bIsNew && m_bActiveControlModified )
1304 return true;
1306 return false;
1310 bool FormOperations::impl_isInsertionRow_throw() const
1312 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISNEW, false );
1316 sal_Int32 FormOperations::impl_getRowCount_throw() const
1318 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNT, sal_Int32(0) );
1321 bool FormOperations::impl_isRowCountFinal_throw() const
1323 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNTFINAL, false );
1327 bool FormOperations::impl_isModifiedRow_throw() const
1329 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISMODIFIED, false );
1333 bool FormOperations::impl_isParseable_throw() const
1335 const_cast< FormOperations* >( this )->impl_ensureInitializedParser_nothrow();
1336 return m_xParser.is() && !m_xParser->getQuery().isEmpty();
1340 bool FormOperations::impl_hasFilterOrOrder_throw() const
1342 return impl_isParseable_throw() && ( !m_xParser->getFilter().isEmpty() ||
1343 !m_xParser->getHavingClause().isEmpty() ||
1344 !m_xParser->getOrder().isEmpty() );
1348 bool FormOperations::impl_isInsertOnlyForm_throw() const
1350 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_INSERTONLY, true );
1354 Reference< XControlModel > FormOperations::impl_getCurrentControlModel_throw() const
1356 Reference< XControl > xControl( m_xController->getCurrentControl() );
1358 // special handling for grid controls
1359 Reference< XGrid > xGrid( xControl, UNO_QUERY );
1360 Reference< XControlModel > xControlModel;
1362 if ( xGrid.is() )
1364 Reference< XIndexAccess > xColumns( xControl->getModel(), UNO_QUERY_THROW );
1365 sal_Int32 nCurrentPos = impl_gridView2ModelPos_nothrow( xColumns, xGrid->getCurrentColumnPosition() );
1367 if ( nCurrentPos != -1 )
1368 xColumns->getByIndex( nCurrentPos ) >>= xControlModel;
1370 else if ( xControl.is() )
1372 xControlModel = xControl->getModel();
1374 return xControlModel;
1378 Reference< XPropertySet > FormOperations::impl_getCurrentBoundField_nothrow( ) const
1380 OSL_PRECOND( m_xController.is(), "FormOperations::impl_getCurrentBoundField_nothrow: no controller -> no control!" );
1381 if ( !m_xController.is() )
1382 return nullptr;
1384 Reference< XPropertySet > xField;
1387 Reference< XPropertySet > xControlModel( impl_getCurrentControlModel_throw(), UNO_QUERY );
1389 if ( xControlModel.is() && ::comphelper::hasProperty( PROPERTY_BOUNDFIELD, xControlModel ) )
1390 xControlModel->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xField;
1393 catch( const Exception& )
1395 DBG_UNHANDLED_EXCEPTION("forms.runtime");
1398 return xField;
1402 sal_Int32 FormOperations::impl_gridView2ModelPos_nothrow( const Reference< XIndexAccess >& _rxColumns, sal_Int16 _nViewPos )
1404 OSL_PRECOND( _rxColumns.is(), "FormOperations::impl_gridView2ModelPos_nothrow: invalid columns container!" );
1407 // loop through all columns
1408 sal_Int32 col = 0;
1409 Reference< XPropertySet > xCol;
1410 bool bHidden( false );
1411 for ( col = 0; col < _rxColumns->getCount(); ++col )
1413 _rxColumns->getByIndex( col ) >>= xCol;
1414 OSL_VERIFY( xCol->getPropertyValue( PROPERTY_HIDDEN ) >>= bHidden );
1415 if ( bHidden )
1416 continue;
1418 // for every visible col : if nViewPos is greater zero, decrement it, else we
1419 // have found the model position
1420 if ( !_nViewPos )
1421 break;
1422 else
1423 --_nViewPos;
1425 if ( col < _rxColumns->getCount() )
1426 return col;
1428 catch( const Exception& )
1430 DBG_UNHANDLED_EXCEPTION("forms.runtime");
1432 return -1;
1436 void FormOperations::impl_moveLeft_throw( ) const
1438 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveLeft_throw: no cursor!" );
1439 if ( !impl_hasCursor_nothrow() )
1440 return;
1442 sal_Bool bRecordInserted = false;
1443 bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1445 if ( !bSuccess )
1446 return;
1448 if ( bRecordInserted )
1450 // retrieve the bookmark of the new record and move to the record preceding this bookmark
1451 Reference< XRowLocate > xLocate( m_xCursor, UNO_QUERY );
1452 OSL_ENSURE( xLocate.is(), "FormOperations::impl_moveLeft_throw: no XRowLocate!" );
1453 if ( xLocate.is() )
1454 xLocate->moveRelativeToBookmark( xLocate->getBookmark(), -1 );
1456 else
1458 if ( impl_isInsertionRow_throw() )
1460 // we assume that the inserted record is now the last record in the
1461 // result set
1462 m_xCursor->last();
1464 else
1465 m_xCursor->previous();
1470 void FormOperations::impl_moveRight_throw( ) const
1472 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveRight_throw: no cursor!" );
1473 if ( !impl_hasCursor_nothrow() )
1474 return;
1476 sal_Bool bRecordInserted = false;
1477 bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1479 if ( !bSuccess )
1480 return;
1482 if ( bRecordInserted )
1484 // go to insert row
1485 m_xUpdateCursor->moveToInsertRow();
1487 else
1489 if ( m_xCursor->isLast() )
1490 m_xUpdateCursor->moveToInsertRow();
1491 else
1492 (void)m_xCursor->next();
1497 void FormOperations::impl_resetAllControls_nothrow() const
1499 Reference< XIndexAccess > xContainer( m_xCursor, UNO_QUERY );
1500 if ( !xContainer.is() )
1501 return;
1505 Reference< XReset > xReset;
1506 sal_Int32 nCount( xContainer->getCount() );
1507 for ( sal_Int32 i = 0; i < nCount; ++i )
1509 if ( xContainer->getByIndex( i ) >>= xReset )
1511 // no resets on sub forms
1512 Reference< XForm > xAsForm( xReset, UNO_QUERY );
1513 if ( !xAsForm.is() )
1514 xReset->reset();
1518 catch( const Exception& )
1520 DBG_UNHANDLED_EXCEPTION("forms.runtime");
1525 void FormOperations::impl_executeAutoSort_throw( bool _bUp ) const
1527 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoSort_throw: need a controller for this!" );
1528 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoSort_throw: need a cursor for this!" );
1529 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoSort_throw: need a parseable statement for this!" );
1530 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1531 return;
1535 Reference< XControl > xControl = m_xController->getCurrentControl();
1536 if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1537 return;
1539 Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1540 if ( !xBoundField.is() )
1541 return;
1543 OUString sOriginalSort;
1544 m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sOriginalSort;
1546 // automatic sort by field is expected to always resets the previous sort order
1547 m_xParser->setOrder( OUString() );
1549 impl_appendOrderByColumn_throw aAction(this, xBoundField, _bUp);
1550 impl_doActionInSQLContext_throw(aAction, RID_STR_COULD_NOT_SET_ORDER );
1552 weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
1555 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1556 m_xLoadableForm->reload();
1558 catch( const Exception& )
1560 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_executeAutoSort_throw: caught an exception while setting the parser properties!" );
1564 if ( !m_xLoadableForm->isLoaded() )
1565 { // something went wrong -> restore the original state
1568 m_xParser->setOrder( sOriginalSort );
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: could not reset the form to its original state!" );
1579 catch( const RuntimeException& ) { throw; }
1580 catch( const SQLException& ) { throw; }
1581 catch( const Exception& )
1583 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1588 void FormOperations::impl_executeAutoFilter_throw( ) const
1590 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoFilter_throw: need a controller for this!" );
1591 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoFilter_throw: need a cursor for this!" );
1592 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoFilter_throw: need a parseable statement for this!" );
1593 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1594 return;
1598 Reference< XControl > xControl = m_xController->getCurrentControl();
1599 if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1600 return;
1602 Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1603 if ( !xBoundField.is() )
1604 return;
1606 OUString sOriginalFilter;
1607 OUString sOriginalHaving;
1608 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
1609 m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sOriginalHaving;
1610 bool bApplied = true;
1611 m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
1613 // if we have a filter, but it's not applied, then we have to overwrite it, else append one
1614 if ( !bApplied )
1616 m_xParser->setFilter( OUString() );
1617 m_xParser->setHavingClause( OUString() );
1620 impl_appendFilterByColumn_throw aAction(this, m_xParser, xBoundField);
1621 impl_doActionInSQLContext_throw( aAction, RID_STR_COULD_NOT_SET_FILTER );
1623 weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
1626 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1627 m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, makeAny( m_xParser->getHavingClause() ) );
1628 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( true ) );
1630 m_xLoadableForm->reload();
1632 catch( const Exception& )
1634 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_executeAutoFilter_throw: caught an exception while setting the parser properties!" );
1638 if ( !m_xLoadableForm->isLoaded() )
1639 { // something went wrong -> restore the original state
1642 m_xParser->setFilter ( sOriginalFilter );
1643 m_xParser->setHavingClause( sOriginalHaving );
1644 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( bApplied ) );
1645 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1646 m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, makeAny( m_xParser->getHavingClause() ) );
1647 m_xLoadableForm->reload();
1649 catch( const Exception& )
1651 OSL_FAIL( "FormOperations::impl_executeAutoFilter_throw: could not reset the form to its original state!" );
1656 catch( const RuntimeException& ) { throw; }
1657 catch( const SQLException& ) { throw; }
1658 catch( const Exception& )
1660 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1664 css::uno::Reference<css::awt::XWindow> FormOperations::GetDialogParent() const
1666 css::uno::Reference<css::awt::XWindow> xDialogParent;
1668 //tdf#122152 extract parent for dialog
1669 if (m_xController.is())
1671 css::uno::Reference<css::awt::XControl> xContainerControl(m_xController->getContainer(), css::uno::UNO_QUERY);
1672 if (xContainerControl.is())
1674 css::uno::Reference<css::awt::XWindowPeer> xContainerPeer = xContainerControl->getPeer();
1675 xDialogParent = css::uno::Reference<css::awt::XWindow>(xContainerPeer, css::uno::UNO_QUERY);
1679 return xDialogParent;
1682 void FormOperations::impl_executeFilterOrSort_throw( bool _bFilter ) const
1684 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeFilterOrSort_throw: need a controller for this!" );
1685 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeFilterOrSort_throw: need a cursor for this!" );
1686 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeFilterOrSort_throw: need a parseable statement for this!" );
1687 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1688 return;
1690 if ( !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1691 return;
1694 css::uno::Reference<css::awt::XWindow> xDialogParent(GetDialogParent());
1696 Reference< XExecutableDialog> xDialog;
1697 if ( _bFilter )
1699 xDialog = css::sdb::FilterDialog::createWithQuery(m_xContext, m_xParser, m_xCursor,
1700 xDialogParent);
1702 else
1704 xDialog = css::sdb::OrderDialog::createWithQuery(m_xContext, m_xParser, m_xCursorProperties,
1705 xDialogParent);
1708 if ( RET_OK == xDialog->execute() )
1710 weld::WaitObject aWO(Application::GetFrameWeld(xDialogParent));
1711 if ( _bFilter )
1713 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1714 m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, makeAny( m_xParser->getHavingClause() ) );
1716 else
1717 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1718 m_xLoadableForm->reload();
1722 catch( const RuntimeException& ) { throw; }
1723 catch( const SQLException& ) { throw; }
1724 catch( const Exception& )
1726 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1731 template < typename FunctObj >
1732 void FormOperations::impl_doActionInSQLContext_throw( FunctObj f, TranslateId pErrorResourceId ) const
1736 f();
1738 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1739 catch( const SQLException& )
1741 if (!pErrorResourceId) // no information to prepend
1742 throw;
1744 SQLExceptionInfo aInfo( ::cppu::getCaughtException() );
1745 OUString sAdditionalError( ResourceManager::loadString(pErrorResourceId) );
1746 aInfo.prepend( sAdditionalError );
1747 aInfo.doThrow();
1749 #endif
1750 catch( const RuntimeException& ) { throw; }
1751 catch( const Exception& )
1753 OUString sAdditionalError( ResourceManager::loadString(pErrorResourceId) );
1754 throw WrappedTargetException( sAdditionalError, *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1759 } // namespace frm
1762 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
1763 com_sun_star_comp_forms_FormOperations_get_implementation(css::uno::XComponentContext* context,
1764 css::uno::Sequence<css::uno::Any> const &)
1766 return cppu::acquire(new frm::FormOperations(context));
1769 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */