1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <sal/macros.h>
22 #include <formcontrolling.hxx>
24 #include <svx/svxids.hrc>
26 #include <formcontroller.hxx>
27 #include <svx/fmtools.hxx>
29 #include <com/sun/star/form/runtime/FormOperations.hpp>
30 #include <com/sun/star/form/runtime/FormFeature.hpp>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/sdbc/SQLException.hpp>
34 #include <comphelper/diagnose_ex.hxx>
35 #include <comphelper/anytostring.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <cppuhelper/exc_hlp.hxx>
38 #include <osl/diagnose.h>
47 using ::com::sun::star::uno::Reference
;
48 using ::com::sun::star::form::runtime::XFormController
;
49 using ::com::sun::star::form::runtime::FormOperations
;
50 using ::com::sun::star::uno::Exception
;
51 using ::com::sun::star::sdbc::XRowSet
;
52 using ::com::sun::star::form::runtime::FeatureState
;
53 using ::com::sun::star::uno::Any
;
54 using ::com::sun::star::uno::Sequence
;
55 using ::com::sun::star::beans::NamedValue
;
56 using ::com::sun::star::beans::XPropertySet
;
57 using ::com::sun::star::uno::UNO_QUERY_THROW
;
58 using ::com::sun::star::sdbc::SQLException
;
59 using ::com::sun::star::sdb::SQLErrorEvent
;
60 using ::com::sun::star::lang::EventObject
;
62 namespace FormFeature
= ::com::sun::star::form::runtime::FormFeature
;
65 //= FeatureSlotTranslation
69 struct FeatureDescription
71 OUString sURL
; // the URL
72 sal_Int32 nSlotId
; // the SFX-compatible slot ID
73 sal_Int16 nFormFeature
; // the css.form.runtime.FormFeature ID
75 typedef ::std::vector
< FeatureDescription
> FeatureDescriptions
;
78 const FeatureDescriptions
& getFeatureDescriptions()
80 static const FeatureDescriptions
s_aFeatureDescriptions({
81 { FMURL_FORM_POSITION
, SID_FM_RECORD_ABSOLUTE
, FormFeature::MoveAbsolute
},
82 { FMURL_FORM_RECORDCOUNT
, SID_FM_RECORD_TOTAL
, FormFeature::TotalRecords
},
83 { FMURL_RECORD_MOVEFIRST
, SID_FM_RECORD_FIRST
, FormFeature::MoveToFirst
},
84 { FMURL_RECORD_MOVEPREV
, SID_FM_RECORD_PREV
, FormFeature::MoveToPrevious
},
85 { FMURL_RECORD_MOVENEXT
, SID_FM_RECORD_NEXT
, FormFeature::MoveToNext
},
86 { FMURL_RECORD_MOVELAST
, SID_FM_RECORD_LAST
, FormFeature::MoveToLast
},
87 { FMURL_RECORD_MOVETONEW
, SID_FM_RECORD_NEW
, FormFeature::MoveToInsertRow
},
88 { FMURL_RECORD_SAVE
, SID_FM_RECORD_SAVE
, FormFeature::SaveRecordChanges
},
89 { FMURL_RECORD_DELETE
, SID_FM_RECORD_DELETE
, FormFeature::DeleteRecord
},
90 { FMURL_FORM_REFRESH
, SID_FM_REFRESH
, FormFeature::ReloadForm
},
91 { FMURL_FORM_REFRESH_CURRENT_CONTROL
,
92 SID_FM_REFRESH_FORM_CONTROL
,FormFeature::RefreshCurrentControl
},
93 { FMURL_RECORD_UNDO
, SID_FM_RECORD_UNDO
, FormFeature::UndoRecordChanges
},
94 { FMURL_FORM_SORT_UP
, SID_FM_SORTUP
, FormFeature::SortAscending
},
95 { FMURL_FORM_SORT_DOWN
, SID_FM_SORTDOWN
, FormFeature::SortDescending
},
96 { FMURL_FORM_SORT
, SID_FM_ORDERCRIT
, FormFeature::InteractiveSort
},
97 { FMURL_FORM_AUTO_FILTER
, SID_FM_AUTOFILTER
, FormFeature::AutoFilter
},
98 { FMURL_FORM_FILTER
, SID_FM_FILTERCRIT
, FormFeature::InteractiveFilter
},
99 { FMURL_FORM_APPLY_FILTER
, SID_FM_FORM_FILTERED
, FormFeature::ToggleApplyFilter
},
100 { FMURL_FORM_REMOVE_FILTER
, SID_FM_REMOVE_FILTER_SORT
, FormFeature::RemoveFilterAndSort
}
102 return s_aFeatureDescriptions
;
110 struct MatchFeatureDescriptionByURL
112 const OUString
& m_rURL
;
113 explicit MatchFeatureDescriptionByURL( const OUString
& _rURL
) :m_rURL( _rURL
) { }
115 bool operator()( const FeatureDescription
& _compare
)
117 return m_rURL
== _compare
.sURL
;
122 struct MatchFeatureDescriptionBySlotId
125 explicit MatchFeatureDescriptionBySlotId( sal_Int32 _nSlotId
) :m_nSlotId( _nSlotId
) { }
127 bool operator()( const FeatureDescription
& _compare
)
129 return m_nSlotId
== _compare
.nSlotId
;
134 struct MatchFeatureDescriptionByFormFeature
136 sal_Int32 m_nFormFeature
;
137 explicit MatchFeatureDescriptionByFormFeature( sal_Int32 _nFormFeature
) :m_nFormFeature( _nFormFeature
) { }
139 bool operator()( const FeatureDescription
& _compare
)
141 return m_nFormFeature
== _compare
.nFormFeature
;
146 struct FormFeatureToSlotId
148 sal_Int32
operator()( sal_Int16 FormFeature
)
150 return FeatureSlotTranslation::getSlotIdForFormFeature( FormFeature
);
156 sal_Int32
FeatureSlotTranslation::getControllerFeatureSlotIdForURL( const OUString
& _rMainURL
)
158 const FeatureDescriptions
& rDescriptions( getFeatureDescriptions() );
159 FeatureDescriptions::const_iterator pos
= ::std::find_if( rDescriptions
.begin(), rDescriptions
.end(), MatchFeatureDescriptionByURL( _rMainURL
) );
160 return ( pos
!= rDescriptions
.end() ) ? pos
->nSlotId
: -1;
164 sal_Int16
FeatureSlotTranslation::getFormFeatureForSlotId( sal_Int32 _nSlotId
)
166 const FeatureDescriptions
& rDescriptions( getFeatureDescriptions() );
167 FeatureDescriptions::const_iterator pos
= ::std::find_if( rDescriptions
.begin(), rDescriptions
.end(), MatchFeatureDescriptionBySlotId( _nSlotId
) );
168 OSL_ENSURE( pos
!= rDescriptions
.end(), "FeatureSlotTranslation::getFormFeatureForSlotId: not found!" );
169 return ( pos
!= rDescriptions
.end() ) ? pos
->nFormFeature
: -1;
173 sal_Int32
FeatureSlotTranslation::getSlotIdForFormFeature( sal_Int16 _nFormFeature
)
175 const FeatureDescriptions
& rDescriptions( getFeatureDescriptions() );
176 FeatureDescriptions::const_iterator pos
= ::std::find_if( rDescriptions
.begin(), rDescriptions
.end(), MatchFeatureDescriptionByFormFeature( _nFormFeature
) );
177 OSL_ENSURE( pos
!= rDescriptions
.end(), "FeatureSlotTranslation::getSlotIdForFormFeature: not found!" );
178 return ( pos
!= rDescriptions
.end() ) ? pos
->nSlotId
: -1;
181 ControllerFeatures::ControllerFeatures( IControllerFeatureInvalidation
* _pInvalidationCallback
)
182 :m_pInvalidationCallback( _pInvalidationCallback
)
187 ControllerFeatures::ControllerFeatures( const Reference
< XFormController
>& _rxController
)
188 :m_pInvalidationCallback( nullptr )
190 assign( _rxController
);
194 void ControllerFeatures::assign( const Reference
< XFormController
>& _rxController
)
197 m_pImpl
= new FormControllerHelper( _rxController
, m_pInvalidationCallback
);
201 ControllerFeatures::~ControllerFeatures()
207 void ControllerFeatures::dispose()
216 FormControllerHelper::FormControllerHelper( const Reference
< XFormController
>& _rxController
, IControllerFeatureInvalidation
* _pInvalidationCallback
)
217 :m_pInvalidationCallback( _pInvalidationCallback
)
219 osl_atomic_increment( &m_refCount
);
222 m_xFormOperations
= FormOperations::createWithFormController( comphelper::getProcessComponentContext(), _rxController
);
223 if ( m_xFormOperations
.is() )
224 m_xFormOperations
->setFeatureInvalidation( this );
226 catch( const Exception
& )
228 DBG_UNHANDLED_EXCEPTION("svx");
230 osl_atomic_decrement( &m_refCount
);
234 FormControllerHelper::~FormControllerHelper( )
241 catch( const Exception
& )
243 DBG_UNHANDLED_EXCEPTION("svx");
248 void FormControllerHelper::dispose()
250 if ( m_xFormOperations
.is() )
251 m_xFormOperations
->dispose();
252 m_xFormOperations
.clear();
256 bool FormControllerHelper::isEnabled( sal_Int32 _nSlotId
) const
258 if ( !m_xFormOperations
.is() )
260 return m_xFormOperations
->isEnabled( FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId
) );
264 Reference
< XRowSet
> FormControllerHelper::getCursor() const
266 Reference
< XRowSet
> xCursor
;
267 if ( m_xFormOperations
.is() )
268 xCursor
= m_xFormOperations
->getCursor();
273 void FormControllerHelper::getState( sal_Int32 _nSlotId
, FeatureState
& _rState
) const
275 if ( m_xFormOperations
.is() )
276 _rState
= m_xFormOperations
->getState( FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId
) );
280 bool FormControllerHelper::commitCurrentControl( ) const
282 return impl_operateForm_nothrow( COMMIT_CONTROL
);
286 bool FormControllerHelper::commitCurrentRecord() const
288 return impl_operateForm_nothrow( COMMIT_RECORD
);
292 void FormControllerHelper::execute( sal_Int32 _nSlotId
, const OUString
& _rParamName
, const Any
& _rParamValue
) const
294 Sequence
< NamedValue
> aArguments
{ { _rParamName
, _rParamValue
} };
295 impl_operateForm_nothrow( EXECUTE_ARGS
, FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId
), aArguments
);
299 bool FormControllerHelper::impl_operateForm_nothrow( const FormOperation _eWhat
, const sal_Int16 _nFeature
,
300 const Sequence
< NamedValue
>& _rArguments
) const
302 if ( !m_xFormOperations
.is() )
306 bool bSuccess
= false;
307 const_cast< FormControllerHelper
* >( this )->m_aOperationError
.clear();
310 // to prevent the controller from displaying any error messages which happen while we operate on it,
311 // we add ourself as XSQLErrorListener. By contract, a FormController displays errors if and only if
312 // no SQLErrorListeners are registered.
313 m_xFormOperations
->getController()->addSQLErrorListener( const_cast< FormControllerHelper
* >(this) );
318 bSuccess
= m_xFormOperations
->commitCurrentControl();
323 sal_Bool
bDummy( false );
324 bSuccess
= m_xFormOperations
->commitCurrentRecord( bDummy
);
329 m_xFormOperations
->execute( _nFeature
);
334 m_xFormOperations
->executeWithArguments( _nFeature
, _rArguments
);
339 catch ( const SQLException
& )
341 aError
= ::cppu::getCaughtException();
342 m_xFormOperations
->getController()->removeSQLErrorListener( const_cast< FormControllerHelper
* >(this) );
344 catch( const Exception
& )
346 aError
= ::cppu::getCaughtException();
347 m_xFormOperations
->getController()->removeSQLErrorListener( const_cast< FormControllerHelper
* >(this) );
348 SQLException
aFallbackError(::comphelper::anyToString(aError
), {}, {}, 0, {});
349 aError
<<= aFallbackError
;
355 // display the error. Prefer the one reported in errorOccurred over the one caught.
356 if ( m_aOperationError
.hasValue() )
357 displayException(m_aOperationError
, svxform::FormController::getDialogParentWindow(m_xFormOperations
->getController()));
358 else if ( aError
.hasValue() )
359 displayException(aError
, svxform::FormController::getDialogParentWindow(m_xFormOperations
->getController()));
361 OSL_FAIL( "FormControllerHelper::impl_operateForm_nothrow: no success, but no error?" );
367 void FormControllerHelper::execute( sal_Int32 _nSlotId
) const
369 impl_operateForm_nothrow( EXECUTE
, FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId
),
370 Sequence
< NamedValue
>() );
374 void SAL_CALL
FormControllerHelper::invalidateFeatures( const Sequence
< ::sal_Int16
>& Features
)
376 if ( !m_pInvalidationCallback
)
377 // nobody's interested in ...
380 ::std::vector
< sal_Int32
> aFeatures( Features
.getLength() );
385 FormFeatureToSlotId()
388 m_pInvalidationCallback
->invalidateFeatures( aFeatures
);
392 void SAL_CALL
FormControllerHelper::invalidateAllFeatures()
394 if ( !m_pInvalidationCallback
)
395 // nobody's interested in ...
398 // actually, it's a little bit more than the supported features,
399 // but on the medium term, we are to support everything listed
401 ::std::vector
< sal_Int32
> aSupportedFeatures
;
402 const sal_Int32 pSupportedFeatures
[] =
409 SID_FM_RECORD_DELETE
,
410 SID_FM_RECORD_ABSOLUTE
,
414 SID_FM_REMOVE_FILTER_SORT
,
420 SID_FM_FORM_FILTERED
,
422 SID_FM_REFRESH_FORM_CONTROL
,
427 sal_Int32 nFeatureCount
= SAL_N_ELEMENTS( pSupportedFeatures
);
428 aSupportedFeatures
.reserve(nFeatureCount
); // work around GCC12 spurious -Werror=stringop-overflow=
429 aSupportedFeatures
.insert( aSupportedFeatures
.begin(), pSupportedFeatures
, pSupportedFeatures
+ nFeatureCount
);
431 m_pInvalidationCallback
->invalidateFeatures( aSupportedFeatures
);
435 void SAL_CALL
FormControllerHelper::errorOccured( const SQLErrorEvent
& Event
)
437 OSL_ENSURE( !m_aOperationError
.hasValue(), "FormControllerHelper::errorOccurred: two errors during one operation?" );
438 m_aOperationError
= Event
.Reason
;
442 void SAL_CALL
FormControllerHelper::disposing( const EventObject
& /*_Source*/ )
448 bool FormControllerHelper::isInsertionRow() const
451 if ( m_xFormOperations
.is() )
452 bIs
= m_xFormOperations
->isInsertionRow();
457 bool FormControllerHelper::isModifiedRow() const
460 if ( m_xFormOperations
.is() )
461 bIs
= m_xFormOperations
->isModifiedRow();
465 bool FormControllerHelper::canDoFormFilter() const
467 if ( !m_xFormOperations
.is() )
473 Reference
< XPropertySet
> xCursorProperties( m_xFormOperations
->getCursor(), UNO_QUERY_THROW
);
475 bool bEscapeProcessing( false );
476 OSL_VERIFY( xCursorProperties
->getPropertyValue( FM_PROP_ESCAPE_PROCESSING
) >>= bEscapeProcessing
);
478 OUString sActiveCommand
;
479 OSL_VERIFY( xCursorProperties
->getPropertyValue( FM_PROP_ACTIVECOMMAND
) >>= sActiveCommand
);
481 bool bInsertOnlyForm( false );
482 OSL_VERIFY( xCursorProperties
->getPropertyValue( FM_PROP_INSERTONLY
) >>= bInsertOnlyForm
);
484 bCanDo
= bEscapeProcessing
&& !sActiveCommand
.isEmpty() && !bInsertOnlyForm
;
486 catch( const Exception
& )
488 DBG_UNHANDLED_EXCEPTION("svx");
497 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */