Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include <sal/macros.h>
22 : #include "formcontrolling.hxx"
23 : #include "fmurl.hxx"
24 : #include "svx/svxids.hrc"
25 : #include "fmprop.hrc"
26 : #include "svx/fmtools.hxx"
27 :
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>
32 :
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>
38 :
39 : #include <functional>
40 : #include <algorithm>
41 :
42 :
43 : namespace svx
44 : {
45 :
46 :
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;
65 :
66 : namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
67 :
68 :
69 : //= FeatureSlotTranslation
70 :
71 : namespace
72 : {
73 0 : struct FeatureDescription
74 : {
75 : OUString sURL; // the URL
76 : sal_Int32 nSlotId; // the SFX-compatible slot ID
77 : sal_Int16 nFormFeature; // the css.form.runtime.FormFeature ID
78 : };
79 : typedef ::std::vector< FeatureDescription > FeatureDescriptions;
80 :
81 :
82 0 : const FeatureDescriptions& getFeatureDescriptions()
83 : {
84 0 : static FeatureDescriptions s_aFeatureDescriptions;
85 0 : if ( s_aFeatureDescriptions.empty() )
86 : {
87 0 : ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
88 0 : if ( s_aFeatureDescriptions.empty() )
89 : {
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 }
111 0 : };
112 0 : for ( size_t i=0; i<sizeof(aDescriptions)/sizeof(aDescriptions[0]); ++i )
113 0 : s_aFeatureDescriptions.push_back( aDescriptions[i] );
114 0 : }
115 : };
116 0 : return s_aFeatureDescriptions;
117 : }
118 : }
119 :
120 :
121 : namespace
122 : {
123 :
124 : struct MatchFeatureDescriptionByURL : public ::std::unary_function< FeatureDescription, bool >
125 : {
126 : const OUString& m_rURL;
127 0 : MatchFeatureDescriptionByURL( const OUString& _rURL ) :m_rURL( _rURL ) { }
128 :
129 0 : bool operator()( const FeatureDescription& _compare )
130 : {
131 0 : return m_rURL == _compare.sURL;
132 : }
133 : };
134 :
135 :
136 : struct MatchFeatureDescriptionBySlotId : public ::std::unary_function< FeatureDescription, bool >
137 : {
138 : sal_Int32 m_nSlotId;
139 0 : MatchFeatureDescriptionBySlotId( sal_Int32 _nSlotId ) :m_nSlotId( _nSlotId ) { }
140 :
141 0 : bool operator()( const FeatureDescription& _compare )
142 : {
143 0 : return m_nSlotId == _compare.nSlotId;
144 : }
145 : };
146 :
147 :
148 : struct MatchFeatureDescriptionByFormFeature : public ::std::unary_function< FeatureDescription, bool >
149 : {
150 : sal_Int32 m_nFormFeature;
151 0 : MatchFeatureDescriptionByFormFeature( sal_Int32 _nFormFeature ) :m_nFormFeature( _nFormFeature ) { }
152 :
153 0 : bool operator()( const FeatureDescription& _compare )
154 : {
155 0 : return m_nFormFeature == _compare.nFormFeature;
156 : }
157 : };
158 :
159 :
160 : struct FormFeatureToSlotId : public ::std::unary_function< sal_Int16, sal_Int32 >
161 : {
162 0 : sal_Int32 operator()( sal_Int16 _FormFeature )
163 : {
164 0 : return FeatureSlotTranslation::getSlotIdForFormFeature( _FormFeature );
165 : }
166 : };
167 : }
168 :
169 :
170 0 : sal_Int32 FeatureSlotTranslation::getControllerFeatureSlotIdForURL( const OUString& _rMainURL )
171 : {
172 0 : const FeatureDescriptions& rDescriptions( getFeatureDescriptions() );
173 0 : FeatureDescriptions::const_iterator pos = ::std::find_if( rDescriptions.begin(), rDescriptions.end(), MatchFeatureDescriptionByURL( _rMainURL ) );
174 0 : return ( pos != rDescriptions.end() ) ? pos->nSlotId : -1;
175 : }
176 :
177 :
178 0 : sal_Int16 FeatureSlotTranslation::getFormFeatureForSlotId( sal_Int32 _nSlotId )
179 : {
180 0 : const FeatureDescriptions& rDescriptions( getFeatureDescriptions() );
181 0 : FeatureDescriptions::const_iterator pos = ::std::find_if( rDescriptions.begin(), rDescriptions.end(), MatchFeatureDescriptionBySlotId( _nSlotId ) );
182 : OSL_ENSURE( pos != rDescriptions.end(), "FeatureSlotTranslation::getFormFeatureForSlotId: not found!" );
183 0 : return ( pos != rDescriptions.end() ) ? pos->nFormFeature : -1;
184 : }
185 :
186 :
187 0 : sal_Int32 FeatureSlotTranslation::getSlotIdForFormFeature( sal_Int16 _nFormFeature )
188 : {
189 0 : const FeatureDescriptions& rDescriptions( getFeatureDescriptions() );
190 0 : FeatureDescriptions::const_iterator pos = ::std::find_if( rDescriptions.begin(), rDescriptions.end(), MatchFeatureDescriptionByFormFeature( _nFormFeature ) );
191 : OSL_ENSURE( pos != rDescriptions.end(), "FeatureSlotTranslation::getSlotIdForFormFeature: not found!" );
192 0 : return ( pos != rDescriptions.end() ) ? pos->nSlotId : -1;
193 : }
194 :
195 :
196 : //= ControllerFeatures
197 :
198 :
199 0 : ControllerFeatures::ControllerFeatures( IControllerFeatureInvalidation* _pInvalidationCallback )
200 : :m_pInvalidationCallback( _pInvalidationCallback )
201 0 : ,m_pImpl( NULL )
202 : {
203 0 : }
204 :
205 :
206 0 : ControllerFeatures::ControllerFeatures( const Reference< XFormController >& _rxController, IControllerFeatureInvalidation* _pInvalidationCallback )
207 : :m_pInvalidationCallback( _pInvalidationCallback )
208 0 : ,m_pImpl( NULL )
209 : {
210 0 : assign( _rxController );
211 0 : }
212 :
213 :
214 0 : void ControllerFeatures::assign( const Reference< XFormController >& _rxController )
215 : {
216 0 : dispose();
217 0 : m_pImpl = new FormControllerHelper( _rxController, m_pInvalidationCallback );
218 0 : m_pImpl->acquire();
219 0 : }
220 :
221 :
222 0 : ControllerFeatures::~ControllerFeatures()
223 : {
224 0 : dispose();
225 0 : }
226 :
227 :
228 0 : void ControllerFeatures::dispose()
229 : {
230 0 : if ( m_pImpl )
231 : {
232 0 : m_pImpl->dispose();
233 0 : m_pImpl->release();
234 0 : m_pImpl = NULL;
235 : }
236 0 : }
237 :
238 :
239 : //= FormControllerHelper
240 :
241 :
242 0 : FormControllerHelper::FormControllerHelper( const Reference< XFormController >& _rxController, IControllerFeatureInvalidation* _pInvalidationCallback )
243 0 : :m_pInvalidationCallback( _pInvalidationCallback )
244 : {
245 0 : osl_atomic_increment( &m_refCount );
246 : try
247 : {
248 0 : m_xFormOperations = FormOperations::createWithFormController( comphelper::getProcessComponentContext(), _rxController );
249 0 : if ( m_xFormOperations.is() )
250 0 : m_xFormOperations->setFeatureInvalidation( this );
251 :
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 0 : _rxController->addSQLErrorListener( this );
256 : }
257 0 : catch( const Exception& )
258 : {
259 : DBG_UNHANDLED_EXCEPTION();
260 : }
261 0 : osl_atomic_decrement( &m_refCount );
262 0 : }
263 :
264 :
265 0 : FormControllerHelper::~FormControllerHelper( )
266 : {
267 : try
268 : {
269 0 : acquire();
270 0 : dispose();
271 : }
272 0 : catch( const Exception& )
273 : {
274 : DBG_UNHANDLED_EXCEPTION();
275 : }
276 0 : }
277 :
278 :
279 0 : void FormControllerHelper::dispose()
280 : {
281 0 : if ( m_xFormOperations.is() )
282 0 : m_xFormOperations->dispose();
283 0 : m_xFormOperations.clear();
284 0 : }
285 :
286 :
287 0 : sal_Bool FormControllerHelper::isEnabled( sal_Int32 _nSlotId ) const
288 : {
289 0 : if ( !m_xFormOperations.is() )
290 0 : return sal_False;
291 0 : return m_xFormOperations->isEnabled( FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ) );
292 : }
293 :
294 :
295 0 : Reference< XRowSet > FormControllerHelper::getCursor() const
296 : {
297 0 : Reference< XRowSet > xCursor;
298 0 : if ( m_xFormOperations.is() )
299 0 : xCursor = m_xFormOperations->getCursor();
300 0 : return xCursor;
301 : }
302 :
303 :
304 0 : void FormControllerHelper::getState( sal_Int32 _nSlotId, FeatureState& _rState ) const
305 : {
306 0 : if ( m_xFormOperations.is() )
307 0 : _rState = m_xFormOperations->getState( FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ) );
308 0 : }
309 :
310 :
311 0 : sal_Bool FormControllerHelper::commitCurrentControl( ) const
312 : {
313 0 : return impl_operateForm_nothrow( COMMIT_CONTROL );
314 : }
315 :
316 :
317 0 : sal_Bool FormControllerHelper::commitCurrentRecord() const
318 : {
319 0 : return impl_operateForm_nothrow( COMMIT_RECORD );
320 : }
321 :
322 :
323 0 : void FormControllerHelper::execute( sal_Int32 _nSlotId, const OUString& _rParamName, const Any& _rParamValue ) const
324 : {
325 0 : Sequence< NamedValue > aArguments(1);
326 0 : aArguments[0].Name = _rParamName;
327 0 : aArguments[0].Value = _rParamValue;
328 :
329 0 : impl_operateForm_nothrow( EXECUTE_ARGS, FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ), aArguments );
330 0 : }
331 :
332 :
333 0 : bool FormControllerHelper::impl_operateForm_nothrow( const FormOperation _eWhat, const sal_Int16 _nFeature,
334 : const Sequence< NamedValue >& _rArguments ) const
335 : {
336 0 : if ( !m_xFormOperations.is() )
337 0 : return false;
338 :
339 0 : Any aError;
340 0 : bool bSuccess = false;
341 0 : const_cast< FormControllerHelper* >( this )->m_aOperationError.clear();
342 : try
343 : {
344 0 : switch ( _eWhat )
345 : {
346 : case COMMIT_CONTROL:
347 0 : bSuccess = m_xFormOperations->commitCurrentControl();
348 0 : break;
349 :
350 : case COMMIT_RECORD:
351 : {
352 0 : sal_Bool bDummy( sal_False );
353 0 : bSuccess = m_xFormOperations->commitCurrentRecord( bDummy );
354 : }
355 0 : break;
356 :
357 : case EXECUTE:
358 0 : m_xFormOperations->execute( _nFeature );
359 0 : bSuccess = true;
360 0 : break;
361 :
362 : case EXECUTE_ARGS:
363 0 : m_xFormOperations->executeWithArguments( _nFeature, _rArguments );
364 0 : bSuccess = true;
365 0 : break;
366 : }
367 : }
368 0 : catch ( const SQLException& )
369 : {
370 0 : aError = ::cppu::getCaughtException();
371 : }
372 0 : catch( const Exception& )
373 : {
374 0 : SQLException aFallbackError;
375 0 : aFallbackError.Message = ::comphelper::anyToString( ::cppu::getCaughtException() );
376 0 : aError <<= aFallbackError;
377 : }
378 :
379 0 : if ( bSuccess )
380 0 : return true;
381 :
382 : // display the error. Prefer the one reported in errorOccurred over the one caught.
383 0 : if ( m_aOperationError.hasValue() )
384 0 : displayException( m_aOperationError );
385 0 : else if ( aError.hasValue() )
386 0 : displayException( aError );
387 : else
388 : OSL_FAIL( "FormControllerHelper::impl_operateForm_nothrow: no success, but no error?" );
389 :
390 0 : return false;
391 : }
392 :
393 :
394 0 : void FormControllerHelper::execute( sal_Int32 _nSlotId ) const
395 : {
396 0 : impl_operateForm_nothrow( EXECUTE, FeatureSlotTranslation::getFormFeatureForSlotId( _nSlotId ),
397 0 : Sequence< NamedValue >() );
398 0 : }
399 :
400 :
401 0 : void SAL_CALL FormControllerHelper::invalidateFeatures( const Sequence< ::sal_Int16 >& _Features ) throw (RuntimeException, std::exception)
402 : {
403 0 : if ( !m_pInvalidationCallback )
404 : // nobody's interested in ...
405 0 : return;
406 :
407 0 : ::std::vector< sal_Int32 > aFeatures( _Features.getLength() );
408 : ::std::transform(
409 : _Features.getConstArray(),
410 0 : _Features.getConstArray() + _Features.getLength(),
411 : aFeatures.begin(),
412 : FormFeatureToSlotId()
413 0 : );
414 :
415 0 : m_pInvalidationCallback->invalidateFeatures( aFeatures );
416 : }
417 :
418 :
419 0 : void SAL_CALL FormControllerHelper::invalidateAllFeatures() throw (RuntimeException, std::exception)
420 : {
421 0 : if ( !m_pInvalidationCallback )
422 : // nobody's interested in ...
423 0 : return;
424 :
425 : // actually, it's a little bit more than the supported features,
426 : // but on the medium term, we are to support everything listed
427 : // here
428 0 : ::std::vector< sal_Int32 > aSupportedFeatures;
429 : sal_Int32 pSupportedFeatures[] =
430 : {
431 : SID_FM_RECORD_FIRST,
432 : SID_FM_RECORD_NEXT,
433 : SID_FM_RECORD_PREV,
434 : SID_FM_RECORD_LAST,
435 : SID_FM_RECORD_NEW,
436 : SID_FM_RECORD_DELETE,
437 : SID_FM_RECORD_ABSOLUTE,
438 : SID_FM_RECORD_TOTAL,
439 : SID_FM_RECORD_SAVE,
440 : SID_FM_RECORD_UNDO,
441 : SID_FM_REMOVE_FILTER_SORT,
442 : SID_FM_SORTUP,
443 : SID_FM_SORTDOWN,
444 : SID_FM_ORDERCRIT,
445 : SID_FM_AUTOFILTER,
446 : SID_FM_FILTERCRIT,
447 : SID_FM_FORM_FILTERED,
448 : SID_FM_REFRESH,
449 : SID_FM_REFRESH_FORM_CONTROL,
450 : SID_FM_SEARCH,
451 : SID_FM_FILTER_START,
452 : SID_FM_VIEW_AS_GRID
453 0 : };
454 0 : sal_Int32 nFeatureCount = sizeof( pSupportedFeatures ) / sizeof( pSupportedFeatures[ 0 ] );
455 0 : aSupportedFeatures.resize( nFeatureCount );
456 0 : ::std::copy( pSupportedFeatures, pSupportedFeatures + nFeatureCount, aSupportedFeatures.begin() );
457 :
458 0 : m_pInvalidationCallback->invalidateFeatures( aSupportedFeatures );
459 : }
460 :
461 :
462 0 : void SAL_CALL FormControllerHelper::errorOccured( const SQLErrorEvent& _Event ) throw (RuntimeException, std::exception)
463 : {
464 : OSL_ENSURE( !m_aOperationError.hasValue(), "FormControllerHelper::errorOccurred: two errors during one operation?" );
465 0 : m_aOperationError = _Event.Reason;
466 0 : }
467 :
468 :
469 0 : void SAL_CALL FormControllerHelper::disposing( const EventObject& /*_Source*/ ) throw (RuntimeException, std::exception)
470 : {
471 : // not interested in
472 0 : }
473 :
474 :
475 0 : sal_Bool FormControllerHelper::isInsertionRow() const
476 : {
477 0 : sal_Bool bIs = sal_False;
478 0 : if ( m_xFormOperations.is() )
479 0 : bIs = m_xFormOperations->isInsertionRow();
480 0 : return bIs;
481 : }
482 :
483 :
484 0 : sal_Bool FormControllerHelper::isModifiedRow() const
485 : {
486 0 : sal_Bool bIs = sal_False;
487 0 : if ( m_xFormOperations.is() )
488 0 : bIs = m_xFormOperations->isModifiedRow();
489 0 : return bIs;
490 : }
491 :
492 0 : bool FormControllerHelper::canDoFormFilter() const
493 : {
494 0 : if ( !m_xFormOperations.is() )
495 0 : return false;
496 :
497 0 : bool bCanDo = false;
498 : try
499 : {
500 0 : Reference< XPropertySet > xCursorProperties( m_xFormOperations->getCursor(), UNO_QUERY_THROW );
501 :
502 0 : bool bEscapeProcessing( false );
503 0 : OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_ESCAPE_PROCESSING ) >>= bEscapeProcessing );
504 :
505 0 : OUString sActiveCommand;
506 0 : OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_ACTIVECOMMAND ) >>= sActiveCommand );
507 :
508 0 : bool bInsertOnlyForm( false );
509 0 : OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_INSERTONLY ) >>= bInsertOnlyForm );
510 :
511 0 : bCanDo = bEscapeProcessing && !sActiveCommand.isEmpty() && !bInsertOnlyForm;
512 : }
513 0 : catch( const Exception& )
514 : {
515 : DBG_UNHANDLED_EXCEPTION();
516 : }
517 0 : return bCanDo;
518 : }
519 :
520 :
521 : } // namespace svx
522 :
523 :
524 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|