bump product version to 7.6.3.2-android
[LibreOffice.git] / forms / source / runtime / formoperations.cxx
blob1e3df2857e74b5a1fa095f9923ca68ad7fd30d21
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 <comphelper/diagnose_ex.hxx>
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::uno::UNO_QUERY;
90 using ::com::sun::star::lang::EventObject;
91 using ::com::sun::star::beans::PropertyChangeEvent;
92 using ::com::sun::star::lang::XMultiServiceFactory;
93 using ::com::sun::star::lang::DisposedException;
94 using ::com::sun::star::beans::XPropertySet;
95 using ::com::sun::star::awt::XControl;
96 using ::com::sun::star::form::XGrid;
97 using ::com::sun::star::container::XIndexAccess;
98 using ::com::sun::star::uno::UNO_QUERY_THROW;
99 using ::com::sun::star::form::XBoundControl;
100 using ::com::sun::star::form::XBoundComponent;
101 using ::com::sun::star::sdbcx::XRowLocate;
102 using ::com::sun::star::form::XConfirmDeleteListener;
103 using ::com::sun::star::sdb::RowChangeEvent;
104 using namespace ::com::sun::star::sdb;
105 using ::com::sun::star::form::XReset;
106 using ::com::sun::star::beans::XMultiPropertySet;
107 using ::com::sun::star::lang::WrappedTargetException;
108 using ::com::sun::star::ui::dialogs::XExecutableDialog;
109 using ::com::sun::star::beans::NamedValue;
110 using ::com::sun::star::util::XRefreshable;
111 using ::com::sun::star::awt::XControlModel;
113 namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
114 namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
116 FormOperations::FormOperations( const Reference< XComponentContext >& _rxContext )
117 :FormOperations_Base( m_aMutex )
118 ,m_xContext( _rxContext )
119 ,m_bInitializedParser( false )
120 ,m_bActiveControlModified( false )
121 ,m_bConstructed( false )
122 #ifdef DBG_UTIL
123 ,m_nMethodNestingLevel( 0 )
124 #endif
128 FormOperations::~FormOperations()
132 void SAL_CALL FormOperations::initialize( const Sequence< Any >& _arguments )
134 if ( m_bConstructed )
135 throw AlreadyInitializedException();
137 if ( _arguments.getLength() == 1 )
139 Reference< XFormController > xController;
140 Reference< XForm > xForm;
141 if ( _arguments[0] >>= xController )
142 createWithFormController( xController );
143 else if ( _arguments[0] >>= xForm )
144 createWithForm( xForm );
145 else
146 throw IllegalArgumentException( OUString(), *this, 1 );
147 return;
150 throw IllegalArgumentException( OUString(), *this, 0 );
153 OUString SAL_CALL FormOperations::getImplementationName( )
155 return "com.sun.star.comp.forms.FormOperations";
158 sal_Bool SAL_CALL FormOperations::supportsService( const OUString& ServiceName )
160 return cppu::supportsService(this, ServiceName);
163 Sequence< OUString > SAL_CALL FormOperations::getSupportedServiceNames( )
165 return { "com.sun.star.form.runtime.FormOperations" };
168 Reference< XRowSet > SAL_CALL FormOperations::getCursor()
170 MethodGuard aGuard( *this );
171 return m_xCursor;
174 Reference< XResultSetUpdate > SAL_CALL FormOperations::getUpdateCursor()
176 MethodGuard aGuard( *this );
177 return m_xUpdateCursor;
181 Reference< XFormController > SAL_CALL FormOperations::getController()
183 MethodGuard aGuard( *this );
184 return m_xController;
188 Reference< XFeatureInvalidation > SAL_CALL FormOperations::getFeatureInvalidation()
190 MethodGuard aGuard( *this );
191 return m_xFeatureInvalidation;
195 void SAL_CALL FormOperations::setFeatureInvalidation( const Reference< XFeatureInvalidation > & _rxFeatureInvalidation )
197 MethodGuard aGuard( *this );
198 m_xFeatureInvalidation = _rxFeatureInvalidation;
202 FeatureState SAL_CALL FormOperations::getState( ::sal_Int16 _nFeature )
204 MethodGuard aGuard( *this );
206 FeatureState aState;
207 aState.Enabled = false;
211 // some checks for basic pre-requisites
212 if ( !m_xLoadableForm.is()
213 || !m_xLoadableForm->isLoaded()
214 || !m_xCursorProperties.is()
217 return aState;
220 switch ( _nFeature )
222 case FormFeature::MoveToFirst:
223 case FormFeature::MoveToPrevious:
224 aState.Enabled = impl_canMoveLeft_throw( );
225 break;
227 case FormFeature::MoveToNext:
228 aState.Enabled = impl_canMoveRight_throw();
229 break;
231 case FormFeature::MoveToLast:
232 aState.Enabled = impl_getRowCount_throw() && ( !m_xCursor->isLast() || impl_isInsertionRow_throw() );
233 break;
235 case FormFeature::DeleteRecord:
236 // already deleted ?
237 if ( m_xCursor->rowDeleted() )
238 aState.Enabled = false;
239 else
241 // allowed to delete the row ?
242 aState.Enabled = !impl_isInsertionRow_throw() && ::dbtools::canDelete( m_xCursorProperties );
244 break;
246 case FormFeature::MoveToInsertRow:
247 // if we are inserting we can move to the next row if the current record or control is modified
248 aState.Enabled = impl_isInsertionRow_throw()
249 ? impl_isModifiedRow_throw() || m_bActiveControlModified
250 : ::dbtools::canInsert( m_xCursorProperties );
251 break;
253 case FormFeature::ReloadForm:
255 // there must be an active connection
256 aState.Enabled = ::dbtools::getConnection( m_xCursor ).is();
258 // and an active command
259 OUString sActiveCommand;
260 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sActiveCommand;
261 aState.Enabled = aState.Enabled && !sActiveCommand.isEmpty();
263 break;
265 case FormFeature::RefreshCurrentControl:
267 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
268 aState.Enabled = xControlModelRefresh.is();
270 break;
272 case FormFeature::SaveRecordChanges:
273 case FormFeature::UndoRecordChanges:
274 aState.Enabled = impl_isModifiedRow_throw() || m_bActiveControlModified;
275 break;
277 case FormFeature::RemoveFilterAndSort:
278 if ( impl_isParseable_throw() && impl_hasFilterOrOrder_throw() )
279 aState.Enabled = !impl_isInsertOnlyForm_throw();
280 break;
282 case FormFeature::SortAscending:
283 case FormFeature::SortDescending:
284 case FormFeature::AutoFilter:
285 if ( m_xController.is() && impl_isParseable_throw() )
287 bool bIsDeleted = m_xCursor->rowDeleted();
289 if ( !bIsDeleted && !impl_isInsertOnlyForm_throw() )
291 Reference< XPropertySet > xBoundField = impl_getCurrentBoundField_nothrow( );
292 if ( xBoundField.is() )
293 xBoundField->getPropertyValue( PROPERTY_SEARCHABLE ) >>= aState.Enabled;
296 break;
298 case FormFeature::InteractiveSort:
299 case FormFeature::InteractiveFilter:
300 if ( impl_isParseable_throw() )
301 aState.Enabled = !impl_isInsertOnlyForm_throw();
302 break;
304 case FormFeature::ToggleApplyFilter:
306 OUString sFilter;
307 OUString sHaving;
308 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
309 m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sHaving;
310 if ( ! (sFilter.isEmpty() && sHaving.isEmpty()) )
312 aState.State = m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER );
313 aState.Enabled = !impl_isInsertOnlyForm_throw();
315 else
316 aState.State <<= false;
318 break;
320 case FormFeature::MoveAbsolute:
322 sal_Int32 nPosition = m_xCursor->getRow();
323 bool bIsNew = impl_isInsertionRow_throw();
324 sal_Int32 nCount = impl_getRowCount_throw();
325 bool bFinalCount = impl_isRowCountFinal_throw();
327 if ( ( nPosition >= 0 ) || bIsNew )
329 if ( bFinalCount )
331 // special case: there are no records at all, and we
332 // can't insert records -> disabled
333 if ( !nCount && !::dbtools::canInsert( m_xCursorProperties ) )
335 aState.Enabled = false;
337 else
339 if ( bIsNew )
340 nPosition = ++nCount;
341 aState.State <<= nPosition;
342 aState.Enabled = true;
345 else
347 aState.State <<= nPosition;
348 aState.Enabled = true;
352 break;
354 case FormFeature::TotalRecords:
356 bool bIsNew = impl_isInsertionRow_throw();
357 sal_Int32 nCount = impl_getRowCount_throw();
358 bool bFinalCount = impl_isRowCountFinal_throw();
360 if ( bIsNew )
361 ++nCount;
363 OUString sValue = OUString::number( nCount );
364 if ( !bFinalCount )
365 sValue += " *";
367 aState.State <<= sValue;
368 aState.Enabled = true;
370 break;
372 default:
373 OSL_FAIL( "FormOperations::getState: unknown feature id!" );
374 break;
377 catch( const Exception& )
379 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::getState" );
382 return aState;
386 sal_Bool SAL_CALL FormOperations::isEnabled( ::sal_Int16 _nFeature )
388 MethodGuard aGuard( *this );
390 FeatureState aState( getState( _nFeature ) );
391 return aState.Enabled;
395 namespace
397 bool lcl_needConfirmCommit( sal_Int32 _nFeature )
399 return ( ( _nFeature == FormFeature::ReloadForm )
400 || ( _nFeature == FormFeature::RemoveFilterAndSort )
401 || ( _nFeature == FormFeature::ToggleApplyFilter )
402 || ( _nFeature == FormFeature::SortAscending )
403 || ( _nFeature == FormFeature::SortDescending )
404 || ( _nFeature == FormFeature::AutoFilter )
405 || ( _nFeature == FormFeature::InteractiveSort )
406 || ( _nFeature == FormFeature::InteractiveFilter )
409 bool lcl_requiresArguments( sal_Int32 _nFeature )
411 return ( _nFeature == FormFeature::MoveAbsolute );
413 bool lcl_isExecutableFeature( sal_Int32 _nFeature )
415 return ( _nFeature != FormFeature::TotalRecords );
418 template < typename TYPE >
419 TYPE lcl_safeGetPropertyValue_throw( const Reference< XPropertySet >& _rxProperties, const OUString& _rPropertyName, TYPE Default )
421 TYPE value( Default );
422 OSL_PRECOND( _rxProperties.is(), "FormOperations::<foo>: no cursor (already disposed?)!" );
423 if ( _rxProperties.is() )
424 OSL_VERIFY( _rxProperties->getPropertyValue( _rPropertyName ) >>= value );
425 return value;
428 // returns false if parent should *abort* (user pressed cancel)
429 bool checkConfirmation(bool &needConfirmation, bool &shouldCommit)
431 if(!needConfirmation)
432 return true;
433 // TODO: shouldn't this be done with an interaction handler?
434 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
435 VclMessageType::Question, VclButtonsType::YesNo,
436 ResourceManager::loadString(RID_STR_QUERY_SAVE_MODIFIED_ROW)));
437 xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
438 xQueryBox->set_default_response(RET_YES);
440 switch (xQueryBox->run())
442 case RET_NO:
443 shouldCommit = false;
444 [[fallthrough]]; // don't ask again!
445 case RET_YES:
446 needConfirmation = false;
447 return true;
448 case RET_CANCEL:
449 return false;
451 return true;
454 bool commit1Form(const Reference< XFormController >& xCntrl, bool &needConfirmation, bool &shouldCommit)
456 Reference< XFormOperations > xFrmOps(xCntrl->getFormOperations());
457 if (!xFrmOps->commitCurrentControl())
458 return false;
460 if(xFrmOps->isModifiedRow())
462 if(!checkConfirmation(needConfirmation, shouldCommit))
463 return false;
464 sal_Bool bTmp;
465 if (shouldCommit && !xFrmOps->commitCurrentRecord(bTmp))
466 return false;
468 return true;
471 bool commitFormAndSubforms(const Reference< XFormController >& xCntrl, bool needConfirmation)
473 bool shouldCommit(true);
474 assert(xCntrl.is());
475 if(xCntrl.is())
477 const sal_Int32 cnt = xCntrl->getCount();
478 for(int i=0; i < cnt; ++i)
480 Reference< XFormController > xSubForm(xCntrl->getByIndex(i), UNO_QUERY);
481 assert(xSubForm.is());
482 if (xSubForm.is())
484 if (!commit1Form(xSubForm, needConfirmation, shouldCommit))
485 return false;
490 return commit1Form(xCntrl, needConfirmation, shouldCommit);
493 bool commit1Form(const Reference< XForm >& xFrm, bool &needConfirmation, bool &shouldCommit)
495 Reference< XPropertySet > xProps(xFrm, UNO_QUERY_THROW);
496 // nothing to do if the record is not modified
497 if(!lcl_safeGetPropertyValue_throw( xProps, PROPERTY_ISMODIFIED, false ))
498 return true;
500 if(!checkConfirmation(needConfirmation, shouldCommit))
501 return false;
502 if(shouldCommit)
504 Reference< XResultSetUpdate > xUpd(xFrm, UNO_QUERY_THROW);
505 // insert respectively update the row
506 if ( lcl_safeGetPropertyValue_throw( xProps, PROPERTY_ISNEW, false ) )
507 xUpd->insertRow();
508 else
509 xUpd->updateRow();
511 return true;
514 bool commitFormAndSubforms(const Reference< XForm >& xFrm, bool needConfirmation)
516 // No control... do what we can with the models
517 bool shouldCommit(true);
518 Reference< XIndexAccess > xFormComps(xFrm, UNO_QUERY_THROW);
520 const sal_Int32 cnt = xFormComps->getCount();
521 for(int i=0; i < cnt; ++i)
523 Reference< XForm > xSubForm(xFormComps->getByIndex(i), UNO_QUERY);
524 if(xSubForm.is())
526 if(!commit1Form(xSubForm, needConfirmation, shouldCommit))
527 return false;
531 return commit1Form(xFrm, needConfirmation, shouldCommit);
535 void SAL_CALL FormOperations::execute( ::sal_Int16 _nFeature )
537 SolarMutexGuard aSolarGuard;
538 MethodGuard aGuard( *this );
540 if ( ( _nFeature != FormFeature::DeleteRecord ) && ( _nFeature != FormFeature::UndoRecordChanges ) )
544 if(m_xController.is())
546 if(!commitFormAndSubforms(m_xController, lcl_needConfirmCommit( _nFeature )))
547 return;
549 else if(m_xCursor.is())
551 Reference< XForm > xForm(m_xCursor, UNO_QUERY);
552 assert(xForm.is());
553 if(!commitFormAndSubforms(xForm, lcl_needConfirmCommit( _nFeature )))
554 return;
556 else
558 SAL_WARN( "forms.runtime", "No cursor, but trying to execute form operation " << _nFeature );
564 switch ( _nFeature )
566 case FormFeature::MoveToFirst:
567 m_xCursor->first();
568 break;
570 case FormFeature::MoveToNext:
571 impl_moveRight_throw( );
572 break;
574 case FormFeature::MoveToPrevious:
575 impl_moveLeft_throw( );
576 break;
578 case FormFeature::MoveToLast:
581 // TODO: re-implement this...
582 // run in an own thread if...
583 // ... the data source is thread safe...
584 sal_Bool bAllowOwnThread = sal_False;
585 if ( ::comphelper::hasProperty( PROPERTY_THREADSAFE, m_xCursorProperties ) )
586 m_xCursorProperties->getPropertyValue( PROPERTY_THREADSAFE ) >>= bAllowOwnThread;
588 // ... the record count is unknown
589 sal_Bool bNeedOwnThread sal_False;
590 if ( ::comphelper::hasProperty( PROPERTY_ROWCOUNTFINAL, m_xCursorProperties ) )
591 m_xCursorProperties->getPropertyValue( PROPERTY_ROWCOUNTFINAL ) >>= bNeedOwnThread;
593 if ( bNeedOwnThread && bAllowOwnThread )
595 else
597 m_xCursor->last();
599 break;
601 case FormFeature::ReloadForm:
602 if ( m_xLoadableForm.is() )
604 weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
605 m_xLoadableForm->reload();
607 // refresh all controls in the form (and sub forms) which can be refreshed
608 // #i90914#
609 ::comphelper::IndexAccessIterator aIter( m_xLoadableForm );
610 Reference< XInterface > xElement( aIter.Next() );
611 while ( xElement.is() )
613 Reference< XRefreshable > xRefresh( xElement, UNO_QUERY );
614 if ( xRefresh.is() )
615 xRefresh->refresh();
616 xElement = aIter.Next();
619 break;
621 case FormFeature::RefreshCurrentControl:
623 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
624 OSL_ENSURE( xControlModelRefresh.is(), "FormOperations::execute: how did you reach this?" );
625 if ( xControlModelRefresh.is() )
626 xControlModelRefresh->refresh();
628 break;
630 case FormFeature::DeleteRecord:
632 sal_uInt32 nCount = impl_getRowCount_throw();
634 // next position
635 bool bLeft = m_xCursor->isLast() && ( nCount > 1 );
636 bool bRight= !m_xCursor->isLast();
637 bool bSuccess = false;
640 // ask for confirmation
641 Reference< XConfirmDeleteListener > xConfirmDelete( m_xController, UNO_QUERY );
643 if ( xConfirmDelete.is() )
645 RowChangeEvent aEvent;
646 aEvent.Source.set( m_xCursor, UNO_QUERY );
647 aEvent.Action = RowChangeAction::DELETE;
648 aEvent.Rows = 1;
649 bSuccess = xConfirmDelete->confirmDelete( aEvent );
652 // delete it
653 if ( bSuccess )
654 m_xUpdateCursor->deleteRow();
656 catch( const Exception& )
658 bSuccess = false;
661 if ( bSuccess )
663 if ( bLeft || bRight )
664 m_xCursor->relative( bRight ? 1 : -1 );
665 else
667 bool bCanInsert = ::dbtools::canInsert( m_xCursorProperties );
668 // is it possible to insert another record?
669 if ( bCanInsert )
670 m_xUpdateCursor->moveToInsertRow();
671 else
672 // move record to update status
673 m_xCursor->first();
677 break;
679 case FormFeature::SaveRecordChanges:
680 case FormFeature::UndoRecordChanges:
682 bool bInserting = impl_isInsertionRow_throw();
684 if ( FormFeature::UndoRecordChanges == _nFeature )
686 if ( !bInserting )
687 m_xUpdateCursor->cancelRowUpdates();
689 // reset all controls for this form
690 impl_resetAllControls_nothrow( );
692 if ( bInserting ) // back to insertion mode for this form
693 m_xUpdateCursor->moveToInsertRow();
695 else
697 if ( bInserting )
699 m_xUpdateCursor->insertRow();
700 m_xCursor->last();
702 else
703 m_xUpdateCursor->updateRow();
706 break;
708 case FormFeature::MoveToInsertRow:
709 // move to the last row before moving to the insert row
710 m_xCursor->last();
711 m_xUpdateCursor->moveToInsertRow();
712 break;
714 case FormFeature::RemoveFilterAndSort:
716 // simultaneously reset Filter and Order property
717 Reference< XMultiPropertySet > xProperties( m_xCursorProperties, UNO_QUERY );
718 OSL_ENSURE( xProperties.is(), "FormOperations::execute: no multi property access!" );
719 if ( xProperties.is() )
721 Sequence< OUString > aNames{ PROPERTY_FILTER, PROPERTY_HAVINGCLAUSE,
722 PROPERTY_SORT };
724 Sequence< Any> aValues{ Any(OUString()), Any(OUString()), Any(OUString()) };
726 weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
727 xProperties->setPropertyValues( aNames, aValues );
729 if ( m_xLoadableForm.is() )
730 m_xLoadableForm->reload();
733 break;
735 case FormFeature::ToggleApplyFilter:
736 if ( impl_commitCurrentControl_throw() && impl_commitCurrentRecord_throw() )
738 // simply toggle the value
739 bool bApplied = false;
740 m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
741 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, Any( !bApplied ) );
743 // and reload
744 weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
745 m_xLoadableForm->reload();
747 break;
749 case FormFeature::SortAscending:
750 impl_executeAutoSort_throw( true );
751 break;
753 case FormFeature::SortDescending:
754 impl_executeAutoSort_throw( false );
755 break;
757 case FormFeature::AutoFilter:
758 impl_executeAutoFilter_throw();
759 break;
761 case FormFeature::InteractiveSort:
762 impl_executeFilterOrSort_throw( false );
763 break;
765 case FormFeature::InteractiveFilter:
766 impl_executeFilterOrSort_throw( true );
767 break;
769 default:
771 TranslateId pErrorResourceId = RID_STR_FEATURE_UNKNOWN;
772 if ( lcl_requiresArguments( _nFeature ) )
773 pErrorResourceId = RID_STR_FEATURE_REQUIRES_PARAMETERS;
774 else if ( !lcl_isExecutableFeature( _nFeature ) )
775 pErrorResourceId = RID_STR_FEATURE_NOT_EXECUTABLE;
776 throw IllegalArgumentException( ResourceManager::loadString(pErrorResourceId), *this, 1 );
778 } // switch
780 catch( const RuntimeException& ) { throw; }
781 catch( const SQLException& ) { throw; }
782 catch( const Exception& )
784 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
787 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
791 void SAL_CALL FormOperations::executeWithArguments( ::sal_Int16 _nFeature, const Sequence< NamedValue >& _rArguments )
793 if ( !lcl_requiresArguments( _nFeature ) )
795 execute( _nFeature );
796 return;
799 SolarMutexGuard aSolarGuard;
800 MethodGuard aGuard( *this );
802 // at the moment we have only one feature which supports execution parameters
803 if ( !lcl_isExecutableFeature( _nFeature ) )
804 throw IllegalArgumentException( ResourceManager::loadString(RID_STR_FEATURE_NOT_EXECUTABLE), *this, 1 );
806 switch ( _nFeature )
808 case FormFeature::MoveAbsolute:
810 sal_Int32 nPosition = -1;
812 ::comphelper::NamedValueCollection aArguments( _rArguments );
813 aArguments.get_ensureType( "Position", nPosition );
815 if ( nPosition < 1 )
816 nPosition = 1;
820 // commit before doing anything else
821 if ( m_xController.is() && !impl_commitCurrentControl_throw() )
822 return;
823 if ( !impl_commitCurrentRecord_throw() )
824 return;
826 sal_Int32 nCount = impl_getRowCount_throw();
827 bool bFinalCount = impl_isRowCountFinal_throw();
829 if ( bFinalCount && ( nPosition > nCount ) )
830 nPosition = nCount;
832 m_xCursor->absolute( nPosition );
834 catch( const RuntimeException& ) { throw; }
835 catch( const SQLException& ) { throw; }
836 catch( const Exception& )
838 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
841 break;
842 default:
843 throw IllegalArgumentException( ResourceManager::loadString(RID_STR_FEATURE_UNKNOWN), *this, 1 );
844 } // switch
848 sal_Bool SAL_CALL FormOperations::commitCurrentRecord( sal_Bool& _out_rRecordInserted )
850 MethodGuard aGuard( *this );
851 _out_rRecordInserted = false;
853 return impl_commitCurrentRecord_throw( &_out_rRecordInserted );
857 bool FormOperations::impl_commitCurrentRecord_throw( sal_Bool* _pRecordInserted ) const
859 #ifdef DBG_UTIL
860 DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentRecord_throw: to be called within a MethodGuard'ed section only!" );
861 #endif
863 if ( !impl_hasCursor_nothrow() )
864 return false;
866 // nothing to do if the record is not modified
867 bool bResult = !impl_isModifiedRow_throw();
868 if ( !bResult )
870 // insert respectively update the row
871 if ( impl_isInsertionRow_throw() )
873 m_xUpdateCursor->insertRow();
874 if ( _pRecordInserted )
875 *_pRecordInserted = true;
877 else
878 m_xUpdateCursor->updateRow();
879 bResult = true;
881 return bResult;
885 sal_Bool SAL_CALL FormOperations::commitCurrentControl()
887 MethodGuard aGuard( *this );
888 return impl_commitCurrentControl_throw();
892 bool FormOperations::impl_commitCurrentControl_throw() const
894 #ifdef DBG_UTIL
895 DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentControl_throw: to be called within a MethodGuard'ed section only!" );
896 #endif
897 OSL_PRECOND( m_xController.is(), "FormOperations::commitCurrentControl: no controller!" );
898 if ( !m_xController.is() )
899 return false;
901 bool bSuccess = false;
904 Reference< XControl > xCurrentControl( m_xController->getCurrentControl() );
906 // check whether the control is locked
907 Reference< XBoundControl > xCheckLock( xCurrentControl, UNO_QUERY );
908 bool bControlIsLocked = xCheckLock.is() && xCheckLock->getLock();
910 // commit if necessary
911 bSuccess = true;
912 if ( xCurrentControl.is() && !bControlIsLocked )
914 // both the control and its model can be committable, so try both
915 Reference< XBoundComponent > xBound( xCurrentControl, UNO_QUERY );
916 if ( !xBound.is() )
917 xBound.set(xCurrentControl->getModel(), css::uno::UNO_QUERY);
918 // and now really commit
919 if ( xBound.is() )
920 bSuccess = xBound->commit();
924 catch( const RuntimeException& ) { throw; }
925 catch( const SQLException& ) { throw; }
926 catch( const Exception& )
928 DBG_UNHANDLED_EXCEPTION("forms.runtime");
929 bSuccess = false;
932 return bSuccess;
936 sal_Bool SAL_CALL FormOperations::isInsertionRow()
938 bool bIs = false;
941 bIs = impl_isInsertionRow_throw();
943 catch( const RuntimeException& ) { throw; }
944 catch( const Exception& )
946 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
948 return bIs;
952 sal_Bool SAL_CALL FormOperations::isModifiedRow()
954 bool bIs = false;
957 bIs = impl_isModifiedRow_throw();
959 catch( const RuntimeException& ) { throw; }
960 catch( const Exception& )
962 throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
964 return bIs;
968 void SAL_CALL FormOperations::cursorMoved( const EventObject& /*_Event*/ )
970 MethodGuard aGuard( *this );
971 m_bActiveControlModified = false;
973 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
977 void SAL_CALL FormOperations::rowChanged( const EventObject& /*_Event*/ )
979 // not interested in
983 void SAL_CALL FormOperations::rowSetChanged( const EventObject& /*_Event*/ )
985 // not interested in
989 void SAL_CALL FormOperations::modified( const EventObject& /*_Source*/ )
991 MethodGuard aGuard( *this );
993 OSL_ENSURE( m_xCursor.is(), "FormOperations::modified: already disposed!" );
994 if ( !m_bActiveControlModified )
996 m_bActiveControlModified = true;
997 impl_invalidateModifyDependentFeatures_nothrow( aGuard );
1002 void SAL_CALL FormOperations::propertyChange( const PropertyChangeEvent& _rEvent )
1004 MethodGuard aGuard( *this );
1006 if ( m_xCursor.is() && ( m_xCursor == _rEvent.Source ) )
1008 if ( ( _rEvent.PropertyName == PROPERTY_ISMODIFIED )
1009 || ( _rEvent.PropertyName == PROPERTY_ISNEW )
1012 bool bIs = false;
1013 if ( ( _rEvent.NewValue >>= bIs ) && !bIs )
1014 m_bActiveControlModified = false;
1016 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
1019 if ( !(m_xParser.is() && ( m_xCursor == _rEvent.Source )) )
1020 return;
1024 OUString sNewValue;
1025 _rEvent.NewValue >>= sNewValue;
1026 if ( _rEvent.PropertyName == PROPERTY_ACTIVECOMMAND )
1028 m_xParser->setElementaryQuery( sNewValue );
1030 else if ( _rEvent.PropertyName == PROPERTY_FILTER )
1032 if ( m_xParser->getFilter() != sNewValue )
1033 m_xParser->setFilter( sNewValue );
1035 else if ( _rEvent.PropertyName == PROPERTY_HAVINGCLAUSE )
1037 if ( m_xParser->getHavingClause() != sNewValue )
1038 m_xParser->setHavingClause( sNewValue );
1040 else if ( _rEvent.PropertyName == PROPERTY_SORT )
1042 _rEvent.NewValue >>= sNewValue;
1043 if ( m_xParser->getOrder() != sNewValue )
1044 m_xParser->setOrder( sNewValue );
1047 catch( const Exception& )
1049 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::propertyChange: caught an exception while updating the parser!" );
1051 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
1055 void SAL_CALL FormOperations::disposing( const EventObject& /*_Source*/ )
1057 // TODO: should we react on this? Or is this the responsibility of our owner to dispose us?
1061 void SAL_CALL FormOperations::disposing()
1063 ::osl::MutexGuard aGuard( m_aMutex );
1065 impl_disposeParser_nothrow();
1069 // revoke various listeners
1070 if ( m_xCursor.is() )
1071 m_xCursor->removeRowSetListener( this );
1073 if ( m_xCursorProperties.is() )
1075 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISMODIFIED,this );
1076 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISNEW, this );
1079 if ( m_xController.is() )
1080 m_xController->removeModifyListener( this );
1082 catch( const Exception& )
1084 DBG_UNHANDLED_EXCEPTION("forms.runtime");
1087 m_xController.clear();
1088 m_xCursor.clear();
1089 m_xUpdateCursor.clear();
1090 m_xCursorProperties.clear();
1091 m_xLoadableForm.clear();
1092 m_xFeatureInvalidation.clear();
1094 m_bActiveControlModified = true;
1098 void FormOperations::impl_checkDisposed_throw() const
1100 if ( !m_xCursor.is() )
1101 throw DisposedException( OUString(), *const_cast< FormOperations* >( this ) );
1105 void FormOperations::impl_initFromController_throw()
1107 OSL_PRECOND( m_xController.is(), "FormOperations::impl_initFromController_throw: invalid controller!" );
1108 m_xCursor.set(m_xController->getModel(), css::uno::UNO_QUERY);
1109 if ( !m_xCursor.is() )
1110 throw IllegalArgumentException( OUString(), *this, 0 );
1112 impl_initFromForm_throw();
1114 if ( m_xController.is() )
1115 m_xController->addModifyListener( this );
1119 void FormOperations::impl_initFromForm_throw()
1121 OSL_PRECOND( m_xCursor.is(), "FormOperations::impl_initFromForm_throw: invalid form!" );
1122 m_xCursorProperties.set(m_xCursor, css::uno::UNO_QUERY);
1123 m_xUpdateCursor.set(m_xCursor, css::uno::UNO_QUERY);
1124 m_xLoadableForm.set(m_xCursor, css::uno::UNO_QUERY);
1126 if ( !m_xCursor.is() || !m_xCursorProperties.is() || !m_xLoadableForm.is() )
1127 throw IllegalArgumentException( OUString(), *this, 0 );
1129 m_xCursor->addRowSetListener( this );
1130 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISMODIFIED,this );
1131 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISNEW, this );
1135 void FormOperations::createWithFormController( const Reference< XFormController >& _rxController )
1137 m_xController = _rxController;
1138 if ( !m_xController.is() )
1139 throw IllegalArgumentException( OUString(), *this, 0 );
1141 impl_initFromController_throw();
1143 m_bConstructed = true;
1147 void FormOperations::createWithForm( const Reference< XForm >& _rxForm )
1149 m_xCursor.set(_rxForm, css::uno::UNO_QUERY);
1150 if ( !m_xCursor.is() )
1151 throw IllegalArgumentException( OUString(), *this, 0 );
1153 impl_initFromForm_throw();
1155 m_bConstructed = true;
1159 void FormOperations::impl_invalidateAllSupportedFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1161 if ( !m_xFeatureInvalidation.is() )
1162 // nobody's interested in ...
1163 return;
1165 Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1166 _rClearForCallback.clear();
1167 xInvalidation->invalidateAllFeatures();
1171 void FormOperations::impl_invalidateModifyDependentFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1173 if ( !m_xFeatureInvalidation.is() )
1174 // nobody's interested in ...
1175 return;
1177 static Sequence< sal_Int16 > const s_aModifyDependentFeatures
1179 FormFeature::MoveToNext,
1180 FormFeature::MoveToInsertRow,
1181 FormFeature::SaveRecordChanges,
1182 FormFeature::UndoRecordChanges
1185 Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1186 _rClearForCallback.clear();
1188 xInvalidation->invalidateFeatures( s_aModifyDependentFeatures );
1192 void FormOperations::impl_ensureInitializedParser_nothrow()
1194 OSL_PRECOND( m_xCursorProperties.is(), "FormOperations::impl_ensureInitializedParser_nothrow: we're disposed!" );
1195 if ( m_bInitializedParser )
1196 return;
1200 bool bUseEscapeProcessing = false;
1201 m_xCursorProperties->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bUseEscapeProcessing;
1202 if ( bUseEscapeProcessing )
1204 Reference< XMultiServiceFactory > xFactory( ::dbtools::getConnection( m_xCursor ), UNO_QUERY );
1205 if ( xFactory.is() )
1207 m_xParser.set( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"), UNO_QUERY );
1208 OSL_ENSURE( m_xParser.is(), "FormOperations::impl_ensureInitializedParser_nothrow: factory did not create a parser for us!" );
1212 if ( m_xParser.is() )
1214 if ( m_xLoadableForm.is() && m_xLoadableForm->isLoaded() )
1216 OUString sStatement;
1217 OUString sFilter;
1218 OUString sHaving;
1219 OUString sSort;
1221 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sStatement;
1222 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
1223 m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sHaving;
1224 m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sSort;
1226 m_xParser->setElementaryQuery( sStatement );
1227 m_xParser->setFilter ( sFilter );
1228 m_xParser->setHavingClause ( sHaving );
1229 m_xParser->setOrder ( sSort );
1232 // start listening at the order/sort properties at the form, so
1233 // we can keep our parser in sync
1234 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1235 m_xCursorProperties->addPropertyChangeListener( PROPERTY_FILTER, this );
1236 m_xCursorProperties->addPropertyChangeListener( PROPERTY_HAVINGCLAUSE, this );
1237 m_xCursorProperties->addPropertyChangeListener( PROPERTY_SORT, this );
1240 catch( const Exception& )
1242 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_ensureInitializedParser_nothrow" );
1245 m_bInitializedParser = true;
1249 void FormOperations::impl_disposeParser_nothrow()
1253 // if we have a parser (and a cursor), then we're listening at the cursor's
1254 // properties to keep the parser in sync with the cursor
1255 if ( m_xParser.is() && m_xCursorProperties.is() )
1257 m_xCursorProperties->removePropertyChangeListener( PROPERTY_FILTER, this );
1258 m_xCursorProperties->removePropertyChangeListener( PROPERTY_HAVINGCLAUSE, this );
1259 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1260 m_xCursorProperties->removePropertyChangeListener( PROPERTY_SORT, this );
1263 Reference< XComponent > xParserComp( m_xParser, UNO_QUERY );
1264 if ( xParserComp.is() )
1265 xParserComp->dispose();
1266 m_xParser.clear();
1268 m_bInitializedParser = false;
1270 catch( const Exception& )
1272 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_disposeParser_nothrow" );
1277 bool FormOperations::impl_canMoveLeft_throw( ) const
1279 if ( !impl_hasCursor_nothrow() )
1280 return false;
1282 return impl_getRowCount_throw() && ( !m_xCursor->isFirst() || impl_isInsertionRow_throw() );
1286 bool FormOperations::impl_canMoveRight_throw( ) const
1288 if ( !impl_hasCursor_nothrow() )
1289 return false;
1291 bool bIsNew = impl_isInsertionRow_throw();
1293 if ( impl_getRowCount_throw() && !m_xCursor->isLast() && !bIsNew )
1294 return true;
1296 if ( ::dbtools::canInsert( m_xCursorProperties ) )
1297 if ( !bIsNew || impl_isModifiedRow_throw() )
1298 return true;
1300 if ( bIsNew && m_bActiveControlModified )
1301 return true;
1303 return false;
1307 bool FormOperations::impl_isInsertionRow_throw() const
1309 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISNEW, false );
1313 sal_Int32 FormOperations::impl_getRowCount_throw() const
1315 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNT, sal_Int32(0) );
1318 bool FormOperations::impl_isRowCountFinal_throw() const
1320 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNTFINAL, false );
1324 bool FormOperations::impl_isModifiedRow_throw() const
1326 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISMODIFIED, false );
1330 bool FormOperations::impl_isParseable_throw() const
1332 const_cast< FormOperations* >( this )->impl_ensureInitializedParser_nothrow();
1333 return m_xParser.is() && !m_xParser->getQuery().isEmpty();
1337 bool FormOperations::impl_hasFilterOrOrder_throw() const
1339 return impl_isParseable_throw() && ( !m_xParser->getFilter().isEmpty() ||
1340 !m_xParser->getHavingClause().isEmpty() ||
1341 !m_xParser->getOrder().isEmpty() );
1345 bool FormOperations::impl_isInsertOnlyForm_throw() const
1347 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_INSERTONLY, true );
1351 Reference< XControlModel > FormOperations::impl_getCurrentControlModel_throw() const
1353 Reference< XControl > xControl( m_xController->getCurrentControl() );
1355 // special handling for grid controls
1356 Reference< XGrid > xGrid( xControl, UNO_QUERY );
1357 Reference< XControlModel > xControlModel;
1359 if ( xGrid.is() )
1361 Reference< XIndexAccess > xColumns( xControl->getModel(), UNO_QUERY_THROW );
1362 sal_Int32 nCurrentPos = impl_gridView2ModelPos_nothrow( xColumns, xGrid->getCurrentColumnPosition() );
1364 if ( nCurrentPos != -1 )
1365 xColumns->getByIndex( nCurrentPos ) >>= xControlModel;
1367 else if ( xControl.is() )
1369 xControlModel = xControl->getModel();
1371 return xControlModel;
1375 Reference< XPropertySet > FormOperations::impl_getCurrentBoundField_nothrow( ) const
1377 OSL_PRECOND( m_xController.is(), "FormOperations::impl_getCurrentBoundField_nothrow: no controller -> no control!" );
1378 if ( !m_xController.is() )
1379 return nullptr;
1381 Reference< XPropertySet > xField;
1384 Reference< XPropertySet > xControlModel( impl_getCurrentControlModel_throw(), UNO_QUERY );
1386 if ( xControlModel.is() && ::comphelper::hasProperty( PROPERTY_BOUNDFIELD, xControlModel ) )
1387 xControlModel->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xField;
1390 catch( const Exception& )
1392 DBG_UNHANDLED_EXCEPTION("forms.runtime");
1395 return xField;
1399 sal_Int32 FormOperations::impl_gridView2ModelPos_nothrow( const Reference< XIndexAccess >& _rxColumns, sal_Int16 _nViewPos )
1401 OSL_PRECOND( _rxColumns.is(), "FormOperations::impl_gridView2ModelPos_nothrow: invalid columns container!" );
1404 // loop through all columns
1405 sal_Int32 col = 0;
1406 Reference< XPropertySet > xCol;
1407 bool bHidden( false );
1408 for ( col = 0; col < _rxColumns->getCount(); ++col )
1410 _rxColumns->getByIndex( col ) >>= xCol;
1411 OSL_VERIFY( xCol->getPropertyValue( PROPERTY_HIDDEN ) >>= bHidden );
1412 if ( bHidden )
1413 continue;
1415 // for every visible col : if nViewPos is greater zero, decrement it, else we
1416 // have found the model position
1417 if ( !_nViewPos )
1418 break;
1419 else
1420 --_nViewPos;
1422 if ( col < _rxColumns->getCount() )
1423 return col;
1425 catch( const Exception& )
1427 DBG_UNHANDLED_EXCEPTION("forms.runtime");
1429 return -1;
1433 void FormOperations::impl_moveLeft_throw( ) const
1435 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveLeft_throw: no cursor!" );
1436 if ( !impl_hasCursor_nothrow() )
1437 return;
1439 sal_Bool bRecordInserted = false;
1440 bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1442 if ( !bSuccess )
1443 return;
1445 if ( bRecordInserted )
1447 // retrieve the bookmark of the new record and move to the record preceding this bookmark
1448 Reference< XRowLocate > xLocate( m_xCursor, UNO_QUERY );
1449 OSL_ENSURE( xLocate.is(), "FormOperations::impl_moveLeft_throw: no XRowLocate!" );
1450 if ( xLocate.is() )
1451 xLocate->moveRelativeToBookmark( xLocate->getBookmark(), -1 );
1453 else
1455 if ( impl_isInsertionRow_throw() )
1457 // we assume that the inserted record is now the last record in the
1458 // result set
1459 m_xCursor->last();
1461 else
1462 m_xCursor->previous();
1467 void FormOperations::impl_moveRight_throw( ) const
1469 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveRight_throw: no cursor!" );
1470 if ( !impl_hasCursor_nothrow() )
1471 return;
1473 sal_Bool bRecordInserted = false;
1474 bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1476 if ( !bSuccess )
1477 return;
1479 if ( bRecordInserted )
1481 // go to insert row
1482 m_xUpdateCursor->moveToInsertRow();
1484 else
1486 if ( m_xCursor->isLast() )
1487 m_xUpdateCursor->moveToInsertRow();
1488 else
1489 (void)m_xCursor->next();
1494 void FormOperations::impl_resetAllControls_nothrow() const
1496 Reference< XIndexAccess > xContainer( m_xCursor, UNO_QUERY );
1497 if ( !xContainer.is() )
1498 return;
1502 Reference< XReset > xReset;
1503 sal_Int32 nCount( xContainer->getCount() );
1504 for ( sal_Int32 i = 0; i < nCount; ++i )
1506 if ( xContainer->getByIndex( i ) >>= xReset )
1508 // no resets on sub forms
1509 Reference< XForm > xAsForm( xReset, UNO_QUERY );
1510 if ( !xAsForm.is() )
1511 xReset->reset();
1515 catch( const Exception& )
1517 DBG_UNHANDLED_EXCEPTION("forms.runtime");
1522 void FormOperations::impl_executeAutoSort_throw( bool _bUp ) const
1524 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoSort_throw: need a controller for this!" );
1525 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoSort_throw: need a cursor for this!" );
1526 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoSort_throw: need a parseable statement for this!" );
1527 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1528 return;
1532 Reference< XControl > xControl = m_xController->getCurrentControl();
1533 if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1534 return;
1536 Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1537 if ( !xBoundField.is() )
1538 return;
1540 OUString sOriginalSort;
1541 m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sOriginalSort;
1543 // automatic sort by field is expected to always resets the previous sort order
1544 m_xParser->setOrder( OUString() );
1546 impl_appendOrderByColumn_throw aAction(this, xBoundField, _bUp);
1547 impl_doActionInSQLContext_throw(std::move(aAction), RID_STR_COULD_NOT_SET_ORDER );
1549 weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
1552 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, Any( m_xParser->getOrder() ) );
1553 m_xLoadableForm->reload();
1555 catch( const Exception& )
1557 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_executeAutoSort_throw: caught an exception while setting the parser properties!" );
1561 if ( !m_xLoadableForm->isLoaded() )
1562 { // something went wrong -> restore the original state
1565 m_xParser->setOrder( sOriginalSort );
1566 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, Any( m_xParser->getOrder() ) );
1567 m_xLoadableForm->reload();
1569 catch( const Exception& )
1571 OSL_FAIL( "FormOperations::impl_executeAutoSort_throw: could not reset the form to its original state!" );
1576 catch( const RuntimeException& ) { throw; }
1577 catch( const SQLException& ) { throw; }
1578 catch( const Exception& )
1580 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1585 void FormOperations::impl_executeAutoFilter_throw( ) const
1587 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoFilter_throw: need a controller for this!" );
1588 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoFilter_throw: need a cursor for this!" );
1589 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoFilter_throw: need a parseable statement for this!" );
1590 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1591 return;
1595 Reference< XControl > xControl = m_xController->getCurrentControl();
1596 if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1597 return;
1599 Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1600 if ( !xBoundField.is() )
1601 return;
1603 OUString sOriginalFilter;
1604 OUString sOriginalHaving;
1605 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
1606 m_xCursorProperties->getPropertyValue( PROPERTY_HAVINGCLAUSE ) >>= sOriginalHaving;
1607 bool bApplied = true;
1608 m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
1610 // if we have a filter, but it's not applied, then we have to overwrite it, else append one
1611 if ( !bApplied )
1613 m_xParser->setFilter( OUString() );
1614 m_xParser->setHavingClause( OUString() );
1617 impl_appendFilterByColumn_throw aAction(this, m_xParser, xBoundField);
1618 impl_doActionInSQLContext_throw( std::move(aAction), RID_STR_COULD_NOT_SET_FILTER );
1620 weld::WaitObject aWO(Application::GetFrameWeld(GetDialogParent()));
1623 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, Any( m_xParser->getFilter() ) );
1624 m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, Any( m_xParser->getHavingClause() ) );
1625 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, Any( true ) );
1627 m_xLoadableForm->reload();
1629 catch( const Exception& )
1631 TOOLS_WARN_EXCEPTION( "forms.runtime", "FormOperations::impl_executeAutoFilter_throw: caught an exception while setting the parser properties!" );
1635 if ( !m_xLoadableForm->isLoaded() )
1636 { // something went wrong -> restore the original state
1639 m_xParser->setFilter ( sOriginalFilter );
1640 m_xParser->setHavingClause( sOriginalHaving );
1641 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, Any( bApplied ) );
1642 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, Any( m_xParser->getFilter() ) );
1643 m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, Any( m_xParser->getHavingClause() ) );
1644 m_xLoadableForm->reload();
1646 catch( const Exception& )
1648 OSL_FAIL( "FormOperations::impl_executeAutoFilter_throw: could not reset the form to its original state!" );
1653 catch( const RuntimeException& ) { throw; }
1654 catch( const SQLException& ) { throw; }
1655 catch( const Exception& )
1657 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1661 css::uno::Reference<css::awt::XWindow> FormOperations::GetDialogParent() const
1663 css::uno::Reference<css::awt::XWindow> xDialogParent;
1665 //tdf#122152 extract parent for dialog
1666 if (m_xController.is())
1668 css::uno::Reference<css::awt::XControl> xContainerControl(m_xController->getContainer(), css::uno::UNO_QUERY);
1669 if (xContainerControl.is())
1671 css::uno::Reference<css::awt::XWindowPeer> xContainerPeer = xContainerControl->getPeer();
1672 xDialogParent = css::uno::Reference<css::awt::XWindow>(xContainerPeer, css::uno::UNO_QUERY);
1676 return xDialogParent;
1679 void FormOperations::impl_executeFilterOrSort_throw( bool _bFilter ) const
1681 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeFilterOrSort_throw: need a controller for this!" );
1682 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeFilterOrSort_throw: need a cursor for this!" );
1683 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeFilterOrSort_throw: need a parseable statement for this!" );
1684 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1685 return;
1687 if ( !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1688 return;
1691 css::uno::Reference<css::awt::XWindow> xDialogParent(GetDialogParent());
1693 Reference< XExecutableDialog> xDialog;
1694 if ( _bFilter )
1696 xDialog = css::sdb::FilterDialog::createWithQuery(m_xContext, m_xParser, m_xCursor,
1697 xDialogParent);
1699 else
1701 xDialog = css::sdb::OrderDialog::createWithQuery(m_xContext, m_xParser, m_xCursorProperties,
1702 xDialogParent);
1705 if ( RET_OK == xDialog->execute() )
1707 weld::WaitObject aWO(Application::GetFrameWeld(xDialogParent));
1708 if ( _bFilter )
1710 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, Any( m_xParser->getFilter() ) );
1711 m_xCursorProperties->setPropertyValue( PROPERTY_HAVINGCLAUSE, Any( m_xParser->getHavingClause() ) );
1713 else
1714 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, Any( m_xParser->getOrder() ) );
1715 m_xLoadableForm->reload();
1719 catch( const RuntimeException& ) { throw; }
1720 catch( const SQLException& ) { throw; }
1721 catch( const Exception& )
1723 throw WrappedTargetException( OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1728 template < typename FunctObj >
1729 void FormOperations::impl_doActionInSQLContext_throw( FunctObj f, TranslateId pErrorResourceId ) const
1733 f();
1735 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1736 catch( const SQLException& )
1738 if (!pErrorResourceId) // no information to prepend
1739 throw;
1741 SQLExceptionInfo aInfo( ::cppu::getCaughtException() );
1742 OUString sAdditionalError( ResourceManager::loadString(pErrorResourceId) );
1743 aInfo.prepend( sAdditionalError );
1744 aInfo.doThrow();
1746 #endif
1747 catch( const RuntimeException& ) { throw; }
1748 catch( const Exception& )
1750 OUString sAdditionalError( ResourceManager::loadString(pErrorResourceId) );
1751 throw WrappedTargetException( sAdditionalError, *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1756 } // namespace frm
1759 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
1760 com_sun_star_comp_forms_FormOperations_get_implementation(css::uno::XComponentContext* context,
1761 css::uno::Sequence<css::uno::Any> const &)
1763 return cppu::acquire(new frm::FormOperations(context));
1766 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */