1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <jobs/helponstartup.hxx>
25 #include <officecfg/Office/Common.hxx>
26 #include <officecfg/Setup.hxx>
29 #include <comphelper/sequenceashashmap.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/help.hxx>
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>
39 #include <cppuhelper/supportsservice.hxx>
43 // XInterface, XTypeProvider, XServiceInfo
45 OUString SAL_CALL
HelpOnStartup::getImplementationName()
47 return "com.sun.star.comp.framework.HelpOnStartup";
50 sal_Bool SAL_CALL
HelpOnStartup::supportsService( const OUString
& sServiceName
)
52 return cppu::supportsService(this, sServiceName
);
55 css::uno::Sequence
< OUString
> SAL_CALL
HelpOnStartup::getSupportedServiceNames()
57 return { SERVICENAME_JOB
};
60 HelpOnStartup::HelpOnStartup(css::uno::Reference
< css::uno::XComponentContext
> xContext
)
61 : m_xContext (std::move(xContext
))
63 // create some needed uno services and cache it
64 m_xModuleManager
= css::frame::ModuleManager::create( m_xContext
);
66 m_xDesktop
= css::frame::Desktop::create(m_xContext
);
68 // ask for office locale
69 m_sLocale
= officecfg::Setup::L10N::ooLocale::get();
72 m_sSystem
= officecfg::Office::Common::Help::System::get();
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
);
79 xComponent
->addEventListener(static_cast< css::lang::XEventListener
* >(this));
81 m_xDesktop
->addEventListener(static_cast< css::lang::XEventListener
* >(this));
82 xComponent
.set(m_xConfig
, css::uno::UNO_QUERY
);
84 xComponent
->addEventListener(static_cast< css::lang::XEventListener
* >(this));
87 HelpOnStartup::~HelpOnStartup()
92 css::uno::Any SAL_CALL
HelpOnStartup::execute(const css::uno::Sequence
< css::beans::NamedValue
>& lArguments
)
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
);
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();
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;
112 if (sCurrentHelpURL
.isEmpty())
115 else if (bCurrentHelpURLIsAnyDefaultURL
)
120 // retrieve the help URL for the detected application module
121 OUString sModuleDependentHelpURL
= its_checkIfHelpEnabledAndGetURL(sModule
);
122 if (!sModuleDependentHelpURL
.isEmpty())
124 // Show this help page.
125 // Note: The help window brings itself to front ...
126 Help
* pHelp
= Application::GetHelp();
128 pHelp
->Start(sModuleDependentHelpURL
);
132 return css::uno::Any();
135 void SAL_CALL
HelpOnStartup::disposing(const css::lang::EventObject
& aEvent
)
137 std::unique_lock
g(m_mutex
);
138 if (aEvent
.Source
== m_xModuleManager
)
139 m_xModuleManager
.clear();
140 else if (aEvent
.Source
== m_xDesktop
)
142 else if (aEvent
.Source
== m_xConfig
)
146 OUString
HelpOnStartup::its_getModuleIdFromEnv(const css::uno::Sequence
< css::beans::NamedValue
>& lArguments
)
148 ::comphelper::SequenceAsHashMap
lArgs (lArguments
);
149 ::comphelper::SequenceAsHashMap lEnvironment
= lArgs
.getUnpackedValueOrDefault("Environment", css::uno::Sequence
< css::beans::NamedValue
>());
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")
158 css::uno::Reference
< css::frame::XModel
> xDoc
= lEnvironment
.getUnpackedValueOrDefault("Model", css::uno::Reference
< css::frame::XModel
>());
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())
175 // OK - now we are sure this document is a top level document.
178 std::unique_lock
aLock(m_mutex
);
179 css::uno::Reference
< css::frame::XModuleManager2
> xModuleManager
= m_xModuleManager
;
186 sModuleId
= xModuleManager
->identify(xDoc
);
188 catch(const css::uno::RuntimeException
&)
190 catch(const css::uno::Exception
&)
191 { sModuleId
.clear(); }
196 OUString
HelpOnStartup::its_getCurrentHelpURL()
199 std::unique_lock
aLock(m_mutex
);
200 css::uno::Reference
< css::frame::XDesktop2
> xDesktop
= m_xDesktop
;
207 css::uno::Reference
< css::frame::XFrame
> xHelp
= xDesktop
->findFrame(SPECIALTARGET_HELPTASK
, css::frame::FrameSearchFlag::CHILDREN
);
211 OUString sCurrentHelpURL
;
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
);
217 css::uno::Reference
< css::frame::XFrame
> xHelpChild
;
218 css::uno::Reference
< css::frame::XController
> xHelpView
;
219 css::uno::Reference
< css::frame::XModel
> xHelpContent
;
221 xHelpChildren
->getByIndex(0) >>= xHelpChild
;
223 xHelpView
= xHelpChild
->getController();
225 xHelpContent
= xHelpView
->getModel();
226 if (xHelpContent
.is())
227 sCurrentHelpURL
= xHelpContent
->getURL();
229 catch(const css::uno::RuntimeException
&)
231 catch(const css::uno::Exception
&)
232 { sCurrentHelpURL
.clear(); }
234 return sCurrentHelpURL
;
237 bool HelpOnStartup::its_isHelpUrlADefaultOne(std::u16string_view sHelpURL
)
239 if (sHelpURL
.empty())
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
;
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();
263 css::uno::Reference
< css::container::XNameAccess
> xModuleConfig
;
264 xConfig
->getByName(pModules
[i
]) >>= xModuleConfig
;
265 if (!xModuleConfig
.is())
268 OUString sHelpBaseURL
;
269 xModuleConfig
->getByName("ooSetupFactoryHelpBaseURL") >>= sHelpBaseURL
;
270 OUString sHelpURLForModule
= HelpOnStartup::ist_createHelpURL(sHelpBaseURL
, sLocale
, sSystem
);
271 if (sHelpURL
== sHelpURLForModule
)
274 catch(const css::uno::RuntimeException
&)
276 catch(const css::uno::Exception
&)
283 OUString
HelpOnStartup::its_checkIfHelpEnabledAndGetURL(const OUString
& sModule
)
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
;
297 css::uno::Reference
< css::container::XNameAccess
> xModuleConfig
;
299 xConfig
->getByName(sModule
) >>= xModuleConfig
;
301 bool bHelpEnabled
= false;
302 if (xModuleConfig
.is())
303 xModuleConfig
->getByName("ooSetupFactoryHelpOnOpen") >>= bHelpEnabled
;
307 OUString sHelpBaseURL
;
308 xModuleConfig
->getByName("ooSetupFactoryHelpBaseURL") >>= sHelpBaseURL
;
309 sHelpURL
= HelpOnStartup::ist_createHelpURL(sHelpBaseURL
, sLocale
, sSystem
);
312 catch(const css::uno::RuntimeException
&)
314 catch(const css::uno::Exception
&)
315 { sHelpURL
.clear(); }
320 OUString
HelpOnStartup::ist_createHelpURL(std::u16string_view sBaseURL
,
321 std::u16string_view sLocale
,
322 std::u16string_view sSystem
)
324 return OUString::Concat(sBaseURL
) + "?Language=" + sLocale
+ "&System=" + sSystem
;
327 } // namespace framework
329 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
330 framework_HelpOnStartup_get_implementation(
331 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const& )
333 return cppu::acquire(new framework::HelpOnStartup(context
));
336 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */