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_framework.hxx"
26 
27 //_________________________________________________________________________________________________________________
28 //	my own includes
29 //_________________________________________________________________________________________________________________
30 
31 #ifndef __FRAMEWORK_UICONFIGURATION_UICATEGORYDESCRPTION_HXX_
32 #include "uiconfiguration/uicategorydescription.hxx"
33 #endif
34 #include <threadhelp/resetableguard.hxx>
35 #include "services.h"
36 
37 #include "properties.h"
38 
39 //_________________________________________________________________________________________________________________
40 //	interface includes
41 //_________________________________________________________________________________________________________________
42 #include <com/sun/star/beans/PropertyValue.hpp>
43 #include <com/sun/star/beans/XPropertySet.hpp>
44 #include <com/sun/star/container/XNameAccess.hpp>
45 #include <com/sun/star/container/XNameContainer.hpp>
46 #include <com/sun/star/container/XContainer.hpp>
47 
48 //_________________________________________________________________________________________________________________
49 //	includes of other projects
50 //_________________________________________________________________________________________________________________
51 #include <rtl/ustrbuf.hxx>
52 #include <cppuhelper/implbase2.hxx>
53 #include <unotools/configmgr.hxx>
54 #include <tools/string.hxx>
55 
56 #ifndef _VCL_MNEMONIC_HXX_
57 #include <vcl/mnemonic.hxx>
58 #endif
59 #include <comphelper/sequence.hxx>
60 #include <rtl/logfile.hxx>
61 
62 //_________________________________________________________________________________________________________________
63 //	Defines
64 //_________________________________________________________________________________________________________________
65 //
66 
67 using namespace com::sun::star::uno;
68 using namespace com::sun::star::lang;
69 using namespace com::sun::star::beans;
70 using namespace com::sun::star::container;
71 using namespace ::com::sun::star::frame;
72 
73 //_________________________________________________________________________________________________________________
74 //	Namespace
75 //_________________________________________________________________________________________________________________
76 //
77 
78 struct ModuleToCategory
79 {
80     const char* pModuleId;
81     const char* pCommands;
82 };
83 
84 static const char CATEGORY[]                                = "Category";
85 static const char GENERIC_MODULE_NAME[]                     = "generic";
86 static const char CONFIGURATION_ROOT_ACCESS[]               = "/org.openoffice.Office.UI.";
87 static const char CONFIGURATION_CATEGORY_ELEMENT_ACCESS[]   = "/Commands/Categories";
88 static const char CONFIGURATION_PROPERTY_NAME[]             = "Name";
89 
90 namespace framework
91 {
92 
93 //*****************************************************************************************************************
94 //	Configuration access class for PopupMenuControllerFactory implementation
95 //*****************************************************************************************************************
96 
97 class ConfigurationAccess_UICategory : // Order is neccessary for right initialization!
98                                         private ThreadHelpBase                           ,
99                                         public  ::cppu::WeakImplHelper2<XNameAccess,XContainerListener>
100 {
101     public:
102                                   ConfigurationAccess_UICategory( const ::rtl::OUString& aModuleName, const Reference< XNameAccess >& xGenericUICommands, const Reference< XMultiServiceFactory >& rServiceManager );
103         virtual                   ~ConfigurationAccess_UICategory();
104 
105         // XNameAccess
106         virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName )
107             throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
108 
109         virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames()
110             throw (::com::sun::star::uno::RuntimeException);
111 
112         virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName )
113             throw (::com::sun::star::uno::RuntimeException);
114 
115         // XElementAccess
116         virtual ::com::sun::star::uno::Type SAL_CALL getElementType()
117             throw (::com::sun::star::uno::RuntimeException);
118 
119         virtual sal_Bool SAL_CALL hasElements()
120             throw (::com::sun::star::uno::RuntimeException);
121 
122         // container.XContainerListener
123         virtual void SAL_CALL     elementInserted( const ContainerEvent& aEvent ) throw(RuntimeException);
124         virtual void SAL_CALL     elementRemoved ( const ContainerEvent& aEvent ) throw(RuntimeException);
125         virtual void SAL_CALL     elementReplaced( const ContainerEvent& aEvent ) throw(RuntimeException);
126 
127         // lang.XEventListener
128         virtual void SAL_CALL disposing( const EventObject& aEvent ) throw(RuntimeException);
129 
130     protected:
131         Any                       getUINameFromID( const rtl::OUString& rId );
132         Any                       getUINameFromCache( const rtl::OUString& rId );
133         Sequence< rtl::OUString > getAllIds();
134         sal_Bool                  fillCache();
135 
136     private:
137         typedef ::std::hash_map< ::rtl::OUString,
138                                  ::rtl::OUString,
139                                  OUStringHashCode,
140                                  ::std::equal_to< ::rtl::OUString > > IdToInfoCache;
141 
142         sal_Bool initializeConfigAccess();
143 
144         rtl::OUString                     m_aConfigCategoryAccess;
145         rtl::OUString                     m_aPropUIName;
146         Reference< XNameAccess >          m_xGenericUICategories;
147         Reference< XMultiServiceFactory > m_xServiceManager;
148         Reference< XMultiServiceFactory > m_xConfigProvider;
149         Reference< XNameAccess >          m_xConfigAccess;
150         sal_Bool                          m_bConfigAccessInitialized;
151         sal_Bool                          m_bCacheFilled;
152         IdToInfoCache                     m_aIdCache;
153 };
154 
155 //*****************************************************************************************************************
156 //	XInterface, XTypeProvider
157 //*****************************************************************************************************************
158 
159 ConfigurationAccess_UICategory::ConfigurationAccess_UICategory( const rtl::OUString& aModuleName, const Reference< XNameAccess >& rGenericUICategories, const Reference< XMultiServiceFactory >& rServiceManager ) :
160     ThreadHelpBase(),
161     m_aConfigCategoryAccess( RTL_CONSTASCII_USTRINGPARAM( CONFIGURATION_ROOT_ACCESS )),
162     m_aPropUIName( RTL_CONSTASCII_USTRINGPARAM( CONFIGURATION_PROPERTY_NAME )),
163     m_xGenericUICategories( rGenericUICategories ),
164     m_xServiceManager( rServiceManager ),
165     m_bConfigAccessInitialized( sal_False ),
166     m_bCacheFilled( sal_False )
167 {
168     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::ConfigurationAccess_UICategory" );
169     // Create configuration hierachical access name
170     m_aConfigCategoryAccess += aModuleName;
171     m_aConfigCategoryAccess += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( CONFIGURATION_CATEGORY_ELEMENT_ACCESS ));
172 
173     m_xConfigProvider = Reference< XMultiServiceFactory >( rServiceManager->createInstance(SERVICENAME_CFGPROVIDER),UNO_QUERY );
174 }
175 
176 ConfigurationAccess_UICategory::~ConfigurationAccess_UICategory()
177 {
178     // SAFE
179     ResetableGuard aLock( m_aLock );
180     Reference< XContainer > xContainer( m_xConfigAccess, UNO_QUERY );
181     if ( xContainer.is() )
182         xContainer->removeContainerListener( this );
183 }
184 
185 // XNameAccess
186 Any SAL_CALL ConfigurationAccess_UICategory::getByName( const ::rtl::OUString& rId )
187 throw ( NoSuchElementException, WrappedTargetException, RuntimeException)
188 {
189     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::getByName" );
190     ResetableGuard aLock( m_aLock );
191     if ( !m_bConfigAccessInitialized )
192     {
193         initializeConfigAccess();
194         m_bConfigAccessInitialized = sal_True;
195         fillCache();
196     }
197 
198     // SAFE
199     Any a = getUINameFromID( rId );
200 
201     if ( !a.hasValue() )
202         throw NoSuchElementException();
203 
204     return a;
205 }
206 
207 Sequence< ::rtl::OUString > SAL_CALL ConfigurationAccess_UICategory::getElementNames()
208 throw ( RuntimeException )
209 {
210     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::getElementNames" );
211     return getAllIds();
212 }
213 
214 sal_Bool SAL_CALL ConfigurationAccess_UICategory::hasByName( const ::rtl::OUString& rId )
215 throw (::com::sun::star::uno::RuntimeException)
216 {
217     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::hasByName" );
218     return getByName( rId ).hasValue();
219 }
220 
221 // XElementAccess
222 Type SAL_CALL ConfigurationAccess_UICategory::getElementType()
223 throw ( RuntimeException )
224 {
225     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::getElementType" );
226     return( ::getCppuType( (const rtl::OUString*)NULL ) );
227 }
228 
229 sal_Bool SAL_CALL ConfigurationAccess_UICategory::hasElements()
230 throw ( RuntimeException )
231 {
232     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::hasElements" );
233     // There must be global categories!
234     return sal_True;
235 }
236 
237 sal_Bool ConfigurationAccess_UICategory::fillCache()
238 {
239     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::fillCache" );
240     RTL_LOGFILE_CONTEXT( aLog, "framework (cd100003) ::ConfigurationAccess_UICategory::fillCache" );
241 
242     if ( m_bCacheFilled )
243         return sal_True;
244 
245     sal_Int32            i( 0 );
246     rtl::OUString        aUIName;
247     Sequence< ::rtl::OUString > aNameSeq = m_xConfigAccess->getElementNames();
248 
249     for ( i = 0; i < aNameSeq.getLength(); i++ )
250     {
251         try
252         {
253             Reference< XNameAccess > xNameAccess(m_xConfigAccess->getByName( aNameSeq[i] ),UNO_QUERY);
254             if ( xNameAccess.is() )
255             {
256                 xNameAccess->getByName( m_aPropUIName ) >>= aUIName;
257 
258                 m_aIdCache.insert( IdToInfoCache::value_type( aNameSeq[i], aUIName ));
259             }
260         }
261         catch ( com::sun::star::lang::WrappedTargetException& )
262         {
263         }
264         catch ( com::sun::star::container::NoSuchElementException& )
265         {
266         }
267     }
268 
269     m_bCacheFilled = sal_True;
270 
271     return sal_True;
272 }
273 
274 Any ConfigurationAccess_UICategory::getUINameFromID( const rtl::OUString& rId )
275 {
276     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::getUINameFromID" );
277     Any a;
278 
279     try
280     {
281         a = getUINameFromCache( rId );
282         if ( !a.hasValue() )
283         {
284             // Try to ask our global commands configuration access
285             if ( m_xGenericUICategories.is() )
286             {
287                 try
288                 {
289                     return m_xGenericUICategories->getByName( rId );
290                 }
291                 catch ( com::sun::star::lang::WrappedTargetException& )
292                 {
293                 }
294                 catch ( com::sun::star::container::NoSuchElementException& )
295                 {
296                 }
297             }
298         }
299     }
300     catch( com::sun::star::container::NoSuchElementException& )
301     {
302     }
303     catch ( com::sun::star::lang::WrappedTargetException& )
304     {
305     }
306 
307     return a;
308 }
309 
310 Any ConfigurationAccess_UICategory::getUINameFromCache( const rtl::OUString& rId )
311 {
312     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::getUINameFromCache" );
313     Any a;
314 
315     IdToInfoCache::const_iterator pIter = m_aIdCache.find( rId );
316     if ( pIter != m_aIdCache.end() )
317         a <<= pIter->second;
318 
319     return a;
320 }
321 
322 Sequence< rtl::OUString > ConfigurationAccess_UICategory::getAllIds()
323 {
324     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::getAllIds" );
325     // SAFE
326     ResetableGuard aLock( m_aLock );
327 
328     if ( !m_bConfigAccessInitialized )
329     {
330         initializeConfigAccess();
331         m_bConfigAccessInitialized = sal_True;
332         fillCache();
333     }
334 
335     if ( m_xConfigAccess.is() )
336     {
337         Any                      a;
338         Reference< XNameAccess > xNameAccess;
339 
340         try
341         {
342             Sequence< ::rtl::OUString > aNameSeq = m_xConfigAccess->getElementNames();
343 
344             if ( m_xGenericUICategories.is() )
345             {
346                 // Create concat list of supported user interface commands of the module
347                 Sequence< ::rtl::OUString > aGenericNameSeq = m_xGenericUICategories->getElementNames();
348                 sal_uInt32 nCount1 = aNameSeq.getLength();
349                 sal_uInt32 nCount2 = aGenericNameSeq.getLength();
350 
351                 aNameSeq.realloc( nCount1 + nCount2 );
352                 ::rtl::OUString* pNameSeq = aNameSeq.getArray();
353                 const ::rtl::OUString* pGenericSeq = aGenericNameSeq.getConstArray();
354                 for ( sal_uInt32 i = 0; i < nCount2; i++ )
355                     pNameSeq[nCount1+i] = pGenericSeq[i];
356             }
357 
358             return aNameSeq;
359         }
360         catch( com::sun::star::container::NoSuchElementException& )
361         {
362         }
363         catch ( com::sun::star::lang::WrappedTargetException& )
364         {
365         }
366     }
367 
368     return Sequence< rtl::OUString >();
369 }
370 
371 sal_Bool ConfigurationAccess_UICategory::initializeConfigAccess()
372 {
373     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::initializeConfigAccess" );
374     Sequence< Any > aArgs( 1 );
375     PropertyValue   aPropValue;
376 
377     try
378     {
379         aPropValue.Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ));
380         aPropValue.Value <<= m_aConfigCategoryAccess;
381         aArgs[0] <<= aPropValue;
382 
383         m_xConfigAccess = Reference< XNameAccess >( m_xConfigProvider->createInstanceWithArguments(SERVICENAME_CFGREADACCESS,aArgs ),UNO_QUERY );
384         if ( m_xConfigAccess.is() )
385         {
386             // Add as container listener
387             Reference< XContainer > xContainer( m_xConfigAccess, UNO_QUERY );
388             if ( xContainer.is() )
389                 xContainer->addContainerListener( this );
390         }
391 
392         return sal_True;
393     }
394     catch ( WrappedTargetException& )
395     {
396     }
397     catch ( Exception& )
398     {
399     }
400 
401     return sal_False;
402 }
403 
404 // container.XContainerListener
405 void SAL_CALL ConfigurationAccess_UICategory::elementInserted( const ContainerEvent& ) throw(RuntimeException)
406 {
407     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::elementInserted" );
408 }
409 
410 void SAL_CALL ConfigurationAccess_UICategory::elementRemoved ( const ContainerEvent& ) throw(RuntimeException)
411 {
412     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::elementRemoved " );
413 }
414 
415 void SAL_CALL ConfigurationAccess_UICategory::elementReplaced( const ContainerEvent& ) throw(RuntimeException)
416 {
417     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::elementReplaced" );
418 }
419 
420 // lang.XEventListener
421 void SAL_CALL ConfigurationAccess_UICategory::disposing( const EventObject& aEvent ) throw(RuntimeException)
422 {
423     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "ConfigurationAccess_UICategory::disposing" );
424     // SAFE
425     // remove our reference to the config access
426     ResetableGuard aLock( m_aLock );
427 
428     Reference< XInterface > xIfac1( aEvent.Source, UNO_QUERY );
429     Reference< XInterface > xIfac2( m_xConfigAccess, UNO_QUERY );
430     if ( xIfac1 == xIfac2 )
431         m_xConfigAccess.clear();
432 }
433 
434 //*****************************************************************************************************************
435 //	XInterface, XTypeProvider, XServiceInfo
436 //*****************************************************************************************************************
437 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE  (   UICategoryDescription				    ,
438                                             ::cppu::OWeakObject						,
439                                             SERVICENAME_UICATEGORYDESCRIPTION	    ,
440 											IMPLEMENTATIONNAME_UICATEGORYDESCRIPTION
441 										)
442 
443 DEFINE_INIT_SERVICE                     (   UICategoryDescription, {} )
444 
445 UICategoryDescription::UICategoryDescription( const Reference< XMultiServiceFactory >& xServiceManager ) :
446     UICommandDescription(xServiceManager,true)
447 {
448     Reference< XNameAccess > xEmpty;
449     rtl::OUString aGenericCategories( RTL_CONSTASCII_USTRINGPARAM( "GenericCategories" ));
450     m_xGenericUICommands = new ConfigurationAccess_UICategory( aGenericCategories, xEmpty, xServiceManager );
451 
452     // insert generic categories mappings
453     m_aModuleToCommandFileMap.insert( ModuleToCommandFileMap::value_type(
454         rtl::OUString::createFromAscii( GENERIC_MODULE_NAME ), aGenericCategories ));
455 
456     UICommandsHashMap::iterator pCatIter = m_aUICommandsHashMap.find( aGenericCategories );
457     if ( pCatIter != m_aUICommandsHashMap.end() )
458         pCatIter->second = m_xGenericUICommands;
459 
460     impl_fillElements("ooSetupFactoryCmdCategoryConfigRef");
461 }
462 
463 UICategoryDescription::~UICategoryDescription()
464 {
465 }
466 Reference< XNameAccess > UICategoryDescription::impl_createConfigAccess(const ::rtl::OUString& _sName)
467 {
468     return new ConfigurationAccess_UICategory( _sName,m_xGenericUICommands,m_xServiceManager );
469 }
470 
471 } // namespace framework
472 
473