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_sfx2.hxx" 30 31 #include "sfx2/sfxhelp.hxx" 32 33 #include <set> 34 #include <algorithm> 35 #include <com/sun/star/uno/Reference.h> 36 #include <com/sun/star/frame/XFrame.hpp> 37 #include <com/sun/star/frame/XComponentLoader.hpp> 38 #include <com/sun/star/lang/XComponent.hpp> 39 #include <comphelper/processfactory.hxx> 40 #include <com/sun/star/awt/XWindow.hpp> 41 #include <com/sun/star/awt/XTopWindow.hpp> 42 #include <com/sun/star/awt/PosSize.hpp> 43 #include <com/sun/star/frame/XDesktop.hpp> 44 #include <com/sun/star/util/XURLTransformer.hpp> 45 #include <com/sun/star/frame/XDispatch.hpp> 46 #include <com/sun/star/frame/XDispatchProvider.hpp> 47 #include <com/sun/star/container/XNameAccess.hpp> 48 #include <com/sun/star/beans/XPropertySet.hpp> 49 #include <com/sun/star/frame/FrameSearchFlag.hpp> 50 #include <toolkit/helper/vclunohelper.hxx> 51 #include <com/sun/star/frame/XModuleManager.hpp> 52 #include <unotools/configmgr.hxx> 53 #include <unotools/configitem.hxx> 54 #include <svtools/helpopt.hxx> 55 #include <unotools/moduleoptions.hxx> 56 #include <tools/urlobj.hxx> 57 #include <unotools/configmgr.hxx> 58 #include <ucbhelper/content.hxx> 59 #include <unotools/pathoptions.hxx> 60 #include <rtl/ustring.hxx> 61 #include <osl/process.h> 62 #include <osl/file.hxx> 63 #include <unotools/bootstrap.hxx> 64 #include <rtl/uri.hxx> 65 #include <vcl/msgbox.hxx> 66 #include <svtools/ehdl.hxx> 67 #include <svtools/sfxecode.hxx> 68 69 #define _SVSTDARR_STRINGSDTOR 70 #define _SVSTDARR_ULONGSSORT 71 #include <svl/svstdarr.hxx> 72 73 #include "newhelp.hxx" 74 #include <sfx2/objsh.hxx> 75 #include <sfx2/docfac.hxx> 76 #include "sfx2/sfxresid.hxx" 77 #include "helper.hxx" 78 #include "app.hrc" 79 #include <sfx2/sfxuno.hxx> 80 #include <vcl/svapp.hxx> 81 #include <sfx2/frame.hxx> 82 #include <rtl/string.hxx> 83 84 using namespace ::com::sun::star::beans; 85 using namespace ::com::sun::star::frame; 86 using namespace ::com::sun::star::uno; 87 using namespace ::com::sun::star::util; 88 using namespace ::com::sun::star::frame; 89 using namespace ::com::sun::star::lang; 90 91 #define ERROR_TAG String( DEFINE_CONST_UNICODE("Error: ") ) 92 #define PATH_TAG String( DEFINE_CONST_UNICODE("\nPath: ") ) 93 94 // class NoHelpErrorBox -------------------------------------------------- 95 96 class NoHelpErrorBox : public ErrorBox 97 { 98 public: 99 NoHelpErrorBox( Window* _pParent ); 100 101 virtual void RequestHelp( const HelpEvent& rHEvt ); 102 }; 103 104 NoHelpErrorBox::NoHelpErrorBox( Window* _pParent ) : 105 106 ErrorBox( _pParent, WB_OK, String( SfxResId( RID_STR_HLPFILENOTEXIST ) ) ) 107 { 108 // Error message: "No help available" 109 } 110 111 void NoHelpErrorBox::RequestHelp( const HelpEvent& ) 112 { 113 // do nothing, because no help available 114 } 115 116 // ----------------------------------------------------------------------- 117 118 #define STARTERLIST 0 119 120 rtl::OUString HelpLocaleString() 121 { 122 static rtl::OUString aLocaleStr; 123 if (!aLocaleStr.getLength()) 124 { 125 // detect installed locale 126 Any aLocale = 127 ::utl::ConfigManager::GetConfigManager()->GetDirectConfigProperty( 128 ::utl::ConfigManager::LOCALE ); 129 aLocale >>= aLocaleStr; 130 bool bOk = aLocaleStr.getLength() != 0; 131 if ( bOk ) 132 { 133 rtl::OUString aBaseInstallPath; 134 // utl::Bootstrap::PathStatus aBaseLocateResult = 135 utl::Bootstrap::locateBaseInstallation(aBaseInstallPath); 136 static const char *szHelpPath = "/help/"; 137 138 rtl::OUString sHelpPath = aBaseInstallPath + 139 rtl::OUString::createFromAscii(szHelpPath) + aLocaleStr; 140 osl::DirectoryItem aDirItem; 141 142 if (!osl::DirectoryItem::get(sHelpPath, aDirItem) == osl::FileBase::E_None) 143 { 144 bOk = false; 145 String sLang(aLocaleStr); 146 xub_StrLen nSepPos = sLang.Search( '-' ); 147 if (nSepPos != STRING_NOTFOUND) 148 { 149 bOk = true; 150 sLang = sLang.Copy( 0, nSepPos ); 151 sHelpPath = aBaseInstallPath + 152 rtl::OUString::createFromAscii(szHelpPath) + sLang; 153 if (!osl::DirectoryItem::get(sHelpPath, aDirItem) == osl::FileBase::E_None) 154 bOk = false; 155 } 156 } 157 } 158 if (!bOk) 159 aLocaleStr = rtl::OUString( DEFINE_CONST_UNICODE("en") ); 160 } 161 return aLocaleStr; 162 } 163 164 void AppendConfigToken_Impl( String& rURL, sal_Bool bQuestionMark ) 165 { 166 ::rtl::OUString aLocaleStr(HelpLocaleString()); 167 168 // query part exists? 169 if ( bQuestionMark ) 170 // no, so start with '?' 171 rURL += '?'; 172 else 173 // yes, so only append with '&' 174 rURL += '&'; 175 176 // set parameters 177 rURL += DEFINE_CONST_UNICODE("Language="); 178 rURL += String( aLocaleStr ); 179 rURL += DEFINE_CONST_UNICODE("&System="); 180 rURL += SvtHelpOptions().GetSystem(); 181 182 } 183 184 // ----------------------------------------------------------------------- 185 186 sal_Bool GetHelpAnchor_Impl( const String& _rURL, String& _rAnchor ) 187 { 188 sal_Bool bRet = sal_False; 189 ::rtl::OUString sAnchor; 190 191 // --> OD 2009-07-01 #159496# 192 // do not release solar mutex due to crash regarding accessibility 193 // sal_uIntPtr nSolarCount = Application::ReleaseSolarMutex(); 194 // <-- 195 try 196 { 197 ::ucbhelper::Content aCnt( INetURLObject( _rURL ).GetMainURL( INetURLObject::NO_DECODE ), 198 Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); 199 if ( ( aCnt.getPropertyValue( ::rtl::OUString::createFromAscii( "AnchorName" ) ) >>= sAnchor ) ) 200 { 201 202 if ( sAnchor.getLength() > 0 ) 203 { 204 _rAnchor = String( sAnchor ); 205 bRet = sal_True; 206 } 207 } 208 else 209 { 210 DBG_ERRORFILE( "Property 'AnchorName' is missing" ); 211 } 212 } 213 catch( ::com::sun::star::uno::Exception& ) 214 { 215 } 216 // --> OD 2009-07-01 #159496# 217 // Application::AcquireSolarMutex( nSolarCount ); 218 // <-- 219 220 return bRet; 221 } 222 223 // ----------------------------------------------------------------------- 224 225 class SfxHelpOptions_Impl : public utl::ConfigItem 226 { 227 private: 228 std::set < rtl::OString > m_aIds; 229 230 public: 231 SfxHelpOptions_Impl(); 232 ~SfxHelpOptions_Impl(); 233 234 bool HasId( const rtl::OString& rId ) { return m_aIds.size() ? m_aIds.find( rId ) != m_aIds.end() : false; } 235 virtual void Notify( const com::sun::star::uno::Sequence< rtl::OUString >& aPropertyNames ); 236 virtual void Commit(); 237 }; 238 239 static Sequence< ::rtl::OUString > GetPropertyNames() 240 { 241 static const char* aPropNames[] = 242 { 243 "HelpAgentStarterList", 244 }; 245 246 const int nCount = sizeof( aPropNames ) / sizeof( const char* ); 247 Sequence< ::rtl::OUString > aNames( nCount ); 248 ::rtl::OUString* pNames = aNames.getArray(); 249 ::rtl::OUString* pEnd = pNames + aNames.getLength(); 250 int i = 0; 251 for ( ; pNames != pEnd; ++pNames ) 252 *pNames = ::rtl::OUString::createFromAscii( aPropNames[i++] ); 253 254 return aNames; 255 } 256 257 // ----------------------------------------------------------------------- 258 259 SfxHelpOptions_Impl::SfxHelpOptions_Impl() 260 : ConfigItem( ::rtl::OUString::createFromAscii("Office.SFX/Help") ) 261 { 262 Sequence< ::rtl::OUString > aNames = GetPropertyNames(); 263 Sequence< Any > aValues = GetProperties( aNames ); 264 EnableNotification( aNames ); 265 const Any* pValues = aValues.getConstArray(); 266 DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" ); 267 if ( aValues.getLength() == aNames.getLength() ) 268 { 269 for ( int nProp = 0; nProp < aNames.getLength(); nProp++ ) 270 { 271 DBG_ASSERT( pValues[nProp].hasValue(), "property value missing" ); 272 if ( pValues[nProp].hasValue() ) 273 { 274 switch ( nProp ) 275 { 276 case STARTERLIST : 277 { 278 ::rtl::OUString aCodedList; 279 if ( pValues[nProp] >>= aCodedList ) 280 { 281 rtl::OString aTmp( aCodedList, aCodedList.getLength(), RTL_TEXTENCODING_UTF8 ); 282 sal_Int32 nIndex = 0; 283 do 284 { 285 rtl::OString aToken = aTmp.getToken( 0, ',', nIndex ); 286 if ( aToken.getLength() ) 287 m_aIds.insert( aToken ); 288 } 289 while ( nIndex >= 0 ); 290 } 291 else { 292 DBG_ERRORFILE( "Wrong property type!" ); 293 } 294 295 break; 296 } 297 298 default: 299 DBG_ERRORFILE( "Wrong property!" ); 300 break; 301 } 302 } 303 } 304 } 305 } 306 307 SfxHelpOptions_Impl::~SfxHelpOptions_Impl() 308 { 309 } 310 311 312 void SfxHelpOptions_Impl::Notify( const com::sun::star::uno::Sequence< rtl::OUString >& ) 313 { 314 } 315 316 void SfxHelpOptions_Impl::Commit() 317 { 318 } 319 320 // class SfxHelp_Impl ---------------------------------------------------- 321 322 class SfxHelp_Impl 323 { 324 private: 325 sal_Bool m_bIsDebug; // environment variable "help_debug=1" 326 SfxHelpOptions_Impl* m_pOpt; // the options 327 ::std::vector< ::rtl::OUString > m_aModulesList; // list of all installed modules 328 void Load(); 329 330 public: 331 SfxHelp_Impl( sal_Bool bDebug ); 332 ~SfxHelp_Impl(); 333 334 SfxHelpOptions_Impl* GetOptions(); 335 static String GetHelpText( const rtl::OUString& aCommandURL, const String& rModule ); 336 sal_Bool HasModule( const ::rtl::OUString& rModule ); // module installed 337 sal_Bool IsHelpInstalled(); // module list not empty 338 }; 339 340 SfxHelp_Impl::SfxHelp_Impl( sal_Bool bDebug ) : 341 342 m_bIsDebug ( bDebug ), 343 m_pOpt ( NULL ) 344 345 { 346 } 347 348 SfxHelp_Impl::~SfxHelp_Impl() 349 { 350 delete m_pOpt; 351 } 352 353 void SfxHelp_Impl::Load() 354 { 355 // fill modules list 356 // create the help url (empty, without module and helpid) 357 String sHelpURL( DEFINE_CONST_UNICODE("vnd.sun.star.help://") ); 358 AppendConfigToken_Impl( sHelpURL, sal_True ); 359 360 // open ucb content and get the list of the help modules 361 // the list contains strings with three tokens "ui title \t type \t url" 362 Sequence< ::rtl::OUString > aAllModulesList = SfxContentHelper::GetResultSet( sHelpURL ); 363 sal_Int32 nLen = aAllModulesList.getLength(); 364 m_aModulesList.reserve( nLen + 1 ); 365 const ::rtl::OUString* pBegin = aAllModulesList.getConstArray(); 366 const ::rtl::OUString* pEnd = pBegin + nLen; 367 for ( ; pBegin != pEnd; ++pBegin ) 368 { 369 // get one module string 370 String sModule( *pBegin ); 371 // extract the url 372 String sURL = sModule.GetToken( 2, '\t' ); 373 // insert the module (the host part of the "vnd.sun.star.help" url) 374 m_aModulesList.push_back( ::rtl::OUString( INetURLObject( sURL ).GetHost() ) ); 375 } 376 } 377 378 String SfxHelp_Impl::GetHelpText( const rtl::OUString& aCommandURL, const String& rModule ) 379 { 380 // create help url 381 String aHelpURL = SfxHelp::CreateHelpURL( aCommandURL, rModule ); 382 // added 'active' parameter 383 aHelpURL.Insert( String( DEFINE_CONST_UNICODE("&Active=true") ), aHelpURL.SearchBackward( '#' ) ); 384 // load help string 385 return SfxContentHelper::GetActiveHelpString( aHelpURL ); 386 } 387 388 SfxHelpOptions_Impl* SfxHelp_Impl::GetOptions() 389 { 390 // create if not exists 391 if ( !m_pOpt ) 392 m_pOpt = new SfxHelpOptions_Impl; 393 return m_pOpt; 394 } 395 396 sal_Bool SfxHelp_Impl::HasModule( const ::rtl::OUString& rModule ) 397 { 398 if ( !m_aModulesList.size() ) 399 Load(); 400 return ( ::std::find( m_aModulesList.begin(), m_aModulesList.end(), rModule ) != m_aModulesList.end() ); 401 } 402 403 sal_Bool SfxHelp_Impl::IsHelpInstalled() 404 { 405 if ( !m_aModulesList.size() ) 406 Load(); 407 return ( m_aModulesList.begin() != m_aModulesList.end() ); 408 } 409 410 // class SfxHelp --------------------------------------------------------- 411 /* some test code for HID conversion - please don't remove 412 413 #include <tools/stream.hxx> 414 void TestHids() 415 { 416 static const char* aModules[] = 417 { 418 "swriter", 419 "scalc", 420 "simpress", 421 "sdraw", 422 "sdatabase", 423 "smath", 424 "schart", 425 "sbasic" 426 }; 427 428 SvFileStream* pOut[] = 429 { 430 0,0,0,0,0,0,0,0,0 431 }; 432 433 String aIn = String::CreateFromAscii("/data/OOo/replacer/hidsin.lst"); 434 String aOut = String::CreateFromAscii("/data/OOo/replacer/"); 435 SvFileStream aInStrm( aIn, STREAM_READ ); 436 ByteString aBuffer; 437 while ( aInStrm.ReadLine( aBuffer ) ) 438 { 439 ByteString aHid = aBuffer.GetToken(0, ' '); 440 ByteString aNr = aBuffer.GetToken(1, ' '); 441 bool bFound=false; 442 for (sal_Int32 n= 0; n<8; n++) 443 { 444 bFound = false; 445 String aHelpURL = SfxHelp::CreateHelpURL( String( aNr, RTL_TEXTENCODING_UTF8 ), String( aModules[n], RTL_TEXTENCODING_UTF8 ) ); 446 if ( !SfxContentHelper::IsHelpErrorDocument( aHelpURL ) ) 447 { 448 if (!pOut[n]) 449 { 450 String aTmp( aOut ); 451 aTmp += String( aModules[n], RTL_TEXTENCODING_UTF8 ); 452 aTmp += String::CreateFromAscii(".lst"); 453 pOut[n] = new SvFileStream( aTmp, STREAM_WRITE | STREAM_TRUNC ); 454 } 455 pOut[n]->WriteLine( aHid ); 456 bFound = true; 457 break; 458 } 459 } 460 461 if (!bFound) 462 { 463 if (!pOut[8]) 464 { 465 String aTmp( aOut ); 466 aTmp += String( "notfound", RTL_TEXTENCODING_UTF8 ); 467 aTmp += String::CreateFromAscii(".lst"); 468 pOut[8] = new SvFileStream( aTmp, STREAM_WRITE | STREAM_TRUNC ); 469 } 470 pOut[8]->WriteLine( aHid ); 471 } 472 } 473 474 for (sal_Int32 n= 0; n<9; n++) 475 DELETEZ( pOut[n] ); 476 } 477 478 void TestHids2() 479 { 480 static const char* aModules[] = 481 { 482 "swriter", 483 "scalc", 484 "simpress", 485 "smath", 486 "sbasic" 487 }; 488 489 String aOut = String::CreateFromAscii("/data/OOo/replacer/"); 490 aOut += String::CreateFromAscii("lost.lst"); 491 SvFileStream aOutStrm( aOut, STREAM_WRITE | STREAM_TRUNC ); 492 for (sal_Int32 n= 0; n<5; n++) 493 { 494 String aIn = String::CreateFromAscii("/data/OOo/replacer/help/"); 495 aIn += String::CreateFromAscii( aModules[n] ); 496 aIn += String::CreateFromAscii(".lst"); 497 SvFileStream aInStrm( aIn, STREAM_READ ); 498 ByteString aBuffer; 499 while ( aInStrm.ReadLine( aBuffer ) ) 500 { 501 String aHelpURL = SfxHelp::CreateHelpURL( String( aBuffer, RTL_TEXTENCODING_UTF8 ), String( aModules[n], RTL_TEXTENCODING_UTF8 ) ); 502 if ( SfxContentHelper::IsHelpErrorDocument( aHelpURL ) ) 503 aOutStrm.WriteLine( aBuffer ); 504 } 505 } 506 } 507 508 #include <tools/stream.hxx> 509 void TestHids3() 510 { 511 static const char* aModules[] = 512 { 513 "swriter", 514 "scalc", 515 "simpress", 516 "sdraw", 517 "sdatabase", 518 "smath", 519 "schart", 520 "sbasic" 521 }; 522 523 SvFileStream* pOut[] = 524 { 525 0,0,0,0,0,0,0,0,0 526 }; 527 528 String aIn = String::CreateFromAscii("/data/OOo/replacer/hidsin.lst"); 529 String aOut = String::CreateFromAscii("/data/OOo/replacer/quickhelp/"); 530 SvFileStream aInStrm( aIn, STREAM_READ ); 531 ByteString aBuffer; 532 while ( aInStrm.ReadLine( aBuffer ) ) 533 { 534 ByteString aHid = aBuffer.GetToken(0, ' '); 535 ByteString aNr = aBuffer.GetToken(1, ' '); 536 bool bFound=false; 537 for (sal_Int32 n= 0; n<8; n++) 538 { 539 bFound = false; 540 String aHelpURL = SfxHelp::CreateHelpURL( String( aNr, RTL_TEXTENCODING_UTF8 ), String( aModules[n], RTL_TEXTENCODING_UTF8 ) ); 541 if ( SfxContentHelper::GetActiveHelpString( aHelpURL ).Len() ) 542 // if ( SfxHelp_Impl::GetHelpText( String( aNr, RTL_TEXTENCODING_UTF8 ), String( aModules[n], RTL_TEXTENCODING_UTF8 ) ).Len() ) 543 { 544 if (!pOut[n]) 545 { 546 String aTmp( aOut ); 547 aTmp += String( aModules[n], RTL_TEXTENCODING_UTF8 ); 548 aTmp += String::CreateFromAscii(".lst"); 549 pOut[n] = new SvFileStream( aTmp, STREAM_WRITE | STREAM_TRUNC ); 550 } 551 pOut[n]->WriteLine( aHid ); 552 bFound = true; 553 break; 554 } 555 } 556 557 if (!bFound) 558 { 559 if (!pOut[8]) 560 { 561 String aTmp( aOut ); 562 aTmp += String( "notfound", RTL_TEXTENCODING_UTF8 ); 563 aTmp += String::CreateFromAscii(".lst"); 564 pOut[8] = new SvFileStream( aTmp, STREAM_WRITE | STREAM_TRUNC ); 565 } 566 pOut[8]->WriteLine( aHid ); 567 } 568 } 569 570 for (sal_Int32 n= 0; n<9; n++) 571 DELETEZ( pOut[n] ); 572 } 573 574 void TestHids4() 575 { 576 static const char* aModules[] = 577 { 578 "swriter", 579 "scalc", 580 "simpress", 581 "smath", 582 "sbasic" 583 }; 584 585 String aOut = String::CreateFromAscii("/data/OOo/replacer/quickhelp/"); 586 aOut += String::CreateFromAscii("lost.lst"); 587 SvFileStream aOutStrm( aOut, STREAM_WRITE | STREAM_TRUNC ); 588 for (sal_Int32 n= 0; n<5; n++) 589 { 590 String aIn = String::CreateFromAscii("/data/OOo/replacer/quickhelp/"); 591 aIn += String::CreateFromAscii( aModules[n] ); 592 aIn += String::CreateFromAscii(".lst"); 593 SvFileStream aInStrm( aIn, STREAM_READ ); 594 ByteString aBuffer; 595 while ( aInStrm.ReadLine( aBuffer ) ) 596 { 597 String aHelpURL = SfxHelp::CreateHelpURL( String( aBuffer, RTL_TEXTENCODING_UTF8 ), String( aModules[n], RTL_TEXTENCODING_UTF8 ) ); 598 if ( !SfxContentHelper::GetActiveHelpString( aHelpURL ).Len() ) 599 aOutStrm.WriteLine( aBuffer ); 600 } 601 } 602 } 603 */ 604 605 SfxHelp::SfxHelp() : 606 607 bIsDebug( sal_False ), 608 pImp ( NULL ) 609 610 { 611 // read the environment variable "HELP_DEBUG" 612 // if it's set, you will see debug output on active help 613 { 614 ::rtl::OUString sHelpDebug; 615 ::rtl::OUString sEnvVarName( RTL_CONSTASCII_USTRINGPARAM( "HELP_DEBUG" ) ); 616 osl_getEnvironment( sEnvVarName.pData, &sHelpDebug.pData ); 617 bIsDebug = ( 0 != sHelpDebug.getLength() ); 618 } 619 620 pImp = new SfxHelp_Impl( bIsDebug ); 621 622 ::rtl::OUString aLocaleStr = HelpLocaleString(); 623 624 sal_Int32 nSepPos = aLocaleStr.indexOf( '_' ); 625 if ( nSepPos != -1 ) 626 { 627 aLanguageStr = aLocaleStr.copy( 0, nSepPos ); 628 aCountryStr = aLocaleStr.copy( nSepPos+1 ); 629 } 630 else 631 { 632 nSepPos = aLocaleStr.indexOf( '-' ); 633 if ( nSepPos != -1 ) 634 { 635 aLanguageStr = aLocaleStr.copy( 0, nSepPos ); 636 aCountryStr = aLocaleStr.copy( nSepPos+1 ); 637 } 638 else 639 { 640 aLanguageStr = aLocaleStr; 641 } 642 } 643 } 644 645 SfxHelp::~SfxHelp() 646 { 647 delete pImp; 648 } 649 650 ::rtl::OUString getDefaultModule_Impl() 651 { 652 rtl::OUString sDefaultModule; 653 SvtModuleOptions aModOpt; 654 if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) ) 655 sDefaultModule = DEFINE_CONST_UNICODE("swriter"); 656 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) ) 657 sDefaultModule = DEFINE_CONST_UNICODE("scalc"); 658 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) ) 659 sDefaultModule = DEFINE_CONST_UNICODE("simpress"); 660 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) ) 661 sDefaultModule = DEFINE_CONST_UNICODE("sdraw"); 662 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SMATH ) ) 663 sDefaultModule = DEFINE_CONST_UNICODE("smath"); 664 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SCHART ) ) 665 sDefaultModule = DEFINE_CONST_UNICODE("schart"); 666 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SBASIC ) ) 667 sDefaultModule = DEFINE_CONST_UNICODE("sbasic"); 668 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) ) 669 sDefaultModule = DEFINE_CONST_UNICODE("sdatabase"); 670 else 671 { 672 DBG_ERRORFILE( "getDefaultModule_Impl(): no module installed" ); 673 } 674 return sDefaultModule; 675 } 676 677 ::rtl::OUString getCurrentModuleIdentifier_Impl() 678 { 679 ::rtl::OUString sIdentifier; 680 Reference < XFrame > xCurrentFrame; 681 Reference < XModuleManager > xModuleManager( ::comphelper::getProcessServiceFactory()->createInstance( 682 DEFINE_CONST_UNICODE("com.sun.star.frame.ModuleManager") ), UNO_QUERY ); 683 Reference < XDesktop > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance( 684 DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY ); 685 if ( xDesktop.is() ) 686 xCurrentFrame = xDesktop->getCurrentFrame(); 687 688 if ( xCurrentFrame.is() && xModuleManager.is() ) 689 { 690 try 691 { 692 sIdentifier = xModuleManager->identify( xCurrentFrame ); 693 } 694 catch ( ::com::sun::star::frame::UnknownModuleException& ) 695 { 696 DBG_WARNING( "SfxHelp::getCurrentModuleIdentifier_Impl(): unknown module (help in help?)" ); 697 } 698 catch ( Exception& ) 699 { 700 DBG_ERRORFILE( "SfxHelp::getCurrentModuleIdentifier_Impl(): exception of XModuleManager::identify()" ); 701 } 702 } 703 704 return sIdentifier; 705 } 706 707 String SfxHelp::GetHelpModuleName_Impl() 708 { 709 String sModuleName; 710 rtl::OUString aFactoryShortName; 711 rtl::OUString aModuleIdentifier = getCurrentModuleIdentifier_Impl(); 712 713 if ( aModuleIdentifier.getLength() > 0 ) 714 { 715 try 716 { 717 Reference < XModuleManager > xModuleManager( 718 ::comphelper::getProcessServiceFactory()->createInstance( 719 DEFINE_CONST_UNICODE("com.sun.star.frame.ModuleManager") ), UNO_QUERY ); 720 Sequence< PropertyValue > lProps; 721 Reference< ::com::sun::star::container::XNameAccess > xCont( xModuleManager, UNO_QUERY); 722 if ( xCont.is() ) 723 xCont->getByName( aModuleIdentifier ) >>= lProps; 724 for ( sal_Int32 i = 0; i < lProps.getLength(); ++i ) 725 { 726 if ( lProps[i].Name.equalsAscii("ooSetupFactoryShortName") ) 727 { 728 lProps[i].Value >>= aFactoryShortName; 729 break; 730 } 731 } 732 } 733 catch ( Exception& ) 734 { 735 DBG_ERRORFILE( "SfxHelp::GetHelpModuleName_Impl(): exception of XNameAccess::getByName()" ); 736 } 737 } 738 739 rtl::OUString sDefaultModule = getDefaultModule_Impl(); 740 if ( aFactoryShortName.getLength() > 0 ) 741 { 742 // Map some module identifiers to their "real" help module string. 743 if ( aFactoryShortName.equalsAscii( "chart2" ) ) 744 aFactoryShortName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "schart" ) ); 745 else if ( aFactoryShortName.equalsAscii( "BasicIDE" ) ) 746 aFactoryShortName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "sbasic" ) ); 747 else if ( aFactoryShortName.equalsAscii( "sweb" ) 748 || aFactoryShortName.equalsAscii( "sglobal" ) 749 || aFactoryShortName.equalsAscii( "swxform" ) ) 750 aFactoryShortName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "swriter" ) ); 751 else if ( aFactoryShortName.equalsAscii( "dbquery" ) 752 || aFactoryShortName.equalsAscii( "dbbrowser" ) 753 || aFactoryShortName.equalsAscii( "dbrelation" ) 754 || aFactoryShortName.equalsAscii( "dbtable" ) 755 || aFactoryShortName.equalsAscii( "dbapp" ) 756 || aFactoryShortName.equalsAscii( "dbreport" ) 757 || aFactoryShortName.equalsAscii( "swreport" ) 758 || aFactoryShortName.equalsAscii( "dbbrowser" ) 759 || aFactoryShortName.equalsAscii( "swform" ) ) 760 aFactoryShortName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "sdatabase" ) ); 761 else if ( aFactoryShortName.equalsAscii( "sbibliography" ) 762 || aFactoryShortName.equalsAscii( "StartModule" ) ) 763 aFactoryShortName = sDefaultModule; 764 } 765 else 766 aFactoryShortName = sDefaultModule; 767 768 sModuleName = String( aFactoryShortName ); 769 return sModuleName; 770 } 771 772 String SfxHelp::CreateHelpURL_Impl( const String& aCommandURL, const String& rModuleName ) 773 { 774 // build up the help URL 775 String aHelpURL; 776 sal_Bool bHasAnchor = sal_False; 777 String aAnchor; 778 779 String aModuleName( rModuleName ); 780 if ( aModuleName.Len() == 0 ) 781 aModuleName = getDefaultModule_Impl(); 782 783 aHelpURL = String::CreateFromAscii("vnd.sun.star.help://"); 784 aHelpURL += aModuleName; 785 786 if ( !aCommandURL.Len() ) 787 aHelpURL += String::CreateFromAscii("/start"); 788 else 789 { 790 aHelpURL += '/'; 791 aHelpURL += String( rtl::Uri::encode( aCommandURL, 792 rtl_UriCharClassRelSegment, 793 rtl_UriEncodeKeepEscapes, 794 RTL_TEXTENCODING_UTF8 )); 795 796 String aTempURL = aHelpURL; 797 AppendConfigToken_Impl( aTempURL, sal_True ); 798 bHasAnchor = GetHelpAnchor_Impl( aTempURL, aAnchor ); 799 } 800 801 AppendConfigToken_Impl( aHelpURL, sal_True ); 802 803 if ( bHasAnchor ) 804 { 805 aHelpURL += '#'; 806 aHelpURL += aAnchor; 807 } 808 809 return aHelpURL; 810 } 811 812 SfxHelpWindow_Impl* impl_createHelp(Reference< XFrame >& rHelpTask , 813 Reference< XFrame >& rHelpContent) 814 { 815 Reference < XFrame > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance( 816 DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY ); 817 818 // otherwhise - create new help task 819 Reference< XFrame > xHelpTask = xDesktop->findFrame( 820 ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")), 821 FrameSearchFlag::TASKS | FrameSearchFlag::CREATE); 822 if (!xHelpTask.is()) 823 return 0; 824 825 // create all internal windows and sub frames ... 826 Reference< ::com::sun::star::awt::XWindow > xParentWindow = xHelpTask->getContainerWindow(); 827 Window* pParentWindow = VCLUnoHelper::GetWindow( xParentWindow ); 828 SfxHelpWindow_Impl* pHelpWindow = new SfxHelpWindow_Impl( xHelpTask, pParentWindow, WB_DOCKBORDER ); 829 Reference< ::com::sun::star::awt::XWindow > xHelpWindow = VCLUnoHelper::GetInterface( pHelpWindow ); 830 831 Reference< XFrame > xHelpContent; 832 if (xHelpTask->setComponent( xHelpWindow, Reference< XController >() )) 833 { 834 // Customize UI ... 835 xHelpTask->setName( ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")) ); 836 837 Reference< XPropertySet > xProps(xHelpTask, UNO_QUERY); 838 if (xProps.is()) 839 xProps->setPropertyValue( 840 DEFINE_CONST_UNICODE("Title"), 841 makeAny(::rtl::OUString(String(SfxResId(STR_HELP_WINDOW_TITLE))))); 842 843 pHelpWindow->setContainerWindow( xParentWindow ); 844 xParentWindow->setVisible(sal_True); 845 xHelpWindow->setVisible(sal_True); 846 847 // This sub frame is created internaly (if we called new SfxHelpWindow_Impl() ...) 848 // It should exist :-) 849 xHelpContent = xHelpTask->findFrame(::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")), FrameSearchFlag::CHILDREN); 850 } 851 852 if (!xHelpContent.is()) 853 delete pHelpWindow; 854 855 xHelpContent->setName(::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP"))); 856 857 rHelpTask = xHelpTask; 858 rHelpContent = xHelpContent; 859 return pHelpWindow; 860 } 861 862 XubString SfxHelp::GetHelpText( const String& aCommandURL, const Window* pWindow ) 863 { 864 String sModuleName = GetHelpModuleName_Impl(); 865 String sHelpText = pImp->GetHelpText( aCommandURL, sModuleName ); 866 867 ByteString aNewHelpId; 868 869 if ( pWindow && !sHelpText.Len() ) 870 { 871 // no help text found -> try with parent help id. 872 Window* pParent = pWindow->GetParent(); 873 while ( pParent ) 874 { 875 aNewHelpId = pParent->GetHelpId(); 876 sHelpText = pImp->GetHelpText( String( aNewHelpId, RTL_TEXTENCODING_UTF8 ), sModuleName ); 877 if ( sHelpText.Len() > 0 ) 878 pParent = NULL; 879 else 880 pParent = pParent->GetParent(); 881 } 882 883 if ( bIsDebug && !sHelpText.Len() ) 884 aNewHelpId.Erase(); 885 } 886 887 // add some debug information? 888 if ( bIsDebug ) 889 { 890 sHelpText += DEFINE_CONST_UNICODE("\n-------------\n"); 891 sHelpText += String( sModuleName ); 892 sHelpText += DEFINE_CONST_UNICODE(": "); 893 sHelpText += aCommandURL; 894 if ( aNewHelpId.Len() ) 895 { 896 sHelpText += DEFINE_CONST_UNICODE(" - "); 897 sHelpText += String( aNewHelpId, RTL_TEXTENCODING_UTF8 ); 898 } 899 } 900 901 return sHelpText; 902 } 903 904 sal_Bool SfxHelp::SearchKeyword( const XubString& rKeyword ) 905 { 906 return Start_Impl( String(), NULL, rKeyword ); 907 } 908 909 sal_Bool SfxHelp::Start( const String& rURL, const Window* pWindow ) 910 { 911 return Start_Impl( rURL, pWindow, String() ); 912 } 913 914 sal_Bool SfxHelp::Start_Impl( const String& rURL, const Window* pWindow, const String& rKeyword ) 915 { 916 // check if help is available 917 String aHelpRootURL( DEFINE_CONST_OUSTRING("vnd.sun.star.help://") ); 918 AppendConfigToken_Impl( aHelpRootURL, sal_True ); 919 Sequence< ::rtl::OUString > aFactories = SfxContentHelper::GetResultSet( aHelpRootURL ); 920 if ( 0 == aFactories.getLength() ) 921 { 922 // no factories -> no help -> error message and return 923 NoHelpErrorBox aErrBox( const_cast< Window* >( pWindow ) ); 924 aErrBox.Execute(); 925 return sal_False; 926 } 927 928 /* rURL may be 929 - a "real" URL 930 - a HelpID (formerly a long, now a string) 931 If rURL is a URL, CreateHelpURL should be called for this URL 932 If rURL is an arbitrary string, the same should happen, but the URL should be tried out 933 if it delivers real help content. In case only the Help Error Document is returned, the 934 parent of the window for that help was called, is asked for its HelpID. 935 For compatibility reasons this upward search is not implemented for "real" URLs. 936 Help keyword search now is implemented as own method; in former versions it 937 was done via Help::Start, but this implementation conflicted with the upward search. 938 */ 939 String aHelpURL; 940 INetURLObject aParser( rURL ); 941 INetProtocol nProtocol = aParser.GetProtocol(); 942 String aHelpModuleName( GetHelpModuleName_Impl() ); 943 switch ( nProtocol ) 944 { 945 case INET_PROT_VND_SUN_STAR_HELP: 946 // already a vnd.sun.star.help URL -> nothing to do 947 aHelpURL = rURL; 948 break; 949 default: 950 { 951 // no URL, just a HelpID (maybe empty in case of keyword search) 952 aHelpURL = CreateHelpURL_Impl( rURL, aHelpModuleName ); 953 if ( pWindow && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) ) 954 { 955 // no help found -> try with parent help id. 956 Window* pParent = pWindow->GetParent(); 957 while ( pParent ) 958 { 959 ByteString aHelpId = pParent->GetHelpId(); 960 aHelpURL = CreateHelpURL( String( aHelpId, RTL_TEXTENCODING_UTF8 ), aHelpModuleName ); 961 if ( !SfxContentHelper::IsHelpErrorDocument( aHelpURL ) ) 962 break; 963 else 964 { 965 pParent = pParent->GetParent(); 966 if ( !pParent ) 967 // create help url of start page ( helpid == 0 -> start page) 968 aHelpURL = CreateHelpURL( String(), aHelpModuleName ); 969 } 970 } 971 } 972 break; 973 } 974 } 975 976 Reference < XFrame > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance( 977 DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY ); 978 979 // check if help window is still open 980 // If not, create a new one and return access directly to the internal sub frame showing the help content 981 // search must be done here; search one desktop level could return an arbitraty frame 982 Reference< XFrame > xHelp = xDesktop->findFrame( 983 ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")), 984 FrameSearchFlag::CHILDREN); 985 Reference< XFrame > xHelpContent = xDesktop->findFrame( 986 ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")), 987 FrameSearchFlag::CHILDREN); 988 989 SfxHelpWindow_Impl* pHelpWindow = 0; 990 if (!xHelp.is()) 991 pHelpWindow = impl_createHelp(xHelp, xHelpContent); 992 else 993 pHelpWindow = (SfxHelpWindow_Impl*)VCLUnoHelper::GetWindow(xHelp->getComponentWindow()); 994 if (!xHelp.is() || !xHelpContent.is() || !pHelpWindow) 995 return sal_False; 996 997 #ifdef DBG_UTIL 998 ByteString aTmp("SfxHelp: HelpId = "); 999 aTmp += ByteString( aHelpURL, RTL_TEXTENCODING_UTF8 ); 1000 DBG_TRACE( aTmp.GetBuffer() ); 1001 #endif 1002 1003 pHelpWindow->SetHelpURL( aHelpURL ); 1004 pHelpWindow->loadHelpContent(aHelpURL); 1005 if ( rKeyword.Len() ) 1006 pHelpWindow->OpenKeyword( rKeyword ); 1007 1008 Reference < ::com::sun::star::awt::XTopWindow > xTopWindow( xHelp->getContainerWindow(), UNO_QUERY ); 1009 if ( xTopWindow.is() ) 1010 xTopWindow->toFront(); 1011 1012 return sal_True; 1013 } 1014 1015 String SfxHelp::CreateHelpURL( const String& aCommandURL, const String& rModuleName ) 1016 { 1017 String aURL; 1018 SfxHelp* pHelp = SAL_STATIC_CAST( SfxHelp*, Application::GetHelp() ); 1019 if ( pHelp ) 1020 aURL = pHelp->CreateHelpURL_Impl( aCommandURL, rModuleName ); 1021 return aURL; 1022 } 1023 1024 void SfxHelp::OpenHelpAgent( SfxFrame*, const rtl::OString& sHelpId ) 1025 { 1026 SfxHelp* pHelp = SAL_STATIC_CAST( SfxHelp*, Application::GetHelp() ); 1027 if ( pHelp ) 1028 pHelp->OpenHelpAgent( sHelpId ); 1029 } 1030 1031 void SfxHelp::OpenHelpAgent( const rtl::OString& sHelpId ) 1032 { 1033 if ( SvtHelpOptions().IsHelpAgentAutoStartMode() ) 1034 { 1035 SfxHelpOptions_Impl *pOpt = pImp->GetOptions(); 1036 if ( !pOpt->HasId( sHelpId ) ) 1037 return; 1038 1039 try 1040 { 1041 URL aURL; 1042 aURL.Complete = CreateHelpURL_Impl( String( ByteString(sHelpId), RTL_TEXTENCODING_UTF8 ), GetHelpModuleName_Impl() ); 1043 Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( 1044 ::rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" ) ), UNO_QUERY ); 1045 xTrans->parseStrict(aURL); 1046 1047 Reference < XFrame > xCurrentFrame; 1048 Reference < XDesktop > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance( 1049 DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY ); 1050 if ( xDesktop.is() ) 1051 xCurrentFrame = xDesktop->getCurrentFrame(); 1052 1053 Reference< XDispatchProvider > xDispProv( xCurrentFrame, UNO_QUERY ); 1054 Reference< XDispatch > xHelpDispatch; 1055 if ( xDispProv.is() ) 1056 xHelpDispatch = xDispProv->queryDispatch( 1057 aURL, ::rtl::OUString::createFromAscii("_helpagent"), 1058 FrameSearchFlag::PARENT | FrameSearchFlag::SELF ); 1059 1060 DBG_ASSERT( xHelpDispatch.is(), "OpenHelpAgent: could not get a dispatcher!" ); 1061 if ( xHelpDispatch.is() ) 1062 xHelpDispatch->dispatch( aURL, Sequence< PropertyValue >() ); 1063 } 1064 catch( const Exception& ) 1065 { 1066 DBG_ERRORFILE( "OpenHelpAgent: caught an exception while executing the dispatch!" ); 1067 } 1068 } 1069 } 1070 1071 String SfxHelp::GetDefaultHelpModule() 1072 { 1073 return getDefaultModule_Impl(); 1074 } 1075 1076 ::rtl::OUString SfxHelp::GetCurrentModuleIdentifier() 1077 { 1078 return getCurrentModuleIdentifier_Impl(); 1079 } 1080 1081