/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
/// Check for built-in help /// Check if help/<lang>/err.html file exist bool impl_hasHelpInstalled()
{ if (comphelper::LibreOfficeKit::isActive()) returnfalse;
SAL_INFO( "sfx.appl", "Checking old help installed " << bOK); return bOK;
}
/// Check for html built-in help /// Check if help/lang/text folder exist. Only html has it. bool impl_hasHTMLHelpInstalled()
{ if (comphelper::LibreOfficeKit::isActive()) returnfalse;
OUString helpRootURL = getHelpRootURL() + "/" + aLocaleStr + "/text"; bool bOK = impl_checkHelpLocalePath( helpRootURL );
SAL_INFO( "sfx.appl", "Checking new help (html) installed " << bOK); return bOK;
}
} // namespace
/// Return the locale we prefer for displaying help static OUString const & HelpLocaleString()
{ if (comphelper::LibreOfficeKit::isActive()) return comphelper::LibreOfficeKit::getLanguageTag().getBcp47();
static OUString aLocaleStr; if (!aLocaleStr.isEmpty()) return aLocaleStr;
SfxHelp::SfxHelp()
: bIsDebug(false)
, bLaunchingHelp(false)
{ // read the environment variable "HELP_DEBUG" // if it's set, you will see debug output on active help
OUString sHelpDebug;
OUString sEnvVarName( u"HELP_DEBUG"_ustr );
osl_getEnvironment( sEnvVarName.pData, &sHelpDebug.pData );
bIsDebug = !sHelpDebug.isEmpty();
}
//rhbz#1438876 detect preferred module for this help id, e.g. csv dialog //for calc import before any toplevel is created and so context is //otherwise unknown. Cosmetic, same help is shown in any case because its //in the shared section, but title bar would state "Writer" when context is //expected to be "Calc"
std::u16string_view sRemainder; if (o3tl::starts_with(rHelpID, u"modules/", &sRemainder))
{
std::size_t nEndModule = sRemainder.find(u'/');
aFactoryShortName = nEndModule != std::u16string_view::npos
? sRemainder.substr(0, nEndModule) : sRemainder;
}
if (!aFactoryShortName.isEmpty())
aFactoryShortName = MapModuleIdentifier(aFactoryShortName); if (aFactoryShortName.isEmpty())
aFactoryShortName = getDefaultModule_Impl();
return aFactoryShortName;
}
OUString SfxHelp::CreateHelpURL_Impl( const OUString& aCommandURL, const OUString& rModuleName )
{ // build up the help URL
OUStringBuffer aHelpURL("vnd.sun.star.help://"); bool bHasAnchor = false;
OUString aAnchor;
OUString aModuleName( rModuleName ); if (aModuleName.isEmpty())
aModuleName = getDefaultModule_Impl();
// This sub frame is created internally (if we called new SfxHelpWindow_Impl() ...) // It should exist :-)
xHelpContent = xHelpTask->findFrame(u"OFFICE_HELP"_ustr, FrameSearchFlag::CHILDREN);
}
if (!xHelpContent.is())
{
pHelpWindow.disposeAndClear(); return nullptr;
}
OUString SfxHelp::GetURLHelpText(std::u16string_view aURL)
{ // hyperlinks are handled differently in Online if (comphelper::LibreOfficeKit::isActive()) return OUString();
// use a tempfile since e.g. xdg-open doesn't support URL-parameters with file:// URLs staticbool impl_showOfflineHelp(const OUString& rURL, weld::Widget* pDialogParent)
{
OUString aBaseInstallPath = getHelpRootURL(); // For the flatpak case, find the pathname outside the flatpak sandbox that corresponds to // aBaseInstallPath, because that is what needs to be stored in aTempFile below: if (flatpak::isFlatpak() && !rewriteFlatpakHelpRootUrl(&aBaseInstallPath)) { returnfalse;
}
// Get a html tempfile (for the flatpak case, create it in XDG_CACHE_HOME instead of /tmp for // technical reasons, so that it can be accessed by the browser running outside the sandbox): static constexpr OUStringLiteral aExtension(u".html");
OUString * parent = nullptr; if (flatpak::isFlatpak() && !flatpak::createTemporaryHtmlDirectory(&parent)) { returnfalse;
}
::utl::TempFileNamed aTempFile(u"NewHelp", true, aExtension, parent, false );
/* rURL may be * - a "real" URL * - a HelpID (formerly a long, now a string) * If rURL is a URL, CreateHelpURL should be called for this URL * If rURL is an arbitrary string, the same should happen, but the URL should be tried out * if it delivers real help content. In case only the Help Error Document is returned, the * parent of the window for that help was called, is asked for its HelpID. * For compatibility reasons this upward search is not implemented for "real" URLs. * Help keyword search now is implemented as own method; in former versions it * was done via Help::Start, but this implementation conflicted with the upward search.
*/
OUString aHelpURL;
INetURLObject aParser( rURL );
INetProtocol nProtocol = aParser.GetProtocol();
switch ( nProtocol )
{ case INetProtocol::VndSunStarHelp: // already a vnd.sun.star.help URL -> nothing to do
aHelpURL = rURL; break; default:
{
OUString aHelpModuleName(GetHelpModuleName_Impl(rURL));
OUString aRealCommand;
if ( nProtocol == INetProtocol::Uno )
{ // Command can be just an alias to another command. auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rURL, getCurrentModuleIdentifier_Impl());
aRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
}
// no URL, just a HelpID (maybe empty in case of keyword search)
aHelpURL = CreateHelpURL_Impl( aRealCommand.isEmpty() ? rURL : aRealCommand, aHelpModuleName );
if ( impl_hasHelpInstalled() && pWindow && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
{ // no help found -> try with parent help id.
vcl::Window* pParent = pWindow->GetParent(); while ( pParent )
{
OUString aHelpId = pParent->GetHelpId();
aHelpURL = CreateHelpURL( aHelpId, aHelpModuleName );
if ( comphelper::LibreOfficeKit::isActive() )
{
impl_showOnlineHelp(aHelpURL, pWeldWindow); returntrue;
} #ifdef MACOSX if (@available(macOS 10.14, *)) { // Workaround: Safari sandboxing prevents it from accessing files in the LibreOffice.app folder // force online-help instead if Safari is default browser.
CFURLRef pBrowser = LSCopyDefaultApplicationURLForURL(
CFURLCreateWithString(
kCFAllocatorDefault, static_cast<CFStringRef>(@"https://www.libreoffice.org"),
nullptr),
kLSRolesAll, nullptr); if([static_cast<NSString*>(CFURLGetString(pBrowser)) hasSuffix:@"/Applications/Safari.app/"]) {
impl_showOnlineHelp(aHelpURL, pWeldWindow); returntrue;
}
} #endif
// If the HTML or no help is installed, but aHelpURL nevertheless references valid help content, // that implies that this help content belongs to an extension (and thus would not be available // in neither the offline nor online HTML help); in that case, fall through to the "old-help to // display" code below: if (SfxContentHelper::IsHelpErrorDocument(aHelpURL))
{ if ( impl_hasHTMLHelpInstalled() && impl_showOfflineHelp(aHelpURL, pWeldWindow) )
{ returntrue;
}
if ( !impl_hasHelpInstalled() )
{ bool bShowOfflineHelpPopUp = officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::get(); short retOnlineHelpBox = RET_CLOSE;
TopLevelWindowLocker aBusy;
if(bShowOfflineHelpPopUp)
{
aBusy.incBusy(pWeldWindow);
HelpManualMessage aQueryBox(pWeldWindow);
retOnlineHelpBox = aQueryBox.run(); auto xChanges = comphelper::ConfigurationChanges::create();
officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::set(aQueryBox.GetOfflineHelpPopUp(), xChanges);
xChanges->commit();
aBusy.decBusy();
} // Checks whether the user clicked "Read Help Online" (RET_OK) or "Information on downloading offline help" (RET_YES) if(!bShowOfflineHelpPopUp || retOnlineHelpBox == RET_OK || retOnlineHelpBox == RET_YES)
{ bool bTopicExists;
if (!bShowOfflineHelpPopUp || retOnlineHelpBox == RET_OK)
{
bTopicExists = impl_showOnlineHelp(aHelpURL, pWeldWindow);
} else
{ // Opens the help page that explains how to install offline help
OUString aOfflineHelpURL(CreateHelpURL_Impl(HID_HELPMANUAL_OFFLINE, u"shared"_ustr));
impl_showOnlineHelp(aOfflineHelpURL, pWeldWindow);
bTopicExists = true;
}
// check if help window is still open // If not, create a new one and return access directly to the internal sub frame showing the help content // search must be done here; search one desktop level could return an arbitrary frame
Reference< XFrame2 > xHelp(
xDesktop->findFrame( u"OFFICE_HELP_TASK"_ustr, FrameSearchFlag::CHILDREN),
UNO_QUERY);
Reference< XFrame > xHelpContent = xDesktop->findFrame(
u"OFFICE_HELP"_ustr,
FrameSearchFlag::CHILDREN);
/* rURL may be * - a "real" URL * - a HelpID (formerly a long, now a string) * If rURL is a URL, CreateHelpURL should be called for this URL * If rURL is an arbitrary string, the same should happen, but the URL should be tried out * if it delivers real help content. In case only the Help Error Document is returned, the * parent of the window for that help was called, is asked for its HelpID. * For compatibility reasons this upward search is not implemented for "real" URLs. * Help keyword search now is implemented as own method; in former versions it * was done via Help::Start, but this implementation conflicted with the upward search.
*/
OUString aHelpURL;
INetURLObject aParser( rURL );
INetProtocol nProtocol = aParser.GetProtocol();
switch ( nProtocol )
{ case INetProtocol::VndSunStarHelp: // already a vnd.sun.star.help URL -> nothing to do
aHelpURL = rURL; break; default:
{
OUString aHelpModuleName(GetHelpModuleName_Impl(rURL));
OUString aRealCommand;
if ( nProtocol == INetProtocol::Uno )
{ // Command can be just an alias to another command. auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rURL, getCurrentModuleIdentifier_Impl());
aRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
}
// no URL, just a HelpID (maybe empty in case of keyword search)
aHelpURL = CreateHelpURL_Impl( aRealCommand.isEmpty() ? rURL : aRealCommand, aHelpModuleName );
if ( impl_hasHelpInstalled() && pWidget && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
{ bool bUseFinalFallback = true; // no help found -> try ids of parents.
pWidget->help_hierarchy_foreach([&aHelpModuleName, &aHelpURL, &bUseFinalFallback](const OUString& rHelpId){ if (rHelpId.isEmpty()) returnfalse;
aHelpURL = CreateHelpURL(rHelpId, aHelpModuleName); bool bFinished = !SfxContentHelper::IsHelpErrorDocument(aHelpURL); if (bFinished)
bUseFinalFallback = false; return bFinished;
});
if (bUseFinalFallback)
{ // create help url of start page ( helpid == 0 -> start page)
aHelpURL = CreateHelpURL( OUString(), aHelpModuleName );
}
} break;
}
}
if ( comphelper::LibreOfficeKit::isActive() )
{
impl_showOnlineHelp(aHelpURL, pWidget); returntrue;
} #ifdef MACOSX if (@available(macOS 10.14, *)) { // Workaround: Safari sandboxing prevents it from accessing files in the LibreOffice.app folder // force online-help instead if Safari is default browser.
CFURLRef pBrowser = LSCopyDefaultApplicationURLForURL(
CFURLCreateWithString(
kCFAllocatorDefault, static_cast<CFStringRef>(@"https://www.libreoffice.org"),
nullptr),
kLSRolesAll, nullptr); if([static_cast<NSString*>(CFURLGetString(pBrowser)) hasSuffix:@"/Applications/Safari.app/"]) {
impl_showOnlineHelp(aHelpURL, pWidget); returntrue;
}
} #endif
// If the HTML or no help is installed, but aHelpURL nevertheless references valid help content, // that implies that help content belongs to an extension (and thus would not be available // in neither the offline nor online HTML help); in that case, fall through to the "old-help to // display" code below: if (SfxContentHelper::IsHelpErrorDocument(aHelpURL))
{ if ( impl_hasHTMLHelpInstalled() && impl_showOfflineHelp(aHelpURL, pWidget) )
{ returntrue;
}
if ( !impl_hasHelpInstalled() )
{ bool bShowOfflineHelpPopUp = officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::get(); short retOnlineHelpBox = RET_CLOSE;
TopLevelWindowLocker aBusy;
if(bShowOfflineHelpPopUp)
{
aBusy.incBusy(pWidget);
HelpManualMessage aQueryBox(pWidget);
retOnlineHelpBox = aQueryBox.run(); auto xChanges = comphelper::ConfigurationChanges::create();
officecfg::Office::Common::Help::BuiltInHelpNotInstalledPopUp::set(aQueryBox.GetOfflineHelpPopUp(), xChanges);
xChanges->commit();
aBusy.decBusy();
} // Checks whether the user clicked "Read Help Online" (RET_OK) or "Information on downloading offline help" (RET_YES) if(!bShowOfflineHelpPopUp || retOnlineHelpBox == RET_OK || retOnlineHelpBox == RET_YES)
{ bool bTopicExists;
if (!bShowOfflineHelpPopUp || retOnlineHelpBox == RET_OK)
{
bTopicExists = impl_showOnlineHelp(aHelpURL, pWidget);
} else
{ // Opens the help page that explains how to install offline help
OUString aOfflineHelpURL(CreateHelpURL_Impl(HID_HELPMANUAL_OFFLINE, u"shared"_ustr));
impl_showOnlineHelp(aOfflineHelpURL, pWidget);
bTopicExists = true;
}
// check if help window is still open // If not, create a new one and return access directly to the internal sub frame showing the help content // search must be done here; search one desktop level could return an arbitrary frame
Reference< XFrame2 > xHelp(
xDesktop->findFrame( u"OFFICE_HELP_TASK"_ustr, FrameSearchFlag::CHILDREN),
UNO_QUERY);
Reference< XFrame > xHelpContent = xDesktop->findFrame(
u"OFFICE_HELP"_ustr,
FrameSearchFlag::CHILDREN);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.