LibreOffice Module svx (master) 1
formcontrolling.cxx
Go to the documentation of this file.
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.hxx>
26#include <formcontroller.hxx>
27#include <svx/fmtools.hxx>
28
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>
33
38#include <osl/diagnose.h>
39
40#include <algorithm>
41
42
43namespace svx
44{
45
46
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;
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;
61
62 namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
63
64
65 //= FeatureSlotTranslation
66
67 namespace
68 {
69 struct FeatureDescription
70 {
71 OUString sURL; // the URL
72 sal_Int32 nSlotId; // the SFX-compatible slot ID
73 sal_Int16 nFormFeature; // the css.form.runtime.FormFeature ID
74 };
75 typedef ::std::vector< FeatureDescription > FeatureDescriptions;
76
77
78 const FeatureDescriptions& getFeatureDescriptions()
79 {
80 static const FeatureDescriptions s_aFeatureDescriptions({
81 { OUString(FMURL_FORM_POSITION), SID_FM_RECORD_ABSOLUTE, FormFeature::MoveAbsolute },
82 { OUString(FMURL_FORM_RECORDCOUNT), SID_FM_RECORD_TOTAL, FormFeature::TotalRecords },
83 { OUString(FMURL_RECORD_MOVEFIRST), SID_FM_RECORD_FIRST, FormFeature::MoveToFirst },
84 { OUString(FMURL_RECORD_MOVEPREV), SID_FM_RECORD_PREV, FormFeature::MoveToPrevious },
85 { OUString(FMURL_RECORD_MOVENEXT), SID_FM_RECORD_NEXT, FormFeature::MoveToNext },
86 { OUString(FMURL_RECORD_MOVELAST), SID_FM_RECORD_LAST, FormFeature::MoveToLast },
87 { OUString(FMURL_RECORD_MOVETONEW), SID_FM_RECORD_NEW, FormFeature::MoveToInsertRow },
88 { OUString(FMURL_RECORD_SAVE), SID_FM_RECORD_SAVE, FormFeature::SaveRecordChanges },
89 { OUString(FMURL_RECORD_DELETE), SID_FM_RECORD_DELETE, FormFeature::DeleteRecord },
90 { OUString(FMURL_FORM_REFRESH), SID_FM_REFRESH, FormFeature::ReloadForm },
92 SID_FM_REFRESH_FORM_CONTROL,FormFeature::RefreshCurrentControl },
93 { OUString(FMURL_RECORD_UNDO), SID_FM_RECORD_UNDO, FormFeature::UndoRecordChanges },
94 { OUString(FMURL_FORM_SORT_UP), SID_FM_SORTUP, FormFeature::SortAscending },
95 { OUString(FMURL_FORM_SORT_DOWN), SID_FM_SORTDOWN, FormFeature::SortDescending },
96 { OUString(FMURL_FORM_SORT), SID_FM_ORDERCRIT, FormFeature::InteractiveSort },
97 { OUString(FMURL_FORM_AUTO_FILTER), SID_FM_AUTOFILTER, FormFeature::AutoFilter },
98 { OUString(FMURL_FORM_FILTER), SID_FM_FILTERCRIT, FormFeature::InteractiveFilter },
99 { OUString(FMURL_FORM_APPLY_FILTER), SID_FM_FORM_FILTERED, FormFeature::ToggleApplyFilter },
100 { OUString(FMURL_FORM_REMOVE_FILTER), SID_FM_REMOVE_FILTER_SORT, FormFeature::RemoveFilterAndSort }
101 });
102 return s_aFeatureDescriptions;
103 }
104 }
105
106
107 namespace
108 {
109
110 struct MatchFeatureDescriptionByURL
111 {
112 const OUString& m_rURL;
113 explicit MatchFeatureDescriptionByURL( const OUString& _rURL ) :m_rURL( _rURL ) { }
114
115 bool operator()( const FeatureDescription& _compare )
116 {
117 return m_rURL == _compare.sURL;
118 }
119 };
120
121
122 struct MatchFeatureDescriptionBySlotId
123 {
124 sal_Int32 m_nSlotId;
125 explicit MatchFeatureDescriptionBySlotId( sal_Int32 _nSlotId ) :m_nSlotId( _nSlotId ) { }
126
127 bool operator()( const FeatureDescription& _compare )
128 {
129 return m_nSlotId == _compare.nSlotId;
130 }
131 };
132
133
134 struct MatchFeatureDescriptionByFormFeature
135 {
136 sal_Int32 m_nFormFeature;
137 explicit MatchFeatureDescriptionByFormFeature( sal_Int32 _nFormFeature ) :m_nFormFeature( _nFormFeature ) { }
138
139 bool operator()( const FeatureDescription& _compare )
140 {
141 return m_nFormFeature == _compare.nFormFeature;
142 }
143 };
144
145
146 struct FormFeatureToSlotId
147 {
148 sal_Int32 operator()( sal_Int16 FormFeature )
149 {
151 }
152 };
153 }
154
155
156 sal_Int32 FeatureSlotTranslation::getControllerFeatureSlotIdForURL( const OUString& _rMainURL )
157 {
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;
161 }
162
163
165 {
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;
170 }
171
172
173 sal_Int32 FeatureSlotTranslation::getSlotIdForFormFeature( sal_Int16 _nFormFeature )
174 {
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;
179 }
180
182 :m_pInvalidationCallback( _pInvalidationCallback )
183 {
184 }
185
186
187 ControllerFeatures::ControllerFeatures( const Reference< XFormController >& _rxController )
188 :m_pInvalidationCallback( nullptr )
189 {
190 assign( _rxController );
191 }
192
193
194 void ControllerFeatures::assign( const Reference< XFormController >& _rxController )
195 {
196 dispose();
198 }
199
200
202 {
203 dispose();
204 }
205
206
208 {
209 if ( m_pImpl.is() )
210 {
211 m_pImpl->dispose();
212 m_pImpl.clear();
213 }
214 }
215
216 FormControllerHelper::FormControllerHelper( const Reference< XFormController >& _rxController, IControllerFeatureInvalidation* _pInvalidationCallback )
217 :m_pInvalidationCallback( _pInvalidationCallback )
218 {
219 osl_atomic_increment( &m_refCount );
220 try
221 {
222 m_xFormOperations = FormOperations::createWithFormController( comphelper::getProcessComponentContext(), _rxController );
223 if ( m_xFormOperations.is() )
224 m_xFormOperations->setFeatureInvalidation( this );
225 }
226 catch( const Exception& )
227 {
229 }
230 osl_atomic_decrement( &m_refCount );
231 }
232
233
235 {
236 try
237 {
238 acquire();
239 dispose();
240 }
241 catch( const Exception& )
242 {
244 }
245 }
246
247
249 {
250 if ( m_xFormOperations.is() )
251 m_xFormOperations->dispose();
252 m_xFormOperations.clear();
253 }
254
255
256 bool FormControllerHelper::isEnabled( sal_Int32 _nSlotId ) const
257 {
258 if ( !m_xFormOperations.is() )
259 return false;
261 }
262
263
264 Reference< XRowSet > FormControllerHelper::getCursor() const
265 {
266 Reference< XRowSet > xCursor;
267 if ( m_xFormOperations.is() )
268 xCursor = m_xFormOperations->getCursor();
269 return xCursor;
270 }
271
272
273 void FormControllerHelper::getState( sal_Int32 _nSlotId, FeatureState& _rState ) const
274 {
275 if ( m_xFormOperations.is() )
277 }
278
279
281 {
283 }
284
285
287 {
289 }
290
291
292 void FormControllerHelper::execute( sal_Int32 _nSlotId, const OUString& _rParamName, const Any& _rParamValue ) const
293 {
294 Sequence< NamedValue > aArguments { { _rParamName, _rParamValue } };
296 }
297
298
299 bool FormControllerHelper::impl_operateForm_nothrow( const FormOperation _eWhat, const sal_Int16 _nFeature,
300 const Sequence< NamedValue >& _rArguments ) const
301 {
302 if ( !m_xFormOperations.is() )
303 return false;
304
305 Any aError;
306 bool bSuccess = false;
307 const_cast< FormControllerHelper* >( this )->m_aOperationError.clear();
308 try
309 {
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) );
314
315 switch ( _eWhat )
316 {
317 case COMMIT_CONTROL:
318 bSuccess = m_xFormOperations->commitCurrentControl();
319 break;
320
321 case COMMIT_RECORD:
322 {
323 sal_Bool bDummy( false );
324 bSuccess = m_xFormOperations->commitCurrentRecord( bDummy );
325 }
326 break;
327
328 case EXECUTE:
329 m_xFormOperations->execute( _nFeature );
330 bSuccess = true;
331 break;
332
333 case EXECUTE_ARGS:
334 m_xFormOperations->executeWithArguments( _nFeature, _rArguments );
335 bSuccess = true;
336 break;
337 }
338 }
339 catch ( const SQLException& )
340 {
341 m_xFormOperations->getController()->removeSQLErrorListener( const_cast< FormControllerHelper* >(this) );
342 aError = ::cppu::getCaughtException();
343 }
344 catch( const Exception& )
345 {
346 m_xFormOperations->getController()->removeSQLErrorListener( const_cast< FormControllerHelper* >(this) );
347 SQLException aFallbackError;
348 aFallbackError.Message = ::comphelper::anyToString( ::cppu::getCaughtException() );
349 aError <<= aFallbackError;
350 }
351
352 if ( bSuccess )
353 return true;
354
355 // display the error. Prefer the one reported in errorOccurred over the one caught.
356 if ( m_aOperationError.hasValue() )
358 else if ( aError.hasValue() )
360 else
361 OSL_FAIL( "FormControllerHelper::impl_operateForm_nothrow: no success, but no error?" );
362
363 return false;
364 }
365
366
367 void FormControllerHelper::execute( sal_Int32 _nSlotId ) const
368 {
370 Sequence< NamedValue >() );
371 }
372
373
374 void SAL_CALL FormControllerHelper::invalidateFeatures( const Sequence< ::sal_Int16 >& Features )
375 {
377 // nobody's interested in ...
378 return;
379
380 ::std::vector< sal_Int32 > aFeatures( Features.getLength() );
381 ::std::transform(
382 Features.begin(),
383 Features.end(),
384 aFeatures.begin(),
385 FormFeatureToSlotId()
386 );
387
389 }
390
391
393 {
395 // nobody's interested in ...
396 return;
397
398 // actually, it's a little bit more than the supported features,
399 // but on the medium term, we are to support everything listed
400 // here
401 ::std::vector< sal_Int32 > aSupportedFeatures;
402 const sal_Int32 pSupportedFeatures[] =
403 {
404 SID_FM_RECORD_FIRST,
405 SID_FM_RECORD_NEXT,
406 SID_FM_RECORD_PREV,
407 SID_FM_RECORD_LAST,
408 SID_FM_RECORD_NEW,
409 SID_FM_RECORD_DELETE,
410 SID_FM_RECORD_ABSOLUTE,
411 SID_FM_RECORD_TOTAL,
412 SID_FM_RECORD_SAVE,
413 SID_FM_RECORD_UNDO,
414 SID_FM_REMOVE_FILTER_SORT,
415 SID_FM_SORTUP,
416 SID_FM_SORTDOWN,
417 SID_FM_ORDERCRIT,
418 SID_FM_AUTOFILTER,
419 SID_FM_FILTERCRIT,
420 SID_FM_FORM_FILTERED,
421 SID_FM_REFRESH,
422 SID_FM_REFRESH_FORM_CONTROL,
423 SID_FM_SEARCH,
424 SID_FM_FILTER_START,
425 SID_FM_VIEW_AS_GRID
426 };
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 );
430
431 m_pInvalidationCallback->invalidateFeatures( aSupportedFeatures );
432 }
433
434
435 void SAL_CALL FormControllerHelper::errorOccured( const SQLErrorEvent& Event )
436 {
437 OSL_ENSURE( !m_aOperationError.hasValue(), "FormControllerHelper::errorOccurred: two errors during one operation?" );
438 m_aOperationError = Event.Reason;
439 }
440
441
442 void SAL_CALL FormControllerHelper::disposing( const EventObject& /*_Source*/ )
443 {
444 // not interested in
445 }
446
447
449 {
450 bool bIs = false;
451 if ( m_xFormOperations.is() )
452 bIs = m_xFormOperations->isInsertionRow();
453 return bIs;
454 }
455
456
458 {
459 bool bIs = false;
460 if ( m_xFormOperations.is() )
461 bIs = m_xFormOperations->isModifiedRow();
462 return bIs;
463 }
464
466 {
467 if ( !m_xFormOperations.is() )
468 return false;
469
470 bool bCanDo = false;
471 try
472 {
473 Reference< XPropertySet > xCursorProperties( m_xFormOperations->getCursor(), UNO_QUERY_THROW );
474
475 bool bEscapeProcessing( false );
476 OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_ESCAPE_PROCESSING ) >>= bEscapeProcessing );
477
478 OUString sActiveCommand;
479 OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_ACTIVECOMMAND ) >>= sActiveCommand );
480
481 bool bInsertOnlyForm( false );
482 OSL_VERIFY( xCursorProperties->getPropertyValue( FM_PROP_INSERTONLY ) >>= bInsertOnlyForm );
483
484 bCanDo = bEscapeProcessing && !sActiveCommand.isEmpty() && !bInsertOnlyForm;
485 }
486 catch( const Exception& )
487 {
489 }
490 return bCanDo;
491 }
492
493
494}
495
496
497/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
rtl::Reference< FormControllerHelper > m_pImpl
void assign(const css::uno::Reference< css::form::runtime::XFormController > &_rxController)
assign to a controller
void dispose()
clears the instance so that it cannot be used afterwards
ControllerFeatures(IControllerFeatureInvalidation *_pInvalidationCallback)
standard ctor
IControllerFeatureInvalidation * m_pInvalidationCallback
static sal_Int32 getControllerFeatureSlotIdForURL(const OUString &_rMainURL)
retrieves the feature id for a given feature URL
static sal_Int16 getFormFeatureForSlotId(sal_Int32 _nSlotId)
retrieves the css.form.runtime.FormFeature ID for a given slot ID
static sal_Int32 getSlotIdForFormFeature(sal_Int16 _nFormFeature)
retrieves the slot id for a given css.form.runtime.FormFeature ID
is a helper class which manages form controller functionality (such as moveNext etc....
FormControllerHelper(const css::uno::Reference< css::form::runtime::XFormController > &_rxController, IControllerFeatureInvalidation *_pInvalidationCallback)
constructs the helper from a <type scope="css::form::runtime">XFormController<type> instance
virtual void SAL_CALL invalidateFeatures(const css::uno::Sequence< ::sal_Int16 > &Features) override
void dispose()
disposes this instance.
css::uno::Reference< css::sdbc::XRowSet > getCursor() const
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
bool impl_operateForm_nothrow(const FormOperation _eWhat, const sal_Int16 _nFeature, const css::uno::Sequence< css::beans::NamedValue > &_rArguments) const
virtual void SAL_CALL errorOccured(const css::sdb::SQLErrorEvent &Event) override
virtual void SAL_CALL invalidateAllFeatures() override
bool isEnabled(sal_Int32 _nSlotId) const
void getState(sal_Int32 _nSlotId, css::form::runtime::FeatureState &_out_rState) const
css::uno::Reference< css::form::runtime::XFormOperations > m_xFormOperations
virtual ~FormControllerHelper() override
dtor
void execute(sal_Int32 _nSlotId) const
IControllerFeatureInvalidation * m_pInvalidationCallback
virtual void invalidateFeatures(const ::std::vector< sal_Int32 > &_rFeatures)=0
invalidates the given features
static css::uno::Reference< css::awt::XWindow > getDialogParentWindow(css::uno::Reference< css::form::runtime::XFormController > xFormController)
#define DBG_UNHANDLED_EXCEPTION(...)
constexpr OUStringLiteral FM_PROP_ACTIVECOMMAND
Definition: fmprop.hxx:127
constexpr OUStringLiteral FM_PROP_ESCAPE_PROCESSING
Definition: fmprop.hxx:124
constexpr OUStringLiteral FM_PROP_INSERTONLY
Definition: fmprop.hxx:122
void displayException(const Any &_rExcept, const css::uno::Reference< css::awt::XWindow > &rParent)
Definition: fmtools.cxx:83
constexpr OUStringLiteral FMURL_FORM_APPLY_FILTER
Definition: fmurl.hxx:42
constexpr OUStringLiteral FMURL_FORM_AUTO_FILTER
Definition: fmurl.hxx:40
constexpr OUStringLiteral FMURL_RECORD_MOVETONEW
Definition: fmurl.hxx:31
constexpr OUStringLiteral FMURL_RECORD_SAVE
Definition: fmurl.hxx:33
constexpr OUStringLiteral FMURL_FORM_RECORDCOUNT
Definition: fmurl.hxx:26
constexpr OUStringLiteral FMURL_FORM_REMOVE_FILTER
Definition: fmurl.hxx:43
constexpr OUStringLiteral FMURL_RECORD_MOVELAST
Definition: fmurl.hxx:30
constexpr OUStringLiteral FMURL_FORM_REFRESH_CURRENT_CONTROL
Definition: fmurl.hxx:36
constexpr OUStringLiteral FMURL_FORM_REFRESH
Definition: fmurl.hxx:35
constexpr OUStringLiteral FMURL_FORM_FILTER
Definition: fmurl.hxx:41
constexpr OUStringLiteral FMURL_RECORD_DELETE
Definition: fmurl.hxx:34
constexpr OUStringLiteral FMURL_RECORD_MOVENEXT
Definition: fmurl.hxx:29
constexpr OUStringLiteral FMURL_FORM_POSITION
Definition: fmurl.hxx:25
constexpr OUStringLiteral FMURL_FORM_SORT_DOWN
Definition: fmurl.hxx:38
constexpr OUStringLiteral FMURL_RECORD_MOVEPREV
Definition: fmurl.hxx:28
constexpr OUStringLiteral FMURL_FORM_SORT
Definition: fmurl.hxx:39
constexpr OUStringLiteral FMURL_RECORD_MOVEFIRST
Definition: fmurl.hxx:27
constexpr OUStringLiteral FMURL_FORM_SORT_UP
Definition: fmurl.hxx:37
constexpr OUStringLiteral FMURL_RECORD_UNDO
Definition: fmurl.hxx:32
const sal_Int16 nFormFeature
Sequence< PropertyValue > aArguments
#define SAL_N_ELEMENTS(arr)
const OUString & m_rURL
@ Exception
class SAL_NO_VTABLE XPropertySet
Definition: xmlexchg.hxx:28
Reference< XComponentContext > getProcessComponentContext()
unsigned char sal_Bool
size_t pos