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 "sfx2/sfxhelp.hxx"
21 :
22 : #include <set>
23 : #include <algorithm>
24 : #include <com/sun/star/uno/Reference.h>
25 : #include <com/sun/star/frame/Desktop.hpp>
26 : #include <com/sun/star/frame/XFrame2.hpp>
27 : #include <com/sun/star/frame/XComponentLoader.hpp>
28 : #include <com/sun/star/lang/XComponent.hpp>
29 : #include <comphelper/processfactory.hxx>
30 : #include <com/sun/star/awt/XWindow.hpp>
31 : #include <com/sun/star/awt/XTopWindow.hpp>
32 : #include <com/sun/star/awt/PosSize.hpp>
33 : #include <com/sun/star/frame/XDesktop.hpp>
34 : #include <com/sun/star/util/URLTransformer.hpp>
35 : #include <com/sun/star/util/XURLTransformer.hpp>
36 : #include <com/sun/star/frame/XDispatch.hpp>
37 : #include <com/sun/star/frame/XDispatchProvider.hpp>
38 : #include <com/sun/star/beans/XPropertySet.hpp>
39 : #include <com/sun/star/frame/FrameSearchFlag.hpp>
40 : #include <toolkit/helper/vclunohelper.hxx>
41 : #include <com/sun/star/frame/ModuleManager.hpp>
42 : #include <com/sun/star/system/SystemShellExecute.hpp>
43 : #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
44 : #include <unotools/configmgr.hxx>
45 : #include <unotools/configitem.hxx>
46 : #include <svtools/helpopt.hxx>
47 : #include <unotools/moduleoptions.hxx>
48 : #include <tools/urlobj.hxx>
49 : #include <ucbhelper/content.hxx>
50 : #include <unotools/pathoptions.hxx>
51 : #include <rtl/ustring.hxx>
52 : #include <osl/process.h>
53 : #include <osl/file.hxx>
54 : #include <unotools/bootstrap.hxx>
55 : #include <rtl/uri.hxx>
56 : #include <vcl/msgbox.hxx>
57 : #include <svtools/ehdl.hxx>
58 : #include <svtools/sfxecode.hxx>
59 :
60 : #include "newhelp.hxx"
61 : #include <sfx2/objsh.hxx>
62 : #include <sfx2/docfac.hxx>
63 : #include "sfx2/sfxresid.hxx"
64 : #include "helper.hxx"
65 : #include "app.hrc"
66 : #include <sfx2/sfxuno.hxx>
67 : #include <vcl/svapp.hxx>
68 : #include <sfx2/frame.hxx>
69 : #include <rtl/strbuf.hxx>
70 : #include <rtl/string.hxx>
71 :
72 : using namespace ::com::sun::star::beans;
73 : using namespace ::com::sun::star::frame;
74 : using namespace ::com::sun::star::uno;
75 : using namespace ::com::sun::star::util;
76 : using namespace ::com::sun::star::lang;
77 : using namespace ::com::sun::star::system;
78 :
79 0 : class NoHelpErrorBox : public ErrorBox
80 : {
81 : public:
82 : NoHelpErrorBox( Window* _pParent );
83 :
84 : virtual void RequestHelp( const HelpEvent& rHEvt );
85 : };
86 :
87 0 : NoHelpErrorBox::NoHelpErrorBox( Window* _pParent ) :
88 :
89 0 : ErrorBox( _pParent, WB_OK, SfxResId( RID_STR_HLPFILENOTEXIST ).toString() )
90 : {
91 : // Error message: "No help available"
92 0 : }
93 :
94 0 : void NoHelpErrorBox::RequestHelp( const HelpEvent& )
95 : {
96 : // do nothing, because no help available
97 0 : }
98 :
99 : static bool impl_hasHelpInstalled( const OUString &rLang );
100 :
101 : /// Return the locale we prefer for displaying help
102 775 : static OUString HelpLocaleString()
103 : {
104 775 : static OUString aLocaleStr;
105 775 : if (aLocaleStr.isEmpty())
106 : {
107 133 : const OUString aEnglish( "en" );
108 : // detect installed locale
109 133 : aLocaleStr = utl::ConfigManager::getLocale();
110 133 : bool bOk = !aLocaleStr.isEmpty();
111 133 : if ( !bOk )
112 50 : aLocaleStr = aEnglish;
113 : else
114 : {
115 83 : OUString aBaseInstallPath;
116 83 : utl::Bootstrap::locateBaseInstallation(aBaseInstallPath);
117 : static const char *szHelpPath = "/help/";
118 :
119 166 : OUString sHelpPath = aBaseInstallPath +
120 332 : OUString::createFromAscii(szHelpPath) + aLocaleStr;
121 166 : osl::DirectoryItem aDirItem;
122 :
123 83 : if (!osl::DirectoryItem::get(sHelpPath, aDirItem) == osl::FileBase::E_None)
124 : {
125 83 : bOk = false;
126 83 : OUString sLang(aLocaleStr);
127 83 : sal_Int32 nSepPos = sLang.indexOf( '-' );
128 83 : if (nSepPos != -1)
129 : {
130 83 : bOk = true;
131 83 : sLang = sLang.copy( 0, nSepPos );
132 332 : sHelpPath = aBaseInstallPath +
133 415 : OUString::createFromAscii(szHelpPath) + sLang;
134 83 : if (!osl::DirectoryItem::get(sHelpPath, aDirItem) == osl::FileBase::E_None)
135 83 : bOk = false;
136 83 : }
137 83 : }
138 : }
139 : // if not OK, and not even English installed, we use online help, and
140 : // have to preserve the full locale name
141 133 : if ( !bOk && impl_hasHelpInstalled( aEnglish ) )
142 0 : aLocaleStr = aEnglish;
143 : }
144 775 : return aLocaleStr;
145 : }
146 :
147 775 : void AppendConfigToken( OUStringBuffer& rURL, sal_Bool bQuestionMark, const OUString &rLang )
148 : {
149 775 : OUString aLocaleStr( rLang );
150 775 : if ( aLocaleStr.isEmpty() )
151 642 : aLocaleStr = HelpLocaleString();
152 :
153 : // query part exists?
154 775 : if ( bQuestionMark )
155 : // no, so start with '?'
156 775 : rURL.append('?');
157 : else
158 : // yes, so only append with '&'
159 0 : rURL.append('&');
160 :
161 : // set parameters
162 775 : rURL.append("Language=");
163 775 : rURL.append(aLocaleStr);
164 775 : rURL.append("&System=");
165 775 : rURL.append(SvtHelpOptions().GetSystem());
166 775 : rURL.append("&Version=");
167 775 : rURL.append(utl::ConfigManager::getProductVersion());
168 775 : }
169 :
170 248 : sal_Bool GetHelpAnchor_Impl( const OUString& _rURL, OUString& _rAnchor )
171 : {
172 248 : sal_Bool bRet = sal_False;
173 248 : OUString sAnchor;
174 :
175 : try
176 : {
177 : ::ucbhelper::Content aCnt( INetURLObject( _rURL ).GetMainURL( INetURLObject::NO_DECODE ),
178 : Reference< ::com::sun::star::ucb::XCommandEnvironment >(),
179 248 : comphelper::getProcessComponentContext() );
180 248 : if ( ( aCnt.getPropertyValue("AnchorName") >>= sAnchor ) )
181 : {
182 :
183 248 : if ( !sAnchor.isEmpty() )
184 : {
185 0 : _rAnchor = sAnchor;
186 0 : bRet = sal_True;
187 : }
188 : }
189 : else
190 : {
191 : SAL_WARN( "sfx2.appl", "Property 'AnchorName' is missing" );
192 248 : }
193 : }
194 0 : catch (const ::com::sun::star::uno::Exception&)
195 : {
196 : }
197 :
198 248 : return bRet;
199 : }
200 :
201 : class SfxHelp_Impl
202 : {
203 : public:
204 : static OUString GetHelpText( const OUString& aCommandURL, const OUString& rModule );
205 : };
206 :
207 394 : OUString SfxHelp_Impl::GetHelpText( const OUString& aCommandURL, const OUString& rModule )
208 : {
209 : // create help url
210 394 : OUStringBuffer aHelpURL( SfxHelp::CreateHelpURL( aCommandURL, rModule ) );
211 : // added 'active' parameter
212 394 : sal_Int32 nIndex = aHelpURL.lastIndexOf( '#' );
213 394 : if ( nIndex < 0 )
214 394 : nIndex = aHelpURL.getLength();
215 394 : aHelpURL.insert( nIndex, "&Active=true" );
216 : // load help string
217 394 : return SfxContentHelper::GetActiveHelpString( aHelpURL.makeStringAndClear() );
218 : }
219 :
220 133 : SfxHelp::SfxHelp() :
221 : bIsDebug( sal_False ),
222 133 : pImp ( NULL )
223 : {
224 : // read the environment variable "HELP_DEBUG"
225 : // if it's set, you will see debug output on active help
226 : {
227 133 : OUString sHelpDebug;
228 266 : OUString sEnvVarName( "HELP_DEBUG" );
229 133 : osl_getEnvironment( sEnvVarName.pData, &sHelpDebug.pData );
230 266 : bIsDebug = !sHelpDebug.isEmpty();
231 : }
232 :
233 133 : pImp = new SfxHelp_Impl();
234 :
235 133 : OUString aLocaleStr = HelpLocaleString();
236 :
237 133 : sal_Int32 nSepPos = aLocaleStr.indexOf( '_' );
238 133 : if ( nSepPos != -1 )
239 : {
240 0 : aLanguageStr = aLocaleStr.copy( 0, nSepPos );
241 0 : aCountryStr = aLocaleStr.copy( nSepPos+1 );
242 : }
243 : else
244 : {
245 133 : nSepPos = aLocaleStr.indexOf( '-' );
246 133 : if ( nSepPos != -1 )
247 : {
248 83 : aLanguageStr = aLocaleStr.copy( 0, nSepPos );
249 83 : aCountryStr = aLocaleStr.copy( nSepPos+1 );
250 : }
251 : else
252 : {
253 50 : aLanguageStr = aLocaleStr;
254 : }
255 133 : }
256 133 : }
257 :
258 249 : SfxHelp::~SfxHelp()
259 : {
260 83 : delete pImp;
261 166 : }
262 :
263 239 : OUString getDefaultModule_Impl()
264 : {
265 239 : OUString sDefaultModule;
266 478 : SvtModuleOptions aModOpt;
267 239 : if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
268 239 : sDefaultModule = "swriter";
269 0 : else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) )
270 0 : sDefaultModule = "scalc";
271 0 : else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) )
272 0 : sDefaultModule = "simpress";
273 0 : else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) )
274 0 : sDefaultModule = "sdraw";
275 0 : else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SMATH ) )
276 0 : sDefaultModule = "smath";
277 0 : else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SCHART ) )
278 0 : sDefaultModule = "schart";
279 0 : else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SBASIC ) )
280 0 : sDefaultModule = "sbasic";
281 0 : else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) )
282 0 : sDefaultModule = "sdatabase";
283 : else
284 : {
285 : SAL_WARN( "sfx2.appl", "getDefaultModule_Impl(): no module installed" );
286 : }
287 478 : return sDefaultModule;
288 : }
289 :
290 239 : OUString getCurrentModuleIdentifier_Impl()
291 : {
292 239 : OUString sIdentifier;
293 478 : Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
294 478 : Reference < XModuleManager2 > xModuleManager = ModuleManager::create(xContext);
295 478 : Reference < XDesktop2 > xDesktop = Desktop::create(xContext);
296 478 : Reference < XFrame > xCurrentFrame = xDesktop->getCurrentFrame();
297 :
298 239 : if ( xCurrentFrame.is() )
299 : {
300 : try
301 : {
302 239 : sIdentifier = xModuleManager->identify( xCurrentFrame );
303 : }
304 0 : catch (const ::com::sun::star::frame::UnknownModuleException&)
305 : {
306 : DBG_WARNING( "SfxHelp::getCurrentModuleIdentifier_Impl(): unknown module (help in help?)" );
307 : }
308 0 : catch (const Exception&)
309 : {
310 : SAL_WARN( "sfx2.appl", "SfxHelp::getCurrentModuleIdentifier_Impl(): exception of XModuleManager::identify()" );
311 : }
312 : }
313 :
314 478 : return sIdentifier;
315 : }
316 :
317 239 : OUString SfxHelp::GetHelpModuleName_Impl()
318 : {
319 239 : OUString aFactoryShortName;
320 478 : OUString aModuleIdentifier = getCurrentModuleIdentifier_Impl();
321 :
322 239 : if ( !aModuleIdentifier.isEmpty() )
323 : {
324 : try
325 : {
326 : Reference < XModuleManager2 > xModuleManager(
327 239 : ModuleManager::create(::comphelper::getProcessComponentContext()) );
328 478 : Sequence< PropertyValue > lProps;
329 239 : xModuleManager->getByName( aModuleIdentifier ) >>= lProps;
330 2151 : for ( sal_Int32 i = 0; i < lProps.getLength(); ++i )
331 : {
332 2151 : if ( lProps[i].Name == "ooSetupFactoryShortName" )
333 : {
334 239 : lProps[i].Value >>= aFactoryShortName;
335 239 : break;
336 : }
337 239 : }
338 : }
339 0 : catch (const Exception&)
340 : {
341 : SAL_WARN( "sfx2.appl", "SfxHelp::GetHelpModuleName_Impl(): exception of XNameAccess::getByName()" );
342 : }
343 : }
344 :
345 478 : OUString sDefaultModule = getDefaultModule_Impl();
346 239 : if ( !aFactoryShortName.isEmpty() )
347 : {
348 : // Map some module identifiers to their "real" help module string.
349 239 : if ( aFactoryShortName == "chart2" )
350 0 : aFactoryShortName = OUString( "schart" );
351 239 : else if ( aFactoryShortName == "BasicIDE" )
352 0 : aFactoryShortName = OUString( "sbasic" );
353 478 : else if ( aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("sweb"))
354 239 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("sglobal"))
355 478 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("swxform")) )
356 0 : aFactoryShortName = OUString( "swriter" );
357 478 : else if ( aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbquery"))
358 239 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbbrowser"))
359 239 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbrelation"))
360 239 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbtable"))
361 239 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbapp"))
362 239 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbreport"))
363 239 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("swreport"))
364 239 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("dbbrowser"))
365 478 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("swform")) )
366 0 : aFactoryShortName = OUString( "sdatabase" );
367 478 : else if ( aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("sbibliography"))
368 239 : || aFactoryShortName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("StartModule")) )
369 0 : aFactoryShortName = sDefaultModule;
370 : }
371 : else
372 0 : aFactoryShortName = sDefaultModule;
373 :
374 478 : return aFactoryShortName;
375 : }
376 :
377 394 : OUString SfxHelp::CreateHelpURL_Impl( const OUString& aCommandURL, const OUString& rModuleName )
378 : {
379 : // build up the help URL
380 394 : OUStringBuffer aHelpURL("vnd.sun.star.help://");
381 394 : sal_Bool bHasAnchor = sal_False;
382 788 : OUString aAnchor;
383 :
384 788 : OUString aModuleName( rModuleName );
385 394 : if (aModuleName.isEmpty())
386 0 : aModuleName = getDefaultModule_Impl();
387 :
388 394 : aHelpURL.append(aModuleName);
389 :
390 394 : if ( aCommandURL.isEmpty() )
391 146 : aHelpURL.append("/start");
392 : else
393 : {
394 248 : aHelpURL.append('/');
395 : aHelpURL.append(rtl::Uri::encode(aCommandURL,
396 : rtl_UriCharClassRelSegment,
397 : rtl_UriEncodeKeepEscapes,
398 248 : RTL_TEXTENCODING_UTF8));
399 :
400 248 : OUStringBuffer aTempURL = aHelpURL;
401 248 : AppendConfigToken( aTempURL, sal_True );
402 248 : bHasAnchor = GetHelpAnchor_Impl(aTempURL.makeStringAndClear(), aAnchor);
403 : }
404 :
405 394 : AppendConfigToken( aHelpURL, sal_True );
406 :
407 394 : if ( bHasAnchor )
408 : {
409 0 : aHelpURL.append('#');
410 0 : aHelpURL.append(aAnchor);
411 : }
412 :
413 788 : return aHelpURL.makeStringAndClear();
414 : }
415 :
416 0 : SfxHelpWindow_Impl* impl_createHelp(Reference< XFrame2 >& rHelpTask ,
417 : Reference< XFrame >& rHelpContent)
418 : {
419 0 : Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
420 :
421 : // otherwise - create new help task
422 : Reference< XFrame2 > xHelpTask(
423 0 : xDesktop->findFrame( "OFFICE_HELP_TASK", FrameSearchFlag::TASKS | FrameSearchFlag::CREATE),
424 0 : UNO_QUERY);
425 0 : if (!xHelpTask.is())
426 0 : return 0;
427 :
428 : // create all internal windows and sub frames ...
429 0 : Reference< ::com::sun::star::awt::XWindow > xParentWindow = xHelpTask->getContainerWindow();
430 0 : Window* pParentWindow = VCLUnoHelper::GetWindow( xParentWindow );
431 0 : SfxHelpWindow_Impl* pHelpWindow = new SfxHelpWindow_Impl( xHelpTask, pParentWindow, WB_DOCKBORDER );
432 0 : Reference< ::com::sun::star::awt::XWindow > xHelpWindow = VCLUnoHelper::GetInterface( pHelpWindow );
433 :
434 0 : Reference< XFrame > xHelpContent;
435 0 : if (xHelpTask->setComponent( xHelpWindow, Reference< XController >() ))
436 : {
437 : // Customize UI ...
438 0 : xHelpTask->setName("OFFICE_HELP_TASK");
439 :
440 0 : Reference< XPropertySet > xProps(xHelpTask, UNO_QUERY);
441 0 : if (xProps.is())
442 0 : xProps->setPropertyValue(
443 : "Title",
444 0 : makeAny(SfxResId(STR_HELP_WINDOW_TITLE).toString()));
445 :
446 0 : pHelpWindow->setContainerWindow( xParentWindow );
447 0 : xParentWindow->setVisible(sal_True);
448 0 : xHelpWindow->setVisible(sal_True);
449 :
450 : // This sub frame is created internaly (if we called new SfxHelpWindow_Impl() ...)
451 : // It should exist :-)
452 0 : xHelpContent = xHelpTask->findFrame(OUString("OFFICE_HELP"), FrameSearchFlag::CHILDREN);
453 : }
454 :
455 0 : if (!xHelpContent.is())
456 : {
457 0 : delete pHelpWindow;
458 0 : return NULL;
459 : }
460 :
461 0 : xHelpContent->setName("OFFICE_HELP");
462 :
463 0 : rHelpTask = xHelpTask;
464 0 : rHelpContent = xHelpContent;
465 0 : return pHelpWindow;
466 : }
467 :
468 239 : OUString SfxHelp::GetHelpText( const OUString& aCommandURL, const Window* pWindow )
469 : {
470 239 : OUString sModuleName = GetHelpModuleName_Impl();
471 239 : OUString sHelpText = SfxHelp_Impl::GetHelpText( aCommandURL, sModuleName );
472 :
473 478 : OString aNewHelpId;
474 :
475 239 : if (pWindow && sHelpText.isEmpty())
476 : {
477 : // no help text found -> try with parent help id.
478 38 : Window* pParent = pWindow->GetParent();
479 231 : while ( pParent )
480 : {
481 155 : aNewHelpId = pParent->GetHelpId();
482 155 : sHelpText = SfxHelp_Impl::GetHelpText( OStringToOUString(aNewHelpId, RTL_TEXTENCODING_UTF8), sModuleName );
483 155 : if (!sHelpText.isEmpty())
484 0 : pParent = NULL;
485 : else
486 155 : pParent = pParent->GetParent();
487 : }
488 :
489 38 : if (bIsDebug && sHelpText.isEmpty())
490 0 : aNewHelpId = OString();
491 : }
492 :
493 : // add some debug information?
494 239 : if ( bIsDebug )
495 : {
496 0 : sHelpText += "\n-------------\n";
497 0 : sHelpText += sModuleName;
498 0 : sHelpText += ": ";
499 0 : sHelpText += aCommandURL;
500 0 : if ( !aNewHelpId.isEmpty() )
501 : {
502 0 : sHelpText += " - ";
503 0 : sHelpText += OStringToOUString(aNewHelpId, RTL_TEXTENCODING_UTF8);
504 : }
505 : }
506 :
507 478 : return sHelpText;
508 : }
509 :
510 : /// Check for built-in help
511 133 : static bool impl_hasHelpInstalled( const OUString &rLang = OUString() )
512 : {
513 133 : OUStringBuffer aHelpRootURL("vnd.sun.star.help://");
514 133 : AppendConfigToken(aHelpRootURL, sal_True, rLang);
515 266 : std::vector< OUString > aFactories = SfxContentHelper::GetResultSet(aHelpRootURL.makeStringAndClear());
516 :
517 266 : return !aFactories.empty();
518 : }
519 :
520 0 : sal_Bool SfxHelp::SearchKeyword( const OUString& rKeyword )
521 : {
522 0 : return Start_Impl( OUString(), NULL, rKeyword );
523 : }
524 :
525 0 : sal_Bool SfxHelp::Start( const OUString& rURL, const Window* pWindow )
526 : {
527 0 : return Start_Impl( rURL, pWindow, OUString() );
528 : }
529 :
530 : /// Redirect the vnd.sun.star.help:// urls to http://help.libreoffice.org
531 0 : static bool impl_showOnlineHelp( const OUString& rURL )
532 : {
533 0 : OUString aInternal( "vnd.sun.star.help://" );
534 0 : if ( rURL.getLength() <= aInternal.getLength() || !rURL.startsWith(aInternal) )
535 0 : return false;
536 :
537 0 : OUString aHelpLink( "http://help.libreoffice.org/" );
538 0 : aHelpLink += rURL.copy( aInternal.getLength() );
539 0 : aHelpLink = aHelpLink.replaceAll("%2F","/");
540 : try
541 : {
542 : Reference< XSystemShellExecute > xSystemShell(
543 0 : SystemShellExecute::create(::comphelper::getProcessComponentContext()) );
544 :
545 0 : xSystemShell->execute( aHelpLink, OUString(), SystemShellExecuteFlags::URIS_ONLY );
546 0 : return true;
547 : }
548 0 : catch (const Exception&)
549 : {
550 : }
551 0 : return false;
552 : }
553 :
554 0 : sal_Bool SfxHelp::Start_Impl(const OUString& rURL, const Window* pWindow, const OUString& rKeyword)
555 : {
556 0 : OUStringBuffer aHelpRootURL("vnd.sun.star.help://");
557 0 : AppendConfigToken(aHelpRootURL, sal_True);
558 0 : SfxContentHelper::GetResultSet(aHelpRootURL.makeStringAndClear());
559 :
560 : /* rURL may be
561 : - a "real" URL
562 : - a HelpID (formerly a long, now a string)
563 : If rURL is a URL, CreateHelpURL should be called for this URL
564 : If rURL is an arbitrary string, the same should happen, but the URL should be tried out
565 : if it delivers real help content. In case only the Help Error Document is returned, the
566 : parent of the window for that help was called, is asked for its HelpID.
567 : For compatibility reasons this upward search is not implemented for "real" URLs.
568 : Help keyword search now is implemented as own method; in former versions it
569 : was done via Help::Start, but this implementation conflicted with the upward search.
570 : */
571 0 : OUString aHelpURL;
572 0 : INetURLObject aParser( rURL );
573 0 : INetProtocol nProtocol = aParser.GetProtocol();
574 :
575 0 : switch ( nProtocol )
576 : {
577 : case INET_PROT_VND_SUN_STAR_HELP:
578 : // already a vnd.sun.star.help URL -> nothing to do
579 0 : aHelpURL = rURL;
580 0 : break;
581 : default:
582 : {
583 0 : OUString aHelpModuleName( GetHelpModuleName_Impl() );
584 : // no URL, just a HelpID (maybe empty in case of keyword search)
585 0 : aHelpURL = CreateHelpURL_Impl( rURL, aHelpModuleName );
586 :
587 0 : if ( impl_hasHelpInstalled() && pWindow && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
588 : {
589 : // no help found -> try with parent help id.
590 0 : Window* pParent = pWindow->GetParent();
591 0 : bool bTriedTabPage = false;
592 0 : while ( pParent )
593 : {
594 0 : OString aHelpId = pParent->GetHelpId();
595 0 : aHelpURL = CreateHelpURL( OStringToOUString(aHelpId, RTL_TEXTENCODING_UTF8), aHelpModuleName );
596 0 : if ( !SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
597 : {
598 0 : break;
599 : }
600 : else
601 : {
602 0 : pParent = pParent->GetParent();
603 0 : if (!pParent)
604 : {
605 : // create help url of start page ( helpid == 0 -> start page)
606 0 : aHelpURL = CreateHelpURL( OUString(), aHelpModuleName );
607 : }
608 0 : else if (pParent->IsDialog() && !bTriedTabPage)
609 : {
610 : //During help fallback, before we ask a dialog for its help
611 : //see if it has a TabControl and ask the active tab of
612 : //that for help
613 0 : bTriedTabPage = true;
614 0 : TabControl *pCtrl = ((Dialog*)pParent)->get<TabControl>("tabcontrol");
615 0 : TabPage* pTabPage = pCtrl ? pCtrl->GetTabPage(pCtrl->GetCurPageId()) : NULL;
616 0 : Window *pTabChild = pTabPage ? pTabPage->GetWindow(WINDOW_FIRSTCHILD) : NULL;
617 0 : if (pTabChild)
618 0 : pParent = pTabChild;
619 : }
620 : }
621 0 : }
622 : }
623 0 : break;
624 : }
625 : }
626 :
627 0 : if ( !impl_hasHelpInstalled() )
628 : {
629 0 : if ( impl_showOnlineHelp( aHelpURL ) )
630 0 : return sal_True;
631 : else
632 : {
633 0 : NoHelpErrorBox aErrBox( const_cast< Window* >( pWindow ) );
634 0 : aErrBox.Execute();
635 0 : return sal_False;
636 : }
637 : }
638 :
639 0 : Reference < XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
640 :
641 : // check if help window is still open
642 : // If not, create a new one and return access directly to the internal sub frame showing the help content
643 : // search must be done here; search one desktop level could return an arbitraty frame
644 : Reference< XFrame2 > xHelp(
645 0 : xDesktop->findFrame( "OFFICE_HELP_TASK", FrameSearchFlag::CHILDREN),
646 0 : UNO_QUERY);
647 0 : Reference< XFrame > xHelpContent = xDesktop->findFrame(
648 : OUString("OFFICE_HELP"),
649 0 : FrameSearchFlag::CHILDREN);
650 :
651 0 : SfxHelpWindow_Impl* pHelpWindow = 0;
652 0 : if (!xHelp.is())
653 0 : pHelpWindow = impl_createHelp(xHelp, xHelpContent);
654 : else
655 0 : pHelpWindow = (SfxHelpWindow_Impl*)VCLUnoHelper::GetWindow(xHelp->getComponentWindow());
656 0 : if (!xHelp.is() || !xHelpContent.is() || !pHelpWindow)
657 0 : return sal_False;
658 :
659 : #ifdef DBG_UTIL
660 : OStringBuffer aTmp(RTL_CONSTASCII_STRINGPARAM("SfxHelp: HelpId = "));
661 : aTmp.append(OUStringToOString(aHelpURL, RTL_TEXTENCODING_UTF8));
662 : OSL_TRACE( aTmp.getStr() );
663 : #endif
664 :
665 0 : pHelpWindow->SetHelpURL( aHelpURL );
666 0 : pHelpWindow->loadHelpContent(aHelpURL);
667 0 : if (!rKeyword.isEmpty())
668 0 : pHelpWindow->OpenKeyword( rKeyword );
669 :
670 0 : Reference < ::com::sun::star::awt::XTopWindow > xTopWindow( xHelp->getContainerWindow(), UNO_QUERY );
671 0 : if ( xTopWindow.is() )
672 0 : xTopWindow->toFront();
673 :
674 0 : return sal_True;
675 : }
676 :
677 394 : OUString SfxHelp::CreateHelpURL(const OUString& aCommandURL, const OUString& rModuleName)
678 : {
679 394 : SfxHelp* pHelp = static_cast< SfxHelp* >(Application::GetHelp());
680 394 : return pHelp ? pHelp->CreateHelpURL_Impl( aCommandURL, rModuleName ) : OUString();
681 : }
682 :
683 0 : OUString SfxHelp::GetDefaultHelpModule()
684 : {
685 0 : return getDefaultModule_Impl();
686 : }
687 :
688 0 : OUString SfxHelp::GetCurrentModuleIdentifier()
689 : {
690 0 : return getCurrentModuleIdentifier_Impl();
691 408 : }
692 :
693 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|