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