xref: /AOO41X/main/sfx2/source/appl/sfxhelp.cxx (revision 24c56ab9f1bd1305754aa2f564704f38ff57627e)
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