Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sfx2/source/appl/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 49 kB image not shown  

Quelle  sfxhelp.cxx   Sprache: C

 
/* -*- 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 .
 */


#include <config_folders.h>
#include <sfx2/sfxhelp.hxx>
#include <helpids.h>

#include <string_view>
#include <algorithm>
#include <cassert>
#include <cstddef>
#ifdef MACOSX
#include <premac.h>
#include <Foundation/NSString.h>
#include <CoreFoundation/CFURL.h>
#include <CoreServices/CoreServices.h>
#include <postmac.h>
#endif

#include <sal/log.hxx>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/UnknownModuleException.hpp>
#include <com/sun/star/frame/XFrame2.hpp>
#include <comphelper/processfactory.hxx>
#include <com/sun/star/awt/XWindow.hpp>
#include <com/sun/star/awt/XTopWindow.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/frame/FrameSearchFlag.hpp>
#include <toolkit/helper/vclunohelper.hxx>
#include <com/sun/star/frame/ModuleManager.hpp>
#include <unotools/configmgr.hxx>
#include <unotools/moduleoptions.hxx>
#include <tools/urlobj.hxx>
#include <ucbhelper/content.hxx>
#include <unotools/pathoptions.hxx>
#include <rtl/byteseq.hxx>
#include <rtl/ustring.hxx>
#include <o3tl/string_view.hxx>
#include <officecfg/Office/Common.hxx>
#include <osl/process.h>
#include <osl/file.hxx>
#include <unotools/tempfile.hxx>
#include <unotools/securityoptions.hxx>
#include <rtl/uri.hxx>
#include <vcl/commandinfoprovider.hxx>
#include <vcl/keycod.hxx>
#include <vcl/settings.hxx>
#include <vcl/locktoplevels.hxx>
#include <vcl/weld.hxx>
#include <openuriexternally.hxx>

#include <comphelper/lok.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <sfx2/viewsh.hxx>

#include "newhelp.hxx"
#include <sfx2/flatpak.hxx>
#include <sfx2/sfxresid.hxx>
#include <helper.hxx>
#include <sfx2/strings.hrc>
#include <vcl/svapp.hxx>
#include <rtl/string.hxx>
#include <svtools/langtab.hxx>
#include <comphelper/diagnose_ex.hxx>

using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::uno;

namespace {

class NoHelpErrorBox
{
private:
    std::unique_ptr<weld::MessageDialog> m_xErrBox;
public:
    DECL_STATIC_LINK(NoHelpErrorBox, HelpRequestHdl, weld::Widget&, bool);
public:
    explicit NoHelpErrorBox(weld::Widget* pParent)
        : m_xErrBox(Application::CreateMessageDialog(pParent, VclMessageType::Error, VclButtonsType::Ok,
                                                     SfxResId(RID_STR_HLPFILENOTEXIST)))
    {
        // Error message: "No help available"
        m_xErrBox->connect_help(LINK(nullptr, NoHelpErrorBox, HelpRequestHdl));
    }
    void run()
    {
        m_xErrBox->run();
    }
};

}

IMPL_STATIC_LINK_NOARG(NoHelpErrorBox, HelpRequestHdl, weld::Widget&, bool)
{
    // do nothing, because no help available
    return false;
}

static OUString const & HelpLocaleString();

namespace {

/// Root path of the help.
OUString const & getHelpRootURL()
{
    static OUString const s_instURL = []()
    {
        OUString tmp = officecfg::Office::Common::Path::Current::Help::get();
        if (tmp.isEmpty())
        {
            // try to determine path from default
            tmp = "$(instpath)/" LIBO_SHARE_HELP_FOLDER;
        }

        // replace anything like $(instpath);
        SvtPathOptions aOptions;
        tmp = aOptions.SubstituteVariable(tmp);

        OUString url;
        if (osl::FileBase::getFileURLFromSystemPath(tmp, url) == osl::FileBase::E_None)
            tmp = url;
        return tmp;
    }();
    return s_instURL;
}

bool impl_checkHelpLocalePath(OUString const & rpPath)
{
    osl::DirectoryItem directoryItem;
    bool bOK = false;

    osl::FileStatus fileStatus(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName);
    if (osl::DirectoryItem::get(rpPath, directoryItem) == osl::FileBase::E_None &&
        directoryItem.getFileStatus(fileStatus) == osl::FileBase::E_None &&
        fileStatus.isDirectory())
    {
        bOK = true;
    }
    return bOK;
}

/// Check for built-in help
/// Check if help/<lang>/err.html file exist
bool impl_hasHelpInstalled()
{
    if (comphelper::LibreOfficeKit::isActive())
        return false;

        // detect installed locale
    static OUString const aLocaleStr = HelpLocaleString();

    OUString helpRootURL = getHelpRootURL() + "/" + aLocaleStr + "/err.html";
    bool bOK = false;
    osl::DirectoryItem directoryItem;
    if(osl::DirectoryItem::get(helpRootURL, directoryItem) == osl::FileBase::E_None){
        bOK=true;
    }

    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())
        return false;

    // detect installed locale
    static OUString const aLocaleStr = HelpLocaleString();

    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;

    static constexpr OUString aEnglish(u"en-US"_ustr);
    // detect installed locale
    aLocaleStr = utl::ConfigManager::getUILocale();

    if ( aLocaleStr.isEmpty() )
    {
        aLocaleStr = aEnglish;
        return aLocaleStr;
    }

    // get fall-back language (country)
    OUString sLang = aLocaleStr;
    sal_Int32 nSepPos = sLang.indexOf( '-' );
    if (nSepPos != -1)
    {
        sLang = sLang.copy( 0, nSepPos );
    }
    OUString sHelpPath(u""_ustr);
    sHelpPath = getHelpRootURL() + "/" + utl::ConfigManager::getProductVersion() + "/" + aLocaleStr;
    if (impl_checkHelpLocalePath(sHelpPath))
    {
        return aLocaleStr;
    }
    sHelpPath = getHelpRootURL() + "/" + utl::ConfigManager::getProductVersion() + "/" + sLang;
    if (impl_checkHelpLocalePath(sHelpPath))
    {
        aLocaleStr = sLang;
        return aLocaleStr;
    }
    sHelpPath = getHelpRootURL() + "/" + aLocaleStr;
    if (impl_checkHelpLocalePath(sHelpPath))
    {
        return aLocaleStr;
    }
    sHelpPath = getHelpRootURL() + "/" + sLang;
    if (impl_checkHelpLocalePath(sHelpPath))
    {
        aLocaleStr = sLang;
        return aLocaleStr;
    }
    sHelpPath = getHelpRootURL() + "/" + utl::ConfigManager::getProductVersion() + "/" + aEnglish;
    if (impl_checkHelpLocalePath(sHelpPath))
    {
        aLocaleStr = aEnglish;
        return aLocaleStr;
    }
    sHelpPath = getHelpRootURL() + "/" + aEnglish;
    if (impl_checkHelpLocalePath(sHelpPath))
    {
        aLocaleStr = aEnglish;
        return aLocaleStr;
    }
    return aLocaleStr;
}



void AppendConfigToken( OUStringBuffer& rURL, bool bQuestionMark )
{
    const OUString& aLocaleStr = HelpLocaleString();

    // query part exists?
    if ( bQuestionMark )
        // no, so start with '?'
        rURL.append('?');
    else
        // yes, so only append with '&'
        rURL.append('&');

    // set parameters
    rURL.append("Language=");
    rURL.append(aLocaleStr);
    rURL.append("&System=");
    rURL.append(officecfg::Office::Common::Help::System::get());
    rURL.append("&Version=");
    rURL.append(utl::ConfigManager::getProductVersion());
}

static bool GetHelpAnchor_Impl( std::u16string_view _rURL, OUString& _rAnchor )
{
    bool bRet = false;

    try
    {
        ::ucbhelper::Content aCnt( INetURLObject( _rURL ).GetMainURL( INetURLObject::DecodeMechanism::NONE ),
                             Reference< css::ucb::XCommandEnvironment >(),
                             comphelper::getProcessComponentContext() );
        OUString sAnchor;
        if ( aCnt.getPropertyValue(u"AnchorName"_ustr) >>= sAnchor )
        {

            if ( !sAnchor.isEmpty() )
            {
                _rAnchor = sAnchor;
                bRet = true;
            }
        }
        else
        {
            SAL_WARN( "sfx.appl""Property 'AnchorName' is missing" );
        }
    }
    catch (const css::uno::Exception&)
    {
    }

    return bRet;
}

namespace {

class SfxHelp_Impl
{
public:
    static OUString GetHelpText( const OUString& aCommandURL, const OUString& rModule );
};

}

OUString SfxHelp_Impl::GetHelpText( const OUString& aCommandURL, const OUString&&nbsp;rModule )
{
    // create help url
    OUStringBuffer aHelpURL( SfxHelp::CreateHelpURL( aCommandURL, rModule ) );
    // added 'active' parameter
    sal_Int32 nIndex = aHelpURL.lastIndexOf( '#' );
    if ( nIndex < 0 )
        nIndex = aHelpURL.getLength();
    aHelpURL.insert( nIndex, "&Active=true" );
    // load help string
    return SfxContentHelper::GetActiveHelpString( aHelpURL.makeStringAndClear() );
}

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();
}

SfxHelp::~SfxHelp()
{
}

static OUString getDefaultModule_Impl()
{
    OUString sDefaultModule;
    SvtModuleOptions aModOpt;
    if (aModOpt.IsWriterInstalled())
        sDefaultModule = "swriter";
    else if (aModOpt.IsCalcInstalled())
        sDefaultModule = "scalc";
    else if (aModOpt.IsImpressInstalled())
        sDefaultModule = "simpress";
    else if (aModOpt.IsDrawInstalled())
        sDefaultModule = "sdraw";
    else if (aModOpt.IsMathInstalled())
        sDefaultModule = "smath";
    else if (aModOpt.IsChartInstalled())
        sDefaultModule = "schart";
    else if (SvtModuleOptions::IsBasicIDEInstalled())
        sDefaultModule = "sbasic";
    else if (aModOpt.IsDataBaseInstalled())
        sDefaultModule = "sdatabase";
    else
    {
        SAL_WARN( "sfx.appl""getDefaultModule_Impl(): no module installed" );
    }
    return sDefaultModule;
}

static OUString getCurrentModuleIdentifier_Impl()
{
    OUString sIdentifier;
    const Reference < XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
    Reference < XModuleManager2 > xModuleManager = ModuleManager::create(xContext);
    Reference < XDesktop2 > xDesktop = Desktop::create(xContext);
    Reference < XFrame > xCurrentFrame = xDesktop->getCurrentFrame();

    if ( xCurrentFrame.is() )
    {
        try
        {
            sIdentifier = xModuleManager->identify( xCurrentFrame );
        }
        catch (const css::frame::UnknownModuleException&)
        {
            SAL_INFO( "sfx.appl""SfxHelp::getCurrentModuleIdentifier_Impl(): unknown module (help in help?)" );
        }
        catch (const Exception&)
        {
            TOOLS_WARN_EXCEPTION( "sfx.appl""SfxHelp::getCurrentModuleIdentifier_Impl(): exception of XModuleManager::identify()" );
        }
    }

    return sIdentifier;
}

namespace
{
    OUString MapModuleIdentifier(const OUString &rFactoryShortName)
    {
        OUString aFactoryShortName(rFactoryShortName);

        // Map some module identifiers to their "real" help module string.
        if ( aFactoryShortName == "chart2" )
            aFactoryShortName = "schart" ;
        else if ( aFactoryShortName == "BasicIDE" )
            aFactoryShortName = "sbasic";
        else if ( aFactoryShortName == "sweb"
                || aFactoryShortName == "sglobal"
                || aFactoryShortName == "swxform" )
            aFactoryShortName = "swriter" ;
        else if ( aFactoryShortName == "dbquery"
                || aFactoryShortName == "dbbrowser"
                || aFactoryShortName == "dbrelation"
                || aFactoryShortName == "dbtable"
                || aFactoryShortName == "dbapp"
                || aFactoryShortName == "dbreport"
                || aFactoryShortName == "dbtdata"
                || aFactoryShortName == "swreport"
                || aFactoryShortName == "swform" )
            aFactoryShortName = "sdatabase";
        else if ( aFactoryShortName == "sbibliography"
                || aFactoryShortName == "sabpilot"
                || aFactoryShortName == "scanner"
                || aFactoryShortName == "spropctrlr"
                || aFactoryShortName == "StartModule" )
            aFactoryShortName.clear();

        return aFactoryShortName;
    }
}

OUString SfxHelp::GetHelpModuleName_Impl(std::u16string_view rHelpID)
{
    OUString aFactoryShortName;

    //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())
    {
        OUString aModuleIdentifier = getCurrentModuleIdentifier_Impl();
        if (!aModuleIdentifier.isEmpty())
        {
            try
            {
                Reference < XModuleManager2 > xModuleManager(
                    ModuleManager::create(::comphelper::getProcessComponentContext()) );
                Sequence< PropertyValue > lProps;
                xModuleManager->getByName( aModuleIdentifier ) >>= lProps;
                auto pProp = std::find_if(std::cbegin(lProps), std::cend(lProps),
                    [](const PropertyValue& rProp) { return rProp.Name == "ooSetupFactoryShortName"; });
                if (pProp != std::cend(lProps))
                    pProp->Value >>= aFactoryShortName;
            }
            catch (const Exception&)
            {
                TOOLS_WARN_EXCEPTION( "sfx.appl""SfxHelp::GetHelpModuleName_Impl()" );
            }
        }
    }

    if (!aFactoryShortName.isEmpty())
        aFactoryShortName = MapModuleIdentifier(aFactoryShortName);
    if (aFactoryShortName.isEmpty())
        aFactoryShortName = getDefaultModule_Impl();

    return aFactoryShortName;
}

OUString SfxHelp::CreateHelpURL_Impl( const OUString& aCommandURL, const OUString&&nbsp;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();

    aHelpURL.append(aModuleName);

    if ( aCommandURL.isEmpty() )
        aHelpURL.append("/start");
    else
    {
        aHelpURL.append("/" +
            rtl::Uri::encode(aCommandURL,
                              rtl_UriCharClassRelSegment,
                              rtl_UriEncodeKeepEscapes,
                              RTL_TEXTENCODING_UTF8));

        OUStringBuffer aTempURL = aHelpURL;
        AppendConfigToken( aTempURL, true );
        bHasAnchor = GetHelpAnchor_Impl(aTempURL, aAnchor);
    }

    AppendConfigToken( aHelpURL, true );

    if ( bHasAnchor )
        aHelpURL.append("#" + aAnchor);

    return aHelpURL.makeStringAndClear();
}

static SfxHelpWindow_Impl* impl_createHelp(Reference< XFrame2 >& rHelpTask   ,
                                    Reference< XFrame >& rHelpContent)
{
    Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );

    // otherwise - create new help task
    Reference< XFrame2 > xHelpTask(
        xDesktop->findFrame(  u"OFFICE_HELP_TASK"_ustr, FrameSearchFlag::TASKS | FrameSearchFlag::CREATE),
        UNO_QUERY);
    if (!xHelpTask.is())
        return nullptr;

    // create all internal windows and sub frames ...
    Reference< css::awt::XWindow >      xParentWindow = xHelpTask->getContainerWindow();
    VclPtr<vcl::Window>                 pParentWindow = VCLUnoHelper::GetWindow( xParentWindow );
    VclPtrInstance<SfxHelpWindow_Impl>  pHelpWindow( xHelpTask, pParentWindow );
    Reference< css::awt::XWindow >      xHelpWindow   = VCLUnoHelper::GetInterface( pHelpWindow );

    Reference< XFrame > xHelpContent;
    if (xHelpTask->setComponent( xHelpWindow, Reference< XController >() ))
    {
        // Customize UI ...
        xHelpTask->setName(u"OFFICE_HELP_TASK"_ustr);

        Reference< XPropertySet > xProps(xHelpTask, UNO_QUERY);
        if (xProps.is())
            xProps->setPropertyValue(
                u"Title"_ustr,
                Any(SfxResId(STR_HELP_WINDOW_TITLE)));

        pHelpWindow->setContainerWindow( xParentWindow );
        xParentWindow->setVisible(true);
        xHelpWindow->setVisible(true);

        // 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;
    }

    xHelpContent->setName(u"OFFICE_HELP"_ustr);

    rHelpTask    = std::move(xHelpTask);
    rHelpContent = std::move(xHelpContent);
    return pHelpWindow;
}

OUString SfxHelp::GetHelpText(const OUString& aCommandURL)
{
    OUString sModuleName = GetHelpModuleName_Impl(aCommandURL);
    auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommandURL, getCurrentModuleIdentifier_Impl());
    OUString sRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
    OUString sHelpText = SfxHelp_Impl::GetHelpText( sRealCommand.isEmpty() ? aCommandURL : sRealCommand, sModuleName );

    // add some debug information?
    if ( bIsDebug )
    {
        sHelpText += "\n-------------\n" +
            sModuleName + ": " + aCommandURL;
    }

    return sHelpText;
}

OUString SfxHelp::GetURLHelpText(std::u16string_view aURL)
{
    // hyperlinks are handled differently in Online
    if (comphelper::LibreOfficeKit::isActive())
        return OUString();

    bool bCtrlClickHlink = SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink);

    // "ctrl-click to follow link:" for not MacOS
    // "⌘-click to follow link:" for MacOs
    vcl::KeyCode aCode(KEY_SPACE);
    vcl::KeyCode aModifiedCode(KEY_SPACE, KEY_MOD1);
    OUString aModStr(aModifiedCode.GetName());
    aModStr = aModStr.replaceFirst(aCode.GetName(), "");
    aModStr = aModStr.replaceAll("+""");
    OUString aHelpStr
        = bCtrlClickHlink ? SfxResId(STR_CTRLCLICKHYPERLINK) : SfxResId(STR_CLICKHYPERLINK);
    aHelpStr = aHelpStr.replaceFirst("%{key}", aModStr);
    aHelpStr = aHelpStr.replaceFirst("%{link}", aURL);
    return aHelpStr;
}

void SfxHelp::SearchKeyword( const OUString& rKeyword )
{
    Start_Impl(OUString(), static_cast<weld::Widget*>(nullptr), rKeyword);
}

bool SfxHelp::Start( const OUString& rURL, const vcl::Window* pWindow )
{
    if (bLaunchingHelp)
        return true;
    bLaunchingHelp = true;
    bool bRet = Start_Impl( rURL, pWindow );
    bLaunchingHelp = false;
    return bRet;
}

bool SfxHelp::Start(const OUString& rURL, weld::Widget* pWidget)
{
    if (bLaunchingHelp)
        return true;
    bLaunchingHelp = true;
    bool bRet = Start_Impl(rURL, pWidget, OUString());
    bLaunchingHelp = false;
    return bRet;
}

/// Redirect the vnd.sun.star.help:// urls to http://help.libreoffice.org
static bool impl_showOnlineHelp(const OUString& rURL, weld::Widget* pDialogParent)
{
    static constexpr OUString aInternal(u"vnd.sun.star.help://"_ustr);
    if ( rURL.getLength() <= aInternal.getLength() || !rURL.startsWith(aInternal) )
        return false;

    OUString aHelpLink = officecfg::Office::Common::Help::HelpRootURL::get();
    OUString aTarget = OUString::Concat("Target=") + rURL.subView(aInternal.getLength());
    aTarget = aTarget.replaceAll("%2F""/").replaceAll("?""&");
    aHelpLink += aTarget;

    if (comphelper::LibreOfficeKit::isActive())
    {
        if(SfxViewShell* pViewShell = SfxViewShell::Current())
        {
            pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED,
                                                   aHelpLink.toUtf8());
            return true;
        }
        else if (GetpApp())
        {
            GetpApp()->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED,
                                                   aHelpLink.toUtf8());
            return true;
        }

        return false;
    }

    try
    {
#ifdef MACOSX
        LSOpenCFURLRef(CFURLCreateWithString(kCFAllocatorDefault,
                           CFStringCreateWithCString(kCFAllocatorDefault,
                               aHelpLink.toUtf8().getStr(),
                               kCFStringEncodingUTF8),
                           nullptr),
            nullptr);
        (void)pDialogParent;
#else
        sfx2::openUriExternally(aHelpLink, false, pDialogParent);
#endif
        return true;
    }
    catch (const Exception&)
    {
    }
    return false;
}

namespace {

bool rewriteFlatpakHelpRootUrl(OUString * helpRootUrl) {
    assert(helpRootUrl != nullptr);
    //TODO: this function for now assumes that the passed-in *helpRootUrl references
    // /app/libreoffice/help (which belongs to the org.libreoffice.LibreOffice.Help
    // extension); it replaces it with the corresponding file URL as seen outside the flatpak
    // sandbox:
    struct Failure: public std::exception {};
    try {
        static auto const url = [] {
            // From /.flatpak-info [Instance] section, read
            //   app-path=<path>
            //   app-extensions=...;org.libreoffice.LibreOffice.Help=<sha>;...
            // lines:
            osl::File ini(u"file:///.flatpak-info"_ustr);
            auto err = ini.open(osl_File_OpenFlag_Read);
            if (err != osl::FileBase::E_None) {
                SAL_WARN("sfx.appl""LIBO_FLATPAK mode failure opening /.flatpak-info: " << err);
                throw Failure();
            }
            OUString path;
            OUString extensions;
            bool havePath = false;
            bool haveExtensions = false;
            for (bool instance = false; !(havePath && haveExtensions);) {
                rtl::ByteSequence bytes;
                err = ini.readLine(bytes);
                if (err != osl::FileBase::E_None) {
                    SAL_WARN(
                        "sfx.appl",
                        "LIBO_FLATPAK mode reading /.flatpak-info fails with " << err
                            << " before [Instance] app-path");
                    throw Failure();
                }
                std::string_view const line(
                    reinterpret_cast<char const *>(bytes.getConstArray()), bytes.getLength());
                if (instance) {
                    static constexpr auto keyPath = std::string_view("app-path=");
                    static constexpr auto keyExtensions = std::string_view("app-extensions=");
                    if (!havePath && line.length() >= keyPath.size()
                        && line.substr(0, keyPath.size()) == keyPath.data())
                    {
                        auto const value = line.substr(keyPath.size());
                        if (!rtl_convertStringToUString(
                                &path.pData, value.data(), value.length(),
                                osl_getThreadTextEncoding(),
                                (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
                                 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
                                 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
                        {
                            SAL_WARN(
                                "sfx.appl",
                                "LIBO_FLATPAK mode failure converting app-path \"" << value
                                    << "\" encoding");
                            throw Failure();
                        }
                        havePath = true;
                    } else if (!haveExtensions && line.length() >= keyExtensions.size()
                               && line.substr(0, keyExtensions.size()) == keyExtensions.data())
                    {
                        auto const value = line.substr(keyExtensions.size());
                        if (!rtl_convertStringToUString(
                                &extensions.pData, value.data(), value.length(),
                                osl_getThreadTextEncoding(),
                                (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
                                 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
                                 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
                        {
                            SAL_WARN(
                                "sfx.appl",
                                "LIBO_FLATPAK mode failure converting app-extensions \"" << value
                                    << "\" encoding");
                            throw Failure();
                        }
                        haveExtensions = true;
                    } else if (line.length() > 0 && line[0] == '[') {
                        SAL_WARN(
                            "sfx.appl",
                            "LIBO_FLATPAK mode /.flatpak-info lacks [Instance] app-path and"
                                " app-extensions");
                        throw Failure();
                    }
                } else if (line == "[Instance]") {
                    instance = true;
                }
            }
            ini.close();
            // Extract <sha> from ...;org.libreoffice.LibreOffice.Help=<sha>;...:
            std::u16string_view sha;
            for (sal_Int32 i = 0;;) {
                OUString elem = extensions.getToken(0, ';', i);
                if (elem.startsWith("org.libreoffice.LibreOffice.Help=", &sha)) {
                    break;
                }
                if (i == -1) {
                    SAL_WARN(
                        "sfx.appl",
                        "LIBO_FLATPAK mode /.flatpak-info [Instance] app-extensions \""
                            << extensions << "\" org.libreoffice.LibreOffice.Help");
                    throw Failure();
                }
            }
            // Assuming that <path> is of the form
            //   /.../app/org.libreoffice.LibreOffice/<arch>/<branch>/<sha'>/files
            // rewrite it as
            //   /.../runtime/org.libreoffice.LibreOffice.Help/<arch>/<branch>/<sha>/files
            // because the extension's files are stored at a different place than the app's files,
            // so use this hack until flatpak itself provides a better solution:
            static constexpr OUString segments = u"/app/org.libreoffice.LibreOffice/"_ustr;
            auto const i1 = path.lastIndexOf(segments);
                // use lastIndexOf instead of indexOf, in case the user-controlled prefix /.../
                // happens to contain such segments
            if (i1 == -1) {
                SAL_WARN(
                    "sfx.appl",
                    "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
                        << "\" doesn't contain /app/org.libreoffice.LibreOffice/");
                throw Failure();
            }
            auto const i2 = i1 + segments.getLength();
            auto i3 = path.indexOf('/', i2);
            if (i3 == -1) {
                SAL_WARN(
                    "sfx.appl",
                    "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
                        << "\" doesn't contain branch segment");
                throw Failure();
            }
            i3 = path.indexOf('/', i3 + 1);
            if (i3 == -1) {
                SAL_WARN(
                    "sfx.appl",
                    "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
                        << "\" doesn't contain sha segment");
                throw Failure();
            }
            ++i3;
            auto const i4 = path.indexOf('/', i3);
            if (i4 == -1) {
                SAL_WARN(
                    "sfx.appl",
                    "LIBO_FLATPAK mode /.flatpak-info [Instance] app-path \"" << path
                        << "\" doesn't contain files segment");
                throw Failure();
            }
            path = path.subView(0, i1) + OUString::Concat("/runtime/org.libreoffice.LibreOffice.Help/")
                + path.subView(i2, i3 - i2) + sha + path.subView(i4);
            // Turn <path> into a file URL:
            OUString url_;
            err = osl::FileBase::getFileURLFromSystemPath(path, url_);
            if (err != osl::FileBase::E_None) {
                SAL_WARN(
                    "sfx.appl",
                    "LIBO_FLATPAK mode failure converting app-path \"" << path << "\" to URL: "
                        << err);
                throw Failure();
            }
            return url_;
        }();
        *helpRootUrl = url;
        return true;
    } catch (Failure &) {
        return false;
    }
}

}

// add <noscript> meta for browsers without javascript

constexpr OUStringLiteral SHTML1 = u"en-US\">UTF-8\">";
constexpr OUStringLiteral SHTML2 = u"

Messung V0.5
C=95 H=77 G=86

¤ Dauer der Verarbeitung: 0.15 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.