xref: /aoo41x/main/sfx2/source/appl/sfxhelp.cxx (revision 24c56ab9)
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     // otherwhise - 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 internaly (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         delete pHelpWindow;
850 
851     xHelpContent->setName(::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")));
852 
853     rHelpTask    = xHelpTask;
854     rHelpContent = xHelpContent;
855     return pHelpWindow;
856 }
857 
GetHelpText(const String & aCommandURL,const Window * pWindow)858 XubString SfxHelp::GetHelpText( const String& aCommandURL, const Window* pWindow )
859 {
860     String sModuleName = GetHelpModuleName_Impl();
861     String sHelpText = pImp->GetHelpText( aCommandURL, sModuleName );
862 
863 	ByteString aNewHelpId;
864 
865 	if ( pWindow && !sHelpText.Len() )
866 	{
867 		// no help text found -> try with parent help id.
868 		Window* pParent = pWindow->GetParent();
869 		while ( pParent )
870 		{
871 			aNewHelpId = pParent->GetHelpId();
872 			sHelpText = pImp->GetHelpText( String( aNewHelpId, RTL_TEXTENCODING_UTF8 ), sModuleName );
873 			if ( sHelpText.Len() > 0 )
874 				pParent = NULL;
875 			else
876 				pParent = pParent->GetParent();
877 		}
878 
879 		if ( bIsDebug && !sHelpText.Len() )
880 			aNewHelpId.Erase();
881 	}
882 
883     // add some debug information?
884     if ( bIsDebug )
885     {
886         sHelpText += DEFINE_CONST_UNICODE("\n-------------\n");
887         sHelpText += String( sModuleName );
888         sHelpText += DEFINE_CONST_UNICODE(": ");
889         sHelpText += aCommandURL;
890 		if ( aNewHelpId.Len() )
891 		{
892 			sHelpText += DEFINE_CONST_UNICODE(" - ");
893 			sHelpText += String( aNewHelpId, RTL_TEXTENCODING_UTF8 );
894 		}
895     }
896 
897     return sHelpText;
898 }
899 
SearchKeyword(const XubString & rKeyword)900 sal_Bool SfxHelp::SearchKeyword( const XubString& rKeyword )
901 {
902 	return Start_Impl( String(), NULL, rKeyword );
903 }
904 
Start(const String & rURL,const Window * pWindow)905 sal_Bool SfxHelp::Start( const String& rURL, const Window* pWindow )
906 {
907     return Start_Impl( rURL, pWindow, String() );
908 }
909 
Start_Impl(const String & rURL,const Window * pWindow,const String & rKeyword)910 sal_Bool SfxHelp::Start_Impl( const String& rURL, const Window* pWindow, const String& rKeyword )
911 {
912     // check if help is available
913     String aHelpRootURL( DEFINE_CONST_OUSTRING("vnd.sun.star.help://") );
914     AppendConfigToken_Impl( aHelpRootURL, sal_True );
915     Sequence< ::rtl::OUString > aFactories = SfxContentHelper::GetResultSet( aHelpRootURL );
916     if ( 0 == aFactories.getLength() )
917     {
918         // no factories -> no help -> error message and return
919         NoHelpErrorBox aErrBox( const_cast< Window* >( pWindow ) );
920         aErrBox.Execute();
921         return sal_False;
922     }
923 
924 	/* rURL may be
925 		- a "real" URL
926 		- a HelpID (formerly a long, now a string)
927 	   If rURL is a URL, CreateHelpURL should be called for this URL
928 	   If rURL is an arbitrary string, the same should happen, but the URL should be tried out
929 	   if it delivers real help content. In case only the Help Error Document is returned, the
930 	   parent of the window for that help was called, is asked for its HelpID.
931 	   For compatibility reasons this upward search is not implemented for "real" URLs.
932 	   Help keyword search now is implemented as own method; in former versions it
933 	   was done via Help::Start, but this implementation conflicted with the upward search.
934 	*/
935 	String aHelpURL;
936 	INetURLObject aParser( rURL );
937     INetProtocol nProtocol = aParser.GetProtocol();
938 	String aHelpModuleName( GetHelpModuleName_Impl() );
939 	switch ( nProtocol )
940 	{
941 		case INET_PROT_VND_SUN_STAR_HELP:
942 			// already a vnd.sun.star.help URL -> nothing to do
943 			aHelpURL = rURL;
944 			break;
945 		default:
946 		{
947 			// no URL, just a HelpID (maybe empty in case of keyword search)
948 			aHelpURL  = CreateHelpURL_Impl( rURL, aHelpModuleName );
949 			if ( pWindow && SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
950 			{
951 				// no help found -> try with parent help id.
952 				Window* pParent = pWindow->GetParent();
953 				while ( pParent )
954 				{
955 					ByteString aHelpId = pParent->GetHelpId();
956 					aHelpURL = CreateHelpURL( String( aHelpId, RTL_TEXTENCODING_UTF8 ), aHelpModuleName );
957 					if ( !SfxContentHelper::IsHelpErrorDocument( aHelpURL ) )
958 						break;
959 					else
960 					{
961 						pParent = pParent->GetParent();
962 						if ( !pParent )
963 							// create help url of start page ( helpid == 0 -> start page)
964 							aHelpURL = CreateHelpURL( String(), aHelpModuleName );
965 					}
966 				}
967 			}
968 			break;
969 		}
970 	}
971 
972     Reference < XFrame > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
973 		DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );
974 
975     // check if help window is still open
976     // If not, create a new one and return access directly to the internal sub frame showing the help content
977 	// search must be done here; search one desktop level could return an arbitraty frame
978     Reference< XFrame > xHelp = xDesktop->findFrame(
979         ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP_TASK")),
980         FrameSearchFlag::CHILDREN);
981     Reference< XFrame > xHelpContent = xDesktop->findFrame(
982         ::rtl::OUString(DEFINE_CONST_UNICODE("OFFICE_HELP")),
983         FrameSearchFlag::CHILDREN);
984 
985     SfxHelpWindow_Impl* pHelpWindow = 0;
986     if (!xHelp.is())
987         pHelpWindow = impl_createHelp(xHelp, xHelpContent);
988     else
989         pHelpWindow = (SfxHelpWindow_Impl*)VCLUnoHelper::GetWindow(xHelp->getComponentWindow());
990     if (!xHelp.is() || !xHelpContent.is() || !pHelpWindow)
991         return sal_False;
992 
993 #ifdef DBG_UTIL
994     ByteString aTmp("SfxHelp: HelpId = ");
995     aTmp += ByteString( aHelpURL, RTL_TEXTENCODING_UTF8 );
996     DBG_TRACE( aTmp.GetBuffer() );
997 #endif
998 
999     pHelpWindow->SetHelpURL( aHelpURL );
1000     pHelpWindow->loadHelpContent(aHelpURL);
1001     if ( rKeyword.Len() )
1002 		pHelpWindow->OpenKeyword( rKeyword );
1003 
1004 	Reference < ::com::sun::star::awt::XTopWindow > xTopWindow( xHelp->getContainerWindow(), UNO_QUERY );
1005     if ( xTopWindow.is() )
1006         xTopWindow->toFront();
1007 
1008     return sal_True;
1009 }
1010 
CreateHelpURL(const String & aCommandURL,const String & rModuleName)1011 String SfxHelp::CreateHelpURL( const String& aCommandURL, const String& rModuleName )
1012 {
1013 	String aURL;
1014 	SfxHelp* pHelp = SAL_STATIC_CAST( SfxHelp*, Application::GetHelp() );
1015 	if ( pHelp )
1016 		aURL = pHelp->CreateHelpURL_Impl( aCommandURL, rModuleName );
1017 	return aURL;
1018 }
1019 
OpenHelpAgent(SfxFrame *,const rtl::OString & sHelpId)1020 void SfxHelp::OpenHelpAgent( SfxFrame*, const rtl::OString& sHelpId )
1021 {
1022 	SfxHelp* pHelp = SAL_STATIC_CAST( SfxHelp*, Application::GetHelp() );
1023 	if ( pHelp )
1024 		pHelp->OpenHelpAgent( sHelpId );
1025 }
1026 
OpenHelpAgent(const rtl::OString & sHelpId)1027 void SfxHelp::OpenHelpAgent( const rtl::OString& sHelpId )
1028 {
1029 	if ( SvtHelpOptions().IsHelpAgentAutoStartMode() )
1030 	{
1031 			SfxHelpOptions_Impl *pOpt = pImp->GetOptions();
1032     		if ( !pOpt->HasId( sHelpId ) )
1033         		return;
1034 
1035 			try
1036 			{
1037 				URL aURL;
1038                 aURL.Complete = CreateHelpURL_Impl( String( ByteString(sHelpId), RTL_TEXTENCODING_UTF8 ), GetHelpModuleName_Impl() );
1039         		Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance(
1040 					::rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" ) ), UNO_QUERY );
1041         		xTrans->parseStrict(aURL);
1042 
1043 				Reference < XFrame > xCurrentFrame;
1044 				Reference < XDesktop > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance(
1045 					DEFINE_CONST_UNICODE("com.sun.star.frame.Desktop") ), UNO_QUERY );
1046 				if ( xDesktop.is() )
1047 					xCurrentFrame = xDesktop->getCurrentFrame();
1048 
1049         		Reference< XDispatchProvider > xDispProv( xCurrentFrame, UNO_QUERY );
1050 				Reference< XDispatch > xHelpDispatch;
1051 				if ( xDispProv.is() )
1052 					xHelpDispatch = xDispProv->queryDispatch(
1053 						aURL, ::rtl::OUString::createFromAscii("_helpagent"),
1054 						FrameSearchFlag::PARENT | FrameSearchFlag::SELF );
1055 
1056         		DBG_ASSERT( xHelpDispatch.is(), "OpenHelpAgent: could not get a dispatcher!" );
1057 				if ( xHelpDispatch.is() )
1058 					xHelpDispatch->dispatch( aURL, Sequence< PropertyValue >() );
1059 			}
1060 			catch( const Exception& )
1061 			{
1062         		DBG_ERRORFILE( "OpenHelpAgent: caught an exception while executing the dispatch!" );
1063 			}
1064 	}
1065 }
1066 
GetDefaultHelpModule()1067 String SfxHelp::GetDefaultHelpModule()
1068 {
1069     return getDefaultModule_Impl();
1070 }
1071 
GetCurrentModuleIdentifier()1072 ::rtl::OUString SfxHelp::GetCurrentModuleIdentifier()
1073 {
1074     return getCurrentModuleIdentifier_Impl();
1075 }
1076 
1077