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