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