Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / sfx2 / source / appl / sfxhelp.cxx
blobcabfc39e8e47bdd474289e999765d900e5983149
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include "sfx2/sfxhelp.hxx"
31 #include <set>
32 #include <algorithm>
33 #include <com/sun/star/uno/Reference.h>
34 #include <com/sun/star/frame/XFrame.hpp>
35 #include <com/sun/star/frame/XComponentLoader.hpp>
36 #include <com/sun/star/lang/XComponent.hpp>
37 #include <comphelper/processfactory.hxx>
38 #include <com/sun/star/awt/XWindow.hpp>
39 #include <com/sun/star/awt/XTopWindow.hpp>
40 #include <com/sun/star/awt/PosSize.hpp>
41 #include <com/sun/star/frame/XDesktop.hpp>
42 #include <com/sun/star/util/XURLTransformer.hpp>
43 #include <com/sun/star/frame/XDispatch.hpp>
44 #include <com/sun/star/frame/XDispatchProvider.hpp>
45 #include <com/sun/star/container/XNameAccess.hpp>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <com/sun/star/frame/FrameSearchFlag.hpp>
48 #include <toolkit/helper/vclunohelper.hxx>
49 #include <com/sun/star/frame/XModuleManager.hpp>
50 #include <com/sun/star/system/XSystemShellExecute.hpp>
51 #include <com/sun/star/system/SystemShellExecuteFlags.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 <ucbhelper/content.hxx>
58 #include <unotools/pathoptions.hxx>
59 #include <rtl/ustring.hxx>
60 #include <osl/process.h>
61 #include <osl/file.hxx>
62 #include <unotools/bootstrap.hxx>
63 #include <rtl/uri.hxx>
64 #include <vcl/msgbox.hxx>
65 #include <svtools/ehdl.hxx>
66 #include <svtools/sfxecode.hxx>
67 #include <svl/svstdarr.hxx>
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/strbuf.hxx>
79 #include <rtl/string.hxx>
81 using namespace ::com::sun::star::beans;
82 using namespace ::com::sun::star::frame;
83 using namespace ::com::sun::star::uno;
84 using namespace ::com::sun::star::util;
85 using namespace ::com::sun::star::frame;
86 using namespace ::com::sun::star::lang;
87 using namespace ::com::sun::star::system;
89 class NoHelpErrorBox : public ErrorBox
91 public:
92 NoHelpErrorBox( Window* _pParent );
94 virtual void RequestHelp( const HelpEvent& rHEvt );
97 NoHelpErrorBox::NoHelpErrorBox( Window* _pParent ) :
99 ErrorBox( _pParent, WB_OK, String( SfxResId( RID_STR_HLPFILENOTEXIST ) ) )
101 // Error message: "No help available"
104 void NoHelpErrorBox::RequestHelp( const HelpEvent& )
106 // do nothing, because no help available
109 #define STARTERLIST 0
111 static bool impl_hasHelpInstalled( const rtl::OUString &rLang );
113 /// Return the locale we prefer for displaying help
114 static rtl::OUString HelpLocaleString()
116 static rtl::OUString aLocaleStr;
117 if (aLocaleStr.isEmpty())
119 const rtl::OUString aEnglish( "en" );
120 // detect installed locale
121 aLocaleStr = utl::ConfigManager::getLocale();
122 bool bOk = !aLocaleStr.isEmpty();
123 if ( !bOk )
124 aLocaleStr = aEnglish;
125 else
127 rtl::OUString aBaseInstallPath;
128 utl::Bootstrap::locateBaseInstallation(aBaseInstallPath);
129 static const char *szHelpPath = "/help/";
131 rtl::OUString sHelpPath = aBaseInstallPath +
132 rtl::OUString::createFromAscii(szHelpPath) + aLocaleStr;
133 osl::DirectoryItem aDirItem;
135 if (!osl::DirectoryItem::get(sHelpPath, aDirItem) == osl::FileBase::E_None)
137 bOk = false;
138 String sLang(aLocaleStr);
139 xub_StrLen nSepPos = sLang.Search( '-' );
140 if (nSepPos != STRING_NOTFOUND)
142 bOk = true;
143 sLang = sLang.Copy( 0, nSepPos );
144 sHelpPath = aBaseInstallPath +
145 rtl::OUString::createFromAscii(szHelpPath) + sLang;
146 if (!osl::DirectoryItem::get(sHelpPath, aDirItem) == osl::FileBase::E_None)
147 bOk = false;
151 // if not OK, and not even English installed, we use online help, and
152 // have to preserve the full locale name
153 if ( !bOk && impl_hasHelpInstalled( aEnglish ) )
154 aLocaleStr = aEnglish;
156 return aLocaleStr;
159 void AppendConfigToken( String& rURL, sal_Bool bQuestionMark, const rtl::OUString &rLang )
161 ::rtl::OUString aLocaleStr( rLang );
162 if ( aLocaleStr.isEmpty() )
163 aLocaleStr = HelpLocaleString();
165 // query part exists?
166 if ( bQuestionMark )
167 // no, so start with '?'
168 rURL += '?';
169 else
170 // yes, so only append with '&'
171 rURL += '&';
173 // set parameters
174 rURL += DEFINE_CONST_UNICODE("Language=");
175 rURL += String( aLocaleStr );
176 rURL += DEFINE_CONST_UNICODE("&System=");
177 rURL += SvtHelpOptions().GetSystem();
178 rURL += DEFINE_CONST_UNICODE("&Version=");
179 rURL += utl::ConfigManager::getProductVersion();
182 sal_Bool GetHelpAnchor_Impl( const String& _rURL, String& _rAnchor )
184 sal_Bool bRet = sal_False;
185 ::rtl::OUString sAnchor;
189 ::ucbhelper::Content aCnt( INetURLObject( _rURL ).GetMainURL( INetURLObject::NO_DECODE ),
190 Reference< ::com::sun::star::ucb::XCommandEnvironment > () );
191 if ( ( aCnt.getPropertyValue( ::rtl::OUString("AnchorName") ) >>= sAnchor ) )
194 if ( !sAnchor.isEmpty() )
196 _rAnchor = String( sAnchor );
197 bRet = sal_True;
200 else
202 SAL_WARN( "sfx2.appl", "Property 'AnchorName' is missing" );
205 catch (const ::com::sun::star::uno::Exception&)
209 return bRet;
212 class SfxHelpOptions_Impl : public utl::ConfigItem
214 private:
215 std::set < rtl::OString > m_aIds;
217 public:
218 SfxHelpOptions_Impl();
219 ~SfxHelpOptions_Impl();
221 bool HasId( const rtl::OString& rId ) { return m_aIds.size() ? m_aIds.find( rId ) != m_aIds.end() : false; }
222 virtual void Notify( const com::sun::star::uno::Sequence< rtl::OUString >& aPropertyNames );
223 virtual void Commit();
226 static Sequence< ::rtl::OUString > GetPropertyNames()
228 static const char* aPropNames[] =
230 "HelpAgentStarterList",
233 const int nCount = sizeof( aPropNames ) / sizeof( const char* );
234 Sequence< ::rtl::OUString > aNames( nCount );
235 ::rtl::OUString* pNames = aNames.getArray();
236 ::rtl::OUString* pEnd = pNames + aNames.getLength();
237 int i = 0;
238 for ( ; pNames != pEnd; ++pNames )
239 *pNames = ::rtl::OUString::createFromAscii( aPropNames[i++] );
241 return aNames;
244 SfxHelpOptions_Impl::SfxHelpOptions_Impl()
245 : ConfigItem( ::rtl::OUString("Office.SFX/Help") )
247 Sequence< ::rtl::OUString > aNames = GetPropertyNames();
248 Sequence< Any > aValues = GetProperties( aNames );
249 EnableNotification( aNames );
250 const Any* pValues = aValues.getConstArray();
251 DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" );
252 if ( aValues.getLength() == aNames.getLength() )
254 for ( int nProp = 0; nProp < aNames.getLength(); nProp++ )
256 DBG_ASSERT( pValues[nProp].hasValue(), "property value missing" );
257 if ( pValues[nProp].hasValue() )
259 switch ( nProp )
261 case STARTERLIST :
263 ::rtl::OUString aCodedList;
264 if ( pValues[nProp] >>= aCodedList )
266 rtl::OString aTmp(
267 rtl::OUStringToOString(
268 aCodedList, RTL_TEXTENCODING_UTF8 ) );
269 sal_Int32 nIndex = 0;
272 rtl::OString aToken = aTmp.getToken( 0, ',', nIndex );
273 if ( !aToken.isEmpty() )
274 m_aIds.insert( aToken );
276 while ( nIndex >= 0 );
278 else {
279 SAL_WARN( "sfx2.appl", "Wrong property type!" );
282 break;
285 default:
286 SAL_WARN( "sfx2.appl", "Wrong property!" );
287 break;
294 SfxHelpOptions_Impl::~SfxHelpOptions_Impl()
299 void SfxHelpOptions_Impl::Notify( const com::sun::star::uno::Sequence< rtl::OUString >& )
303 void SfxHelpOptions_Impl::Commit()
307 class SfxHelp_Impl
309 private:
310 sal_Bool m_bIsDebug; // environment variable "help_debug=1"
311 SfxHelpOptions_Impl* m_pOpt; // the options
312 ::std::vector< ::rtl::OUString > m_aModulesList; // list of all installed modules
314 public:
315 SfxHelp_Impl( sal_Bool bDebug );
316 ~SfxHelp_Impl();
318 SfxHelpOptions_Impl* GetOptions();
319 static String GetHelpText( const rtl::OUString& aCommandURL, const String& rModule );
322 SfxHelp_Impl::SfxHelp_Impl( sal_Bool bDebug ) :
324 m_bIsDebug ( bDebug ),
325 m_pOpt ( NULL )
330 SfxHelp_Impl::~SfxHelp_Impl()
332 delete m_pOpt;
335 String SfxHelp_Impl::GetHelpText( const rtl::OUString& aCommandURL, const String& rModule )
337 // create help url
338 String aHelpURL = SfxHelp::CreateHelpURL( aCommandURL, rModule );
339 // added 'active' parameter
340 aHelpURL.Insert( String( DEFINE_CONST_UNICODE("&Active=true") ), aHelpURL.SearchBackward( '#' ) );
341 // load help string
342 return SfxContentHelper::GetActiveHelpString( aHelpURL );
345 SfxHelpOptions_Impl* SfxHelp_Impl::GetOptions()
347 // create if not exists
348 if ( !m_pOpt )
349 m_pOpt = new SfxHelpOptions_Impl;
350 return m_pOpt;
353 SfxHelp::SfxHelp() :
355 bIsDebug( sal_False ),
356 pImp ( NULL )
359 // read the environment variable "HELP_DEBUG"
360 // if it's set, you will see debug output on active help
362 ::rtl::OUString sHelpDebug;
363 ::rtl::OUString sEnvVarName( "HELP_DEBUG" );
364 osl_getEnvironment( sEnvVarName.pData, &sHelpDebug.pData );
365 bIsDebug = !sHelpDebug.isEmpty();
368 pImp = new SfxHelp_Impl( bIsDebug );
370 ::rtl::OUString aLocaleStr = HelpLocaleString();
372 sal_Int32 nSepPos = aLocaleStr.indexOf( '_' );
373 if ( nSepPos != -1 )
375 aLanguageStr = aLocaleStr.copy( 0, nSepPos );
376 aCountryStr = aLocaleStr.copy( nSepPos+1 );
378 else
380 nSepPos = aLocaleStr.indexOf( '-' );
381 if ( nSepPos != -1 )
383 aLanguageStr = aLocaleStr.copy( 0, nSepPos );
384 aCountryStr = aLocaleStr.copy( nSepPos+1 );
386 else
388 aLanguageStr = aLocaleStr;
393 SfxHelp::~SfxHelp()
395 delete pImp;
398 ::rtl::OUString getDefaultModule_Impl()
400 rtl::OUString sDefaultModule;
401 SvtModuleOptions aModOpt;
402 if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
403 sDefaultModule = DEFINE_CONST_UNICODE("swriter");
404 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) )
405 sDefaultModule = DEFINE_CONST_UNICODE("scalc");
406 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) )
407 sDefaultModule = DEFINE_CONST_UNICODE("simpress");
408 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) )
409 sDefaultModule = DEFINE_CONST_UNICODE("sdraw");
410 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SMATH ) )
411 sDefaultModule = DEFINE_CONST_UNICODE("smath");
412 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SCHART ) )
413 sDefaultModule = DEFINE_CONST_UNICODE("schart");
414 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SBASIC ) )
415 sDefaultModule = DEFINE_CONST_UNICODE("sbasic");
416 else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) )
417 sDefaultModule = DEFINE_CONST_UNICODE("sdatabase");
418 else
420 SAL_WARN( "sfx2.appl", "getDefaultModule_Impl(): no module installed" );
422 return sDefaultModule;
425 ::rtl::OUString getCurrentModuleIdentifier_Impl()
427 ::rtl::OUString sIdentifier;
428 Reference < XFrame > xCurrentFrame;
429 Reference < XModuleManager > xModuleManager( ::comphelper::getProcessServiceFactory()->createInstance(
430 DEFINE_CONST_UNICODE("com.sun.star.frame.ModuleManager") ), UNO_QUERY );
431 Reference < XDesktop > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
432 DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );
433 if ( xDesktop.is() )
434 xCurrentFrame = xDesktop->getCurrentFrame();
436 if ( xCurrentFrame.is() && xModuleManager.is() )
440 sIdentifier = xModuleManager->identify( xCurrentFrame );
442 catch (const ::com::sun::star::frame::UnknownModuleException&)
444 DBG_WARNING( "SfxHelp::getCurrentModuleIdentifier_Impl(): unknown module (help in help?)" );
446 catch (const Exception&)
448 SAL_WARN( "sfx2.appl", "SfxHelp::getCurrentModuleIdentifier_Impl(): exception of XModuleManager::identify()" );
452 return sIdentifier;
455 String SfxHelp::GetHelpModuleName_Impl()
457 String sModuleName;
458 rtl::OUString aFactoryShortName;
459 rtl::OUString aModuleIdentifier = getCurrentModuleIdentifier_Impl();
461 if ( !aModuleIdentifier.isEmpty() )
465 Reference < XModuleManager > xModuleManager(
466 ::comphelper::getProcessServiceFactory()->createInstance(
467 DEFINE_CONST_UNICODE("com.sun.star.frame.ModuleManager") ), UNO_QUERY );
468 Sequence< PropertyValue > lProps;
469 Reference< ::com::sun::star::container::XNameAccess > xCont( xModuleManager, UNO_QUERY);
470 if ( xCont.is() )
471 xCont->getByName( aModuleIdentifier ) >>= lProps;
472 for ( sal_Int32 i = 0; i < lProps.getLength(); ++i )
474 if ( lProps[i].Name == "ooSetupFactoryShortName" )
476 lProps[i].Value >>= aFactoryShortName;
477 break;
481 catch (const Exception&)
483 SAL_WARN( "sfx2.appl", "SfxHelp::GetHelpModuleName_Impl(): exception of XNameAccess::getByName()" );
487 rtl::OUString sDefaultModule = getDefaultModule_Impl();
488 if ( !aFactoryShortName.isEmpty() )
490 // Map some module identifiers to their "real" help module string.
491 if ( aFactoryShortName == "chart2" )
492 aFactoryShortName = rtl::OUString( "schart" );
493 else if ( aFactoryShortName == "BasicIDE" )
494 aFactoryShortName = rtl::OUString( "sbasic" );
495 else if ( aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("sweb"))
496 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("sglobal"))
497 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("swxform")) )
498 aFactoryShortName = rtl::OUString( "swriter" );
499 else if ( aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbquery"))
500 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbbrowser"))
501 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbrelation"))
502 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbtable"))
503 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbapp"))
504 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbreport"))
505 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("swreport"))
506 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbbrowser"))
507 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("swform")) )
508 aFactoryShortName = rtl::OUString( "sdatabase" );
509 else if ( aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("sbibliography"))
510 || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("StartModule")) )
511 aFactoryShortName = sDefaultModule;
513 else
514 aFactoryShortName = sDefaultModule;
516 sModuleName = String( aFactoryShortName );
517 return sModuleName;
520 String SfxHelp::CreateHelpURL_Impl( const String& aCommandURL, const String& rModuleName )
522 // build up the help URL
523 String aHelpURL;
524 sal_Bool bHasAnchor = sal_False;
525 String aAnchor;
527 String aModuleName( rModuleName );
528 if ( aModuleName.Len() == 0 )
529 aModuleName = getDefaultModule_Impl();
531 aHelpURL = String::CreateFromAscii("vnd.sun.star.help://");
532 aHelpURL += aModuleName;
534 if ( !aCommandURL.Len() )
535 aHelpURL += String::CreateFromAscii("/start");
536 else
538 aHelpURL += '/';
539 aHelpURL += String( rtl::Uri::encode( aCommandURL,
540 rtl_UriCharClassRelSegment,
541 rtl_UriEncodeKeepEscapes,
542 RTL_TEXTENCODING_UTF8 ));
544 String aTempURL = aHelpURL;
545 AppendConfigToken( aTempURL, sal_True );
546 bHasAnchor = GetHelpAnchor_Impl( aTempURL, aAnchor );
549 AppendConfigToken( aHelpURL, sal_True );
551 if ( bHasAnchor )
553 aHelpURL += '#';
554 aHelpURL += aAnchor;
557 return aHelpURL;
560 SfxHelpWindow_Impl* impl_createHelp(Reference< XFrame >& rHelpTask ,
561 Reference< XFrame >& rHelpContent)
563 Reference < XFrame > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
564 DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );
566 // otherwhise - create new help task
567 Reference< XFrame > xHelpTask = xDesktop->findFrame(
568 ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")),
569 FrameSearchFlag::TASKS | FrameSearchFlag::CREATE);
570 if (!xHelpTask.is())
571 return 0;
573 // create all internal windows and sub frames ...
574 Reference< ::com::sun::star::awt::XWindow > xParentWindow = xHelpTask->getContainerWindow();
575 Window* pParentWindow = VCLUnoHelper::GetWindow( xParentWindow );
576 SfxHelpWindow_Impl* pHelpWindow = new SfxHelpWindow_Impl( xHelpTask, pParentWindow, WB_DOCKBORDER );
577 Reference< ::com::sun::star::awt::XWindow > xHelpWindow = VCLUnoHelper::GetInterface( pHelpWindow );
579 Reference< XFrame > xHelpContent;
580 if (xHelpTask->setComponent( xHelpWindow, Reference< XController >() ))
582 // Customize UI ...
583 xHelpTask->setName( ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")) );
585 Reference< XPropertySet > xProps(xHelpTask, UNO_QUERY);
586 if (xProps.is())
587 xProps->setPropertyValue(
588 DEFINE_CONST_UNICODE("Title"),
589 makeAny(::rtl::OUString(String(SfxResId(STR_HELP_WINDOW_TITLE)))));
591 pHelpWindow->setContainerWindow( xParentWindow );
592 xParentWindow->setVisible(sal_True);
593 xHelpWindow->setVisible(sal_True);
595 // This sub frame is created internaly (if we called new SfxHelpWindow_Impl() ...)
596 // It should exist :-)
597 xHelpContent = xHelpTask->findFrame(::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")), FrameSearchFlag::CHILDREN);
600 if (!xHelpContent.is())
601 delete pHelpWindow;
603 xHelpContent->setName(::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")));
605 rHelpTask = xHelpTask;
606 rHelpContent = xHelpContent;
607 return pHelpWindow;
610 XubString SfxHelp::GetHelpText( const String& aCommandURL, const Window* pWindow )
612 String sModuleName = GetHelpModuleName_Impl();
613 String sHelpText = pImp->GetHelpText( aCommandURL, sModuleName );
615 rtl::OString aNewHelpId;
617 if ( pWindow && !sHelpText.Len() )
619 // no help text found -> try with parent help id.
620 Window* pParent = pWindow->GetParent();
621 while ( pParent )
623 aNewHelpId = pParent->GetHelpId();
624 sHelpText = pImp->GetHelpText( rtl::OStringToOUString(aNewHelpId, RTL_TEXTENCODING_UTF8), sModuleName );
625 if ( sHelpText.Len() > 0 )
626 pParent = NULL;
627 else
628 pParent = pParent->GetParent();
631 if ( bIsDebug && !sHelpText.Len() )
632 aNewHelpId = rtl::OString();
635 // add some debug information?
636 if ( bIsDebug )
638 sHelpText += DEFINE_CONST_UNICODE("\n-------------\n");
639 sHelpText += String( sModuleName );
640 sHelpText += DEFINE_CONST_UNICODE(": ");
641 sHelpText += aCommandURL;
642 if ( !aNewHelpId.isEmpty() )
644 sHelpText += DEFINE_CONST_UNICODE(" - ");
645 sHelpText += String(rtl::OStringToOUString(aNewHelpId, RTL_TEXTENCODING_UTF8));
649 return sHelpText;
652 /// Check for built-in help
653 static bool impl_hasHelpInstalled( const rtl::OUString &rLang = rtl::OUString() )
655 String aHelpRootURL( DEFINE_CONST_OUSTRING("vnd.sun.star.help://") );
656 AppendConfigToken( aHelpRootURL, sal_True, rLang );
657 Sequence< ::rtl::OUString > aFactories = SfxContentHelper::GetResultSet( aHelpRootURL );
659 return ( aFactories.getLength() != 0 );
662 sal_Bool SfxHelp::SearchKeyword( const XubString& rKeyword )
664 return Start_Impl( String(), NULL, rKeyword );
667 sal_Bool SfxHelp::Start( const String& rURL, const Window* pWindow )
669 return Start_Impl( rURL, pWindow, String() );
672 /// Redirect the vnd.sun.star.help:// urls to http://help.libreoffice.org
673 static bool impl_showOnlineHelp( const String& rURL )
675 String aInternal( "vnd.sun.star.help://" );
676 if ( rURL.Len() <= aInternal.Len() || rURL.Copy( 0, aInternal.Len() ) != aInternal )
677 return false;
679 rtl::OUString aHelpLink( "http://help.libreoffice.org/" );
680 aHelpLink += rURL.Copy( aInternal.Len() );
683 Reference< XSystemShellExecute > xSystemShell(
684 ::comphelper::getProcessServiceFactory()->createInstance(
685 rtl::OUString( "com.sun.star.system.SystemShellExecute" ) ),
686 UNO_QUERY );
688 if ( xSystemShell.is() )
690 xSystemShell->execute( aHelpLink, rtl::OUString(), SystemShellExecuteFlags::URIS_ONLY );
691 return true;
694 catch (const Exception&)
697 return false;
700 sal_Bool SfxHelp::Start_Impl( const String& rURL, const Window* pWindow, const String& rKeyword )
702 String aHelpRootURL( DEFINE_CONST_OUSTRING("vnd.sun.star.help://") );
703 AppendConfigToken( aHelpRootURL, sal_True);
704 Sequence< ::rtl::OUString > aFactories = SfxContentHelper::GetResultSet( aHelpRootURL );
706 /* rURL may be
707 - a "real" URL
708 - a HelpID (formerly a long, now a string)
709 If rURL is a URL, CreateHelpURL should be called for this URL
710 If rURL is an arbitrary string, the same should happen, but the URL should be tried out
711 if it delivers real help content. In case only the Help Error Document is returned, the
712 parent of the window for that help was called, is asked for its HelpID.
713 For compatibility reasons this upward search is not implemented for "real" URLs.
714 Help keyword search now is implemented as own method; in former versions it
715 was done via Help::Start, but this implementation conflicted with the upward search.
717 String aHelpURL;
718 INetURLObject aParser( rURL );
719 INetProtocol nProtocol = aParser.GetProtocol();
720 String aHelpModuleName( GetHelpModuleName_Impl() );
722 ::rtl::OUString sKeyword;
723 switch ( nProtocol )
725 case INET_PROT_VND_SUN_STAR_HELP:
726 // already a vnd.sun.star.help URL -> nothing to do
727 aHelpURL = rURL;
728 break;
729 default:
731 // no URL, just a HelpID (maybe empty in case of keyword search)
732 aHelpURL = CreateHelpURL_Impl( rURL, aHelpModuleName );
734 // pb i91715: strings begin with ".HelpId:" are not words of the basic ide
735 // they are helpid-strings used by the testtool -> so we ignore them
736 static const String sHelpIdScheme( DEFINE_CONST_OUSTRING(".HelpId:") );
737 if ( rURL.Search( sHelpIdScheme ) != 0 )
738 sKeyword = ::rtl::OUString( rURL );
740 if ( impl_hasHelpInstalled() && pWindow && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
742 // no help found -> try with parent help id.
743 Window* pParent = pWindow->GetParent();
744 while ( pParent )
746 rtl::OString aHelpId = pParent->GetHelpId();
747 aHelpURL = CreateHelpURL( rtl::OStringToOUString(aHelpId, RTL_TEXTENCODING_UTF8), aHelpModuleName );
748 if ( !SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
749 break;
750 else
752 pParent = pParent->GetParent();
753 if ( !pParent )
754 // create help url of start page ( helpid == 0 -> start page)
755 aHelpURL = CreateHelpURL( String(), aHelpModuleName );
759 break;
763 if ( !impl_hasHelpInstalled() )
765 if ( impl_showOnlineHelp( aHelpURL ) )
766 return sal_True;
767 else
769 NoHelpErrorBox aErrBox( const_cast< Window* >( pWindow ) );
770 aErrBox.Execute();
771 return sal_False;
775 Reference < XFrame > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
776 DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );
778 // check if help window is still open
779 // If not, create a new one and return access directly to the internal sub frame showing the help content
780 // search must be done here; search one desktop level could return an arbitraty frame
781 Reference< XFrame > xHelp = xDesktop->findFrame(
782 ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")),
783 FrameSearchFlag::CHILDREN);
784 Reference< XFrame > xHelpContent = xDesktop->findFrame(
785 ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")),
786 FrameSearchFlag::CHILDREN);
788 SfxHelpWindow_Impl* pHelpWindow = 0;
789 if (!xHelp.is())
790 pHelpWindow = impl_createHelp(xHelp, xHelpContent);
791 else
792 pHelpWindow = (SfxHelpWindow_Impl*)VCLUnoHelper::GetWindow(xHelp->getComponentWindow());
793 if (!xHelp.is() || !xHelpContent.is() || !pHelpWindow)
794 return sal_False;
796 #ifdef DBG_UTIL
797 rtl::OStringBuffer aTmp(RTL_CONSTASCII_STRINGPARAM("SfxHelp: HelpId = "));
798 aTmp.append(rtl::OUStringToOString(aHelpURL, RTL_TEXTENCODING_UTF8));
799 OSL_TRACE( aTmp.getStr() );
800 #endif
802 pHelpWindow->SetHelpURL( aHelpURL );
803 pHelpWindow->loadHelpContent(aHelpURL);
804 if ( rKeyword.Len() )
805 pHelpWindow->OpenKeyword( rKeyword );
807 Reference < ::com::sun::star::awt::XTopWindow > xTopWindow( xHelp->getContainerWindow(), UNO_QUERY );
808 if ( xTopWindow.is() )
809 xTopWindow->toFront();
811 return sal_True;
814 String SfxHelp::CreateHelpURL( const String& aCommandURL, const String& rModuleName )
816 String aURL;
817 SfxHelp* pHelp = (static_cast< SfxHelp* >(Application::GetHelp()) );
818 if ( pHelp )
819 aURL = pHelp->CreateHelpURL_Impl( aCommandURL, rModuleName );
820 return aURL;
823 void SfxHelp::OpenHelpAgent( SfxFrame*, const rtl::OString& sHelpId )
825 SfxHelp* pHelp = (static_cast< SfxHelp* >(Application::GetHelp()) );
826 if ( pHelp )
827 pHelp->OpenHelpAgent( sHelpId );
830 void SfxHelp::OpenHelpAgent( const rtl::OString& sHelpId )
832 if ( SvtHelpOptions().IsHelpAgentAutoStartMode() )
834 SfxHelpOptions_Impl *pOpt = pImp->GetOptions();
835 if ( !pOpt->HasId( sHelpId ) )
836 return;
840 URL aURL;
841 aURL.Complete = CreateHelpURL_Impl( rtl::OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8), GetHelpModuleName_Impl() );
842 Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance(
843 ::rtl::OUString("com.sun.star.util.URLTransformer") ), UNO_QUERY );
844 xTrans->parseStrict(aURL);
846 Reference < XFrame > xCurrentFrame;
847 Reference < XDesktop > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
848 DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );
849 if ( xDesktop.is() )
850 xCurrentFrame = xDesktop->getCurrentFrame();
852 Reference< XDispatchProvider > xDispProv( xCurrentFrame, UNO_QUERY );
853 Reference< XDispatch > xHelpDispatch;
854 if ( xDispProv.is() )
855 xHelpDispatch = xDispProv->queryDispatch(
856 aURL, ::rtl::OUString("_helpagent"),
857 FrameSearchFlag::PARENT | FrameSearchFlag::SELF );
859 DBG_ASSERT( xHelpDispatch.is(), "OpenHelpAgent: could not get a dispatcher!" );
860 if ( xHelpDispatch.is() )
861 xHelpDispatch->dispatch( aURL, Sequence< PropertyValue >() );
863 catch (const Exception&)
865 SAL_WARN( "sfx2.appl", "OpenHelpAgent: caught an exception while executing the dispatch!" );
870 String SfxHelp::GetDefaultHelpModule()
872 return getDefaultModule_Impl();
875 ::rtl::OUString SfxHelp::GetCurrentModuleIdentifier()
877 return getCurrentModuleIdentifier_Impl();
880 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */