4f5f24a4a3
Change-Id: I2fdc32aa5de6a1315fe69997f9b531259aa78605 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167339 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
336 lines
12 KiB
C++
336 lines
12 KiB
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 own header
|
|
#include <jobs/helponstartup.hxx>
|
|
#include <services.h>
|
|
#include <targets.h>
|
|
|
|
#include <officecfg/Office/Common.hxx>
|
|
#include <officecfg/Setup.hxx>
|
|
|
|
// include others
|
|
#include <comphelper/sequenceashashmap.hxx>
|
|
#include <utility>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/help.hxx>
|
|
|
|
// include interfaces
|
|
#include <com/sun/star/frame/FrameSearchFlag.hpp>
|
|
#include <com/sun/star/frame/ModuleManager.hpp>
|
|
#include <com/sun/star/frame/XFramesSupplier.hpp>
|
|
#include <com/sun/star/frame/Desktop.hpp>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
|
|
namespace framework{
|
|
|
|
// XInterface, XTypeProvider, XServiceInfo
|
|
|
|
OUString SAL_CALL HelpOnStartup::getImplementationName()
|
|
{
|
|
return u"com.sun.star.comp.framework.HelpOnStartup"_ustr;
|
|
}
|
|
|
|
sal_Bool SAL_CALL HelpOnStartup::supportsService( const OUString& sServiceName )
|
|
{
|
|
return cppu::supportsService(this, sServiceName);
|
|
}
|
|
|
|
css::uno::Sequence< OUString > SAL_CALL HelpOnStartup::getSupportedServiceNames()
|
|
{
|
|
return { SERVICENAME_JOB };
|
|
}
|
|
|
|
HelpOnStartup::HelpOnStartup(css::uno::Reference< css::uno::XComponentContext > xContext)
|
|
: m_xContext (std::move(xContext))
|
|
{
|
|
// create some needed uno services and cache it
|
|
m_xModuleManager = css::frame::ModuleManager::create( m_xContext );
|
|
|
|
m_xDesktop = css::frame::Desktop::create(m_xContext);
|
|
|
|
// ask for office locale
|
|
m_sLocale = officecfg::Setup::L10N::ooLocale::get();
|
|
|
|
// detect system
|
|
m_sSystem = officecfg::Office::Common::Help::System::get();
|
|
|
|
// Start listening for disposing events of these services,
|
|
// so we can react e.g. for an office shutdown
|
|
css::uno::Reference< css::lang::XComponent > xComponent;
|
|
xComponent.set(m_xModuleManager, css::uno::UNO_QUERY);
|
|
if (xComponent.is())
|
|
xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this));
|
|
if (m_xDesktop.is())
|
|
m_xDesktop->addEventListener(static_cast< css::lang::XEventListener* >(this));
|
|
xComponent.set(m_xConfig, css::uno::UNO_QUERY);
|
|
if (xComponent.is())
|
|
xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this));
|
|
}
|
|
|
|
HelpOnStartup::~HelpOnStartup()
|
|
{
|
|
}
|
|
|
|
// css.task.XJob
|
|
css::uno::Any SAL_CALL HelpOnStartup::execute(const css::uno::Sequence< css::beans::NamedValue >& lArguments)
|
|
{
|
|
// Analyze the given arguments; try to locate a model there and
|
|
// classify it's used application module.
|
|
OUString sModule = its_getModuleIdFromEnv(lArguments);
|
|
|
|
// Attention: we are bound to events for opening any document inside the office.
|
|
// That includes e.g. the help module itself. But we have to do nothing then!
|
|
if (sModule.isEmpty())
|
|
return css::uno::Any();
|
|
|
|
// check current state of the help module
|
|
// a) help isn't open => show default page for the detected module
|
|
// b) help shows any other default page(!) => show default page for the detected module
|
|
// c) help shows any other content => do nothing (user travelled to any other content and leaved the set of default pages)
|
|
OUString sCurrentHelpURL = its_getCurrentHelpURL();
|
|
bool bCurrentHelpURLIsAnyDefaultURL = its_isHelpUrlADefaultOne(sCurrentHelpURL);
|
|
bool bShowIt = false;
|
|
|
|
// a)
|
|
if (sCurrentHelpURL.isEmpty())
|
|
bShowIt = true;
|
|
// b)
|
|
else if (bCurrentHelpURLIsAnyDefaultURL)
|
|
bShowIt = true;
|
|
|
|
if (bShowIt)
|
|
{
|
|
// retrieve the help URL for the detected application module
|
|
OUString sModuleDependentHelpURL = its_checkIfHelpEnabledAndGetURL(sModule);
|
|
if (!sModuleDependentHelpURL.isEmpty())
|
|
{
|
|
// Show this help page.
|
|
// Note: The help window brings itself to front ...
|
|
Help* pHelp = Application::GetHelp();
|
|
if (pHelp)
|
|
pHelp->Start(sModuleDependentHelpURL);
|
|
}
|
|
}
|
|
|
|
return css::uno::Any();
|
|
}
|
|
|
|
void SAL_CALL HelpOnStartup::disposing(const css::lang::EventObject& aEvent)
|
|
{
|
|
std::unique_lock g(m_mutex);
|
|
if (aEvent.Source == m_xModuleManager)
|
|
m_xModuleManager.clear();
|
|
else if (aEvent.Source == m_xDesktop)
|
|
m_xDesktop.clear();
|
|
else if (aEvent.Source == m_xConfig)
|
|
m_xConfig.clear();
|
|
}
|
|
|
|
OUString HelpOnStartup::its_getModuleIdFromEnv(const css::uno::Sequence< css::beans::NamedValue >& lArguments)
|
|
{
|
|
::comphelper::SequenceAsHashMap lArgs (lArguments);
|
|
::comphelper::SequenceAsHashMap lEnvironment = lArgs.getUnpackedValueOrDefault(u"Environment"_ustr, css::uno::Sequence< css::beans::NamedValue >());
|
|
|
|
// check for right environment.
|
|
// If it's not a DocumentEvent, which triggered this job,
|
|
// we can't work correctly! => return immediately and do nothing
|
|
OUString sEnvType = lEnvironment.getUnpackedValueOrDefault(u"EnvType"_ustr, OUString());
|
|
if (sEnvType != "DOCUMENTEVENT")
|
|
return OUString();
|
|
|
|
css::uno::Reference< css::frame::XModel > xDoc = lEnvironment.getUnpackedValueOrDefault(u"Model"_ustr, css::uno::Reference< css::frame::XModel >());
|
|
if (!xDoc.is())
|
|
return OUString();
|
|
|
|
// be sure that we work on top level documents only, which are registered
|
|
// on the desktop instance. Ignore e.g. life previews, which are top frames too ...
|
|
// but not registered at this global desktop instance.
|
|
css::uno::Reference< css::frame::XDesktop > xDesktopCheck;
|
|
css::uno::Reference< css::frame::XFrame > xFrame;
|
|
css::uno::Reference< css::frame::XController > xController = xDoc->getCurrentController();
|
|
if (xController.is())
|
|
xFrame = xController->getFrame();
|
|
if (xFrame.is() && xFrame->isTop())
|
|
xDesktopCheck.set(xFrame->getCreator(), css::uno::UNO_QUERY);
|
|
if (!xDesktopCheck.is())
|
|
return OUString();
|
|
|
|
// OK - now we are sure this document is a top level document.
|
|
// Classify it.
|
|
// SAFE ->
|
|
std::unique_lock aLock(m_mutex);
|
|
css::uno::Reference< css::frame::XModuleManager2 > xModuleManager = m_xModuleManager;
|
|
aLock.unlock();
|
|
// <- SAFE
|
|
|
|
OUString sModuleId;
|
|
try
|
|
{
|
|
sModuleId = xModuleManager->identify(xDoc);
|
|
}
|
|
catch(const css::uno::RuntimeException&)
|
|
{ throw; }
|
|
catch(const css::uno::Exception&)
|
|
{ sModuleId.clear(); }
|
|
|
|
return sModuleId;
|
|
}
|
|
|
|
OUString HelpOnStartup::its_getCurrentHelpURL()
|
|
{
|
|
// SAFE ->
|
|
std::unique_lock aLock(m_mutex);
|
|
css::uno::Reference< css::frame::XDesktop2 > xDesktop = m_xDesktop;
|
|
aLock.unlock();
|
|
// <- SAFE
|
|
|
|
if (!xDesktop.is())
|
|
return OUString();
|
|
|
|
css::uno::Reference< css::frame::XFrame > xHelp = xDesktop->findFrame(SPECIALTARGET_HELPTASK, css::frame::FrameSearchFlag::CHILDREN);
|
|
if (!xHelp.is())
|
|
return OUString();
|
|
|
|
OUString sCurrentHelpURL;
|
|
try
|
|
{
|
|
css::uno::Reference< css::frame::XFramesSupplier > xHelpRoot (xHelp , css::uno::UNO_QUERY_THROW);
|
|
css::uno::Reference< css::container::XIndexAccess > xHelpChildren(xHelpRoot->getFrames(), css::uno::UNO_QUERY_THROW);
|
|
|
|
css::uno::Reference< css::frame::XFrame > xHelpChild;
|
|
css::uno::Reference< css::frame::XController > xHelpView;
|
|
css::uno::Reference< css::frame::XModel > xHelpContent;
|
|
|
|
xHelpChildren->getByIndex(0) >>= xHelpChild;
|
|
if (xHelpChild.is())
|
|
xHelpView = xHelpChild->getController();
|
|
if (xHelpView.is())
|
|
xHelpContent = xHelpView->getModel();
|
|
if (xHelpContent.is())
|
|
sCurrentHelpURL = xHelpContent->getURL();
|
|
}
|
|
catch(const css::uno::RuntimeException&)
|
|
{ throw; }
|
|
catch(const css::uno::Exception&)
|
|
{ sCurrentHelpURL.clear(); }
|
|
|
|
return sCurrentHelpURL;
|
|
}
|
|
|
|
bool HelpOnStartup::its_isHelpUrlADefaultOne(std::u16string_view sHelpURL)
|
|
{
|
|
if (sHelpURL.empty())
|
|
return false;
|
|
|
|
// SAFE ->
|
|
std::unique_lock aLock(m_mutex);
|
|
css::uno::Reference< css::container::XNameAccess > xConfig = m_xConfig;
|
|
OUString sLocale = m_sLocale;
|
|
OUString sSystem = m_sSystem;
|
|
aLock.unlock();
|
|
// <- SAFE
|
|
|
|
if (!xConfig.is())
|
|
return false;
|
|
|
|
// check given help url against all default ones
|
|
const css::uno::Sequence< OUString > lModules = xConfig->getElementNames();
|
|
const OUString* pModules = lModules.getConstArray();
|
|
::sal_Int32 c = lModules.getLength();
|
|
::sal_Int32 i = 0;
|
|
|
|
for (i=0; i<c; ++i)
|
|
{
|
|
try
|
|
{
|
|
css::uno::Reference< css::container::XNameAccess > xModuleConfig;
|
|
xConfig->getByName(pModules[i]) >>= xModuleConfig;
|
|
if (!xModuleConfig.is())
|
|
continue;
|
|
|
|
OUString sHelpBaseURL;
|
|
xModuleConfig->getByName(u"ooSetupFactoryHelpBaseURL"_ustr) >>= sHelpBaseURL;
|
|
OUString sHelpURLForModule = HelpOnStartup::ist_createHelpURL(sHelpBaseURL, sLocale, sSystem);
|
|
if (sHelpURL == sHelpURLForModule)
|
|
return true;
|
|
}
|
|
catch(const css::uno::RuntimeException&)
|
|
{ throw; }
|
|
catch(const css::uno::Exception&)
|
|
{}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
OUString HelpOnStartup::its_checkIfHelpEnabledAndGetURL(const OUString& sModule)
|
|
{
|
|
// SAFE ->
|
|
std::unique_lock aLock(m_mutex);
|
|
css::uno::Reference< css::container::XNameAccess > xConfig = m_xConfig;
|
|
OUString sLocale = m_sLocale;
|
|
OUString sSystem = m_sSystem;
|
|
aLock.unlock();
|
|
// <- SAFE
|
|
|
|
OUString sHelpURL;
|
|
|
|
try
|
|
{
|
|
css::uno::Reference< css::container::XNameAccess > xModuleConfig;
|
|
if (xConfig.is())
|
|
xConfig->getByName(sModule) >>= xModuleConfig;
|
|
|
|
bool bHelpEnabled = false;
|
|
if (xModuleConfig.is())
|
|
xModuleConfig->getByName(u"ooSetupFactoryHelpOnOpen"_ustr) >>= bHelpEnabled;
|
|
|
|
if (bHelpEnabled)
|
|
{
|
|
OUString sHelpBaseURL;
|
|
xModuleConfig->getByName(u"ooSetupFactoryHelpBaseURL"_ustr) >>= sHelpBaseURL;
|
|
sHelpURL = HelpOnStartup::ist_createHelpURL(sHelpBaseURL, sLocale, sSystem);
|
|
}
|
|
}
|
|
catch(const css::uno::RuntimeException&)
|
|
{ throw; }
|
|
catch(const css::uno::Exception&)
|
|
{ sHelpURL.clear(); }
|
|
|
|
return sHelpURL;
|
|
}
|
|
|
|
OUString HelpOnStartup::ist_createHelpURL(std::u16string_view sBaseURL,
|
|
std::u16string_view sLocale ,
|
|
std::u16string_view sSystem )
|
|
{
|
|
return OUString::Concat(sBaseURL) + "?Language=" + sLocale + "&System=" + sSystem;
|
|
}
|
|
|
|
} // namespace framework
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
|
|
framework_HelpOnStartup_get_implementation(
|
|
css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
|
|
{
|
|
return cppu::acquire(new framework::HelpOnStartup(context));
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|