Line data Source code
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
21 : #include <jobs/helponstartup.hxx>
22 : #include <loadenv/targethelper.hxx>
23 : #include <services.h>
24 :
25 : // include others
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>
32 :
33 : // include interfaces
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>
38 :
39 : namespace framework{
40 :
41 11 : DEFINE_XSERVICEINFO_MULTISERVICE_2(HelpOnStartup ,
42 : ::cppu::OWeakObject ,
43 : SERVICENAME_JOB ,
44 : IMPLEMENTATIONNAME_HELPONSTARTUP)
45 :
46 1 : DEFINE_INIT_SERVICE(HelpOnStartup,
47 : {
48 : /* Attention
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!
52 : */
53 : // create some needed uno services and cache it
54 : m_xModuleManager = css::frame::ModuleManager::create( m_xContext );
55 :
56 : m_xDesktop = css::frame::Desktop::create(m_xContext);
57 :
58 : m_xConfig = css::uno::Reference< css::container::XNameAccess >(
59 : ::comphelper::ConfigurationHelper::openConfig(
60 : m_xContext,
61 : "/org.openoffice.Setup/Office/Factories",
62 : ::comphelper::ConfigurationHelper::E_READONLY),
63 : css::uno::UNO_QUERY_THROW);
64 :
65 : // ask for office locale
66 : ::comphelper::ConfigurationHelper::readDirectKey(
67 : m_xContext,
68 : "/org.openoffice.Setup",
69 : "L10N",
70 : "ooLocale",
71 : ::comphelper::ConfigurationHelper::E_READONLY) >>= m_sLocale;
72 :
73 : // detect system
74 : ::comphelper::ConfigurationHelper::readDirectKey(
75 : m_xContext,
76 : "/org.openoffice.Office.Common",
77 : "Help",
78 : "System",
79 : ::comphelper::ConfigurationHelper::E_READONLY) >>= m_sSystem;
80 :
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);
85 : if (xComponent.is())
86 : xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this));
87 : xComponent = css::uno::Reference< css::lang::XComponent >(m_xDesktop, css::uno::UNO_QUERY);
88 : if (xComponent.is())
89 : xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this));
90 : xComponent = css::uno::Reference< css::lang::XComponent >(m_xConfig, css::uno::UNO_QUERY);
91 : if (xComponent.is())
92 : xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this));
93 : }
94 : )
95 :
96 1 : HelpOnStartup::HelpOnStartup(const css::uno::Reference< css::uno::XComponentContext >& xContext)
97 1 : : m_xContext (xContext)
98 : {
99 1 : }
100 :
101 0 : HelpOnStartup::~HelpOnStartup()
102 : {
103 0 : }
104 :
105 : // css.task.XJob
106 0 : 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 )
110 : {
111 : // Analyze the given arguments; try to locate a model there and
112 : // classify it's used application module.
113 0 : OUString sModule = its_getModuleIdFromEnv(lArguments);
114 :
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 0 : if (sModule.isEmpty())
118 0 : return css::uno::Any();
119 :
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 0 : OUString sCurrentHelpURL = its_getCurrentHelpURL();
125 0 : bool bCurrentHelpURLIsAnyDefaultURL = its_isHelpUrlADefaultOne(sCurrentHelpURL);
126 0 : bool bShowIt = false;
127 :
128 : // a)
129 0 : if (sCurrentHelpURL.isEmpty())
130 0 : bShowIt = true;
131 : // b)
132 0 : else if (bCurrentHelpURLIsAnyDefaultURL)
133 0 : bShowIt = true;
134 :
135 0 : if (bShowIt)
136 : {
137 : // retrieve the help URL for the detected application module
138 0 : OUString sModuleDependendHelpURL = its_checkIfHelpEnabledAndGetURL(sModule);
139 0 : if (!sModuleDependendHelpURL.isEmpty())
140 : {
141 : // Show this help page.
142 : // Note: The help window brings itself to front ...
143 0 : Help* pHelp = Application::GetHelp();
144 0 : if (pHelp)
145 0 : pHelp->Start(sModuleDependendHelpURL, 0);
146 0 : }
147 : }
148 :
149 0 : return css::uno::Any();
150 : }
151 :
152 1 : void SAL_CALL HelpOnStartup::disposing(const css::lang::EventObject& aEvent)
153 : throw(css::uno::RuntimeException, std::exception)
154 : {
155 1 : osl::MutexGuard g(m_mutex);
156 1 : if (aEvent.Source == m_xModuleManager)
157 0 : m_xModuleManager.clear();
158 1 : else if (aEvent.Source == m_xDesktop)
159 1 : m_xDesktop.clear();
160 0 : else if (aEvent.Source == m_xConfig)
161 0 : m_xConfig.clear();
162 1 : }
163 :
164 0 : OUString HelpOnStartup::its_getModuleIdFromEnv(const css::uno::Sequence< css::beans::NamedValue >& lArguments)
165 : {
166 0 : ::comphelper::SequenceAsHashMap lArgs (lArguments);
167 0 : ::comphelper::SequenceAsHashMap lEnvironment = lArgs.getUnpackedValueOrDefault("Environment", css::uno::Sequence< css::beans::NamedValue >());
168 0 : ::comphelper::SequenceAsHashMap lJobConfig = lArgs.getUnpackedValueOrDefault("JobConfig", css::uno::Sequence< css::beans::NamedValue >());
169 :
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 0 : OUString sEnvType = lEnvironment.getUnpackedValueOrDefault("EnvType", OUString());
174 0 : if (sEnvType != "DOCUMENTEVENT")
175 0 : return OUString();
176 :
177 0 : css::uno::Reference< css::frame::XModel > xDoc = lEnvironment.getUnpackedValueOrDefault("Model", css::uno::Reference< css::frame::XModel >());
178 0 : if (!xDoc.is())
179 0 : return OUString();
180 :
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 0 : css::uno::Reference< css::frame::XDesktop > xDesktopCheck;
185 0 : css::uno::Reference< css::frame::XFrame > xFrame;
186 0 : css::uno::Reference< css::frame::XController > xController = xDoc->getCurrentController();
187 0 : if (xController.is())
188 0 : xFrame = xController->getFrame();
189 0 : if (xFrame.is() && xFrame->isTop())
190 0 : xDesktopCheck = css::uno::Reference< css::frame::XDesktop >(xFrame->getCreator(), css::uno::UNO_QUERY);
191 0 : if (!xDesktopCheck.is())
192 0 : return OUString();
193 :
194 : // OK - now we are sure this document is a top level document.
195 : // Classify it.
196 : // SAFE ->
197 0 : osl::ClearableMutexGuard aLock(m_mutex);
198 0 : css::uno::Reference< css::frame::XModuleManager2 > xModuleManager = m_xModuleManager;
199 0 : aLock.clear();
200 : // <- SAFE
201 :
202 0 : OUString sModuleId;
203 : try
204 : {
205 0 : sModuleId = xModuleManager->identify(xDoc);
206 : }
207 0 : catch(const css::uno::RuntimeException&)
208 0 : { throw; }
209 0 : catch(const css::uno::Exception&)
210 0 : { sModuleId.clear(); }
211 :
212 0 : return sModuleId;
213 : }
214 :
215 0 : OUString HelpOnStartup::its_getCurrentHelpURL()
216 : {
217 : // SAFE ->
218 0 : osl::ClearableMutexGuard aLock(m_mutex);
219 0 : css::uno::Reference< css::frame::XDesktop2 > xDesktop = m_xDesktop;
220 0 : aLock.clear();
221 : // <- SAFE
222 :
223 0 : if (!xDesktop.is())
224 0 : return OUString();
225 :
226 0 : css::uno::Reference< css::frame::XFrame > xHelp = xDesktop->findFrame(SPECIALTARGET_HELPTASK, css::frame::FrameSearchFlag::CHILDREN);
227 0 : if (!xHelp.is())
228 0 : return OUString();
229 :
230 0 : OUString sCurrentHelpURL;
231 : try
232 : {
233 0 : css::uno::Reference< css::frame::XFramesSupplier > xHelpRoot (xHelp , css::uno::UNO_QUERY_THROW);
234 0 : css::uno::Reference< css::container::XIndexAccess > xHelpChildren(xHelpRoot->getFrames(), css::uno::UNO_QUERY_THROW);
235 :
236 0 : css::uno::Reference< css::frame::XFrame > xHelpChild;
237 0 : css::uno::Reference< css::frame::XController > xHelpView;
238 0 : css::uno::Reference< css::frame::XModel > xHelpContent;
239 :
240 0 : xHelpChildren->getByIndex(0) >>= xHelpChild;
241 0 : if (xHelpChild.is())
242 0 : xHelpView = xHelpChild->getController();
243 0 : if (xHelpView.is())
244 0 : xHelpContent = xHelpView->getModel();
245 0 : if (xHelpContent.is())
246 0 : sCurrentHelpURL = xHelpContent->getURL();
247 : }
248 0 : catch(const css::uno::RuntimeException&)
249 0 : { throw; }
250 0 : catch(const css::uno::Exception&)
251 0 : { sCurrentHelpURL.clear(); }
252 :
253 0 : return sCurrentHelpURL;
254 : }
255 :
256 0 : bool HelpOnStartup::its_isHelpUrlADefaultOne(const OUString& sHelpURL)
257 : {
258 0 : if (sHelpURL.isEmpty())
259 0 : return false;
260 :
261 : // SAFE ->
262 0 : osl::ClearableMutexGuard aLock(m_mutex);
263 0 : css::uno::Reference< css::container::XNameAccess > xConfig = m_xConfig;
264 0 : OUString sLocale = m_sLocale;
265 0 : OUString sSystem = m_sSystem;
266 0 : aLock.clear();
267 : // <- SAFE
268 :
269 0 : if (!xConfig.is())
270 0 : return false;
271 :
272 : // check given help url against all default ones
273 0 : const css::uno::Sequence< OUString > lModules = xConfig->getElementNames();
274 0 : const OUString* pModules = lModules.getConstArray();
275 0 : ::sal_Int32 c = lModules.getLength();
276 0 : ::sal_Int32 i = 0;
277 :
278 0 : for (i=0; i<c; ++i)
279 : {
280 : try
281 : {
282 0 : css::uno::Reference< css::container::XNameAccess > xModuleConfig;
283 0 : xConfig->getByName(pModules[i]) >>= xModuleConfig;
284 0 : if (!xModuleConfig.is())
285 0 : continue;
286 :
287 0 : OUString sHelpBaseURL;
288 0 : xModuleConfig->getByName("ooSetupFactoryHelpBaseURL") >>= sHelpBaseURL;
289 0 : OUString sHelpURLForModule = HelpOnStartup::ist_createHelpURL(sHelpBaseURL, sLocale, sSystem);
290 0 : if (sHelpURL.equals(sHelpURLForModule))
291 0 : return true;
292 : }
293 0 : catch(const css::uno::RuntimeException&)
294 0 : { throw; }
295 0 : catch(const css::uno::Exception&)
296 : {}
297 : }
298 :
299 0 : return false;
300 : }
301 :
302 0 : OUString HelpOnStartup::its_checkIfHelpEnabledAndGetURL(const OUString& sModule)
303 : {
304 : // SAFE ->
305 0 : osl::ClearableMutexGuard aLock(m_mutex);
306 0 : css::uno::Reference< css::container::XNameAccess > xConfig = m_xConfig;
307 0 : OUString sLocale = m_sLocale;
308 0 : OUString sSystem = m_sSystem;
309 0 : aLock.clear();
310 : // <- SAFE
311 :
312 0 : OUString sHelpURL;
313 :
314 : try
315 : {
316 0 : css::uno::Reference< css::container::XNameAccess > xModuleConfig;
317 0 : if (xConfig.is())
318 0 : xConfig->getByName(sModule) >>= xModuleConfig;
319 :
320 0 : bool bHelpEnabled = false;
321 0 : if (xModuleConfig.is())
322 0 : xModuleConfig->getByName("ooSetupFactoryHelpOnOpen") >>= bHelpEnabled;
323 :
324 0 : if (bHelpEnabled)
325 : {
326 0 : OUString sHelpBaseURL;
327 0 : xModuleConfig->getByName("ooSetupFactoryHelpBaseURL") >>= sHelpBaseURL;
328 0 : sHelpURL = HelpOnStartup::ist_createHelpURL(sHelpBaseURL, sLocale, sSystem);
329 0 : }
330 : }
331 0 : catch(const css::uno::RuntimeException&)
332 0 : { throw; }
333 0 : catch(const css::uno::Exception&)
334 0 : { sHelpURL.clear(); }
335 :
336 0 : return sHelpURL;
337 : }
338 :
339 0 : OUString HelpOnStartup::ist_createHelpURL(const OUString& sBaseURL,
340 : const OUString& sLocale ,
341 : const OUString& sSystem )
342 : {
343 0 : OUStringBuffer sHelpURL(256);
344 0 : sHelpURL.append (sBaseURL );
345 0 : sHelpURL.appendAscii("?Language=");
346 0 : sHelpURL.append (sLocale );
347 0 : sHelpURL.appendAscii("&System=" );
348 0 : sHelpURL.append (sSystem );
349 :
350 0 : return sHelpURL.makeStringAndClear();
351 : }
352 :
353 : } // namespace framework
354 :
355 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|