xref: /trunk/main/sfx2/source/appl/sfxhelp.cxx (revision 15e1fb6f8be2dab068d70089d19ab118cd5fa46f)
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