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