1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_forms.hxx"
26 #include "formnavigation.hxx"
27 #include "urltransformer.hxx"
28 #include "controlfeatureinterception.hxx"
29 #include "frm_strings.hxx"
30 
31 #include <com/sun/star/form/runtime/FormFeature.hpp>
32 
33 #include <tools/debug.hxx>
34 
35 
36 //.........................................................................
37 namespace frm
38 {
39 //.........................................................................
40 
41     using namespace ::com::sun::star::uno;
42     using namespace ::com::sun::star::beans;
43     using namespace ::com::sun::star::lang;
44     using namespace ::com::sun::star::util;
45     using namespace ::com::sun::star::frame;
46     namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
47 
48     //==================================================================
49     //= OFormNavigationHelper
50     //==================================================================
DBG_NAME(OFormNavigationHelper)51     DBG_NAME( OFormNavigationHelper )
52     //------------------------------------------------------------------
53     OFormNavigationHelper::OFormNavigationHelper( const Reference< XMultiServiceFactory >& _rxORB )
54         :m_xORB( _rxORB )
55         ,m_nConnectedFeatures( 0 )
56     {
57         DBG_CTOR( OFormNavigationHelper, NULL );
58         m_pFeatureInterception.reset( new ControlFeatureInterception( m_xORB ) );
59     }
60 
61     //------------------------------------------------------------------
~OFormNavigationHelper()62     OFormNavigationHelper::~OFormNavigationHelper()
63     {
64         DBG_DTOR( OFormNavigationHelper, NULL );
65     }
66 
67     //------------------------------------------------------------------
dispose()68     void SAL_CALL OFormNavigationHelper::dispose( ) throw( RuntimeException )
69     {
70         m_pFeatureInterception->dispose();
71         disconnectDispatchers();
72     }
73 
74     //------------------------------------------------------------------
interceptorsChanged()75     void OFormNavigationHelper::interceptorsChanged( )
76     {
77         updateDispatches();
78     }
79 
80     //------------------------------------------------------------------
featureStateChanged(sal_Int16,sal_Bool)81     void OFormNavigationHelper::featureStateChanged( sal_Int16 /*_nFeatureId*/, sal_Bool /*_bEnabled*/ )
82     {
83         // not interested in
84     }
85 
86     //------------------------------------------------------------------
allFeatureStatesChanged()87     void OFormNavigationHelper::allFeatureStatesChanged( )
88     {
89         // not interested in
90     }
91 
92     //------------------------------------------------------------------
registerDispatchProviderInterceptor(const Reference<XDispatchProviderInterceptor> & _rxInterceptor)93     void SAL_CALL OFormNavigationHelper::registerDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) throw (RuntimeException)
94     {
95         m_pFeatureInterception->registerDispatchProviderInterceptor( _rxInterceptor );
96         interceptorsChanged();
97     }
98 
99     //------------------------------------------------------------------
releaseDispatchProviderInterceptor(const Reference<XDispatchProviderInterceptor> & _rxInterceptor)100     void SAL_CALL OFormNavigationHelper::releaseDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) throw (RuntimeException)
101     {
102         m_pFeatureInterception->releaseDispatchProviderInterceptor( _rxInterceptor );
103         interceptorsChanged();
104     }
105 
106     //------------------------------------------------------------------
statusChanged(const FeatureStateEvent & _rState)107     void SAL_CALL OFormNavigationHelper::statusChanged( const FeatureStateEvent& _rState ) throw (RuntimeException)
108     {
109         for (   FeatureMap::iterator aFeature = m_aSupportedFeatures.begin();
110                 aFeature != m_aSupportedFeatures.end();
111                 ++aFeature
112             )
113         {
114             if ( aFeature->second.aURL.Main == _rState.FeatureURL.Main )
115             {
116                 if  (  ( aFeature->second.bCachedState != _rState.IsEnabled )
117                     || ( aFeature->second.aCachedAdditionalState != _rState.State )
118                     )
119                 {
120                     // change the cached state
121                     aFeature->second.bCachedState           = _rState.IsEnabled;
122                     aFeature->second.aCachedAdditionalState = _rState.State;
123                     // tell derivees what happened
124                     featureStateChanged( aFeature->first, _rState.IsEnabled );
125                 }
126                 return;
127             }
128         }
129 
130         // unreachable
131         DBG_ERROR( "OFormNavigationHelper::statusChanged: huh? An invalid/unknown URL?" );
132     }
133 
134     //------------------------------------------------------------------
disposing(const EventObject & _rSource)135     void SAL_CALL OFormNavigationHelper::disposing( const EventObject& _rSource ) throw (RuntimeException)
136     {
137         // was it one of our external dispatchers?
138 	    if ( m_nConnectedFeatures )
139 	    {
140             for (   FeatureMap::iterator aFeature = m_aSupportedFeatures.begin();
141                     aFeature != m_aSupportedFeatures.end();
142                     ++aFeature
143                 )
144 		    {
145 			    if ( aFeature->second.xDispatcher == _rSource.Source )
146 			    {
147 				    aFeature->second.xDispatcher->removeStatusListener( static_cast< XStatusListener* >( this ), aFeature->second.aURL );
148 				    aFeature->second.xDispatcher = NULL;
149                     aFeature->second.bCachedState = sal_False;
150                     aFeature->second.aCachedAdditionalState.clear();
151                     --m_nConnectedFeatures;
152 
153                     featureStateChanged( aFeature->first, sal_False );
154                     break;
155 			    }
156 		    }
157 	    }
158     }
159 
160     //------------------------------------------------------------------
updateDispatches()161     void OFormNavigationHelper::updateDispatches()
162     {
163 	    if ( !m_nConnectedFeatures )
164 	    {	// we don't have any dispatchers yet -> do the initial connect
165 		    connectDispatchers();
166 		    return;
167 	    }
168 
169         initializeSupportedFeatures();
170 
171 	    m_nConnectedFeatures = 0;
172 
173         Reference< XDispatch >  xNewDispatcher;
174         Reference< XDispatch >  xCurrentDispatcher;
175 
176         for (   FeatureMap::iterator aFeature = m_aSupportedFeatures.begin();
177                 aFeature != m_aSupportedFeatures.end();
178                 ++aFeature
179             )
180 	    {
181             xNewDispatcher = queryDispatch( aFeature->second.aURL );
182             xCurrentDispatcher = aFeature->second.xDispatcher;
183 		    if ( xNewDispatcher != xCurrentDispatcher )
184 		    {
185                 // the dispatcher for this particular URL changed
186 			    if ( xCurrentDispatcher.is() )
187 				    xCurrentDispatcher->removeStatusListener( static_cast< XStatusListener* >( this ), aFeature->second.aURL );
188 
189                 xCurrentDispatcher = aFeature->second.xDispatcher = xNewDispatcher;
190 
191                 if ( xCurrentDispatcher.is() )
192 				    xCurrentDispatcher->addStatusListener( static_cast< XStatusListener* >( this ), aFeature->second.aURL );
193 		    }
194 
195             if ( xCurrentDispatcher.is() )
196 			    ++m_nConnectedFeatures;
197             else
198                 aFeature->second.bCachedState = sal_False;
199 	    }
200 
201         // notify derivee that (potentially) all features changed their state
202         allFeatureStatesChanged( );
203     }
204 
205     //------------------------------------------------------------------
connectDispatchers()206     void OFormNavigationHelper::connectDispatchers()
207     {
208         if ( m_nConnectedFeatures )
209 	    {	// already connected -> just do an update
210 		    updateDispatches();
211 		    return;
212 	    }
213 
214         initializeSupportedFeatures();
215 
216 	    m_nConnectedFeatures = 0;
217 
218         for (   FeatureMap::iterator aFeature = m_aSupportedFeatures.begin();
219                 aFeature != m_aSupportedFeatures.end();
220                 ++aFeature
221             )
222 	    {
223             aFeature->second.bCachedState = sal_False;
224             aFeature->second.aCachedAdditionalState.clear();
225             aFeature->second.xDispatcher = queryDispatch( aFeature->second.aURL );
226 		    if ( aFeature->second.xDispatcher.is() )
227 		    {
228 			    ++m_nConnectedFeatures;
229 			    aFeature->second.xDispatcher->addStatusListener( static_cast< XStatusListener* >( this ), aFeature->second.aURL );
230 		    }
231 	    }
232 
233         // notify derivee that (potentially) all features changed their state
234         allFeatureStatesChanged( );
235     }
236 
237     //------------------------------------------------------------------
disconnectDispatchers()238     void OFormNavigationHelper::disconnectDispatchers()
239     {
240 	    if ( m_nConnectedFeatures )
241         {
242             for (   FeatureMap::iterator aFeature = m_aSupportedFeatures.begin();
243                     aFeature != m_aSupportedFeatures.end();
244                     ++aFeature
245                 )
246 	        {
247 		        if ( aFeature->second.xDispatcher.is() )
248 			        aFeature->second.xDispatcher->removeStatusListener( static_cast< XStatusListener* >( this ), aFeature->second.aURL );
249 
250                 aFeature->second.xDispatcher = NULL;
251                 aFeature->second.bCachedState = sal_False;
252                 aFeature->second.aCachedAdditionalState.clear();
253 	        }
254 
255             m_nConnectedFeatures = 0;
256         }
257 
258         // notify derivee that (potentially) all features changed their state
259         allFeatureStatesChanged( );
260     }
261 
262     //------------------------------------------------------------------
initializeSupportedFeatures()263     void OFormNavigationHelper::initializeSupportedFeatures( )
264     {
265         if ( m_aSupportedFeatures.empty() )
266         {
267             // ask the derivee which feature ids it wants us to support
268             ::std::vector< sal_Int16 > aFeatureIds;
269             getSupportedFeatures( aFeatureIds );
270 
271             OFormNavigationMapper aUrlMapper( m_xORB );
272 
273             for (   ::std::vector< sal_Int16 >::const_iterator aLoop = aFeatureIds.begin();
274                     aLoop != aFeatureIds.end();
275                     ++aLoop
276                 )
277             {
278                 FeatureInfo aFeatureInfo;
279 
280                 bool bKnownId =
281                     aUrlMapper.getFeatureURL( *aLoop, aFeatureInfo.aURL );
282                 DBG_ASSERT( bKnownId, "OFormNavigationHelper::initializeSupportedFeatures: unknown feature id!" );
283 
284                 if ( bKnownId )
285                     // add to our map
286                     m_aSupportedFeatures.insert( FeatureMap::value_type( *aLoop, aFeatureInfo ) );
287             }
288         }
289     }
290 
291     //------------------------------------------------------------------
queryDispatch(const URL & _rURL)292     Reference< XDispatch > OFormNavigationHelper::queryDispatch( const URL& _rURL )
293     {
294         return m_pFeatureInterception->queryDispatch( _rURL );
295     }
296 
297     //------------------------------------------------------------------
dispatchWithArgument(sal_Int16 _nFeatureId,const sal_Char * _pParamAsciiName,const Any & _rParamValue) const298     void OFormNavigationHelper::dispatchWithArgument( sal_Int16 _nFeatureId, const sal_Char* _pParamAsciiName,
299         const Any& _rParamValue ) const
300     {
301         FeatureMap::const_iterator aInfo = m_aSupportedFeatures.find( _nFeatureId );
302         if ( m_aSupportedFeatures.end() != aInfo )
303         {
304             if ( aInfo->second.xDispatcher.is() )
305             {
306                 Sequence< PropertyValue > aArgs( 1 );
307                 aArgs[0].Name = ::rtl::OUString::createFromAscii( _pParamAsciiName );
308                 aArgs[0].Value = _rParamValue;
309 
310                 aInfo->second.xDispatcher->dispatch( aInfo->second.aURL, aArgs );
311             }
312         }
313     }
314 
315     //------------------------------------------------------------------
dispatch(sal_Int16 _nFeatureId) const316     void OFormNavigationHelper::dispatch( sal_Int16 _nFeatureId ) const
317     {
318         FeatureMap::const_iterator aInfo = m_aSupportedFeatures.find( _nFeatureId );
319         if ( m_aSupportedFeatures.end() != aInfo )
320         {
321             if ( aInfo->second.xDispatcher.is() )
322             {
323                 Sequence< PropertyValue > aEmptyArgs;
324                 aInfo->second.xDispatcher->dispatch( aInfo->second.aURL, aEmptyArgs );
325             }
326         }
327     }
328 
329     //------------------------------------------------------------------
isEnabled(sal_Int16 _nFeatureId) const330     bool OFormNavigationHelper::isEnabled( sal_Int16 _nFeatureId ) const
331     {
332         FeatureMap::const_iterator aInfo = m_aSupportedFeatures.find( _nFeatureId );
333         if ( m_aSupportedFeatures.end() != aInfo )
334             return aInfo->second.bCachedState;
335 
336         return false;
337     }
338 
339     //------------------------------------------------------------------
getBooleanState(sal_Int16 _nFeatureId) const340     bool OFormNavigationHelper::getBooleanState( sal_Int16 _nFeatureId ) const
341     {
342         sal_Bool bState = sal_False;
343 
344         FeatureMap::const_iterator aInfo = m_aSupportedFeatures.find( _nFeatureId );
345         if ( m_aSupportedFeatures.end() != aInfo )
346             aInfo->second.aCachedAdditionalState >>= bState;
347 
348         return (bool)bState;
349     }
350 
351     //------------------------------------------------------------------
getStringState(sal_Int16 _nFeatureId) const352     ::rtl::OUString OFormNavigationHelper::getStringState( sal_Int16 _nFeatureId ) const
353     {
354         ::rtl::OUString sState;
355 
356         FeatureMap::const_iterator aInfo = m_aSupportedFeatures.find( _nFeatureId );
357         if ( m_aSupportedFeatures.end() != aInfo )
358             aInfo->second.aCachedAdditionalState >>= sState;
359 
360         return sState;
361     }
362 
363     //------------------------------------------------------------------
getIntegerState(sal_Int16 _nFeatureId) const364     sal_Int32 OFormNavigationHelper::getIntegerState( sal_Int16 _nFeatureId ) const
365     {
366         sal_Int32 nState = 0;
367 
368         FeatureMap::const_iterator aInfo = m_aSupportedFeatures.find( _nFeatureId );
369         if ( m_aSupportedFeatures.end() != aInfo )
370             aInfo->second.aCachedAdditionalState >>= nState;
371 
372         return nState;
373     }
374 
375     //------------------------------------------------------------------
invalidateSupportedFeaturesSet()376     void OFormNavigationHelper::invalidateSupportedFeaturesSet()
377     {
378         disconnectDispatchers( );
379         // no supported features anymore:
380         FeatureMap aEmpty;
381         m_aSupportedFeatures.swap( aEmpty );
382     }
383 
384     //==================================================================
385     //= OFormNavigationMapper
386     //==================================================================
387     //------------------------------------------------------------------
OFormNavigationMapper(const Reference<XMultiServiceFactory> & _rxORB)388     OFormNavigationMapper::OFormNavigationMapper( const Reference< XMultiServiceFactory >& _rxORB )
389     {
390         m_pUrlTransformer.reset( new UrlTransformer( _rxORB ) );
391     }
392 
393     //------------------------------------------------------------------
~OFormNavigationMapper()394     OFormNavigationMapper::~OFormNavigationMapper( )
395     {
396     }
397 
398     //------------------------------------------------------------------
getFeatureURL(sal_Int16 _nFeatureId,URL & _rURL)399     bool OFormNavigationMapper::getFeatureURL( sal_Int16 _nFeatureId, URL& /* [out] */ _rURL )
400     {
401         // get the ascii version of the URL
402         const char* pAsciiURL = getFeatureURLAscii( _nFeatureId );
403         if ( pAsciiURL )
404             _rURL = m_pUrlTransformer->getStrictURLFromAscii( pAsciiURL );
405 
406         return ( pAsciiURL != NULL );
407     }
408 
409     //------------------------------------------------------------------
410     namespace
411     {
412         struct FeatureURL
413         {
414             const sal_Int16 nFormFeature;
415             const sal_Char* pAsciiURL;
416 
FeatureURLfrm::__anon7c8d5a890111::FeatureURL417             FeatureURL( const sal_Int16 _nFormFeature, const sal_Char* _pAsciiURL )
418                 :nFormFeature( _nFormFeature )
419                 ,pAsciiURL( _pAsciiURL )
420             {
421             }
422         };
lcl_getFeatureTable()423         const FeatureURL* lcl_getFeatureTable()
424         {
425             static const FeatureURL s_aFeatureURLs[] =
426             {
427                 FeatureURL( FormFeature::MoveAbsolute,            URL_FORM_POSITION ),
428                 FeatureURL( FormFeature::TotalRecords,            URL_FORM_RECORDCOUNT ),
429                 FeatureURL( FormFeature::MoveToFirst,             URL_RECORD_FIRST ),
430                 FeatureURL( FormFeature::MoveToPrevious,          URL_RECORD_PREV ),
431                 FeatureURL( FormFeature::MoveToNext,              URL_RECORD_NEXT ),
432                 FeatureURL( FormFeature::MoveToLast,              URL_RECORD_LAST ),
433                 FeatureURL( FormFeature::SaveRecordChanges,       URL_RECORD_SAVE ),
434                 FeatureURL( FormFeature::UndoRecordChanges,       URL_RECORD_UNDO ),
435                 FeatureURL( FormFeature::MoveToInsertRow,         URL_RECORD_NEW ),
436                 FeatureURL( FormFeature::DeleteRecord,            URL_RECORD_DELETE ),
437                 FeatureURL( FormFeature::ReloadForm,              URL_FORM_REFRESH ),
438                 FeatureURL( FormFeature::RefreshCurrentControl,   URL_FORM_REFRESH_CURRENT_CONTROL ),
439                 FeatureURL( FormFeature::SortAscending,           URL_FORM_SORT_UP ),
440                 FeatureURL( FormFeature::SortDescending,          URL_FORM_SORT_DOWN ),
441                 FeatureURL( FormFeature::InteractiveSort,         URL_FORM_SORT ),
442                 FeatureURL( FormFeature::AutoFilter,              URL_FORM_AUTO_FILTER ),
443                 FeatureURL( FormFeature::InteractiveFilter,       URL_FORM_FILTER ),
444                 FeatureURL( FormFeature::ToggleApplyFilter,       URL_FORM_APPLY_FILTER ),
445                 FeatureURL( FormFeature::RemoveFilterAndSort,     URL_FORM_REMOVE_FILTER ),
446                 FeatureURL( 0, NULL )
447             };
448             return s_aFeatureURLs;
449         }
450     }
451 
452     //------------------------------------------------------------------
getFeatureURLAscii(sal_Int16 _nFeatureId)453     const char* OFormNavigationMapper::getFeatureURLAscii( sal_Int16 _nFeatureId )
454     {
455         const FeatureURL* pFeatures = lcl_getFeatureTable();
456         while ( pFeatures->pAsciiURL )
457         {
458             if ( pFeatures->nFormFeature == _nFeatureId )
459                 return pFeatures->pAsciiURL;
460             ++pFeatures;
461         }
462         return NULL;
463     }
464 
465     //------------------------------------------------------------------
getFeatureId(const::rtl::OUString & _rCompleteURL)466     sal_Int16 OFormNavigationMapper::getFeatureId( const ::rtl::OUString& _rCompleteURL )
467     {
468         const FeatureURL* pFeatures = lcl_getFeatureTable();
469         while ( pFeatures->pAsciiURL )
470         {
471             if ( _rCompleteURL.compareToAscii( pFeatures->pAsciiURL ) == 0 )
472                 return pFeatures->nFormFeature;
473             ++pFeatures;
474         }
475         return -1;
476     }
477 
478 //.........................................................................
479 }   // namespace frm
480 //.........................................................................
481