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