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>
22 #include <loadenv/targethelper.hxx>
26 #include <comphelper/configurationhelper.hxx>
27 #include <comphelper/sequenceashashmap.hxx>
28 #include <unotools/configmgr.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/help.hxx>
31 #include <rtl/ustrbuf.hxx>
34 #include <com/sun/star/frame/FrameSearchFlag.hpp>
35 #include <com/sun/star/frame/ModuleManager.hpp>
36 #include <com/sun/star/frame/XFramesSupplier.hpp>
37 #include <com/sun/star/frame/Desktop.hpp>
41 DEFINE_XSERVICEINFO_MULTISERVICE_2(HelpOnStartup
,
44 IMPLEMENTATIONNAME_HELPONSTARTUP
)
46 DEFINE_INIT_SERVICE(HelpOnStartup
,
49 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
50 to create a new instance of this class by our own supported service factory.
51 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further information!
53 // create some needed uno services and cache it
54 m_xModuleManager
= css::frame::ModuleManager::create( m_xContext
);
56 m_xDesktop
= css::frame::Desktop::create(m_xContext
);
58 m_xConfig
= css::uno::Reference
< css::container::XNameAccess
>(
59 ::comphelper::ConfigurationHelper::openConfig(
61 "/org.openoffice.Setup/Office/Factories",
62 ::comphelper::ConfigurationHelper::E_READONLY
),
63 css::uno::UNO_QUERY_THROW
);
65 // ask for office locale
66 ::comphelper::ConfigurationHelper::readDirectKey(
68 "/org.openoffice.Setup",
71 ::comphelper::ConfigurationHelper::E_READONLY
) >>= m_sLocale
;
74 ::comphelper::ConfigurationHelper::readDirectKey(
76 "/org.openoffice.Office.Common",
79 ::comphelper::ConfigurationHelper::E_READONLY
) >>= m_sSystem
;
81 // Start listening for disposing events of these services,
82 // so we can react e.g. for an office shutdown
83 css::uno::Reference
< css::lang::XComponent
> xComponent
;
84 xComponent
= css::uno::Reference
< css::lang::XComponent
>(m_xModuleManager
, css::uno::UNO_QUERY
);
86 xComponent
->addEventListener(static_cast< css::lang::XEventListener
* >(this));
87 xComponent
= css::uno::Reference
< css::lang::XComponent
>(m_xDesktop
, css::uno::UNO_QUERY
);
89 xComponent
->addEventListener(static_cast< css::lang::XEventListener
* >(this));
90 xComponent
= css::uno::Reference
< css::lang::XComponent
>(m_xConfig
, css::uno::UNO_QUERY
);
92 xComponent
->addEventListener(static_cast< css::lang::XEventListener
* >(this));
96 HelpOnStartup::HelpOnStartup(const css::uno::Reference
< css::uno::XComponentContext
>& xContext
)
97 : m_xContext (xContext
)
101 HelpOnStartup::~HelpOnStartup()
106 css::uno::Any SAL_CALL
HelpOnStartup::execute(const css::uno::Sequence
< css::beans::NamedValue
>& lArguments
)
107 throw(css::lang::IllegalArgumentException
,
108 css::uno::Exception
,
109 css::uno::RuntimeException
, std::exception
)
111 // Analyze the given arguments; try to locate a model there and
112 // classify it's used application module.
113 OUString sModule
= its_getModuleIdFromEnv(lArguments
);
115 // Attention: We are bound to events for openeing any document inside the office.
116 // That includes e.g. the help module itself. But we have to do nothing then!
117 if (sModule
.isEmpty())
118 return css::uno::Any();
120 // check current state of the help module
121 // a) help isn't open => show default page for the detected module
122 // b) help shows any other default page(!) => show default page for the detected module
123 // c) help shows any other content => do nothing (user travelled to any other content and leaved the set of default pages)
124 OUString sCurrentHelpURL
= its_getCurrentHelpURL();
125 bool bCurrentHelpURLIsAnyDefaultURL
= its_isHelpUrlADefaultOne(sCurrentHelpURL
);
126 bool bShowIt
= false;
129 if (sCurrentHelpURL
.isEmpty())
132 else if (bCurrentHelpURLIsAnyDefaultURL
)
137 // retrieve the help URL for the detected application module
138 OUString sModuleDependendHelpURL
= its_checkIfHelpEnabledAndGetURL(sModule
);
139 if (!sModuleDependendHelpURL
.isEmpty())
141 // Show this help page.
142 // Note: The help window brings itself to front ...
143 Help
* pHelp
= Application::GetHelp();
145 pHelp
->Start(sModuleDependendHelpURL
, 0);
149 return css::uno::Any();
152 void SAL_CALL
HelpOnStartup::disposing(const css::lang::EventObject
& aEvent
)
153 throw(css::uno::RuntimeException
, std::exception
)
155 osl::MutexGuard
g(m_mutex
);
156 if (aEvent
.Source
== m_xModuleManager
)
157 m_xModuleManager
.clear();
158 else if (aEvent
.Source
== m_xDesktop
)
160 else if (aEvent
.Source
== m_xConfig
)
164 OUString
HelpOnStartup::its_getModuleIdFromEnv(const css::uno::Sequence
< css::beans::NamedValue
>& lArguments
)
166 ::comphelper::SequenceAsHashMap
lArgs (lArguments
);
167 ::comphelper::SequenceAsHashMap lEnvironment
= lArgs
.getUnpackedValueOrDefault("Environment", css::uno::Sequence
< css::beans::NamedValue
>());
168 ::comphelper::SequenceAsHashMap lJobConfig
= lArgs
.getUnpackedValueOrDefault("JobConfig", css::uno::Sequence
< css::beans::NamedValue
>());
170 // check for right environment.
171 // If its not a DocumentEvent, which triggered this job,
172 // we can't work correctly! => return immediately and do nothing
173 OUString sEnvType
= lEnvironment
.getUnpackedValueOrDefault("EnvType", OUString());
174 if (sEnvType
!= "DOCUMENTEVENT")
177 css::uno::Reference
< css::frame::XModel
> xDoc
= lEnvironment
.getUnpackedValueOrDefault("Model", css::uno::Reference
< css::frame::XModel
>());
181 // be sure that we work on top level documents only, which are registered
182 // on the desktop instance. Ignore e.g. life previews, which are top frames too ...
183 // but not registered at this global desktop instance.
184 css::uno::Reference
< css::frame::XDesktop
> xDesktopCheck
;
185 css::uno::Reference
< css::frame::XFrame
> xFrame
;
186 css::uno::Reference
< css::frame::XController
> xController
= xDoc
->getCurrentController();
187 if (xController
.is())
188 xFrame
= xController
->getFrame();
189 if (xFrame
.is() && xFrame
->isTop())
190 xDesktopCheck
= css::uno::Reference
< css::frame::XDesktop
>(xFrame
->getCreator(), css::uno::UNO_QUERY
);
191 if (!xDesktopCheck
.is())
194 // OK - now we are sure this document is a top level document.
197 osl::ClearableMutexGuard
aLock(m_mutex
);
198 css::uno::Reference
< css::frame::XModuleManager2
> xModuleManager
= m_xModuleManager
;
205 sModuleId
= xModuleManager
->identify(xDoc
);
207 catch(const css::uno::RuntimeException
&)
209 catch(const css::uno::Exception
&)
210 { sModuleId
.clear(); }
215 OUString
HelpOnStartup::its_getCurrentHelpURL()
218 osl::ClearableMutexGuard
aLock(m_mutex
);
219 css::uno::Reference
< css::frame::XDesktop2
> xDesktop
= m_xDesktop
;
226 css::uno::Reference
< css::frame::XFrame
> xHelp
= xDesktop
->findFrame(SPECIALTARGET_HELPTASK
, css::frame::FrameSearchFlag::CHILDREN
);
230 OUString sCurrentHelpURL
;
233 css::uno::Reference
< css::frame::XFramesSupplier
> xHelpRoot (xHelp
, css::uno::UNO_QUERY_THROW
);
234 css::uno::Reference
< css::container::XIndexAccess
> xHelpChildren(xHelpRoot
->getFrames(), css::uno::UNO_QUERY_THROW
);
236 css::uno::Reference
< css::frame::XFrame
> xHelpChild
;
237 css::uno::Reference
< css::frame::XController
> xHelpView
;
238 css::uno::Reference
< css::frame::XModel
> xHelpContent
;
240 xHelpChildren
->getByIndex(0) >>= xHelpChild
;
242 xHelpView
= xHelpChild
->getController();
244 xHelpContent
= xHelpView
->getModel();
245 if (xHelpContent
.is())
246 sCurrentHelpURL
= xHelpContent
->getURL();
248 catch(const css::uno::RuntimeException
&)
250 catch(const css::uno::Exception
&)
251 { sCurrentHelpURL
.clear(); }
253 return sCurrentHelpURL
;
256 bool HelpOnStartup::its_isHelpUrlADefaultOne(const OUString
& sHelpURL
)
258 if (sHelpURL
.isEmpty())
262 osl::ClearableMutexGuard
aLock(m_mutex
);
263 css::uno::Reference
< css::container::XNameAccess
> xConfig
= m_xConfig
;
264 OUString sLocale
= m_sLocale
;
265 OUString sSystem
= m_sSystem
;
272 // check given help url against all default ones
273 const css::uno::Sequence
< OUString
> lModules
= xConfig
->getElementNames();
274 const OUString
* pModules
= lModules
.getConstArray();
275 ::sal_Int32 c
= lModules
.getLength();
282 css::uno::Reference
< css::container::XNameAccess
> xModuleConfig
;
283 xConfig
->getByName(pModules
[i
]) >>= xModuleConfig
;
284 if (!xModuleConfig
.is())
287 OUString sHelpBaseURL
;
288 xModuleConfig
->getByName("ooSetupFactoryHelpBaseURL") >>= sHelpBaseURL
;
289 OUString sHelpURLForModule
= HelpOnStartup::ist_createHelpURL(sHelpBaseURL
, sLocale
, sSystem
);
290 if (sHelpURL
.equals(sHelpURLForModule
))
293 catch(const css::uno::RuntimeException
&)
295 catch(const css::uno::Exception
&)
302 OUString
HelpOnStartup::its_checkIfHelpEnabledAndGetURL(const OUString
& sModule
)
305 osl::ClearableMutexGuard
aLock(m_mutex
);
306 css::uno::Reference
< css::container::XNameAccess
> xConfig
= m_xConfig
;
307 OUString sLocale
= m_sLocale
;
308 OUString sSystem
= m_sSystem
;
316 css::uno::Reference
< css::container::XNameAccess
> xModuleConfig
;
318 xConfig
->getByName(sModule
) >>= xModuleConfig
;
320 bool bHelpEnabled
= false;
321 if (xModuleConfig
.is())
322 xModuleConfig
->getByName("ooSetupFactoryHelpOnOpen") >>= bHelpEnabled
;
326 OUString sHelpBaseURL
;
327 xModuleConfig
->getByName("ooSetupFactoryHelpBaseURL") >>= sHelpBaseURL
;
328 sHelpURL
= HelpOnStartup::ist_createHelpURL(sHelpBaseURL
, sLocale
, sSystem
);
331 catch(const css::uno::RuntimeException
&)
333 catch(const css::uno::Exception
&)
334 { sHelpURL
.clear(); }
339 OUString
HelpOnStartup::ist_createHelpURL(const OUString
& sBaseURL
,
340 const OUString
& sLocale
,
341 const OUString
& sSystem
)
343 OUStringBuffer
sHelpURL(256);
344 sHelpURL
.append (sBaseURL
);
345 sHelpURL
.appendAscii("?Language=");
346 sHelpURL
.append (sLocale
);
347 sHelpURL
.appendAscii("&System=" );
348 sHelpURL
.append (sSystem
);
350 return sHelpURL
.makeStringAndClear();
353 } // namespace framework
355 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */