xref: /trunk/main/unotools/source/config/cmdoptions.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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_unotools.hxx"
30 
31 //_________________________________________________________________________________________________________________
32 //  includes
33 //_________________________________________________________________________________________________________________
34 
35 #include <unotools/cmdoptions.hxx>
36 #include <unotools/configmgr.hxx>
37 #include <unotools/configitem.hxx>
38 #include <tools/debug.hxx>
39 #include <com/sun/star/uno/Any.hxx>
40 #include <com/sun/star/uno/Sequence.hxx>
41 #include <cppuhelper/weakref.hxx>
42 #include <tools/urlobj.hxx>
43 #include <rtl/ustrbuf.hxx>
44 
45 #include <itemholder1.hxx>
46 
47 #include <algorithm>
48 #include <hash_map>
49 
50 //_________________________________________________________________________________________________________________
51 //  namespaces
52 //_________________________________________________________________________________________________________________
53 
54 using namespace ::std                   ;
55 using namespace ::utl                   ;
56 using namespace ::rtl                   ;
57 using namespace ::osl                   ;
58 using namespace ::com::sun::star::uno   ;
59 using namespace ::com::sun::star::beans ;
60 
61 //_________________________________________________________________________________________________________________
62 //  const
63 //_________________________________________________________________________________________________________________
64 
65 #define ROOTNODE_CMDOPTIONS                             OUString(RTL_CONSTASCII_USTRINGPARAM("Office.Commands/Execute"  ))
66 #define PATHDELIMITER                                   OUString(RTL_CONSTASCII_USTRINGPARAM("/"                        ))
67 
68 #define SETNODE_DISABLED                                OUString(RTL_CONSTASCII_USTRINGPARAM("Disabled"                 ))
69 
70 #define PROPERTYNAME_CMD                                OUString(RTL_CONSTASCII_USTRINGPARAM("Command"                  ))
71 
72 #define PROPERTYCOUNT                                   1
73 
74 #define OFFSET_CMD                                      0
75 
76 //_________________________________________________________________________________________________________________
77 //  private declarations!
78 //_________________________________________________________________________________________________________________
79 
80 // Method to retrieve a hash code from a string. May be we have to change it to decrease collisions in the hash map
81 struct OUStringHashCode
82 {
83     size_t operator()( const ::rtl::OUString& sString ) const
84     {
85         return sString.hashCode();
86     }
87 };
88 
89 /*-****************************************************************************************************************
90     @descr  support simple command option structures and operations on it
91 ****************************************************************************************************************-*/
92 class SvtCmdOptions
93 {
94     public:
95         //---------------------------------------------------------------------------------------------------------
96         // the only way to free memory!
97         void Clear()
98         {
99             m_aCommandHashMap.clear();
100         }
101 
102         sal_Bool HasEntries() const
103         {
104             return ( m_aCommandHashMap.size() > 0 );
105         }
106 
107         void SetContainerSize( sal_Int32 nSize )
108         {
109             m_aCommandHashMap.resize( nSize );
110         }
111 
112         sal_Bool Lookup( const OUString& aCmd ) const
113         {
114             CommandHashMap::const_iterator pEntry = m_aCommandHashMap.find( aCmd );
115             return ( pEntry != m_aCommandHashMap.end() );
116         }
117 
118         void AddCommand( const OUString& aCmd )
119         {
120             m_aCommandHashMap.insert( CommandHashMap::value_type( aCmd, 0 ) );
121         }
122 
123         //---------------------------------------------------------------------------------------------------------
124         // convert internal list to external format
125         // for using it on right menus realy
126         // Notice:   We build a property list with 4 entries and set it on result list then.
127         //           The while-loop starts with pointer on internal member list lSetupEntries, change to
128         //           lUserEntries then and stop after that with NULL!
129         //           Separator entries will be packed in another way then normal entries! We define
130         //           special strings "sEmpty" and "sSeperator" to perform too ...
131         Sequence< OUString > GetList() const
132         {
133             sal_Int32               nCount = (sal_Int32)m_aCommandHashMap.size();
134             sal_Int32               nIndex = 0;
135             Sequence< OUString >    aList( nCount );
136 
137             CommandHashMap::const_iterator pEntry = m_aCommandHashMap.begin();
138             while ( pEntry != m_aCommandHashMap.end() )
139                 aList[nIndex++] = pEntry->first;
140 
141             return aList;
142         }
143 
144     private:
145         class CommandHashMap : public ::std::hash_map< ::rtl::OUString      ,
146                                                         sal_Int32           ,
147                                                         OUStringHashCode    ,
148                                                         ::std::equal_to< ::rtl::OUString >  >
149         {
150             public:
151                 inline void free()
152                 {
153                     CommandHashMap().swap( *this );
154                 }
155         };
156 
157         CommandHashMap m_aCommandHashMap;
158 };
159 
160 typedef ::std::vector< ::com::sun::star::uno::WeakReference< ::com::sun::star::frame::XFrame > > SvtFrameVector;
161 
162 class SvtCommandOptions_Impl : public ConfigItem
163 {
164     //-------------------------------------------------------------------------------------------------------------
165     //  public methods
166     //-------------------------------------------------------------------------------------------------------------
167 
168     public:
169 
170         //---------------------------------------------------------------------------------------------------------
171         //  constructor / destructor
172         //---------------------------------------------------------------------------------------------------------
173 
174          SvtCommandOptions_Impl();
175         ~SvtCommandOptions_Impl();
176 
177         //---------------------------------------------------------------------------------------------------------
178         //  overloaded methods of baseclass
179         //---------------------------------------------------------------------------------------------------------
180 
181         /*-****************************************************************************************************//**
182             @short      called for notify of configmanager
183             @descr      These method is called from the ConfigManager before application ends or from the
184                         PropertyChangeListener if the sub tree broadcasts changes. You must update your
185                         internal values.
186 
187             @seealso    baseclass ConfigItem
188 
189             @param      "lPropertyNames" is the list of properties which should be updated.
190             @return     -
191 
192             @onerror    -
193         *//*-*****************************************************************************************************/
194 
195         virtual void Notify( const Sequence< OUString >& lPropertyNames );
196 
197         /*-****************************************************************************************************//**
198             @short      write changes to configuration
199             @descr      These method writes the changed values into the sub tree
200                         and should always called in our destructor to guarantee consistency of config data.
201 
202             @seealso    baseclass ConfigItem
203 
204             @param      -
205             @return     -
206 
207             @onerror    -
208         *//*-*****************************************************************************************************/
209 
210         virtual void Commit();
211 
212         //---------------------------------------------------------------------------------------------------------
213         //  public interface
214         //---------------------------------------------------------------------------------------------------------
215 
216         /*-****************************************************************************************************//**
217             @short      base implementation of public interface for "SvtDynamicMenuOptions"!
218             @descr      These class is used as static member of "SvtDynamicMenuOptions" ...
219                         => The code exist only for one time and isn't duplicated for every instance!
220 
221             @seealso    -
222 
223             @param      -
224             @return     -
225 
226             @onerror    -
227         *//*-*****************************************************************************************************/
228 
229         void                    Clear       (   SvtCommandOptions::CmdOption    eCmdOption  );
230         sal_Bool                HasEntries  (   SvtCommandOptions::CmdOption    eOption     ) const;
231         sal_Bool                Lookup      (   SvtCommandOptions::CmdOption    eCmdOption, const OUString& ) const;
232         Sequence< OUString >    GetList     (   SvtCommandOptions::CmdOption    eCmdOption  ) const ;
233         void                    AddCommand  (   SvtCommandOptions::CmdOption    eCmdOption,
234                                                 const OUString& sURL        );
235         void EstablisFrameCallback(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame);
236 
237     //-------------------------------------------------------------------------------------------------------------
238     //  private methods
239     //-------------------------------------------------------------------------------------------------------------
240 
241     private:
242 
243         /*-****************************************************************************************************//**
244             @short      return list of key names of our configuration management which represent oue module tree
245             @descr      These methods return the current list of key names! We need it to get needed values from our
246                         configuration management and support dynamical menu item lists!
247 
248             @seealso    -
249 
250             @param      "nDisabledCount"    ,   returns count of menu entries for "new"
251             @return     A list of configuration key names is returned.
252 
253             @onerror    -
254         *//*-*****************************************************************************************************/
255 
256         Sequence< OUString > impl_GetPropertyNames();
257 
258     //-------------------------------------------------------------------------------------------------------------
259     //  private member
260     //-------------------------------------------------------------------------------------------------------------
261 
262     private:
263         SvtCmdOptions  m_aDisabledCommands;
264         SvtFrameVector m_lFrames;
265 };
266 
267 //_________________________________________________________________________________________________________________
268 //  definitions
269 //_________________________________________________________________________________________________________________
270 
271 //*****************************************************************************************************************
272 //  constructor
273 //*****************************************************************************************************************
274 SvtCommandOptions_Impl::SvtCommandOptions_Impl()
275     // Init baseclasses first
276     :   ConfigItem( ROOTNODE_CMDOPTIONS )
277     // Init member then...
278 {
279     // Get names and values of all accessable menu entries and fill internal structures.
280     // See impl_GetPropertyNames() for further informations.
281     Sequence< OUString >    lNames              = impl_GetPropertyNames ();
282     Sequence< Any >         lValues             = GetProperties         ( lNames         );
283 
284     // Safe impossible cases.
285     // We need values from ALL configuration keys.
286     // Follow assignment use order of values in relation to our list of key names!
287     DBG_ASSERT( !(lNames.getLength()!=lValues.getLength()), "SvtCommandOptions_Impl::SvtCommandOptions_Impl()\nI miss some values of configuration keys!\n" );
288 
289     // Copy values from list in right order to ouer internal member.
290     // Attention: List for names and values have an internal construction pattern!
291     sal_Int32   nItem     = 0 ;
292     OUString    sCmd          ;
293 
294     // Set size of hash_map reach a used size of approx. 60%
295     m_aDisabledCommands.SetContainerSize( lNames.getLength() * 10 / 6 );
296 
297     // Get names/values for disabled commands.
298     for( nItem=0; nItem < lNames.getLength(); ++nItem )
299     {
300         // Currently only one value
301         lValues[nItem] >>= sCmd;
302         m_aDisabledCommands.AddCommand( sCmd );
303     }
304 
305 /*TODO: Not used in the moment! see Notify() ...
306     // Enable notification mechanism of ouer baseclass.
307     // We need it to get information about changes outside these class on ouer used configuration keys! */
308     Sequence< OUString > aNotifySeq( 1 );
309     aNotifySeq[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "Disabled" ));
310     EnableNotification( aNotifySeq, sal_True );
311 }
312 
313 //*****************************************************************************************************************
314 //  destructor
315 //*****************************************************************************************************************
316 SvtCommandOptions_Impl::~SvtCommandOptions_Impl()
317 {
318     // We must save our current values .. if user forget it!
319     if( IsModified() == sal_True )
320     {
321         Commit();
322     }
323 }
324 
325 //*****************************************************************************************************************
326 //  public method
327 //*****************************************************************************************************************
328 void SvtCommandOptions_Impl::Notify( const Sequence< OUString >& )
329 {
330     MutexGuard aGuard( SvtCommandOptions::GetOwnStaticMutex() );
331 
332     Sequence< OUString >    lNames   = impl_GetPropertyNames ();
333     Sequence< Any >         lValues  = GetProperties         ( lNames         );
334 
335     // Safe impossible cases.
336     // We need values from ALL configuration keys.
337     // Follow assignment use order of values in relation to our list of key names!
338     DBG_ASSERT( !(lNames.getLength()!=lValues.getLength()), "SvtCommandOptions_Impl::SvtCommandOptions_Impl()\nI miss some values of configuration keys!\n" );
339 
340     // Copy values from list in right order to ouer internal member.
341     // Attention: List for names and values have an internal construction pattern!
342     sal_Int32   nItem     = 0 ;
343     OUString    sCmd          ;
344 
345     // Set size of hash_map reach a used size of approx. 60%
346     m_aDisabledCommands.Clear();
347     m_aDisabledCommands.SetContainerSize( lNames.getLength() * 10 / 6 );
348 
349     // Get names/values for disabled commands.
350     for( nItem=0; nItem < lNames.getLength(); ++nItem )
351     {
352         // Currently only one value
353         lValues[nItem] >>= sCmd;
354         m_aDisabledCommands.AddCommand( sCmd );
355     }
356 
357     // dont forget to update all existing frames and her might cached dispatch objects!
358     // But look for already killed frames. We hold weak references instead of hard ones ...
359     for (SvtFrameVector::const_iterator pIt  = m_lFrames.begin();
360                                         pIt != m_lFrames.end()  ;
361                                       ++pIt                     )
362     {
363         ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame(pIt->get(), ::com::sun::star::uno::UNO_QUERY);
364         if (xFrame.is())
365             xFrame->contextChanged();
366     }
367 }
368 
369 //*****************************************************************************************************************
370 //  public method
371 //*****************************************************************************************************************
372 void SvtCommandOptions_Impl::Commit()
373 {
374     DBG_ERROR( "SvtCommandOptions_Impl::Commit()\nNot implemented yet!\n" );
375 }
376 
377 //*****************************************************************************************************************
378 //  public method
379 //*****************************************************************************************************************
380 void SvtCommandOptions_Impl::Clear( SvtCommandOptions::CmdOption eCmdOption )
381 {
382     switch( eCmdOption )
383     {
384         case SvtCommandOptions::CMDOPTION_DISABLED:
385         {
386             m_aDisabledCommands.Clear();
387             SetModified();
388         }
389         break;
390 
391         default:
392             DBG_ASSERT( sal_False, "SvtCommandOptions_Impl::Clear()\nUnknown option type given!\n" );
393     }
394 }
395 
396 //*****************************************************************************************************************
397 //  public method
398 //*****************************************************************************************************************
399 sal_Bool SvtCommandOptions_Impl::HasEntries( SvtCommandOptions::CmdOption eOption ) const
400 {
401     if ( eOption == SvtCommandOptions::CMDOPTION_DISABLED )
402         return ( m_aDisabledCommands.HasEntries() > 0 );
403     else
404         return sal_False;
405 }
406 
407 //*****************************************************************************************************************
408 //  public method
409 //*****************************************************************************************************************
410 Sequence< OUString > SvtCommandOptions_Impl::GetList( SvtCommandOptions::CmdOption eCmdOption ) const
411 {
412     Sequence< OUString > lReturn;
413 
414     switch( eCmdOption )
415     {
416         case SvtCommandOptions::CMDOPTION_DISABLED:
417         {
418             lReturn = m_aDisabledCommands.GetList();
419         }
420         break;
421 
422         default:
423             DBG_ASSERT( sal_False, "SvtCommandOptions_Impl::GetList()\nUnknown option type given!\n" );
424     }
425 
426     return lReturn;
427 }
428 
429 //*****************************************************************************************************************
430 //  public method
431 //*****************************************************************************************************************
432 sal_Bool SvtCommandOptions_Impl::Lookup( SvtCommandOptions::CmdOption eCmdOption, const OUString& aCommand ) const
433 {
434     switch( eCmdOption )
435     {
436         case SvtCommandOptions::CMDOPTION_DISABLED:
437         {
438             return m_aDisabledCommands.Lookup( aCommand );
439         }
440         default:
441             DBG_ASSERT( sal_False, "SvtCommandOptions_Impl::GetList()\nUnknown option type given!\n" );
442     }
443 
444     return sal_False;
445 }
446 
447 //*****************************************************************************************************************
448 //  public method
449 //*****************************************************************************************************************
450 void SvtCommandOptions_Impl::AddCommand( SvtCommandOptions::CmdOption eCmdOption, const OUString& sCmd )
451 {
452     switch( eCmdOption )
453     {
454         case SvtCommandOptions::CMDOPTION_DISABLED:
455         {
456             m_aDisabledCommands.AddCommand( sCmd );
457             SetModified();
458         }
459         break;
460 
461         default:
462             DBG_ASSERT( sal_False, "SvtCommandOptions_Impl::GetList()\nUnknown option type given!\n" );
463     }
464 }
465 
466 //*****************************************************************************************************************
467 //  public method
468 //*****************************************************************************************************************
469 void SvtCommandOptions_Impl::EstablisFrameCallback(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame)
470 {
471     // check if frame already exists inside list
472     // ignore double registrations
473     // every frame must be notified one times only!
474     ::com::sun::star::uno::WeakReference< ::com::sun::star::frame::XFrame > xWeak(xFrame);
475     SvtFrameVector::const_iterator pIt = ::std::find(m_lFrames.begin(), m_lFrames.end(), xWeak);
476     if (pIt == m_lFrames.end())
477         m_lFrames.push_back(xWeak);
478 }
479 
480 //*****************************************************************************************************************
481 //  private method
482 //*****************************************************************************************************************
483 Sequence< OUString > SvtCommandOptions_Impl::impl_GetPropertyNames()
484 {
485     // First get ALL names of current existing list items in configuration!
486     Sequence< OUString > lDisabledItems      = GetNodeNames( SETNODE_DISABLED, utl::CONFIG_NAME_LOCAL_PATH );
487 
488     OUString aSetNode( SETNODE_DISABLED );
489     aSetNode += PATHDELIMITER;
490 
491     OUString aCommandKey( PATHDELIMITER );
492     aCommandKey += PROPERTYNAME_CMD;
493 
494     // Expand all keys
495     for (sal_Int32 i=0; i<lDisabledItems.getLength(); ++i )
496     {
497         OUStringBuffer aBuffer( 32 );
498         aBuffer.append( aSetNode );
499         aBuffer.append( lDisabledItems[i] );
500         aBuffer.append( aCommandKey );
501         lDisabledItems[i] = aBuffer.makeStringAndClear();
502     }
503 
504     // Return result.
505     return lDisabledItems;
506 }
507 
508 //*****************************************************************************************************************
509 //  initialize static member
510 //  DON'T DO IT IN YOUR HEADER!
511 //  see definition for further informations
512 //*****************************************************************************************************************
513 SvtCommandOptions_Impl*     SvtCommandOptions::m_pDataContainer = NULL  ;
514 sal_Int32                   SvtCommandOptions::m_nRefCount      = 0     ;
515 
516 //*****************************************************************************************************************
517 //  constructor
518 //*****************************************************************************************************************
519 SvtCommandOptions::SvtCommandOptions()
520 {
521     // Global access, must be guarded (multithreading!).
522     MutexGuard aGuard( GetOwnStaticMutex() );
523     // Increase ouer refcount ...
524     ++m_nRefCount;
525     // ... and initialize ouer data container only if it not already exist!
526     if( m_pDataContainer == NULL )
527     {
528         m_pDataContainer = new SvtCommandOptions_Impl;
529         ItemHolder1::holdConfigItem(E_CMDOPTIONS);
530     }
531 }
532 
533 //*****************************************************************************************************************
534 //  destructor
535 //*****************************************************************************************************************
536 SvtCommandOptions::~SvtCommandOptions()
537 {
538     // Global access, must be guarded (multithreading!)
539     MutexGuard aGuard( GetOwnStaticMutex() );
540     // Decrease ouer refcount.
541     --m_nRefCount;
542     // If last instance was deleted ...
543     // we must destroy ouer static data container!
544     if( m_nRefCount <= 0 )
545     {
546         delete m_pDataContainer;
547         m_pDataContainer = NULL;
548     }
549 }
550 
551 //*****************************************************************************************************************
552 //  public method
553 //*****************************************************************************************************************
554 void SvtCommandOptions::Clear( CmdOption eCmdOption )
555 {
556     MutexGuard aGuard( GetOwnStaticMutex() );
557     m_pDataContainer->Clear( eCmdOption );
558 }
559 
560 //*****************************************************************************************************************
561 //  public method
562 //*****************************************************************************************************************
563 sal_Bool SvtCommandOptions::HasEntries( CmdOption eOption ) const
564 {
565     MutexGuard aGuard( GetOwnStaticMutex() );
566     return m_pDataContainer->HasEntries( eOption );
567 }
568 
569 //*****************************************************************************************************************
570 //  public method
571 //*****************************************************************************************************************
572 sal_Bool SvtCommandOptions::Lookup( CmdOption eCmdOption, const OUString& aCommandURL ) const
573 {
574     MutexGuard aGuard( GetOwnStaticMutex() );
575     return m_pDataContainer->Lookup( eCmdOption, aCommandURL );
576 }
577 
578 //*****************************************************************************************************************
579 //  public method
580 //*****************************************************************************************************************
581 Sequence< OUString > SvtCommandOptions::GetList( CmdOption eCmdOption ) const
582 {
583     MutexGuard aGuard( GetOwnStaticMutex() );
584     return m_pDataContainer->GetList( eCmdOption );
585 }
586 
587 //*****************************************************************************************************************
588 //  public method
589 //*****************************************************************************************************************
590 void SvtCommandOptions::AddCommand( CmdOption eCmdOption, const OUString& sURL )
591 {
592     MutexGuard aGuard( GetOwnStaticMutex() );
593     m_pDataContainer->AddCommand( eCmdOption, sURL );
594 }
595 
596 //*****************************************************************************************************************
597 //  public method
598 //*****************************************************************************************************************
599 void SvtCommandOptions::EstablisFrameCallback(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame)
600 {
601     MutexGuard aGuard( GetOwnStaticMutex() );
602     m_pDataContainer->EstablisFrameCallback(xFrame);
603 }
604 
605 //*****************************************************************************************************************
606 //  private method
607 //*****************************************************************************************************************
608 Mutex& SvtCommandOptions::GetOwnStaticMutex()
609 {
610     // Initialize static mutex only for one time!
611     static Mutex* pMutex = NULL;
612     // If these method first called (Mutex not already exist!) ...
613     if( pMutex == NULL )
614     {
615         // ... we must create a new one. Protect follow code with the global mutex -
616         // It must be - we create a static variable!
617         MutexGuard aGuard( Mutex::getGlobalMutex() );
618         // We must check our pointer again - because it can be that another instance of ouer class will be fastr then these!
619         if( pMutex == NULL )
620         {
621             // Create the new mutex and set it for return on static variable.
622             static Mutex aMutex;
623             pMutex = &aMutex;
624         }
625     }
626     // Return new created or already existing mutex object.
627     return *pMutex;
628 }
629