LibreOffice Module framework (master) 1
helponstartup.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20// include own header
22#include <services.h>
23#include <targets.h>
24
25#include <officecfg/Office/Common.hxx>
26#include <officecfg/Setup.hxx>
27
28// include others
30#include <utility>
31#include <vcl/svapp.hxx>
32#include <vcl/help.hxx>
33
34// include interfaces
35#include <com/sun/star/frame/FrameSearchFlag.hpp>
36#include <com/sun/star/frame/ModuleManager.hpp>
37#include <com/sun/star/frame/XFramesSupplier.hpp>
38#include <com/sun/star/frame/Desktop.hpp>
40
41namespace framework{
42
43// XInterface, XTypeProvider, XServiceInfo
44
46{
47 return "com.sun.star.comp.framework.HelpOnStartup";
48}
49
50sal_Bool SAL_CALL HelpOnStartup::supportsService( const OUString& sServiceName )
51{
53}
54
55css::uno::Sequence< OUString > SAL_CALL HelpOnStartup::getSupportedServiceNames()
56{
57 return { SERVICENAME_JOB };
58}
59
60HelpOnStartup::HelpOnStartup(css::uno::Reference< css::uno::XComponentContext > xContext)
61 : m_xContext (std::move(xContext))
62{
63 // create some needed uno services and cache it
64 m_xModuleManager = css::frame::ModuleManager::create( m_xContext );
65
66 m_xDesktop = css::frame::Desktop::create(m_xContext);
67
68 // ask for office locale
69 m_sLocale = officecfg::Setup::L10N::ooLocale::get();
70
71 // detect system
72 m_sSystem = officecfg::Office::Common::Help::System::get();
73
74 // Start listening for disposing events of these services,
75 // so we can react e.g. for an office shutdown
76 css::uno::Reference< css::lang::XComponent > xComponent;
77 xComponent.set(m_xModuleManager, css::uno::UNO_QUERY);
78 if (xComponent.is())
79 xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this));
80 if (m_xDesktop.is())
81 m_xDesktop->addEventListener(static_cast< css::lang::XEventListener* >(this));
82 xComponent.set(m_xConfig, css::uno::UNO_QUERY);
83 if (xComponent.is())
84 xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this));
85}
86
88{
89}
90
91// css.task.XJob
92css::uno::Any SAL_CALL HelpOnStartup::execute(const css::uno::Sequence< css::beans::NamedValue >& lArguments)
93{
94 // Analyze the given arguments; try to locate a model there and
95 // classify it's used application module.
96 OUString sModule = its_getModuleIdFromEnv(lArguments);
97
98 // Attention: we are bound to events for opening any document inside the office.
99 // That includes e.g. the help module itself. But we have to do nothing then!
100 if (sModule.isEmpty())
101 return css::uno::Any();
102
103 // check current state of the help module
104 // a) help isn't open => show default page for the detected module
105 // b) help shows any other default page(!) => show default page for the detected module
106 // c) help shows any other content => do nothing (user travelled to any other content and leaved the set of default pages)
107 OUString sCurrentHelpURL = its_getCurrentHelpURL();
108 bool bCurrentHelpURLIsAnyDefaultURL = its_isHelpUrlADefaultOne(sCurrentHelpURL);
109 bool bShowIt = false;
110
111 // a)
112 if (sCurrentHelpURL.isEmpty())
113 bShowIt = true;
114 // b)
115 else if (bCurrentHelpURLIsAnyDefaultURL)
116 bShowIt = true;
117
118 if (bShowIt)
119 {
120 // retrieve the help URL for the detected application module
121 OUString sModuleDependentHelpURL = its_checkIfHelpEnabledAndGetURL(sModule);
122 if (!sModuleDependentHelpURL.isEmpty())
123 {
124 // Show this help page.
125 // Note: The help window brings itself to front ...
126 Help* pHelp = Application::GetHelp();
127 if (pHelp)
128 pHelp->Start(sModuleDependentHelpURL);
129 }
130 }
131
132 return css::uno::Any();
133}
134
135void SAL_CALL HelpOnStartup::disposing(const css::lang::EventObject& aEvent)
136{
137 std::unique_lock g(m_mutex);
138 if (aEvent.Source == m_xModuleManager)
139 m_xModuleManager.clear();
140 else if (aEvent.Source == m_xDesktop)
141 m_xDesktop.clear();
142 else if (aEvent.Source == m_xConfig)
143 m_xConfig.clear();
144}
145
146OUString HelpOnStartup::its_getModuleIdFromEnv(const css::uno::Sequence< css::beans::NamedValue >& lArguments)
147{
148 ::comphelper::SequenceAsHashMap lArgs (lArguments);
149 ::comphelper::SequenceAsHashMap lEnvironment = lArgs.getUnpackedValueOrDefault("Environment", css::uno::Sequence< css::beans::NamedValue >());
150
151 // check for right environment.
152 // If it's not a DocumentEvent, which triggered this job,
153 // we can't work correctly! => return immediately and do nothing
154 OUString sEnvType = lEnvironment.getUnpackedValueOrDefault("EnvType", OUString());
155 if (sEnvType != "DOCUMENTEVENT")
156 return OUString();
157
158 css::uno::Reference< css::frame::XModel > xDoc = lEnvironment.getUnpackedValueOrDefault("Model", css::uno::Reference< css::frame::XModel >());
159 if (!xDoc.is())
160 return OUString();
161
162 // be sure that we work on top level documents only, which are registered
163 // on the desktop instance. Ignore e.g. life previews, which are top frames too ...
164 // but not registered at this global desktop instance.
165 css::uno::Reference< css::frame::XDesktop > xDesktopCheck;
166 css::uno::Reference< css::frame::XFrame > xFrame;
167 css::uno::Reference< css::frame::XController > xController = xDoc->getCurrentController();
168 if (xController.is())
169 xFrame = xController->getFrame();
170 if (xFrame.is() && xFrame->isTop())
171 xDesktopCheck.set(xFrame->getCreator(), css::uno::UNO_QUERY);
172 if (!xDesktopCheck.is())
173 return OUString();
174
175 // OK - now we are sure this document is a top level document.
176 // Classify it.
177 // SAFE ->
178 std::unique_lock aLock(m_mutex);
179 css::uno::Reference< css::frame::XModuleManager2 > xModuleManager = m_xModuleManager;
180 aLock.unlock();
181 // <- SAFE
182
183 OUString sModuleId;
184 try
185 {
186 sModuleId = xModuleManager->identify(xDoc);
187 }
188 catch(const css::uno::RuntimeException&)
189 { throw; }
190 catch(const css::uno::Exception&)
191 { sModuleId.clear(); }
192
193 return sModuleId;
194}
195
197{
198 // SAFE ->
199 std::unique_lock aLock(m_mutex);
200 css::uno::Reference< css::frame::XDesktop2 > xDesktop = m_xDesktop;
201 aLock.unlock();
202 // <- SAFE
203
204 if (!xDesktop.is())
205 return OUString();
206
207 css::uno::Reference< css::frame::XFrame > xHelp = xDesktop->findFrame(SPECIALTARGET_HELPTASK, css::frame::FrameSearchFlag::CHILDREN);
208 if (!xHelp.is())
209 return OUString();
210
211 OUString sCurrentHelpURL;
212 try
213 {
214 css::uno::Reference< css::frame::XFramesSupplier > xHelpRoot (xHelp , css::uno::UNO_QUERY_THROW);
215 css::uno::Reference< css::container::XIndexAccess > xHelpChildren(xHelpRoot->getFrames(), css::uno::UNO_QUERY_THROW);
216
217 css::uno::Reference< css::frame::XFrame > xHelpChild;
218 css::uno::Reference< css::frame::XController > xHelpView;
219 css::uno::Reference< css::frame::XModel > xHelpContent;
220
221 xHelpChildren->getByIndex(0) >>= xHelpChild;
222 if (xHelpChild.is())
223 xHelpView = xHelpChild->getController();
224 if (xHelpView.is())
225 xHelpContent = xHelpView->getModel();
226 if (xHelpContent.is())
227 sCurrentHelpURL = xHelpContent->getURL();
228 }
229 catch(const css::uno::RuntimeException&)
230 { throw; }
231 catch(const css::uno::Exception&)
232 { sCurrentHelpURL.clear(); }
233
234 return sCurrentHelpURL;
235}
236
237bool HelpOnStartup::its_isHelpUrlADefaultOne(std::u16string_view sHelpURL)
238{
239 if (sHelpURL.empty())
240 return false;
241
242 // SAFE ->
243 std::unique_lock aLock(m_mutex);
244 css::uno::Reference< css::container::XNameAccess > xConfig = m_xConfig;
245 OUString sLocale = m_sLocale;
246 OUString sSystem = m_sSystem;
247 aLock.unlock();
248 // <- SAFE
249
250 if (!xConfig.is())
251 return false;
252
253 // check given help url against all default ones
254 const css::uno::Sequence< OUString > lModules = xConfig->getElementNames();
255 const OUString* pModules = lModules.getConstArray();
256 ::sal_Int32 c = lModules.getLength();
257 ::sal_Int32 i = 0;
258
259 for (i=0; i<c; ++i)
260 {
261 try
262 {
263 css::uno::Reference< css::container::XNameAccess > xModuleConfig;
264 xConfig->getByName(pModules[i]) >>= xModuleConfig;
265 if (!xModuleConfig.is())
266 continue;
267
268 OUString sHelpBaseURL;
269 xModuleConfig->getByName("ooSetupFactoryHelpBaseURL") >>= sHelpBaseURL;
270 OUString sHelpURLForModule = HelpOnStartup::ist_createHelpURL(sHelpBaseURL, sLocale, sSystem);
271 if (sHelpURL == sHelpURLForModule)
272 return true;
273 }
274 catch(const css::uno::RuntimeException&)
275 { throw; }
276 catch(const css::uno::Exception&)
277 {}
278 }
279
280 return false;
281}
282
283OUString HelpOnStartup::its_checkIfHelpEnabledAndGetURL(const OUString& sModule)
284{
285 // SAFE ->
286 std::unique_lock aLock(m_mutex);
287 css::uno::Reference< css::container::XNameAccess > xConfig = m_xConfig;
288 OUString sLocale = m_sLocale;
289 OUString sSystem = m_sSystem;
290 aLock.unlock();
291 // <- SAFE
292
293 OUString sHelpURL;
294
295 try
296 {
297 css::uno::Reference< css::container::XNameAccess > xModuleConfig;
298 if (xConfig.is())
299 xConfig->getByName(sModule) >>= xModuleConfig;
300
301 bool bHelpEnabled = false;
302 if (xModuleConfig.is())
303 xModuleConfig->getByName("ooSetupFactoryHelpOnOpen") >>= bHelpEnabled;
304
305 if (bHelpEnabled)
306 {
307 OUString sHelpBaseURL;
308 xModuleConfig->getByName("ooSetupFactoryHelpBaseURL") >>= sHelpBaseURL;
309 sHelpURL = HelpOnStartup::ist_createHelpURL(sHelpBaseURL, sLocale, sSystem);
310 }
311 }
312 catch(const css::uno::RuntimeException&)
313 { throw; }
314 catch(const css::uno::Exception&)
315 { sHelpURL.clear(); }
316
317 return sHelpURL;
318}
319
320OUString HelpOnStartup::ist_createHelpURL(std::u16string_view sBaseURL,
321 std::u16string_view sLocale ,
322 std::u16string_view sSystem )
323{
324 return OUString::Concat(sBaseURL) + "?Language=" + sLocale + "&System=" + sSystem;
325}
326
327} // namespace framework
328
329extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
331 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
332{
333 return cppu::acquire(new framework::HelpOnStartup(context));
334}
335
336/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr OUStringLiteral sServiceName
AnyEventRef aEvent
static Help * GetHelp()
virtual bool Start(const OUString &rHelpId, weld::Widget *pWidget=nullptr)
TValueType getUnpackedValueOrDefault(const OUString &sKey, const TValueType &aDefault) const
implements a job component, which handle the special feature to show a suitable help page for every (...
HelpOnStartup(css::uno::Reference< css::uno::XComponentContext > xContext)
create new instance of this class.
css::uno::Reference< css::frame::XDesktop2 > m_xDesktop
is needed to locate a might open help frame.
static OUString ist_createHelpURL(std::u16string_view sBaseURL, std::u16string_view sLocale, std::u16string_view sSystem)
create a help URL for the given parameters.
OUString its_checkIfHelpEnabledAndGetURL(const OUString &sModule)
checks, if the help module should be shown automatically for the currently opened office module.
virtual void SAL_CALL disposing(const css::lang::EventObject &aEvent) override
virtual OUString SAL_CALL getImplementationName() override
OUString its_getCurrentHelpURL()
tries to locate the open help module and return the url of the currently shown help content.
OUString m_sSystem
knows the current operating system of this office session, which is needed to build complete help URL...
bool its_isHelpUrlADefaultOne(std::u16string_view sHelpURL)
checks if the given help url match to a default help url of any office module.
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
css::uno::Reference< css::frame::XModuleManager2 > m_xModuleManager
such module manager is used to classify new opened documents.
OUString m_sLocale
knows the current locale of this office session, which is needed to build complete help URLs.
virtual css::uno::Any SAL_CALL execute(const css::uno::Sequence< css::beans::NamedValue > &lArguments) override
virtual ~HelpOnStartup() override
does nothing real ...
virtual sal_Bool SAL_CALL supportsService(const OUString &sServiceName) override
css::uno::Reference< css::uno::XComponentContext > m_xContext
reference to a uno service manager.
css::uno::Reference< css::container::XNameAccess > m_xConfig
provides read access to the underlying configuration.
OUString its_getModuleIdFromEnv(const css::uno::Sequence< css::beans::NamedValue > &lArguments)
analyze the given job arguments, try to locate a model reference and try to classify this model.
css::uno::Reference< css::uno::XComponentContext > m_xContext
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * framework_HelpOnStartup_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
constexpr OUStringLiteral SERVICENAME_JOB
Definition: services.h:31
constexpr OUStringLiteral SPECIALTARGET_HELPTASK
Definition: targets.h:34
int i
Reference< XController > xController
Reference< XFrame > xFrame
unsigned char sal_Bool