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 "svx/fmtools.hxx"
28 #include <com/sun/star/form/runtime/FormOperations.hpp>
29 #include <com/sun/star/form/runtime/FormFeature.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/sdb/XSQLErrorBroadcaster.hpp>
33 #include <tools/diagnose_ex.h>
34 #include <comphelper/anytostring.hxx>
35 #include <comphelper/processfactory.hxx>
36 #include <cppuhelper/exc_hlp.hxx>
37 #include <osl/diagnose.h>
47 using ::com::sun::star::uno::Reference
;
48 using ::com::sun::star::uno::XComponentContext
;
49 using ::com::sun::star::form::runtime::XFormController
;
50 using ::com::sun::star::form::XForm
;
51 using ::com::sun::star::form::runtime::FormOperations
;
52 using ::com::sun::star::uno::Exception
;
53 using ::com::sun::star::sdbc::XRowSet
;
54 using ::com::sun::star::form::runtime::FeatureState
;
55 using ::com::sun::star::uno::Any
;
56 using ::com::sun::star::uno::Sequence
;
57 using ::com::sun::star::beans::NamedValue
;
58 using ::com::sun::star::uno::RuntimeException
;
59 using ::com::sun::star::beans::XPropertySet
;
60 using ::com::sun::star::uno::UNO_QUERY_THROW
;
61 using ::com::sun::star::sdbc::SQLException
;
62 using ::com::sun::star::sdb::XSQLErrorBroadcaster
;
63 using ::com::sun::star::sdb::SQLErrorEvent
;
64 using ::com::sun::star::lang::EventObject
;
66 namespace FormFeature
= ::com::sun::star::form::runtime::FormFeature
;
69 //= FeatureSlotTranslation
73 struct FeatureDescription
75 OUString sURL
; // the URL
76 sal_Int32 nSlotId
; // the SFX-compatible slot ID
77 sal_Int16 nFormFeature
; // the css.form.runtime.FormFeature ID
79 typedef ::std::vector
< FeatureDescription
> FeatureDescriptions
;
82 const FeatureDescriptions
& getFeatureDescriptions()
84 static FeatureDescriptions s_aFeatureDescriptions
;
85 if ( s_aFeatureDescriptions
.empty() )
87 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
88 if ( s_aFeatureDescriptions
.empty() )
90 FeatureDescription aDescriptions
[] = {
91 { FMURL_FORM_POSITION
, SID_FM_RECORD_ABSOLUTE
, FormFeature::MoveAbsolute
},
92 { FMURL_FORM_RECORDCOUNT
, SID_FM_RECORD_TOTAL
, FormFeature::TotalRecords
},
93 { FMURL_RECORD_MOVEFIRST
, SID_FM_RECORD_FIRST
, FormFeature::MoveToFirst
},
94 { FMURL_RECORD_MOVEPREV
, SID_FM_RECORD_PREV
, FormFeature::MoveToPrevious
},
95 { FMURL_RECORD_MOVENEXT
, SID_FM_RECORD_NEXT
, FormFeature::MoveToNext
},
96 { FMURL_RECORD_MOVELAST
, SID_FM_RECORD_LAST
, FormFeature::MoveToLast
},
97 { FMURL_RECORD_MOVETONEW
, SID_FM_RECORD_NEW
, FormFeature::MoveToInsertRow
},
98 { FMURL_RECORD_SAVE
, SID_FM_RECORD_SAVE
, FormFeature::SaveRecordChanges
},
99 { FMURL_RECORD_DELETE
, SID_FM_RECORD_DELETE
, FormFeature::DeleteRecord
},
100 { FMURL_FORM_REFRESH
, SID_FM_REFRESH
, FormFeature::ReloadForm
},
101 { FMURL_FORM_REFRESH_CURRENT_CONTROL
,
102 SID_FM_REFRESH_FORM_CONTROL
,FormFeature::RefreshCurrentControl
},
103 { FMURL_RECORD_UNDO
, SID_FM_RECORD_UNDO
, FormFeature::UndoRecordChanges
},
104 { FMURL_FORM_SORT_UP
, SID_FM_SORTUP
, FormFeature::SortAscending
},
105 { FMURL_FORM_SORT_DOWN
, SID_FM_SORTDOWN
, FormFeature::SortDescending
},
106 { FMURL_FORM_SORT
, SID_FM_ORDERCRIT
, FormFeature::InteractiveSort
},
107 { FMURL_FORM_AUTO_FILTER
, SID_FM_AUTOFILTER
, FormFeature::AutoFilter
},
108 { FMURL_FORM_FILTER
, SID_FM_FILTERCRIT
, FormFeature::InteractiveFilter
},
109 { FMURL_FORM_APPLY_FILTER
, SID_FM_FORM_FILTERED
, FormFeature::ToggleApplyFilter
},
110 { FMURL_FORM_REMOVE_FILTER
, SID_FM_REMOVE_FILTER_SORT
, FormFeature::RemoveFilterAndSort
}
112 for ( size_t i
=0; i
<sizeof(aDescriptions
)/sizeof(aDescriptions
[0]); ++i
)
113 s_aFeatureDescriptions
.push_back( aDescriptions
[i
] );
116 return s_aFeatureDescriptions
;
124 struct MatchFeatureDescriptionByURL
: public ::std::unary_function
< FeatureDescription
, bool >
126 const OUString
& m_rURL
;
127 MatchFeatureDescriptionByURL( const OUString
& _rURL
) :m_rURL( _rURL
) { }
129 bool operator()( const FeatureDescription
& _compare
)
131 return m_rURL
== _compare
.sURL
;
136 struct MatchFeatureDescriptionBySlotId
: public ::std::unary_function
< FeatureDescription
, bool >
139 MatchFeatureDescriptionBySlotId( sal_Int32 _nSlotId
) :m_nSlotId( _nSlotId
) { }
141 bool operator()( const FeatureDescription
& _compare
)
143 return m_nSlotId
== _compare
.nSlotId
;
148 struct MatchFeatureDescriptionByFormFeature
: public ::std::unary_function
< FeatureDescription
, bool >
150 sal_Int32 m_nFormFeature
;
151 MatchFeatureDescriptionByFormFeature( sal_Int32 _nFormFeature
) :m_nFormFeature( _nFormFeature
) { }
153 bool operator()( const FeatureDescription
& _compare
)
155 return m_nFormFeature
== _compare
.nFormFeature
;
160 struct FormFeatureToSlotId
: public ::std::unary_function
< sal_Int16
, sal_Int32
>
162 sal_Int32
operator()( sal_Int16 _FormFeature
)
164 return FeatureSlotTranslation::getSlotIdForFormFeature( _FormFeature
);
170 sal_Int32
FeatureSlotTranslation::getControllerFeatureSlotIdForURL( const OUString
& _rMainURL
)
172 const FeatureDescriptions
& rDescriptions( getFeatureDescriptions() );
173 FeatureDescriptions::const_iterator pos
= ::std::find_if( rDescriptions
.begin(), rDescriptions
.end(), MatchFeatureDescriptionByURL( _rMainURL
) );
174 return ( pos
!= rDescriptions
.end() ) ? pos
->nSlotId
: -1;
178 sal_Int16
FeatureSlotTranslation::getFormFeatureForSlotId( sal_Int32 _nSlotId
)
180 const FeatureDescriptions
& rDescriptions( getFeatureDescriptions() );
181 FeatureDescriptions::const_iterator pos
= ::std::find_if( rDescriptions
.begin(), rDescriptions
.end(), MatchFeatureDescriptionBySlotId( _nSlotId
) );
182 OSL_ENSURE( pos
!= rDescriptions
.end(), "FeatureSlotTranslation::getFormFeatureForSlotId: not found!" );
183 return ( pos
!= rDescriptions
.end() ) ? pos
->nFormFeature
: -1;
187 sal_Int32
FeatureSlotTranslation::getSlotIdForFormFeature( sal_Int16 _nFormFeature
)
189 const FeatureDescriptions
& rDescriptions( getFeatureDescriptions() );
190 FeatureDescriptions::const_iterator pos
= ::std::find_if( rDescriptions
.begin(), rDescriptions
.end(), MatchFeatureDescriptionByFormFeature( _nFormFeature
) );
191 OSL_ENSURE( pos
!= rDescriptions
.end(), "FeatureSlotTranslation::getSlotIdForFormFeature: not found!" );
192 return ( pos
!= rDescriptions
.end() ) ? pos
->nSlotId
: -1;
196 //= ControllerFeatures
199 ControllerFeatures::ControllerFeatures( IControllerFeatureInvalidation
* _pInvalidationCallback
)
200 :m_pInvalidationCallback( _pInvalidationCallback
)
206 ControllerFeatures::ControllerFeatures( const Reference
< XFormController
>& _rxController
, IControllerFeatureInvalidation
* _pInvalidationCallback
)
207 :m_pInvalidationCallback( _pInvalidationCallback
)
210 assign( _rxController
);
214 void ControllerFeatures::assign( const Reference
< XFormController
>& _rxController
)
217 m_pImpl
= new FormControllerHelper( _rxController
, m_pInvalidationCallback
);
222 ControllerFeatures::~ControllerFeatures()
228 void ControllerFeatures::dispose()
239 //= FormControllerHelper
242 FormControllerHelper::FormControllerHelper( const Reference
< XFormController
>& _rxController
, IControllerFeatureInvalidation
* _pInvalidationCallback
)
243 :m_pInvalidationCallback( _pInvalidationCallback
)
245 osl_atomic_increment( &m_refCount
);
248 m_xFormOperations
= FormOperations::createWithFormController( comphelper::getProcessComponentContext(), _rxController
);
249 if ( m_xFormOperations
.is() )
250 m_xFormOperations
->setFeatureInvalidation( this );
252 // to prevent the controller from displaying any error messages which happen while we operate on it,
253 // we add ourself as XSQLErrorListener. By contract, a FormController displays errors if and only if
254 // no SQLErrorListeners are registered.
255 _rxController
->addSQLErrorListener( this );
257 catch( const Exception
& )
259 DBG_UNHANDLED_EXCEPTION();
261 osl_atomic_decrement( &m_refCount
);
265 FormControllerHelper::~FormControllerHelper( )
272 catch( const Exception
& )
274 DBG_UNHANDLED_EXCEPTION();
279 void FormControllerHelper::dispose()
281 if ( m_xFormOperations
.is() )
282 m_xFormOperations
->dispose();
283 m_xFormOperations
.clear();
287 bool FormControllerHelper::isEnabled( sal_Int32 _nSlotId
) const
289 if ( !m_xFormOperations
.is() )
291 return m_xFormOperations
->isEnabled( FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId
) );
295 Reference
< XRowSet
> FormControllerHelper::getCursor() const
297 Reference
< XRowSet
> xCursor
;
298 if ( m_xFormOperations
.is() )
299 xCursor
= m_xFormOperations
->getCursor();
304 void FormControllerHelper::getState( sal_Int32 _nSlotId
, FeatureState
& _rState
) const
306 if ( m_xFormOperations
.is() )
307 _rState
= m_xFormOperations
->getState( FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId
) );
311 bool FormControllerHelper::commitCurrentControl( ) const
313 return impl_operateForm_nothrow( COMMIT_CONTROL
);
317 bool FormControllerHelper::commitCurrentRecord() const
319 return impl_operateForm_nothrow( COMMIT_RECORD
);
323 void FormControllerHelper::execute( sal_Int32 _nSlotId
, const OUString
& _rParamName
, const Any
& _rParamValue
) const
325 Sequence
< NamedValue
> aArguments(1);
326 aArguments
[0].Name
= _rParamName
;
327 aArguments
[0].Value
= _rParamValue
;
329 impl_operateForm_nothrow( EXECUTE_ARGS
, FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId
), aArguments
);
333 bool FormControllerHelper::impl_operateForm_nothrow( const FormOperation _eWhat
, const sal_Int16 _nFeature
,
334 const Sequence
< NamedValue
>& _rArguments
) const
336 if ( !m_xFormOperations
.is() )
340 bool bSuccess
= false;
341 const_cast< FormControllerHelper
* >( this )->m_aOperationError
.clear();
347 bSuccess
= m_xFormOperations
->commitCurrentControl();
352 sal_Bool
bDummy( sal_False
);
353 bSuccess
= m_xFormOperations
->commitCurrentRecord( bDummy
);
358 m_xFormOperations
->execute( _nFeature
);
363 m_xFormOperations
->executeWithArguments( _nFeature
, _rArguments
);
368 catch ( const SQLException
& )
370 aError
= ::cppu::getCaughtException();
372 catch( const Exception
& )
374 SQLException aFallbackError
;
375 aFallbackError
.Message
= ::comphelper::anyToString( ::cppu::getCaughtException() );
376 aError
<<= aFallbackError
;
382 // display the error. Prefer the one reported in errorOccurred over the one caught.
383 if ( m_aOperationError
.hasValue() )
384 displayException( m_aOperationError
);
385 else if ( aError
.hasValue() )
386 displayException( aError
);
388 OSL_FAIL( "FormControllerHelper::impl_operateForm_nothrow: no success, but no error?" );
394 void FormControllerHelper::execute( sal_Int32 _nSlotId
) const
396 impl_operateForm_nothrow( EXECUTE
, FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId
),
397 Sequence
< NamedValue
>() );
401 void SAL_CALL
FormControllerHelper::invalidateFeatures( const Sequence
< ::sal_Int16
>& _Features
) throw (RuntimeException
, std::exception
)
403 if ( !m_pInvalidationCallback
)
404 // nobody's interested in ...
407 ::std::vector
< sal_Int32
> aFeatures( _Features
.getLength() );
409 _Features
.getConstArray(),
410 _Features
.getConstArray() + _Features
.getLength(),
412 FormFeatureToSlotId()
415 m_pInvalidationCallback
->invalidateFeatures( aFeatures
);
419 void SAL_CALL
FormControllerHelper::invalidateAllFeatures() throw (RuntimeException
, std::exception
)
421 if ( !m_pInvalidationCallback
)
422 // nobody's interested in ...
425 // actually, it's a little bit more than the supported features,
426 // but on the medium term, we are to support everything listed
428 ::std::vector
< sal_Int32
> aSupportedFeatures
;
429 sal_Int32 pSupportedFeatures
[] =
436 SID_FM_RECORD_DELETE
,
437 SID_FM_RECORD_ABSOLUTE
,
441 SID_FM_REMOVE_FILTER_SORT
,
447 SID_FM_FORM_FILTERED
,
449 SID_FM_REFRESH_FORM_CONTROL
,
454 sal_Int32 nFeatureCount
= sizeof( pSupportedFeatures
) / sizeof( pSupportedFeatures
[ 0 ] );
455 aSupportedFeatures
.resize( nFeatureCount
);
456 ::std::copy( pSupportedFeatures
, pSupportedFeatures
+ nFeatureCount
, aSupportedFeatures
.begin() );
458 m_pInvalidationCallback
->invalidateFeatures( aSupportedFeatures
);
462 void SAL_CALL
FormControllerHelper::errorOccured( const SQLErrorEvent
& _Event
) throw (RuntimeException
, std::exception
)
464 OSL_ENSURE( !m_aOperationError
.hasValue(), "FormControllerHelper::errorOccurred: two errors during one operation?" );
465 m_aOperationError
= _Event
.Reason
;
469 void SAL_CALL
FormControllerHelper::disposing( const EventObject
& /*_Source*/ ) throw (RuntimeException
, std::exception
)
475 bool FormControllerHelper::isInsertionRow() const
478 if ( m_xFormOperations
.is() )
479 bIs
= m_xFormOperations
->isInsertionRow();
484 bool FormControllerHelper::isModifiedRow() const
487 if ( m_xFormOperations
.is() )
488 bIs
= m_xFormOperations
->isModifiedRow();
492 bool FormControllerHelper::canDoFormFilter() const
494 if ( !m_xFormOperations
.is() )
500 Reference
< XPropertySet
> xCursorProperties( m_xFormOperations
->getCursor(), UNO_QUERY_THROW
);
502 bool bEscapeProcessing( false );
503 OSL_VERIFY( xCursorProperties
->getPropertyValue( FM_PROP_ESCAPE_PROCESSING
) >>= bEscapeProcessing
);
505 OUString sActiveCommand
;
506 OSL_VERIFY( xCursorProperties
->getPropertyValue( FM_PROP_ACTIVECOMMAND
) >>= sActiveCommand
);
508 bool bInsertOnlyForm( false );
509 OSL_VERIFY( xCursorProperties
->getPropertyValue( FM_PROP_INSERTONLY
) >>= bInsertOnlyForm
);
511 bCanDo
= bEscapeProcessing
&& !sActiveCommand
.isEmpty() && !bInsertOnlyForm
;
513 catch( const Exception
& )
515 DBG_UNHANDLED_EXCEPTION();
524 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */