xref: /trunk/main/sfx2/source/appl/sfxhelp.cxx (revision 15e1fb6f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sfx2.hxx"
26 
27 #include "sfx2/sfxhelp.hxx"
28 
29 #include <set>
30 #include <algorithm>
31 #include <com/sun/star/uno/Reference.h>
32 #include <com/sun/star/frame/XFrame.hpp>
33 #include <com/sun/star/frame/XComponentLoader.hpp>
34 #include <com/sun/star/lang/XComponent.hpp>
35 #include <comphelper/processfactory.hxx>
36 #include <com/sun/star/awt/XWindow.hpp>
37 #include <com/sun/star/awt/XTopWindow.hpp>
38 #include <com/sun/star/awt/PosSize.hpp>
39 #include <com/sun/star/frame/XDesktop.hpp>
40 #include <com/sun/star/util/XURLTransformer.hpp>
41 #include <com/sun/star/frame/XDispatch.hpp>
42 #include <com/sun/star/frame/XDispatchProvider.hpp>
43 #include <com/sun/star/container/XNameAccess.hpp>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/frame/FrameSearchFlag.hpp>
46 #include <toolkit/helper/vclunohelper.hxx>
47 #include <com/sun/star/frame/XModuleManager.hpp>
48 #include <unotools/configmgr.hxx>
49 #include <unotools/configitem.hxx>
50 #include <svtools/helpopt.hxx>
51 #include <unotools/moduleoptions.hxx>
52 #include <tools/urlobj.hxx>
53 #include <unotools/configmgr.hxx>
54 #include <ucbhelper/content.hxx>
55 #include <unotools/pathoptions.hxx>
56 #include <rtl/ustring.hxx>
57 #include <osl/process.h>
58 #include <osl/file.hxx>
59 #include <unotools/bootstrap.hxx>
60 #include <rtl/uri.hxx>
61 #include <vcl/msgbox.hxx>
62 #include <svtools/ehdl.hxx>
63 #include <svtools/sfxecode.hxx>
64 
65 #define _SVSTDARR_STRINGSDTOR
66 #define _SVSTDARR_ULONGSSORT
67 #include <svl/svstdarr.hxx>
68 
69 #include "newhelp.hxx"
70 #include <sfx2/objsh.hxx>
71 #include <sfx2/docfac.hxx>
72 #include "sfx2/sfxresid.hxx"
73 #include "helper.hxx"
74 #include "app.hrc"
75 #include <sfx2/sfxuno.hxx>
76 #include <vcl/svapp.hxx>
77 #include <sfx2/frame.hxx>
78 #include <rtl/string.hxx>
79 
80 using namespace ::com::sun::star::beans;
81 using namespace ::com::sun::star::frame;
82 using namespace ::com::sun::star::uno;
83 using namespace ::com::sun::star::util;
84 using namespace ::com::sun::star::frame;
85 using namespace ::com::sun::star::lang;
86 
87 #define ERROR_TAG	String( DEFINE_CONST_UNICODE("Error: ") )
88 #define PATH_TAG	String( DEFINE_CONST_UNICODE("\nPath: ") )
89 
90 // class NoHelpErrorBox --------------------------------------------------
91 
92 class NoHelpErrorBox : public ErrorBox
93 {
94 public:
95 	NoHelpErrorBox( Window* _pParent );
96 
97 	virtual void RequestHelp( const HelpEvent& rHEvt );
98 };
99 
NoHelpErrorBox(Window * _pParent)100 NoHelpErrorBox::NoHelpErrorBox( Window* _pParent ) :
101 
102 	ErrorBox( _pParent, WB_OK, String( SfxResId( RID_STR_HLPFILENOTEXIST ) ) )
103 {
104 	// Error message: "No help available"
105 }
106 
RequestHelp(const HelpEvent &)107 void NoHelpErrorBox::RequestHelp( const HelpEvent& )
108 {
109 	// do nothing, because no help available
110 }
111 
112 // -----------------------------------------------------------------------
113 
114 #define STARTERLIST 0
115 
HelpLocaleString()116 rtl::OUString HelpLocaleString()
117 {
118 	static rtl::OUString aLocaleStr;
119 	if (!aLocaleStr.getLength())
120 	{
121 		// detect installed locale
122 		Any aLocale =
123 			::utl::ConfigManager::GetConfigManager()->GetDirectConfigProperty(
124 			   ::utl::ConfigManager::LOCALE );
125 		aLocale >>= aLocaleStr;
126 		bool bOk = aLocaleStr.getLength() != 0;
127 		if ( bOk )
128 		{
129 			rtl::OUString aBaseInstallPath;
130 			// utl::Bootstrap::PathStatus aBaseLocateResult =
131 			utl::Bootstrap::locateBaseInstallation(aBaseInstallPath);
132 			static const char *szHelpPath = "/help/";
133 
134 			rtl::OUString sHelpPath = aBaseInstallPath +
135 				rtl::OUString::createFromAscii(szHelpPath) + aLocaleStr;
136 			osl::DirectoryItem aDirItem;
137 
138 			if (!osl::DirectoryItem::get(sHelpPath, aDirItem) == osl::FileBase::E_None)
139 			{
140 				bOk = false;
141 				String sLang(aLocaleStr);
142 				xub_StrLen nSepPos = sLang.Search( '-' );
143 				if (nSepPos != STRING_NOTFOUND)
144 				{
145 					bOk = true;
146 					sLang = sLang.Copy( 0, nSepPos );
147 					sHelpPath = aBaseInstallPath +
148 						rtl::OUString::createFromAscii(szHelpPath) + sLang;
149 					if (!osl::DirectoryItem::get(sHelpPath, aDirItem) == osl::FileBase::E_None)
150 						bOk = false;
151 				}
152 			}
153 		}
154 		if (!bOk)
155 			aLocaleStr = rtl::OUString( DEFINE_CONST_UNICODE("en") );
156 	}
157 	return aLocaleStr;
158 }
159 
AppendConfigToken_Impl(String & rURL,sal_Bool bQuestionMark)160 void AppendConfigToken_Impl( String& rURL, sal_Bool bQuestionMark )
161 {
162 	::rtl::OUString aLocaleStr(HelpLocaleString());
163 
164 	// query part exists?
165 	if ( bQuestionMark )
166 		// no, so start with '?'
167 		rURL += '?';
168 	else
169 		// yes, so only append with '&'
170 		rURL += '&';
171 
172 	// set parameters
173 	rURL += DEFINE_CONST_UNICODE("Language=");
174 	rURL += String( aLocaleStr );
175 	rURL += DEFINE_CONST_UNICODE("&System=");
176 	rURL += SvtHelpOptions().GetSystem();
177 
178 }
179 
180 // -----------------------------------------------------------------------
181 
GetHelpAnchor_Impl(const String & _rURL,String & _rAnchor)182 sal_Bool GetHelpAnchor_Impl( const String& _rURL, String& _rAnchor )
183 {
184 	sal_Bool bRet = sal_False;
185 	::rtl::OUString sAnchor;
186 
187 	// --> OD 2009-07-01 #159496#
188 	// do not release solar mutex due to crash regarding accessibility
189 //	sal_uIntPtr nSolarCount = Application::ReleaseSolarMutex();
190 	// <--
191 	try
192 	{
193 		::ucbhelper::Content aCnt( INetURLObject( _rURL ).GetMainURL( INetURLObject::NO_DECODE ),
194 							 Reference< ::com::sun::star::ucb::XCommandEnvironment > () );
195 		if ( ( aCnt.getPropertyValue( ::rtl::OUString::createFromAscii( "AnchorName" ) ) >>= sAnchor ) )
196 		{
197 
198 			if ( sAnchor.getLength() > 0 )
199 			{
200 				_rAnchor = String( sAnchor );
201 				bRet = sal_True;
202 			}
203 		}
204 		else
205 		{
206 			DBG_ERRORFILE( "Property 'AnchorName' is missing" );
207 		}
208 	}
209 	catch( ::com::sun::star::uno::Exception& )
210 	{
211 	}
212 	// --> OD 2009-07-01 #159496#
213 //	Application::AcquireSolarMutex( nSolarCount );
214 	// <--
215 
216 	return bRet;
217 }
218 
219 // -----------------------------------------------------------------------
220 
221 class SfxHelpOptions_Impl : public utl::ConfigItem
222 {
223 private:
224 	std::set < rtl::OString > m_aIds;
225 
226 public:
227 					SfxHelpOptions_Impl();
228 					~SfxHelpOptions_Impl();
229 
HasId(const rtl::OString & rId)230 	bool			HasId( const rtl::OString& rId ) { return m_aIds.size() ? m_aIds.find( rId ) != m_aIds.end() : false; }
231 	virtual void			Notify( const com::sun::star::uno::Sequence< rtl::OUString >& aPropertyNames );
232 	virtual void			Commit();
233 };
234 
GetPropertyNames()235 static Sequence< ::rtl::OUString > GetPropertyNames()
236 {
237 	static const char* aPropNames[] =
238 	{
239 		"HelpAgentStarterList",
240 	};
241 
242 	const int nCount = sizeof( aPropNames ) / sizeof( const char* );
243 	Sequence< ::rtl::OUString > aNames( nCount );
244 	::rtl::OUString* pNames = aNames.getArray();
245 	::rtl::OUString* pEnd	= pNames + aNames.getLength();
246 	int i = 0;
247 	for ( ; pNames != pEnd; ++pNames )
248 		*pNames = ::rtl::OUString::createFromAscii( aPropNames[i++] );
249 
250 	return aNames;
251 }
252 
253 // -----------------------------------------------------------------------
254 
SfxHelpOptions_Impl()255 SfxHelpOptions_Impl::SfxHelpOptions_Impl()
256 	: ConfigItem( ::rtl::OUString::createFromAscii("Office.SFX/Help") )
257 {
258 	Sequence< ::rtl::OUString > aNames = GetPropertyNames();
259 	Sequence< Any > aValues = GetProperties( aNames );
260 	EnableNotification( aNames );
261 	const Any* pValues = aValues.getConstArray();
262 	DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" );
263 	if ( aValues.getLength() == aNames.getLength() )
264 	{
265 		for ( int nProp = 0; nProp < aNames.getLength(); nProp++ )
266 		{
267 			DBG_ASSERT( pValues[nProp].hasValue(), "property value missing" );
268 			if ( pValues[nProp].hasValue() )
269 			{
270 				switch ( nProp )
271 				{
272 					case STARTERLIST :
273 					{
274 						::rtl::OUString aCodedList;
275 						if ( pValues[nProp] >>= aCodedList )
276 						{
277 							const rtl::OString aTmp( OUStringToOString( aCodedList, RTL_TEXTENCODING_UTF8 ));
278 							sal_Int32 nIndex = 0;
279 							do
280 							{
281 								rtl::OString aToken = aTmp.getToken( 0, ',', nIndex );
282 								if ( aToken.getLength() )
283 									m_aIds.insert( aToken );
284 							}
285 							while ( nIndex >= 0 );
286 						}
287 						else {
288 							DBG_ERRORFILE( "Wrong property type!" );
289 						}
290 
291 						break;
292 					}
293 
294 					default:
295 						DBG_ERRORFILE( "Wrong property!" );
296 						break;
297 				}
298 			}
299 		}
300 	}
301 }
302 
~SfxHelpOptions_Impl()303 SfxHelpOptions_Impl::~SfxHelpOptions_Impl()
304 {
305 }
306 
307 
Notify(const com::sun::star::uno::Sequence<rtl::OUString> &)308 void SfxHelpOptions_Impl::Notify( const com::sun::star::uno::Sequence< rtl::OUString >& )
309 {
310 }
311 
Commit()312 void SfxHelpOptions_Impl::Commit()
313 {
314 }
315 
316 // class SfxHelp_Impl ----------------------------------------------------
317 
318 class SfxHelp_Impl
319 {
320 private:
321 	sal_Bool							m_bIsDebug;		// environment variable "help_debug=1"
322 	SfxHelpOptions_Impl*				m_pOpt;			// the options
323 	::std::vector< ::rtl::OUString >	m_aModulesList;	// list of all installed modules
324 	void					Load();
325 
326 public:
327 	SfxHelp_Impl( sal_Bool bDebug );
328 	~SfxHelp_Impl();
329 
330 	SfxHelpOptions_Impl*	GetOptions();
331 	static String			GetHelpText( const rtl::OUString& aCommandURL, const String& rModule );
332 	sal_Bool				HasModule( const ::rtl::OUString& rModule );			// module installed
333 	sal_Bool				IsHelpInstalled();										// module list not empty
334 };
335 
SfxHelp_Impl(sal_Bool bDebug)336 SfxHelp_Impl::SfxHelp_Impl( sal_Bool bDebug ) :
337 
338 	m_bIsDebug		( bDebug ),
339 	m_pOpt			( NULL )
340 
341 {
342 }
343 
~SfxHelp_Impl()344 SfxHelp_Impl::~SfxHelp_Impl()
345 {
346 	delete m_pOpt;
347 }
348 
Load()349 void SfxHelp_Impl::Load()
350 {
351 	// fill modules list
352 	// create the help url (empty, without module and helpid)
353 	String sHelpURL( DEFINE_CONST_UNICODE("vnd.sun.star.help://") );
354 	AppendConfigToken_Impl( sHelpURL, sal_True );
355 
356 	// open ucb content and get the list of the help modules
357 	// the list contains strings with three tokens "ui title \t type \t url"
358 	Sequence< ::rtl::OUString > aAllModulesList = SfxContentHelper::GetResultSet( sHelpURL );
359 	sal_Int32 nLen = aAllModulesList.getLength();
360 	m_aModulesList.reserve( nLen + 1 );
361 	const ::rtl::OUString* pBegin = aAllModulesList.getConstArray();
362 	const ::rtl::OUString* pEnd	= pBegin + nLen;
363 	for ( ; pBegin != pEnd; ++pBegin )
364 	{
365 		// get one module string
366 		String sModule( *pBegin );
367 		// extract the url
368 		String sURL = sModule.GetToken( 2, '\t' );
369 		// insert the module (the host part of the "vnd.sun.star.help" url)
370 		m_aModulesList.push_back( ::rtl::OUString( INetURLObject( sURL ).GetHost() ) );
371 	}
372 }
373 
GetHelpText(const rtl::OUString & aCommandURL,const String & rModule)374 String SfxHelp_Impl::GetHelpText( const rtl::OUString& aCommandURL, const String& rModule )
375 {
376 	// create help url
377 	String aHelpURL = SfxHelp::CreateHelpURL( aCommandURL, rModule );
378 	// added 'active' parameter
379 	aHelpURL.Insert( String( DEFINE_CONST_UNICODE("&Active=true") ), aHelpURL.SearchBackward( '#' ) );
380 	// load help string
381 	return SfxContentHelper::GetActiveHelpString( aHelpURL );
382 }
383 
GetOptions()384 SfxHelpOptions_Impl* SfxHelp_Impl::GetOptions()
385 {
386 	// create if not exists
387 	if ( !m_pOpt )
388 		m_pOpt = new SfxHelpOptions_Impl;
389 	return m_pOpt;
390 }
391 
HasModule(const::rtl::OUString & rModule)392 sal_Bool SfxHelp_Impl::HasModule( const ::rtl::OUString& rModule )
393 {
394 	if ( !m_aModulesList.size() )
395 		Load();
396 	return ( ::std::find( m_aModulesList.begin(), m_aModulesList.end(), rModule ) != m_aModulesList.end() );
397 }
398 
IsHelpInstalled()399 sal_Bool SfxHelp_Impl::IsHelpInstalled()
400 {
401 	if ( !m_aModulesList.size() )
402 		Load();
403 	return ( m_aModulesList.begin() != m_aModulesList.end() );
404 }
405 
406 // class SfxHelp ---------------------------------------------------------
407 /* some test code for HID conversion - please don't remove
408 
409 #include <tools/stream.hxx>
410 void TestHids()
411 {
412 	static const char* aModules[] =
413 	{
414 		"swriter",
415 		"scalc",
416 		"simpress",
417 		"sdraw",
418 		"sdatabase",
419 		"smath",
420 		"schart",
421 		"sbasic"
422 	};
423 
424 	SvFileStream* pOut[] =
425 	{
426 		0,0,0,0,0,0,0,0,0
427 	};
428 
429 	String aIn = String::CreateFromAscii("/data/OOo/replacer/hidsin.lst");
430 	String aOut = String::CreateFromAscii("/data/OOo/replacer/");
431 	SvFileStream aInStrm( aIn, STREAM_READ );
432 	ByteString aBuffer;
433 	while ( aInStrm.ReadLine( aBuffer ) )
434 	{
435 		ByteString aHid = aBuffer.GetToken(0, ' ');
436 		ByteString aNr  = aBuffer.GetToken(1, ' ');
437 		bool bFound=false;
438 		for (sal_Int32 n= 0; n<8; n++)
439 		{
440 			bFound = false;
441 			String aHelpURL = SfxHelp::CreateHelpURL( String( aNr, RTL_TEXTENCODING_UTF8 ), String( aModules[n], RTL_TEXTENCODING_UTF8 ) );
442 			if ( !SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
443 			{
444 				if (!pOut[n])
445 				{
446 					String aTmp( aOut );
447 					aTmp += String( aModules[n], RTL_TEXTENCODING_UTF8 );
448 					aTmp += String::CreateFromAscii(".lst");
449 					pOut[n] = new SvFileStream( aTmp, STREAM_WRITE | STREAM_TRUNC );
450 				}
451 				pOut[n]->WriteLine( aHid );
452 				bFound = true;
453 				break;
454 			}
455 		}
456 
457 		if (!bFound)
458 		{
459 			if (!pOut[8])
460 			{
461 				String aTmp( aOut );
462 				aTmp += String( "notfound", RTL_TEXTENCODING_UTF8 );
463 				aTmp += String::CreateFromAscii(".lst");
464 				pOut[8] = new SvFileStream( aTmp, STREAM_WRITE | STREAM_TRUNC );
465 			}
466 			pOut[8]->WriteLine( aHid );
467 		}
468 	}
469 
470 	for (sal_Int32 n= 0; n<9; n++)
471 		DELETEZ( pOut[n] );
472 }
473 
474 void TestHids2()
475 {
476 	static const char* aModules[] =
477 	{
478 		"swriter",
479 		"scalc",
480 		"simpress",
481 		"smath",
482 		"sbasic"
483 	};
484 
485 	String aOut = String::CreateFromAscii("/data/OOo/replacer/");
486 	aOut += String::CreateFromAscii("lost.lst");
487 	SvFileStream aOutStrm( aOut, STREAM_WRITE | STREAM_TRUNC );
488 	for (sal_Int32 n= 0; n<5; n++)
489 	{
490 		String aIn = String::CreateFromAscii("/data/OOo/replacer/help/");
491 		aIn += String::CreateFromAscii( aModules[n] );
492 		aIn += String::CreateFromAscii(".lst");
493 		SvFileStream aInStrm( aIn, STREAM_READ );
494 		ByteString aBuffer;
495 		while ( aInStrm.ReadLine( aBuffer ) )
496 		{
497 			String aHelpURL = SfxHelp::CreateHelpURL( String( aBuffer, RTL_TEXTENCODING_UTF8 ), String( aModules[n], RTL_TEXTENCODING_UTF8 ) );
498 			if ( SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
499 				aOutStrm.WriteLine( aBuffer );
500 		}
501 	}
502 }
503 
504 #include <tools/stream.hxx>
505 void TestHids3()
506 {
507 	static const char* aModules[] =
508 	{
509 		"swriter",
510 		"scalc",
511 		"simpress",
512 		"sdraw",
513 		"sdatabase",
514 		"smath",
515 		"schart",
516 		"sbasic"
517 	};
518 
519 	SvFileStream* pOut[] =
520 	{
521 		0,0,0,0,0,0,0,0,0
522 	};
523 
524 	String aIn = String::CreateFromAscii("/data/OOo/replacer/hidsin.lst");
525 	String aOut = String::CreateFromAscii("/data/OOo/replacer/quickhelp/");
526 	SvFileStream aInStrm( aIn, STREAM_READ );
527 	ByteString aBuffer;
528 	while ( aInStrm.ReadLine( aBuffer ) )
529 	{
530 		ByteString aHid = aBuffer.GetToken(0, ' ');
531 		ByteString aNr  = aBuffer.GetToken(1, ' ');
532 		bool bFound=false;
533 		for (sal_Int32 n= 0; n<8; n++)
534 		{
535 			bFound = false;
536 			String aHelpURL = SfxHelp::CreateHelpURL( String( aNr, RTL_TEXTENCODING_UTF8 ), String( aModules[n], RTL_TEXTENCODING_UTF8 ) );
537 			if ( SfxContentHelper::GetActiveHelpString( aHelpURL ).Len() )
538 //			if ( SfxHelp_Impl::GetHelpText( String( aNr, RTL_TEXTENCODING_UTF8 ), String( aModules[n], RTL_TEXTENCODING_UTF8 ) ).Len() )
539 			{
540 				if (!pOut[n])
541 				{
542 					String aTmp( aOut );
543 					aTmp += String( aModules[n], RTL_TEXTENCODING_UTF8 );
544 					aTmp += String::CreateFromAscii(".lst");
545 					pOut[n] = new SvFileStream( aTmp, STREAM_WRITE | STREAM_TRUNC );
546 				}
547 				pOut[n]->WriteLine( aHid );
548 				bFound = true;
549 				break;
550 			}
551 		}
552 
553 		if (!bFound)
554 		{
555 			if (!pOut[8])
556 			{
557 				String aTmp( aOut );
558 				aTmp += String( "notfound", RTL_TEXTENCODING_UTF8 );
559 				aTmp += String::CreateFromAscii(".lst");
560 				pOut[8] = new SvFileStream( aTmp, STREAM_WRITE | STREAM_TRUNC );
561 			}
562 			pOut[8]->WriteLine( aHid );
563 		}
564 	}
565 
566 	for (sal_Int32 n= 0; n<9; n++)
567 		DELETEZ( pOut[n] );
568 }
569 
570 void TestHids4()
571 {
572 	static const char* aModules[] =
573 	{
574 		"swriter",
575 		"scalc",
576 		"simpress",
577 		"smath",
578 		"sbasic"
579 	};
580 
581 	String aOut = String::CreateFromAscii("/data/OOo/replacer/quickhelp/");
582 	aOut += String::CreateFromAscii("lost.lst");
583 	SvFileStream aOutStrm( aOut, STREAM_WRITE | STREAM_TRUNC );
584 	for (sal_Int32 n= 0; n<5; n++)
585 	{
586 		String aIn = String::CreateFromAscii("/data/OOo/replacer/quickhelp/");
587 		aIn += String::CreateFromAscii( aModules[n] );
588 		aIn += String::CreateFromAscii(".lst");
589 		SvFileStream aInStrm( aIn, STREAM_READ );
590 		ByteString aBuffer;
591 		while ( aInStrm.ReadLine( aBuffer ) )
592 		{
593 			String aHelpURL = SfxHelp::CreateHelpURL( String( aBuffer, RTL_TEXTENCODING_UTF8 ), String( aModules[n], RTL_TEXTENCODING_UTF8 ) );
594 			if ( !SfxContentHelper::GetActiveHelpString( aHelpURL ).Len() )
595 				aOutStrm.WriteLine( aBuffer );
596 		}
597 	}
598 }
599 */
600 
SfxHelp()601 SfxHelp::SfxHelp() :
602 
603 	bIsDebug( sal_False ),
604 	pImp	( NULL )
605 
606 {
607 	// read the environment variable "HELP_DEBUG"
608 	// if it's set, you will see debug output on active help
609 	{
610 		::rtl::OUString sHelpDebug;
611 		::rtl::OUString sEnvVarName( RTL_CONSTASCII_USTRINGPARAM( "HELP_DEBUG" ) );
612 		osl_getEnvironment( sEnvVarName.pData, &sHelpDebug.pData );
613 		bIsDebug = ( 0 != sHelpDebug.getLength() );
614 	}
615 
616 	pImp = new SfxHelp_Impl( bIsDebug );
617 
618 	::rtl::OUString aLocaleStr = HelpLocaleString();
619 
620 	sal_Int32 nSepPos = aLocaleStr.indexOf( '_' );
621 	if ( nSepPos != -1 )
622 	{
623 		aLanguageStr = aLocaleStr.copy( 0, nSepPos );
624 		aCountryStr = aLocaleStr.copy( nSepPos+1 );
625 	}
626 	else
627 	{
628 		nSepPos = aLocaleStr.indexOf( '-' );
629 		if ( nSepPos != -1 )
630 		{
631 			aLanguageStr = aLocaleStr.copy( 0, nSepPos );
632 			aCountryStr = aLocaleStr.copy( nSepPos+1 );
633 		}
634 		else
635 		{
636 			aLanguageStr = aLocaleStr;
637 		}
638 	}
639 }
640 
~SfxHelp()641 SfxHelp::~SfxHelp()
642 {
643 	delete pImp;
644 }
645 
getDefaultModule_Impl()646 ::rtl::OUString getDefaultModule_Impl()
647 {
648 	rtl::OUString sDefaultModule;
649 	SvtModuleOptions aModOpt;
650 	if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
651 		sDefaultModule = DEFINE_CONST_UNICODE("swriter");
652 	else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) )
653 		sDefaultModule = DEFINE_CONST_UNICODE("scalc");
654 	else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) )
655 		sDefaultModule = DEFINE_CONST_UNICODE("simpress");
656 	else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) )
657 		sDefaultModule = DEFINE_CONST_UNICODE("sdraw");
658 	else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SMATH ) )
659 		sDefaultModule = DEFINE_CONST_UNICODE("smath");
660 	else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SCHART ) )
661 		sDefaultModule = DEFINE_CONST_UNICODE("schart");
662 	else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SBASIC ) )
663 		sDefaultModule = DEFINE_CONST_UNICODE("sbasic");
664 	else if ( aModOpt.IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) )
665 		sDefaultModule = DEFINE_CONST_UNICODE("sdatabase");
666 	else
667 	{
668 		DBG_ERRORFILE( "getDefaultModule_Impl(): no module installed" );
669 	}
670 	return sDefaultModule;
671 }
672 
getCurrentModuleIdentifier_Impl()673 ::rtl::OUString getCurrentModuleIdentifier_Impl()
674 {
675 	::rtl::OUString sIdentifier;
676 	Reference < XFrame > xCurrentFrame;
677 	Reference < XModuleManager > xModuleManager( ::comphelper::getProcessServiceFactory()->createInstance(
678 		DEFINE_CONST_UNICODE("com.sun.star.frame.ModuleManager") ), UNO_QUERY );
679 	Reference < XDesktop > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
680 		DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );
681 	if ( xDesktop.is() )
682 		xCurrentFrame = xDesktop->getCurrentFrame();
683 
684 	if ( xCurrentFrame.is() && xModuleManager.is() )
685 	{
686 		try
687 		{
688 			sIdentifier = xModuleManager->identify( xCurrentFrame );
689 		}
690 		catch ( ::com::sun::star::frame::UnknownModuleException& )
691 		{
692 			DBG_WARNING( "SfxHelp::getCurrentModuleIdentifier_Impl(): unknown module (help in help?)" );
693 		}
694 		catch ( Exception& )
695 		{
696 			DBG_ERRORFILE( "SfxHelp::getCurrentModuleIdentifier_Impl(): exception of XModuleManager::identify()" );
697 		}
698 	}
699 
700 	return sIdentifier;
701 }
702 
GetHelpModuleName_Impl()703 String SfxHelp::GetHelpModuleName_Impl()
704 {
705 	String sModuleName;
706 	rtl::OUString aFactoryShortName;
707 	rtl::OUString aModuleIdentifier = getCurrentModuleIdentifier_Impl();
708 
709 	if ( aModuleIdentifier.getLength() > 0 )
710 	{
711 		try
712 		{
713 			Reference < XModuleManager > xModuleManager(
714 				::comphelper::getProcessServiceFactory()->createInstance(
715 					DEFINE_CONST_UNICODE("com.sun.star.frame.ModuleManager") ), UNO_QUERY );
716 			Sequence< PropertyValue > lProps;
717 			Reference< ::com::sun::star::container::XNameAccess > xCont( xModuleManager, UNO_QUERY);
718 			if ( xCont.is() )
719 				xCont->getByName( aModuleIdentifier ) >>= lProps;
720 			for ( sal_Int32 i = 0; i < lProps.getLength(); ++i )
721 			{
722 				if ( lProps[i].Name.equalsAscii("ooSetupFactoryShortName") )
723 				{
724 					lProps[i].Value >>= aFactoryShortName;
725 					break;
726 				}
727 			}
728 		}
729 		catch ( Exception& )
730 		{
731 			DBG_ERRORFILE( "SfxHelp::GetHelpModuleName_Impl(): exception of XNameAccess::getByName()" );
732 		}
733 	}
734 
735 	rtl::OUString sDefaultModule = getDefaultModule_Impl();
736 	if ( aFactoryShortName.getLength() > 0 )
737 	{
738 		// Map some module identifiers to their "real" help module string.
739 		if ( aFactoryShortName.equalsAscii( "chart2" ) )
740 			aFactoryShortName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "schart" ) );
741 		else if ( aFactoryShortName.equalsAscii( "BasicIDE" ) )
742 			aFactoryShortName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "sbasic" ) );
743 		else if ( aFactoryShortName.equalsAscii( "sweb" )
744 				|| aFactoryShortName.equalsAscii( "sglobal" )
745 				|| aFactoryShortName.equalsAscii( "swxform" ) )
746 			aFactoryShortName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "swriter" ) );
747 		else if ( aFactoryShortName.equalsAscii( "dbquery" )
748 				|| aFactoryShortName.equalsAscii( "dbbrowser" )
749 				|| aFactoryShortName.equalsAscii( "dbrelation" )
750 				|| aFactoryShortName.equalsAscii( "dbtable" )
751 				|| aFactoryShortName.equalsAscii( "dbapp" )
752 				|| aFactoryShortName.equalsAscii( "dbreport" )
753 				|| aFactoryShortName.equalsAscii( "swreport" )
754 				|| aFactoryShortName.equalsAscii( "dbbrowser" )
755 				|| aFactoryShortName.equalsAscii( "swform" ) )
756 			aFactoryShortName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "sdatabase" ) );
757 		else if ( aFactoryShortName.equalsAscii( "sbibliography" )
758 				|| aFactoryShortName.equalsAscii( "StartModule" ) )
759 			aFactoryShortName = sDefaultModule;
760 	}
761 	else
762 		aFactoryShortName = sDefaultModule;
763 
764 	sModuleName = String( aFactoryShortName );
765 	return sModuleName;
766 }
767 
CreateHelpURL_Impl(const String & aCommandURL,const String & rModuleName)768 String	SfxHelp::CreateHelpURL_Impl( const String& aCommandURL, const String& rModuleName )
769 {
770 	// build up the help URL
771 	String aHelpURL;
772 	sal_Bool bHasAnchor = sal_False;
773 	String aAnchor;
774 
775 	String aModuleName( rModuleName );
776 	if ( aModuleName.Len() == 0 )
777 		aModuleName = getDefaultModule_Impl();
778 
779 	aHelpURL = String::CreateFromAscii("vnd.sun.star.help://");
780 	aHelpURL += aModuleName;
781 
782 	if ( !aCommandURL.Len() )
783 		aHelpURL += String::CreateFromAscii("/start");
784 	else
785 	{
786 		aHelpURL += '/';
787 		aHelpURL += String( rtl::Uri::encode( aCommandURL,
788 											  rtl_UriCharClassRelSegment,
789 											  rtl_UriEncodeKeepEscapes,
790 											  RTL_TEXTENCODING_UTF8 ));
791 
792 		String aTempURL = aHelpURL;
793 		AppendConfigToken_Impl( aTempURL, sal_True );
794 		bHasAnchor = GetHelpAnchor_Impl( aTempURL, aAnchor );
795 	}
796 
797 	AppendConfigToken_Impl( aHelpURL, sal_True );
798 
799 	if ( bHasAnchor )
800 	{
801 		aHelpURL += '#';
802 		aHelpURL += aAnchor;
803 	}
804 
805 	return aHelpURL;
806 }
807 
impl_createHelp(Reference<XFrame> & rHelpTask,Reference<XFrame> & rHelpContent)808 SfxHelpWindow_Impl* impl_createHelp(Reference< XFrame >& rHelpTask ,
809 									Reference< XFrame >& rHelpContent)
810 {
811 	Reference < XFrame > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
812 		DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );
813 
814 	// otherwise - create new help task
815 	Reference< XFrame > xHelpTask = xDesktop->findFrame(
816 		::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")),
817 		FrameSearchFlag::TASKS | FrameSearchFlag::CREATE);
818 	if (!xHelpTask.is())
819 		return 0;
820 
821 	// create all internal windows and sub frames ...
822 	Reference< ::com::sun::star::awt::XWindow > xParentWindow = xHelpTask->getContainerWindow();
823 	Window*                                     pParentWindow = VCLUnoHelper::GetWindow( xParentWindow );
824 	SfxHelpWindow_Impl*                         pHelpWindow   = new SfxHelpWindow_Impl( xHelpTask, pParentWindow, WB_DOCKBORDER );
825 	Reference< ::com::sun::star::awt::XWindow > xHelpWindow   = VCLUnoHelper::GetInterface( pHelpWindow );
826 
827 	Reference< XFrame > xHelpContent;
828 	if (xHelpTask->setComponent( xHelpWindow, Reference< XController >() ))
829 	{
830 		// Customize UI ...
831 		xHelpTask->setName( ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")) );
832 
833 		Reference< XPropertySet > xProps(xHelpTask, UNO_QUERY);
834 		if (xProps.is())
835 			xProps->setPropertyValue(
836 				DEFINE_CONST_UNICODE("Title"),
837 				makeAny(::rtl::OUString(String(SfxResId(STR_HELP_WINDOW_TITLE)))));
838 
839 		pHelpWindow->setContainerWindow( xParentWindow );
840 		xParentWindow->setVisible(sal_True);
841 		xHelpWindow->setVisible(sal_True);
842 
843 		// This sub frame is created internally (if we called new SfxHelpWindow_Impl() ...)
844 		// It should exist :-)
845 		xHelpContent = xHelpTask->findFrame(::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")), FrameSearchFlag::CHILDREN);
846 	}
847 
848 	if (!xHelpContent.is())
849 	{
850 		delete pHelpWindow;
851 		return NULL;
852 		}
853 
854 	xHelpContent->setName(::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")));
855 
856 	rHelpTask    = xHelpTask;
857 	rHelpContent = xHelpContent;
858 	return pHelpWindow;
859 }
860 
GetHelpText(const String & aCommandURL,const Window * pWindow)861 XubString SfxHelp::GetHelpText( const String& aCommandURL, const Window* pWindow )
862 {
863 	String sModuleName = GetHelpModuleName_Impl();
864 	String sHelpText = pImp->GetHelpText( aCommandURL, sModuleName );
865 
866 	ByteString aNewHelpId;
867 
868 	if ( pWindow && !sHelpText.Len() )
869 	{
870 		// no help text found -> try with parent help id.
871 		Window* pParent = pWindow->GetParent();
872 		while ( pParent )
873 		{
874 			aNewHelpId = pParent->GetHelpId();
875 			sHelpText = pImp->GetHelpText( String( aNewHelpId, RTL_TEXTENCODING_UTF8 ), sModuleName );
876 			if ( sHelpText.Len() > 0 )
877 				pParent = NULL;
878 			else
879 				pParent = pParent->GetParent();
880 		}
881 
882 		if ( bIsDebug && !sHelpText.Len() )
883 			aNewHelpId.Erase();
884 	}
885 
886 	// add some debug information?
887 	if ( bIsDebug )
888 	{
889 		sHelpText += DEFINE_CONST_UNICODE("\n_____________\n");
890 		sHelpText += String( sModuleName );
891 		sHelpText += DEFINE_CONST_UNICODE(": ");
892 		sHelpText += aCommandURL;
893 		if ( aNewHelpId.Len() )
894 		{
895 			sHelpText += DEFINE_CONST_UNICODE(" - ");
896 			sHelpText += String( aNewHelpId, RTL_TEXTENCODING_UTF8 );
897 		}
898 	}
899 
900 	return sHelpText;
901 }
902 
SearchKeyword(const XubString & rKeyword)903 sal_Bool SfxHelp::SearchKeyword( const XubString& rKeyword )
904 {
905 	return Start_Impl( String(), NULL, rKeyword );
906 }
907 
Start(const String & rURL,const Window * pWindow)908 sal_Bool SfxHelp::Start( const String& rURL, const Window* pWindow )
909 {
910 	return Start_Impl( rURL, pWindow, String() );
911 }
912 
Start_Impl(const String & rURL,const Window * pWindow,const String & rKeyword)913 sal_Bool SfxHelp::Start_Impl( const String& rURL, const Window* pWindow, const String& rKeyword )
914 {
915 	// check if help is available
916 	String aHelpRootURL( DEFINE_CONST_OUSTRING("vnd.sun.star.help://") );
917 	AppendConfigToken_Impl( aHelpRootURL, sal_True );
918 	Sequence< ::rtl::OUString > aFactories = SfxContentHelper::GetResultSet( aHelpRootURL );
919 	if ( 0 == aFactories.getLength() )
920 	{
921 		// no factories -> no help -> error message and return
922 		NoHelpErrorBox aErrBox( const_cast< Window* >( pWindow ) );
923 		aErrBox.Execute();
924 		return sal_False;
925 	}
926 
927 	/* rURL may be
928 		- a "real" URL
929 		- a HelpID (formerly a long, now a string)
930 	   If rURL is a URL, CreateHelpURL should be called for this URL
931 	   If rURL is an arbitrary string, the same should happen, but the URL should be tried out
932 	   if it delivers real help content. In case only the Help Error Document is returned, the
933 	   parent of the window for that help was called, is asked for its HelpID.
934 	   For compatibility reasons this upward search is not implemented for "real" URLs.
935 	   Help keyword search now is implemented as own method; in former versions it
936 	   was done via Help::Start, but this implementation conflicted with the upward search.
937 	*/
938 	String aHelpURL;
939 	INetURLObject aParser( rURL );
940 	INetProtocol nProtocol = aParser.GetProtocol();
941 	String aHelpModuleName( GetHelpModuleName_Impl() );
942 	switch ( nProtocol )
943 	{
944 		case INET_PROT_VND_SUN_STAR_HELP:
945 			// already a vnd.sun.star.help URL -> nothing to do
946 			aHelpURL = rURL;
947 			break;
948 		default:
949 		{
950 			// no URL, just a HelpID (maybe empty in case of keyword search)
951 			aHelpURL = CreateHelpURL_Impl( rURL, aHelpModuleName );
952 			if ( pWindow && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
953 			{
954 				// no help found -> try with parent help id.
955 				Window* pParent = pWindow->GetParent();
956 				while ( pParent )
957 				{
958 					ByteString aHelpId = pParent->GetHelpId();
959 					aHelpURL = CreateHelpURL( String( aHelpId, RTL_TEXTENCODING_UTF8 ), aHelpModuleName );
960 					if ( !SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
961 						break;
962 					else
963 					{
964 						pParent = pParent->GetParent();
965 						if ( !pParent )
966 							// create help url of start page ( helpid == 0 -> start page)
967 							aHelpURL = CreateHelpURL( String(), aHelpModuleName );
968 					}
969 				}
970 			}
971 			break;
972 		}
973 	}
974 
975 	Reference < XFrame > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
976 		DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );
977 
978 	// check if help window is still open
979 	// If not, create a new one and return access directly to the internal sub frame showing the help content
980 	// search must be done here; search one desktop level could return an arbitrary frame
981 	Reference< XFrame > xHelp = xDesktop->findFrame(
982 		::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")),
983 		FrameSearchFlag::CHILDREN);
984 	Reference< XFrame > xHelpContent = xDesktop->findFrame(
985 		::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")),
986 		FrameSearchFlag::CHILDREN);
987 
988 	SfxHelpWindow_Impl* pHelpWindow = 0;
989 	if (!xHelp.is())
990 		pHelpWindow = impl_createHelp(xHelp, xHelpContent);
991 	else
992 		pHelpWindow = (SfxHelpWindow_Impl*)VCLUnoHelper::GetWindow(xHelp->getComponentWindow());
993 	if (!xHelp.is() || !xHelpContent.is() || !pHelpWindow)
994 		return sal_False;
995 
996 #ifdef DBG_UTIL
997 	ByteString aTmp("SfxHelp: HelpId = ");
998 	aTmp += ByteString( aHelpURL, RTL_TEXTENCODING_UTF8 );
999 	DBG_TRACE( aTmp.GetBuffer() );
1000 #endif
1001 
1002 	pHelpWindow->SetHelpURL( aHelpURL );
1003 	pHelpWindow->loadHelpContent(aHelpURL);
1004 	if ( rKeyword.Len() )
1005 		pHelpWindow->OpenKeyword( rKeyword );
1006 
1007 	Reference < ::com::sun::star::awt::XTopWindow > xTopWindow( xHelp->getContainerWindow(), UNO_QUERY );
1008 	if ( xTopWindow.is() )
1009 		xTopWindow->toFront();
1010 
1011 	return sal_True;
1012 }
1013 
CreateHelpURL(const String & aCommandURL,const String & rModuleName)1014 String SfxHelp::CreateHelpURL( const String& aCommandURL, const String& rModuleName )
1015 {
1016 	String aURL;
1017 	SfxHelp* pHelp = SAL_STATIC_CAST( SfxHelp*, Application::GetHelp() );
1018 	if ( pHelp )
1019 		aURL = pHelp->CreateHelpURL_Impl( aCommandURL, rModuleName );
1020 	return aURL;
1021 }
1022 
OpenHelpAgent(SfxFrame *,const rtl::OString & sHelpId)1023 void SfxHelp::OpenHelpAgent( SfxFrame*, const rtl::OString& sHelpId )
1024 {
1025 	SfxHelp* pHelp = SAL_STATIC_CAST( SfxHelp*, Application::GetHelp() );
1026 	if ( pHelp )
1027 		pHelp->OpenHelpAgent( sHelpId );
1028 }
1029 
OpenHelpAgent(const rtl::OString & sHelpId)1030 void SfxHelp::OpenHelpAgent( const rtl::OString& sHelpId )
1031 {
1032 	if ( SvtHelpOptions().IsHelpAgentAutoStartMode() )
1033 	{
1034 			SfxHelpOptions_Impl *pOpt = pImp->GetOptions();
1035 			if ( !pOpt->HasId( sHelpId ) )
1036 				return;
1037 
1038 			try
1039 			{
1040 				URL aURL;
1041 				aURL.Complete = CreateHelpURL_Impl( String( ByteString(sHelpId), RTL_TEXTENCODING_UTF8 ), GetHelpModuleName_Impl() );
1042 				Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance(
1043 					::rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" ) ), UNO_QUERY );
1044 				xTrans->parseStrict(aURL);
1045 
1046 				Reference < XFrame > xCurrentFrame;
1047 				Reference < XDesktop > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
1048 					DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );
1049 				if ( xDesktop.is() )
1050 					xCurrentFrame = xDesktop->getCurrentFrame();
1051 
1052 				Reference< XDispatchProvider > xDispProv( xCurrentFrame, UNO_QUERY );
1053 				Reference< XDispatch > xHelpDispatch;
1054 				if ( xDispProv.is() )
1055 					xHelpDispatch = xDispProv->queryDispatch(
1056 						aURL, ::rtl::OUString::createFromAscii("_helpagent"),
1057 						FrameSearchFlag::PARENT | FrameSearchFlag::SELF );
1058 
1059 				DBG_ASSERT( xHelpDispatch.is(), "OpenHelpAgent: could not get a dispatcher!" );
1060 				if ( xHelpDispatch.is() )
1061 					xHelpDispatch->dispatch( aURL, Sequence< PropertyValue >() );
1062 			}
1063 			catch( const Exception& )
1064 			{
1065 				DBG_ERRORFILE( "OpenHelpAgent: caught an exception while executing the dispatch!" );
1066 			}
1067 	}
1068 }
1069 
GetDefaultHelpModule()1070 String SfxHelp::GetDefaultHelpModule()
1071 {
1072 	return getDefaultModule_Impl();
1073 }
1074 
GetCurrentModuleIdentifier()1075 ::rtl::OUString SfxHelp::GetCurrentModuleIdentifier()
1076 {
1077 	return getCurrentModuleIdentifier_Impl();
1078 }
1079