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