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 .
20 #include <formnavigation.hxx>
21 #include <urltransformer.hxx>
22 #include <controlfeatureinterception.hxx>
23 #include <frm_strings.hxx>
25 #include <com/sun/star/form/runtime/FormFeature.hpp>
27 #include <comphelper/propertyvalue.hxx>
28 #include <tools/debug.hxx>
29 #include <o3tl/string_view.hxx>
30 #include <osl/diagnose.h>
37 using namespace ::com::sun::star::uno
;
38 using namespace ::com::sun::star::beans
;
39 using namespace ::com::sun::star::lang
;
40 using namespace ::com::sun::star::util
;
41 using namespace ::com::sun::star::frame
;
42 namespace FormFeature
= ::com::sun::star::form::runtime::FormFeature
;
44 OFormNavigationHelper::OFormNavigationHelper( const Reference
< XComponentContext
>& _rxORB
)
46 ,m_aFeatureInterception( m_xORB
)
47 ,m_nConnectedFeatures( 0 )
52 OFormNavigationHelper::~OFormNavigationHelper()
57 void OFormNavigationHelper::dispose( )
59 m_aFeatureInterception
.dispose();
60 disconnectDispatchers();
64 void OFormNavigationHelper::interceptorsChanged( )
70 void OFormNavigationHelper::featureStateChanged( sal_Int16
/*_nFeatureId*/, bool /*_bEnabled*/ )
76 void OFormNavigationHelper::allFeatureStatesChanged( )
82 void SAL_CALL
OFormNavigationHelper::registerDispatchProviderInterceptor( const Reference
< XDispatchProviderInterceptor
>& _rxInterceptor
)
84 m_aFeatureInterception
.registerDispatchProviderInterceptor( _rxInterceptor
);
85 interceptorsChanged();
89 void SAL_CALL
OFormNavigationHelper::releaseDispatchProviderInterceptor( const Reference
< XDispatchProviderInterceptor
>& _rxInterceptor
)
91 m_aFeatureInterception
.releaseDispatchProviderInterceptor( _rxInterceptor
);
92 interceptorsChanged();
96 void SAL_CALL
OFormNavigationHelper::statusChanged( const FeatureStateEvent
& _rState
)
98 for (auto & feature
: m_aSupportedFeatures
)
100 if ( feature
.second
.aURL
.Main
== _rState
.FeatureURL
.Main
)
102 if ( ( feature
.second
.bCachedState
!= bool(_rState
.IsEnabled
) )
103 || ( feature
.second
.aCachedAdditionalState
!= _rState
.State
)
106 // change the cached state
107 feature
.second
.bCachedState
= _rState
.IsEnabled
;
108 feature
.second
.aCachedAdditionalState
= _rState
.State
;
109 // tell derivees what happened
110 featureStateChanged( feature
.first
, _rState
.IsEnabled
);
117 OSL_FAIL( "OFormNavigationHelper::statusChanged: huh? An invalid/unknown URL?" );
121 void SAL_CALL
OFormNavigationHelper::disposing( const EventObject
& _rSource
)
123 // was it one of our external dispatchers?
124 if ( !m_nConnectedFeatures
)
127 for (auto & feature
: m_aSupportedFeatures
)
129 if ( feature
.second
.xDispatcher
== _rSource
.Source
)
131 feature
.second
.xDispatcher
->removeStatusListener( static_cast< XStatusListener
* >( this ), feature
.second
.aURL
);
132 feature
.second
.xDispatcher
= nullptr;
133 feature
.second
.bCachedState
= false;
134 feature
.second
.aCachedAdditionalState
.clear();
135 --m_nConnectedFeatures
;
137 featureStateChanged( feature
.first
, false );
144 void OFormNavigationHelper::updateDispatches()
146 if ( !m_nConnectedFeatures
)
147 { // we don't have any dispatchers yet -> do the initial connect
148 connectDispatchers();
152 initializeSupportedFeatures();
154 m_nConnectedFeatures
= 0;
156 Reference
< XDispatch
> xNewDispatcher
;
157 Reference
< XDispatch
> xCurrentDispatcher
;
159 for (auto & feature
: m_aSupportedFeatures
)
161 xNewDispatcher
= queryDispatch( feature
.second
.aURL
);
162 xCurrentDispatcher
= feature
.second
.xDispatcher
;
163 if ( xNewDispatcher
!= xCurrentDispatcher
)
165 // the dispatcher for this particular URL changed
166 if ( xCurrentDispatcher
.is() )
167 xCurrentDispatcher
->removeStatusListener( static_cast< XStatusListener
* >( this ), feature
.second
.aURL
);
169 xCurrentDispatcher
= feature
.second
.xDispatcher
= xNewDispatcher
;
171 if ( xCurrentDispatcher
.is() )
172 xCurrentDispatcher
->addStatusListener( static_cast< XStatusListener
* >( this ), feature
.second
.aURL
);
175 if ( xCurrentDispatcher
.is() )
176 ++m_nConnectedFeatures
;
178 feature
.second
.bCachedState
= false;
181 // notify derivee that (potentially) all features changed their state
182 allFeatureStatesChanged( );
186 void OFormNavigationHelper::connectDispatchers()
188 if ( m_nConnectedFeatures
)
189 { // already connected -> just do an update
194 initializeSupportedFeatures();
196 m_nConnectedFeatures
= 0;
198 for (auto & feature
: m_aSupportedFeatures
)
200 feature
.second
.bCachedState
= false;
201 feature
.second
.aCachedAdditionalState
.clear();
202 feature
.second
.xDispatcher
= queryDispatch( feature
.second
.aURL
);
203 if ( feature
.second
.xDispatcher
.is() )
205 ++m_nConnectedFeatures
;
206 feature
.second
.xDispatcher
->addStatusListener( static_cast< XStatusListener
* >( this ), feature
.second
.aURL
);
210 // notify derivee that (potentially) all features changed their state
211 allFeatureStatesChanged( );
215 void OFormNavigationHelper::disconnectDispatchers()
217 if ( m_nConnectedFeatures
)
219 for (auto & feature
: m_aSupportedFeatures
)
221 if ( feature
.second
.xDispatcher
.is() )
222 feature
.second
.xDispatcher
->removeStatusListener( static_cast< XStatusListener
* >( this ), feature
.second
.aURL
);
224 feature
.second
.xDispatcher
= nullptr;
225 feature
.second
.bCachedState
= false;
226 feature
.second
.aCachedAdditionalState
.clear();
229 m_nConnectedFeatures
= 0;
232 // notify derivee that (potentially) all features changed their state
233 allFeatureStatesChanged( );
237 void OFormNavigationHelper::initializeSupportedFeatures( )
239 if ( !m_aSupportedFeatures
.empty() )
242 // ask the derivee which feature ids it wants us to support
243 ::std::vector
< sal_Int16
> aFeatureIds
;
244 getSupportedFeatures( aFeatureIds
);
246 OFormNavigationMapper
aUrlMapper( m_xORB
);
248 for (auto const& feature
: aFeatureIds
)
250 FeatureInfo aFeatureInfo
;
253 aUrlMapper
.getFeatureURL( feature
, aFeatureInfo
.aURL
);
254 DBG_ASSERT( bKnownId
, "OFormNavigationHelper::initializeSupportedFeatures: unknown feature id!" );
258 m_aSupportedFeatures
.emplace( feature
, aFeatureInfo
);
263 Reference
< XDispatch
> OFormNavigationHelper::queryDispatch( const URL
& _rURL
)
265 return m_aFeatureInterception
.queryDispatch( _rURL
);
269 void OFormNavigationHelper::dispatchWithArgument( sal_Int16 _nFeatureId
, const OUString
& _pParamAsciiName
,
270 const Any
& _rParamValue
) const
272 FeatureMap::const_iterator aInfo
= m_aSupportedFeatures
.find( _nFeatureId
);
273 if ( m_aSupportedFeatures
.end() != aInfo
)
275 if ( aInfo
->second
.xDispatcher
.is() )
277 Sequence
< PropertyValue
> aArgs
{ comphelper::makePropertyValue(
278 _pParamAsciiName
, _rParamValue
) };
280 aInfo
->second
.xDispatcher
->dispatch( aInfo
->second
.aURL
, aArgs
);
286 void OFormNavigationHelper::dispatch( sal_Int16 _nFeatureId
) const
288 FeatureMap::const_iterator aInfo
= m_aSupportedFeatures
.find( _nFeatureId
);
289 if ( m_aSupportedFeatures
.end() != aInfo
)
291 if ( aInfo
->second
.xDispatcher
.is() )
293 Sequence
< PropertyValue
> aEmptyArgs
;
294 aInfo
->second
.xDispatcher
->dispatch( aInfo
->second
.aURL
, aEmptyArgs
);
300 bool OFormNavigationHelper::isEnabled( sal_Int16 _nFeatureId
) const
302 FeatureMap::const_iterator aInfo
= m_aSupportedFeatures
.find( _nFeatureId
);
303 if ( m_aSupportedFeatures
.end() != aInfo
)
304 return aInfo
->second
.bCachedState
;
310 bool OFormNavigationHelper::getBooleanState( sal_Int16 _nFeatureId
) const
314 FeatureMap::const_iterator aInfo
= m_aSupportedFeatures
.find( _nFeatureId
);
315 if ( m_aSupportedFeatures
.end() != aInfo
)
316 aInfo
->second
.aCachedAdditionalState
>>= bState
;
322 OUString
OFormNavigationHelper::getStringState( sal_Int16 _nFeatureId
) const
326 FeatureMap::const_iterator aInfo
= m_aSupportedFeatures
.find( _nFeatureId
);
327 if ( m_aSupportedFeatures
.end() != aInfo
)
328 aInfo
->second
.aCachedAdditionalState
>>= sState
;
334 sal_Int32
OFormNavigationHelper::getIntegerState( sal_Int16 _nFeatureId
) const
336 sal_Int32 nState
= 0;
338 FeatureMap::const_iterator aInfo
= m_aSupportedFeatures
.find( _nFeatureId
);
339 if ( m_aSupportedFeatures
.end() != aInfo
)
340 aInfo
->second
.aCachedAdditionalState
>>= nState
;
346 void OFormNavigationHelper::invalidateSupportedFeaturesSet()
348 disconnectDispatchers( );
349 // no supported features anymore:
350 FeatureMap().swap(m_aSupportedFeatures
);
353 OFormNavigationMapper::OFormNavigationMapper( const Reference
< XComponentContext
>& _rxORB
)
355 m_pUrlTransformer
.reset( new UrlTransformer( _rxORB
) );
359 OFormNavigationMapper::~OFormNavigationMapper( )
364 bool OFormNavigationMapper::getFeatureURL( sal_Int16 _nFeatureId
, URL
& /* [out] */ _rURL
)
366 // get the ascii version of the URL
367 std::optional
<OUString
> pAsciiURL
= getFeatureURL( _nFeatureId
);
369 _rURL
= m_pUrlTransformer
->getStrictURL( *pAsciiURL
);
371 return pAsciiURL
.has_value();
379 const sal_Int16 nFormFeature
;
382 constexpr FeatureURL s_aFeatureURLs
[]
384 { FormFeature::MoveAbsolute
, u
".uno:FormController/positionForm"_ustr
},
385 { FormFeature::TotalRecords
, u
".uno:FormController/RecordCount"_ustr
},
386 { FormFeature::MoveToFirst
, u
".uno:FormController/moveToFirst"_ustr
},
387 { FormFeature::MoveToPrevious
, u
".uno:FormController/moveToPrev"_ustr
},
388 { FormFeature::MoveToNext
, u
".uno:FormController/moveToNext"_ustr
},
389 { FormFeature::MoveToLast
, u
".uno:FormController/moveToLast"_ustr
},
390 { FormFeature::SaveRecordChanges
, u
".uno:FormController/saveRecord"_ustr
},
391 { FormFeature::UndoRecordChanges
, u
".uno:FormController/undoRecord"_ustr
},
392 { FormFeature::MoveToInsertRow
, u
".uno:FormController/moveToNew"_ustr
},
393 { FormFeature::DeleteRecord
, u
".uno:FormController/deleteRecord"_ustr
},
394 { FormFeature::ReloadForm
, u
".uno:FormController/refreshForm"_ustr
},
395 { FormFeature::RefreshCurrentControl
, u
".uno:FormController/refreshCurrentControl"_ustr
},
396 { FormFeature::SortAscending
, u
".uno:FormController/sortUp"_ustr
},
397 { FormFeature::SortDescending
, u
".uno:FormController/sortDown"_ustr
},
398 { FormFeature::InteractiveSort
, u
".uno:FormController/sort"_ustr
},
399 { FormFeature::AutoFilter
, u
".uno:FormController/autoFilter"_ustr
},
400 { FormFeature::InteractiveFilter
, u
".uno:FormController/filter"_ustr
},
401 { FormFeature::ToggleApplyFilter
, u
".uno:FormController/applyFilter"_ustr
},
402 { FormFeature::RemoveFilterAndSort
, u
".uno:FormController/removeFilterOrder"_ustr
},
407 std::optional
<OUString
> OFormNavigationMapper::getFeatureURL( sal_Int16 _nFeatureId
)
409 for (const FeatureURL
& rFeature
: s_aFeatureURLs
)
411 if ( rFeature
.nFormFeature
== _nFeatureId
)
412 return rFeature
.aAsciiURL
;
418 sal_Int16
OFormNavigationMapper::getFeatureId( std::u16string_view _rCompleteURL
)
420 for (const FeatureURL
& rFeature
: s_aFeatureURLs
)
422 if ( rFeature
.aAsciiURL
== _rCompleteURL
)
423 return rFeature
.nFormFeature
;
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */