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