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 rtl::OString aTmp( aCodedList, aCodedList.getLength(), 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 delete pHelpWindow; 850 851 xHelpContent->setName(::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP"))); 852 853 rHelpTask = xHelpTask; 854 rHelpContent = xHelpContent; 855 return pHelpWindow; 856 } 857 858 XubString SfxHelp::GetHelpText( const String& aCommandURL, const Window* pWindow ) 859 { 860 String sModuleName = GetHelpModuleName_Impl(); 861 String sHelpText = pImp->GetHelpText( aCommandURL, sModuleName ); 862 863 ByteString aNewHelpId; 864 865 if ( pWindow && !sHelpText.Len() ) 866 { 867 // no help text found -> try with parent help id. 868 Window* pParent = pWindow->GetParent(); 869 while ( pParent ) 870 { 871 aNewHelpId = pParent->GetHelpId(); 872 sHelpText = pImp->GetHelpText( String( aNewHelpId, RTL_TEXTENCODING_UTF8 ), sModuleName ); 873 if ( sHelpText.Len() > 0 ) 874 pParent = NULL; 875 else 876 pParent = pParent->GetParent(); 877 } 878 879 if ( bIsDebug && !sHelpText.Len() ) 880 aNewHelpId.Erase(); 881 } 882 883 // add some debug information? 884 if ( bIsDebug ) 885 { 886 sHelpText += DEFINE_CONST_UNICODE("\n-------------\n"); 887 sHelpText += String( sModuleName ); 888 sHelpText += DEFINE_CONST_UNICODE(": "); 889 sHelpText += aCommandURL; 890 if ( aNewHelpId.Len() ) 891 { 892 sHelpText += DEFINE_CONST_UNICODE(" - "); 893 sHelpText += String( aNewHelpId, RTL_TEXTENCODING_UTF8 ); 894 } 895 } 896 897 return sHelpText; 898 } 899 900 sal_Bool SfxHelp::SearchKeyword( const XubString& rKeyword ) 901 { 902 return Start_Impl( String(), NULL, rKeyword ); 903 } 904 905 sal_Bool SfxHelp::Start( const String& rURL, const Window* pWindow ) 906 { 907 return Start_Impl( rURL, pWindow, String() ); 908 } 909 910 sal_Bool SfxHelp::Start_Impl( const String& rURL, const Window* pWindow, const String& rKeyword ) 911 { 912 // check if help is available 913 String aHelpRootURL( DEFINE_CONST_OUSTRING("vnd.sun.star.help://") ); 914 AppendConfigToken_Impl( aHelpRootURL, sal_True ); 915 Sequence< ::rtl::OUString > aFactories = SfxContentHelper::GetResultSet( aHelpRootURL ); 916 if ( 0 == aFactories.getLength() ) 917 { 918 // no factories -> no help -> error message and return 919 NoHelpErrorBox aErrBox( const_cast< Window* >( pWindow ) ); 920 aErrBox.Execute(); 921 return sal_False; 922 } 923 924 /* rURL may be 925 - a "real" URL 926 - a HelpID (formerly a long, now a string) 927 If rURL is a URL, CreateHelpURL should be called for this URL 928 If rURL is an arbitrary string, the same should happen, but the URL should be tried out 929 if it delivers real help content. In case only the Help Error Document is returned, the 930 parent of the window for that help was called, is asked for its HelpID. 931 For compatibility reasons this upward search is not implemented for "real" URLs. 932 Help keyword search now is implemented as own method; in former versions it 933 was done via Help::Start, but this implementation conflicted with the upward search. 934 */ 935 String aHelpURL; 936 INetURLObject aParser( rURL ); 937 INetProtocol nProtocol = aParser.GetProtocol(); 938 String aHelpModuleName( GetHelpModuleName_Impl() ); 939 switch ( nProtocol ) 940 { 941 case INET_PROT_VND_SUN_STAR_HELP: 942 // already a vnd.sun.star.help URL -> nothing to do 943 aHelpURL = rURL; 944 break; 945 default: 946 { 947 // no URL, just a HelpID (maybe empty in case of keyword search) 948 aHelpURL = CreateHelpURL_Impl( rURL, aHelpModuleName ); 949 if ( pWindow && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) ) 950 { 951 // no help found -> try with parent help id. 952 Window* pParent = pWindow->GetParent(); 953 while ( pParent ) 954 { 955 ByteString aHelpId = pParent->GetHelpId(); 956 aHelpURL = CreateHelpURL( String( aHelpId, RTL_TEXTENCODING_UTF8 ), aHelpModuleName ); 957 if ( !SfxContentHelper::IsHelpErrorDocument( aHelpURL ) ) 958 break; 959 else 960 { 961 pParent = pParent->GetParent(); 962 if ( !pParent ) 963 // create help url of start page ( helpid == 0 -> start page) 964 aHelpURL = CreateHelpURL( String(), aHelpModuleName ); 965 } 966 } 967 } 968 break; 969 } 970 } 971 972 Reference < XFrame > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance( 973 DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY ); 974 975 // check if help window is still open 976 // If not, create a new one and return access directly to the internal sub frame showing the help content 977 // search must be done here; search one desktop level could return an arbitraty frame 978 Reference< XFrame > xHelp = xDesktop->findFrame( 979 ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")), 980 FrameSearchFlag::CHILDREN); 981 Reference< XFrame > xHelpContent = xDesktop->findFrame( 982 ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")), 983 FrameSearchFlag::CHILDREN); 984 985 SfxHelpWindow_Impl* pHelpWindow = 0; 986 if (!xHelp.is()) 987 pHelpWindow = impl_createHelp(xHelp, xHelpContent); 988 else 989 pHelpWindow = (SfxHelpWindow_Impl*)VCLUnoHelper::GetWindow(xHelp->getComponentWindow()); 990 if (!xHelp.is() || !xHelpContent.is() || !pHelpWindow) 991 return sal_False; 992 993 #ifdef DBG_UTIL 994 ByteString aTmp("SfxHelp: HelpId = "); 995 aTmp += ByteString( aHelpURL, RTL_TEXTENCODING_UTF8 ); 996 DBG_TRACE( aTmp.GetBuffer() ); 997 #endif 998 999 pHelpWindow->SetHelpURL( aHelpURL ); 1000 pHelpWindow->loadHelpContent(aHelpURL); 1001 if ( rKeyword.Len() ) 1002 pHelpWindow->OpenKeyword( rKeyword ); 1003 1004 Reference < ::com::sun::star::awt::XTopWindow > xTopWindow( xHelp->getContainerWindow(), UNO_QUERY ); 1005 if ( xTopWindow.is() ) 1006 xTopWindow->toFront(); 1007 1008 return sal_True; 1009 } 1010 1011 String SfxHelp::CreateHelpURL( const String& aCommandURL, const String& rModuleName ) 1012 { 1013 String aURL; 1014 SfxHelp* pHelp = SAL_STATIC_CAST( SfxHelp*, Application::GetHelp() ); 1015 if ( pHelp ) 1016 aURL = pHelp->CreateHelpURL_Impl( aCommandURL, rModuleName ); 1017 return aURL; 1018 } 1019 1020 void SfxHelp::OpenHelpAgent( SfxFrame*, const rtl::OString& sHelpId ) 1021 { 1022 SfxHelp* pHelp = SAL_STATIC_CAST( SfxHelp*, Application::GetHelp() ); 1023 if ( pHelp ) 1024 pHelp->OpenHelpAgent( sHelpId ); 1025 } 1026 1027 void SfxHelp::OpenHelpAgent( const rtl::OString& sHelpId ) 1028 { 1029 if ( SvtHelpOptions().IsHelpAgentAutoStartMode() ) 1030 { 1031 SfxHelpOptions_Impl *pOpt = pImp->GetOptions(); 1032 if ( !pOpt->HasId( sHelpId ) ) 1033 return; 1034 1035 try 1036 { 1037 URL aURL; 1038 aURL.Complete = CreateHelpURL_Impl( String( ByteString(sHelpId), RTL_TEXTENCODING_UTF8 ), GetHelpModuleName_Impl() ); 1039 Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( 1040 ::rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" ) ), UNO_QUERY ); 1041 xTrans->parseStrict(aURL); 1042 1043 Reference < XFrame > xCurrentFrame; 1044 Reference < XDesktop > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance( 1045 DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY ); 1046 if ( xDesktop.is() ) 1047 xCurrentFrame = xDesktop->getCurrentFrame(); 1048 1049 Reference< XDispatchProvider > xDispProv( xCurrentFrame, UNO_QUERY ); 1050 Reference< XDispatch > xHelpDispatch; 1051 if ( xDispProv.is() ) 1052 xHelpDispatch = xDispProv->queryDispatch( 1053 aURL, ::rtl::OUString::createFromAscii("_helpagent"), 1054 FrameSearchFlag::PARENT | FrameSearchFlag::SELF ); 1055 1056 DBG_ASSERT( xHelpDispatch.is(), "OpenHelpAgent: could not get a dispatcher!" ); 1057 if ( xHelpDispatch.is() ) 1058 xHelpDispatch->dispatch( aURL, Sequence< PropertyValue >() ); 1059 } 1060 catch( const Exception& ) 1061 { 1062 DBG_ERRORFILE( "OpenHelpAgent: caught an exception while executing the dispatch!" ); 1063 } 1064 } 1065 } 1066 1067 String SfxHelp::GetDefaultHelpModule() 1068 { 1069 return getDefaultModule_Impl(); 1070 } 1071 1072 ::rtl::OUString SfxHelp::GetCurrentModuleIdentifier() 1073 { 1074 return getCurrentModuleIdentifier_Impl(); 1075 } 1076 1077