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