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 { 79 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! 93 void Clear() 94 { 95 m_aCommandHashMap.clear(); 96 } 97 98 sal_Bool HasEntries() const 99 { 100 return ( m_aCommandHashMap.size() > 0 ); 101 } 102 103 void SetContainerSize( sal_Int32 nSize ) 104 { 105 m_aCommandHashMap.rehash( nSize ); 106 } 107 108 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 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 ... 127 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: 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 oue 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 //***************************************************************************************************************** 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 ouer 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 ouer baseclass. 303 // We need it to get information about changes outside these class on ouer 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 //***************************************************************************************************************** 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 //***************************************************************************************************************** 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 ouer 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 //***************************************************************************************************************** 368 void SvtCommandOptions_Impl::Commit() 369 { 370 DBG_ERROR( "SvtCommandOptions_Impl::Commit()\nNot implemented yet!\n" ); 371 } 372 373 //***************************************************************************************************************** 374 // public method 375 //***************************************************************************************************************** 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 //***************************************************************************************************************** 395 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 //***************************************************************************************************************** 406 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 //***************************************************************************************************************** 428 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 //***************************************************************************************************************** 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 //***************************************************************************************************************** 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 //***************************************************************************************************************** 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 //***************************************************************************************************************** 515 SvtCommandOptions::SvtCommandOptions() 516 { 517 // Global access, must be guarded (multithreading!). 518 MutexGuard aGuard( GetOwnStaticMutex() ); 519 // Increase ouer refcount ... 520 ++m_nRefCount; 521 // ... and initialize ouer 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 //***************************************************************************************************************** 532 SvtCommandOptions::~SvtCommandOptions() 533 { 534 // Global access, must be guarded (multithreading!) 535 MutexGuard aGuard( GetOwnStaticMutex() ); 536 // Decrease ouer refcount. 537 --m_nRefCount; 538 // If last instance was deleted ... 539 // we must destroy ouer 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 //***************************************************************************************************************** 550 void SvtCommandOptions::Clear( CmdOption eCmdOption ) 551 { 552 MutexGuard aGuard( GetOwnStaticMutex() ); 553 m_pDataContainer->Clear( eCmdOption ); 554 } 555 556 //***************************************************************************************************************** 557 // public method 558 //***************************************************************************************************************** 559 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 //***************************************************************************************************************** 568 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 //***************************************************************************************************************** 577 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 //***************************************************************************************************************** 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 //***************************************************************************************************************** 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 //***************************************************************************************************************** 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 ouer class will be fastr then 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