1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <rtl/character.hxx>
22 #include <rtl/ustrbuf.hxx>
23 #include <sal/log.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <osl/diagnose.h>
28 #include <osl/file.hxx>
29 #include <unotools/configmgr.hxx>
30 #include <com/sun/star/configuration/theDefaultProvider.hpp>
31 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/propertysequence.hxx>
35 #include <com/sun/star/deployment/thePackageManagerFactory.hpp>
36 #include <com/sun/star/util/theMacroExpander.hpp>
37 #include <com/sun/star/uri/UriReferenceFactory.hpp>
38 #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
39 #include <i18nlangtag/languagetag.hxx>
40 #include <unotools/pathoptions.hxx>
47 friend class TVChildTarget
;
52 explicit TVDom( TVDom
* arent
= nullptr )
53 : kind( Kind::other
),
61 children
.emplace_back( new TVDom( this ) );
62 return children
.back().get();
65 void newChild(std::unique_ptr
<TVDom
> p
)
67 children
.emplace_back(std::move(p
));
68 children
.back()->parent
= this;
71 TVDom
* getParent() const
76 return const_cast<TVDom
*>(this); // I am my own parent, if I am the root
85 bool isLeaf() const { return kind
== TVDom::Kind::tree_leaf
; }
86 void setKind( Kind ind
) { kind
= ind
; }
88 void setApplication( const char* appl
)
90 application
= OUString( appl
,
92 RTL_TEXTENCODING_UTF8
);
95 void setTitle( const char* itle
)
97 title
+= OUString( itle
,
99 RTL_TEXTENCODING_UTF8
);
102 void setTitle( const XML_Char
* itle
,int len
)
104 title
+= OUString( itle
,
106 RTL_TEXTENCODING_UTF8
);
109 void setId( const char* d
)
113 RTL_TEXTENCODING_UTF8
);
116 void setAnchor( const char* nchor
)
118 anchor
= OUString( nchor
,
120 RTL_TEXTENCODING_UTF8
);
123 OUString
const & getTargetURL()
125 if( targetURL
.isEmpty() )
127 targetURL
= "vnd.sun.star.help://" + id
;
136 OUString application
;
143 std::vector
< std::unique_ptr
<TVDom
> > children
;
148 using namespace treeview
;
149 using namespace com::sun::star
;
150 using namespace com::sun::star::uno
;
151 using namespace com::sun::star::beans
;
152 using namespace com::sun::star::configuration
;
153 using namespace com::sun::star::lang
;
154 using namespace com::sun::star::util
;
155 using namespace com::sun::star::container
;
156 using namespace com::sun::star::deployment
;
158 const char prodName
[] = "%PRODUCTNAME";
159 const char vendName
[] = "%VENDORNAME";
160 const char vendVersion
[] = "%VENDORVERSION";
161 const char vendShort
[] = "%VENDORSHORT";
162 const char prodVersion
[] = "%PRODUCTVERSION";
164 ConfigData::ConfigData()
168 void ConfigData::replaceName( OUString
& oustring
) const
170 sal_Int32 idx
= -1,k
= 0,off
;
172 OUStringBuffer
aStrBuf( 0 );
174 while( ( idx
= oustring
.indexOf( '%', ++idx
) ) != -1 )
176 if( oustring
.indexOf( prodName
,idx
) == idx
)
178 else if( oustring
.indexOf( prodVersion
,idx
) == idx
)
179 off
= PRODUCTVERSION
;
180 else if( oustring
.indexOf( vendName
,idx
) == idx
)
182 else if( oustring
.indexOf( vendVersion
,idx
) == idx
)
184 else if( oustring
.indexOf( vendShort
,idx
) == idx
)
194 aStrBuf
.ensureCapacity( 256 );
197 aStrBuf
.append( &oustring
.getStr()[k
],idx
- k
);
198 aStrBuf
.append( m_vReplacement
[off
] );
199 k
= idx
+ m_vAdd
[off
];
205 if( k
< oustring
.getLength() )
206 aStrBuf
.append( &oustring
.getStr()[k
],oustring
.getLength()-k
);
207 oustring
= aStrBuf
.makeStringAndClear();
213 TVRead::TVRead( const ConfigData
& configData
,TVDom
* tvDom
)
218 Title
= tvDom
->title
;
219 configData
.replaceName( Title
);
220 if( tvDom
->isLeaf() )
222 TargetURL
= tvDom
->getTargetURL() + configData
.appendix
;
223 if( !tvDom
->anchor
.isEmpty() )
224 TargetURL
+= "#" + tvDom
->anchor
;
227 Children
= new TVChildTarget( configData
,tvDom
);
237 TVRead::getByName( const OUString
& aName
)
241 if( aName
== "Title" )
243 else if( aName
== "TargetURL" )
245 else if( aName
== "Children" )
247 cppu::OWeakObject
* p
= Children
.get();
248 aAny
<<= Reference
< XInterface
>( p
);
256 throw NoSuchElementException();
259 Sequence
< OUString
> SAL_CALL
260 TVRead::getElementNames( )
262 Sequence
< OUString
> seq( 3 );
265 seq
[1] = "TargetURL";
272 TVRead::hasByName( const OUString
& aName
)
274 if( aName
== "Title" ||
275 aName
== "TargetURL" ||
276 aName
== "Children" )
282 // XHierarchicalNameAccess
285 TVRead::getByHierarchicalName( const OUString
& aName
)
288 if( aName
.startsWith("Children/", &aRest
) )
289 return Children
->getByHierarchicalName( aRest
);
291 return getByName( aName
);
295 TVRead::hasByHierarchicalName( const OUString
& aName
)
298 if( aName
.startsWith("Children/", &aRest
) )
299 return Children
->hasByHierarchicalName( aRest
);
301 return hasByName( aName
);
304 /**************************************************************************/
308 /**************************************************************************/
312 static void start_handler(void *userData
,
313 const XML_Char
*name
,
314 const XML_Char
**atts
)
318 if( strcmp( name
,"help_section" ) == 0 ||
319 strcmp( name
,"node" ) == 0 )
320 kind
= TVDom::Kind::tree_node
;
321 else if( strcmp( name
,"topic" ) == 0 )
322 kind
= TVDom::Kind::tree_leaf
;
326 TVDom
**tvDom
= static_cast< TVDom
** >( userData
);
330 *tvDom
= p
->newChild();
336 if( strcmp( *atts
,"application" ) == 0 )
337 p
->setApplication( *(atts
+1) );
338 else if( strcmp( *atts
,"title" ) == 0 )
339 p
->setTitle( *(atts
+1) );
340 else if( strcmp( *atts
,"id" ) == 0 )
341 p
->setId( *(atts
+1) );
342 else if( strcmp( *atts
,"anchor" ) == 0 )
343 p
->setAnchor( *(atts
+1) );
349 static void end_handler(void *userData
,
350 SAL_UNUSED_PARAMETER
const XML_Char
* )
352 TVDom
**tvDom
= static_cast< TVDom
** >( userData
);
353 *tvDom
= (*tvDom
)->getParent();
356 static void data_handler( void *userData
,
360 TVDom
**tvDom
= static_cast< TVDom
** >( userData
);
361 if( (*tvDom
)->isLeaf() )
362 (*tvDom
)->setTitle( s
,len
);
367 TVChildTarget::TVChildTarget( const ConfigData
& configData
,TVDom
* tvDom
)
369 Elements
.resize( tvDom
->children
.size() );
370 for( size_t i
= 0; i
< Elements
.size(); ++i
)
371 Elements
[i
] = new TVRead( configData
,tvDom
->children
[i
].get() );
374 TVChildTarget::TVChildTarget( const Reference
< XComponentContext
>& xContext
)
376 ConfigData configData
= init( xContext
);
378 if( configData
.locale
.isEmpty() || configData
.system
.isEmpty() )
381 sal_uInt64 ret
,len
= 0;
382 int j
= configData
.vFileURL
.size();
385 TVDom
* pTVDom
= &tvDom
;
389 len
= configData
.vFileLen
[--j
];
390 std::unique_ptr
<char[]> s(new char[ int(len
) ]); // the buffer to hold the installed files
391 osl::File
aFile( configData
.vFileURL
[j
] );
392 (void)aFile
.open( osl_File_OpenFlag_Read
);
393 aFile
.read( s
.get(),len
,ret
);
396 XML_Parser parser
= XML_ParserCreate( nullptr );
397 XML_SetElementHandler( parser
,
400 XML_SetCharacterDataHandler( parser
,
402 XML_SetUserData( parser
,&pTVDom
); // does not return this
404 XML_Status
const parsed
= XML_Parse(parser
, s
.get(), int(len
), j
==0);
405 SAL_WARN_IF(XML_STATUS_ERROR
== parsed
, "xmlhelp",
406 "TVChildTarget::TVChildTarget(): Tree file parsing failed");
408 XML_ParserFree( parser
);
412 // now TVDom holds the relevant information
414 Elements
.resize( tvDom
.children
.size() );
415 for( size_t i
= 0; i
< Elements
.size(); ++i
)
416 Elements
[i
] = new TVRead( configData
,tvDom
.children
[i
].get() );
419 TVChildTarget::~TVChildTarget()
423 void TVChildTarget::Check(TVDom
* tvDom
)
425 if (tvDom
->children
.empty())
433 while((i
<tvDom
->children
.size()-1) && (!h
))
435 if (((tvDom
->children
[i
])->application
== (tvDom
->children
[tvDom
->children
.size()-1])->application
) &&
436 ((tvDom
->children
[i
])->id
== (tvDom
->children
[tvDom
->children
.size()-1])->id
))
438 TVDom
* p
= tvDom
->children
.back().get();
440 for(auto & k
: p
->children
)
442 std::unique_ptr
<TVDom
> tmp(SearchAndInsert(std::move(k
), tvDom
->children
[i
].get()));
445 tvDom
->children
[i
]->newChild(std::move(tmp
));
449 tvDom
->children
.pop_back();
456 std::unique_ptr
<TVDom
>
457 TVChildTarget::SearchAndInsert(std::unique_ptr
<TVDom
> p
, TVDom
* tvDom
)
459 if (p
->isLeaf()) return p
;
464 std::vector
< std::unique_ptr
<TVDom
> >::iterator max_It
, i
;
465 max_It
= tvDom
->children
.begin();
468 sal_Int32 p_int
= p
->id
.toInt32();
470 for(i
= tvDom
->children
.begin(); i
!=tvDom
->children
.end(); ++i
)
471 if (!((*i
)->isLeaf()) &&
472 ((*i
)->id
.getLength() == p
->id
.getLength()) &&
473 (p
->id
.replaceAt((*i
)->parent
->id
.getLength(), p
->id
.getLength()-(*i
)->parent
->id
.getLength(), "") == (*i
)->parent
->id
)) //prefix check
476 c_int
= (*i
)->id
.toInt32();
480 (*(tvDom
->children
.insert(i
+1, std::move(p
))))->parent
= tvDom
;
483 else if(c_int
>max
&& c_int
< p_int
)
491 (*(tvDom
->children
.insert(max_It
, std::move(p
))))->parent
= tvDom
;
496 for (auto& child
: tvDom
->children
)
498 p
= SearchAndInsert(std::move(p
), child
.get());
507 TVChildTarget::getByName( const OUString
& aName
)
509 OUString
num( aName
.copy( 2, aName
.getLength()-4 ) );
510 sal_Int32 idx
= num
.toInt32() - 1;
511 if( idx
< 0 || Elements
.size() <= o3tl::make_unsigned( idx
) )
512 throw NoSuchElementException();
514 cppu::OWeakObject
* p
= Elements
[idx
].get();
515 return Any( Reference
< XInterface
>( p
) );
518 Sequence
< OUString
> SAL_CALL
519 TVChildTarget::getElementNames( )
521 Sequence
< OUString
> seq( Elements
.size() );
522 for( size_t i
= 0; i
< Elements
.size(); ++i
)
523 seq
[i
] = OUString::number( 1+i
);
529 TVChildTarget::hasByName( const OUString
& aName
)
531 OUString
num( aName
.copy( 2, aName
.getLength()-4 ) );
532 sal_Int32 idx
= num
.toInt32() - 1;
533 if( idx
< 0 || Elements
.size() <= o3tl::make_unsigned( idx
) )
539 // XHierarchicalNameAccess
542 TVChildTarget::getByHierarchicalName( const OUString
& aName
)
546 if( ( idx
= aName
.indexOf( '/' ) ) != -1 )
548 OUString
num( aName
.copy( 2, idx
-4 ) );
549 sal_Int32 pref
= num
.toInt32() - 1;
551 if( pref
< 0 || Elements
.size() <= o3tl::make_unsigned( pref
) )
552 throw NoSuchElementException();
554 return Elements
[pref
]->getByHierarchicalName( aName
.copy( 1 + idx
) );
557 return getByName( aName
);
561 TVChildTarget::hasByHierarchicalName( const OUString
& aName
)
565 if( ( idx
= aName
.indexOf( '/' ) ) != -1 )
567 OUString
num( aName
.copy( 2, idx
-4 ) );
568 sal_Int32 pref
= num
.toInt32() - 1;
569 if( pref
< 0 || Elements
.size() <= o3tl::make_unsigned( pref
) )
572 return Elements
[pref
]->hasByHierarchicalName( aName
.copy( 1 + idx
) );
575 return hasByName( aName
);
578 ConfigData
TVChildTarget::init( const Reference
< XComponentContext
>& xContext
)
580 ConfigData configData
;
581 Reference
< XMultiServiceFactory
> sProvider( getConfiguration(xContext
) );
583 /**********************************************************************/
584 /* reading Office.Common */
585 /**********************************************************************/
587 Reference
< XHierarchicalNameAccess
> xHierAccess( getHierAccess( sProvider
,
588 "org.openoffice.Office.Common" ) );
589 OUString
system( getKey( xHierAccess
,"Help/System" ) );
590 bool showBasic( getBooleanKey(xHierAccess
,"Help/ShowBasic") );
591 OUString
instPath( getKey( xHierAccess
,"Path/Current/Help" ) );
592 if( instPath
.isEmpty() )
593 // try to determine path from default
594 instPath
= "$(instpath)/help";
596 // replace anything like $(instpath);
599 /**********************************************************************/
601 /**********************************************************************/
603 xHierAccess
= getHierAccess( sProvider
,
604 "org.openoffice.Setup" );
606 OUString
setupversion( getKey( xHierAccess
,"Product/ooSetupVersion" ) );
607 OUString setupextension
;
611 Reference
< lang::XMultiServiceFactory
> xConfigProvider
= theDefaultProvider::get( xContext
);
613 uno::Sequence
<uno::Any
> lParams(comphelper::InitAnyPropertySequence(
615 {"nodepath", uno::Any(OUString("/org.openoffice.Setup/Product"))}
619 uno::Reference
< uno::XInterface
> xCFG( xConfigProvider
->createInstanceWithArguments(
620 "com.sun.star.configuration.ConfigurationAccess",
623 uno::Reference
< container::XNameAccess
> xDirectAccess(xCFG
, uno::UNO_QUERY
);
624 uno::Any aRet
= xDirectAccess
->getByName("ooSetupExtension");
626 aRet
>>= setupextension
;
628 catch ( uno::Exception
& )
632 OUString
productVersion( setupversion
+ " " + setupextension
);
633 OUString
locale( getKey( xHierAccess
,"L10N/ooLocale" ) );
635 // Determine fileurl from url and locale
637 osl::FileBase::RC errFile
= osl::FileBase::getFileURLFromSystemPath( instPath
,url
);
638 if( errFile
!= osl::FileBase::E_None
) return configData
;
639 if( !url
.endsWith("/") )
643 osl::DirectoryItem aDirItem
;
644 if( osl::FileBase::E_None
== osl::DirectoryItem::get( url
+ locale
,aDirItem
) )
646 else if( ( ( idx
= locale
.indexOf( '-' ) ) != -1 ||
647 ( idx
= locale
.indexOf( '_' ) ) != -1 ) &&
648 osl::FileBase::E_None
== osl::DirectoryItem::get( url
+ locale
.subView( 0,idx
),
650 ret
= locale
.copy( 0,idx
);
658 // first of all, try do determine whether there are any *.tree files present
660 // Start with extensions to set them at the end of the list
661 TreeFileIterator
aTreeIt( locale
);
666 aTreeFile
= aTreeIt
.nextTreeFile( nFileSize
);
667 if( aTreeFile
.isEmpty() )
669 configData
.vFileLen
.push_back( nFileSize
);
670 configData
.vFileURL
.push_back( aTreeFile
);
673 osl::Directory
aDirectory( url
);
674 osl::FileStatus
aFileStatus(
675 osl_FileStatus_Mask_FileName
| osl_FileStatus_Mask_FileURL
);
676 if( osl::Directory::E_None
== aDirectory
.open() )
678 OUString aFileUrl
, aFileName
;
679 while( aDirectory
.getNextItem( aDirItem
) == osl::FileBase::E_None
&&
680 aDirItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
&&
681 aFileStatus
.isValid( osl_FileStatus_Mask_FileURL
) &&
682 aFileStatus
.isValid( osl_FileStatus_Mask_FileName
) )
684 aFileUrl
= aFileStatus
.getFileURL();
685 aFileName
= aFileStatus
.getFileName();
686 int idx_
= aFileName
.lastIndexOf( '.' );
690 const sal_Unicode
* str
= aFileName
.getStr();
692 if( aFileName
.getLength() == idx_
+ 5 &&
693 ( str
[idx_
+ 1] == 't' || str
[idx_
+ 1] == 'T' ) &&
694 ( str
[idx_
+ 2] == 'r' || str
[idx_
+ 2] == 'R' ) &&
695 ( str
[idx_
+ 3] == 'e' || str
[idx_
+ 3] == 'E' ) &&
696 ( str
[idx_
+ 4] == 'e' || str
[idx_
+ 4] == 'E' ) )
698 OUString baseName
= aFileName
.copy(0,idx_
).toAsciiLowerCase();
699 if(! showBasic
&& baseName
== "sbasic" )
701 osl::File
aFile( aFileUrl
);
702 if( osl::FileBase::E_None
== aFile
.open( osl_File_OpenFlag_Read
) )
704 // use the file size, not aFileStatus size, in case the
705 // tree file is a symlink
707 aFile
.getSize( nSize
);
708 configData
.vFileLen
.push_back( nSize
);
709 configData
.vFileURL
.push_back( aFileUrl
);
717 configData
.m_vAdd
[0] = 12;
718 configData
.m_vAdd
[1] = 15;
719 configData
.m_vAdd
[2] = 11;
720 configData
.m_vAdd
[3] = 14;
721 configData
.m_vAdd
[4] = 12;
722 configData
.m_vReplacement
[0] = utl::ConfigManager::getProductName();
723 configData
.m_vReplacement
[1] = productVersion
;
724 // m_vReplacement[2...4] (vendorName/-Version/-Short) are empty strings
726 configData
.system
= system
;
727 configData
.locale
= locale
;
728 configData
.appendix
=
738 Reference
< XMultiServiceFactory
>
739 TVChildTarget::getConfiguration(const Reference
< XComponentContext
>& rxContext
)
741 Reference
< XMultiServiceFactory
> xProvider
;
746 xProvider
= theDefaultProvider::get( rxContext
);
748 catch( const css::uno::Exception
& )
750 OSL_ENSURE( xProvider
.is(),"can not instantiate configuration" );
757 Reference
< XHierarchicalNameAccess
>
758 TVChildTarget::getHierAccess( const Reference
< XMultiServiceFactory
>& sProvider
,
761 Reference
< XHierarchicalNameAccess
> xHierAccess
;
765 Sequence
< Any
> seq(1);
766 seq
[0] <<= OUString::createFromAscii( file
);
771 Reference
< XHierarchicalNameAccess
>
772 ( sProvider
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", seq
),
775 catch( const css::uno::Exception
& )
784 TVChildTarget::getKey( const Reference
< XHierarchicalNameAccess
>& xHierAccess
,
788 if( xHierAccess
.is() )
794 xHierAccess
->getByHierarchicalName( OUString::createFromAscii( key
) );
796 catch( const css::container::NoSuchElementException
& )
805 TVChildTarget::getBooleanKey(const Reference
<
806 XHierarchicalNameAccess
>& xHierAccess
,
810 if( xHierAccess
.is() )
816 xHierAccess
->getByHierarchicalName(
817 OUString::createFromAscii(key
));
819 catch( const css::container::NoSuchElementException
& )
827 void TVChildTarget::subst( OUString
& instpath
)
829 SvtPathOptions aOptions
;
830 instpath
= aOptions
.SubstituteVariable( instpath
);
834 const char aHelpMediaType
[] = "application/vnd.sun.star.help";
836 TreeFileIterator::TreeFileIterator( const OUString
& aLanguage
)
837 : m_eState( IteratorState::UserExtensions
)
838 , m_aLanguage( aLanguage
)
840 m_xContext
= ::comphelper::getProcessComponentContext();
841 if( !m_xContext
.is() )
843 throw RuntimeException( "TreeFileIterator::TreeFileIterator(), no XComponentContext" );
846 m_xSFA
= ucb::SimpleFileAccess::create(m_xContext
);
848 m_bUserPackagesLoaded
= false;
849 m_bSharedPackagesLoaded
= false;
850 m_bBundledPackagesLoaded
= false;
852 m_iSharedPackage
= 0;
853 m_iBundledPackage
= 0;
856 Reference
< deployment::XPackage
> TreeFileIterator::implGetHelpPackageFromPackage
857 ( const Reference
< deployment::XPackage
>& xPackage
, Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
859 o_xParentPackageBundle
.clear();
861 Reference
< deployment::XPackage
> xHelpPackage
;
865 // Check if parent package is registered
866 beans::Optional
< beans::Ambiguous
<sal_Bool
> > option( xPackage
->isRegistered
867 ( Reference
<task::XAbortChannel
>(), Reference
<ucb::XCommandEnvironment
>() ) );
868 bool bRegistered
= false;
869 if( option
.IsPresent
)
871 beans::Ambiguous
<sal_Bool
> const & reg
= option
.Value
;
872 if( !reg
.IsAmbiguous
&& reg
.Value
)
878 if( xPackage
->isBundle() )
880 Sequence
< Reference
< deployment::XPackage
> > aPkgSeq
= xPackage
->getBundle
881 ( Reference
<task::XAbortChannel
>(), Reference
<ucb::XCommandEnvironment
>() );
882 auto pSubPkg
= std::find_if(aPkgSeq
.begin(), aPkgSeq
.end(),
883 [](const Reference
< deployment::XPackage
>& xSubPkg
) {
884 const Reference
< deployment::XPackageTypeInfo
> xPackageTypeInfo
= xSubPkg
->getPackageType();
885 OUString aMediaType
= xPackageTypeInfo
->getMediaType();
886 return aMediaType
== aHelpMediaType
;
888 if (pSubPkg
!= aPkgSeq
.end())
890 xHelpPackage
= *pSubPkg
;
891 o_xParentPackageBundle
= xPackage
;
896 const Reference
< deployment::XPackageTypeInfo
> xPackageTypeInfo
= xPackage
->getPackageType();
897 OUString aMediaType
= xPackageTypeInfo
->getMediaType();
898 if( aMediaType
== aHelpMediaType
)
899 xHelpPackage
= xPackage
;
905 Reference
< deployment::XPackage
> TreeFileIterator::implGetNextUserHelpPackage
906 ( Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
908 Reference
< deployment::XPackage
> xHelpPackage
;
910 if( !m_bUserPackagesLoaded
)
912 Reference
< XPackageManager
> xUserManager
=
913 thePackageManagerFactory::get( m_xContext
)->getPackageManager("user");
914 m_aUserPackagesSeq
= xUserManager
->getDeployedPackages
915 ( Reference
< task::XAbortChannel
>(), Reference
< ucb::XCommandEnvironment
>() );
917 m_bUserPackagesLoaded
= true;
920 if( m_iUserPackage
== m_aUserPackagesSeq
.getLength() )
922 m_eState
= IteratorState::SharedExtensions
; // Later: SHARED_MODULE
926 const Reference
< deployment::XPackage
>* pUserPackages
= m_aUserPackagesSeq
.getConstArray();
927 Reference
< deployment::XPackage
> xPackage
= pUserPackages
[ m_iUserPackage
++ ];
928 OSL_ENSURE( xPackage
.is(), "TreeFileIterator::implGetNextUserHelpPackage(): Invalid package" );
929 xHelpPackage
= implGetHelpPackageFromPackage( xPackage
, o_xParentPackageBundle
);
935 Reference
< deployment::XPackage
> TreeFileIterator::implGetNextSharedHelpPackage
936 ( Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
938 Reference
< deployment::XPackage
> xHelpPackage
;
940 if( !m_bSharedPackagesLoaded
)
942 Reference
< XPackageManager
> xSharedManager
=
943 thePackageManagerFactory::get( m_xContext
)->getPackageManager("shared");
944 m_aSharedPackagesSeq
= xSharedManager
->getDeployedPackages
945 ( Reference
< task::XAbortChannel
>(), Reference
< ucb::XCommandEnvironment
>() );
947 m_bSharedPackagesLoaded
= true;
950 if( m_iSharedPackage
== m_aSharedPackagesSeq
.getLength() )
952 m_eState
= IteratorState::BundledExtensions
;
956 const Reference
< deployment::XPackage
>* pSharedPackages
= m_aSharedPackagesSeq
.getConstArray();
957 Reference
< deployment::XPackage
> xPackage
= pSharedPackages
[ m_iSharedPackage
++ ];
958 OSL_ENSURE( xPackage
.is(), "TreeFileIterator::implGetNextSharedHelpPackage(): Invalid package" );
959 xHelpPackage
= implGetHelpPackageFromPackage( xPackage
, o_xParentPackageBundle
);
965 Reference
< deployment::XPackage
> TreeFileIterator::implGetNextBundledHelpPackage
966 ( Reference
< deployment::XPackage
>& o_xParentPackageBundle
)
968 Reference
< deployment::XPackage
> xHelpPackage
;
970 if( !m_bBundledPackagesLoaded
)
972 Reference
< XPackageManager
> xBundledManager
=
973 thePackageManagerFactory::get( m_xContext
)->getPackageManager("bundled");
974 m_aBundledPackagesSeq
= xBundledManager
->getDeployedPackages
975 ( Reference
< task::XAbortChannel
>(), Reference
< ucb::XCommandEnvironment
>() );
977 m_bBundledPackagesLoaded
= true;
980 if( m_iBundledPackage
== m_aBundledPackagesSeq
.getLength() )
982 m_eState
= IteratorState::EndReached
;
986 const Reference
< deployment::XPackage
>* pBundledPackages
= m_aBundledPackagesSeq
.getConstArray();
987 Reference
< deployment::XPackage
> xPackage
= pBundledPackages
[ m_iBundledPackage
++ ];
988 OSL_ENSURE( xPackage
.is(), "TreeFileIterator::implGetNextBundledHelpPackage(): Invalid package" );
989 xHelpPackage
= implGetHelpPackageFromPackage( xPackage
, o_xParentPackageBundle
);
995 static bool isLetter( sal_Unicode c
)
997 return rtl::isAsciiAlpha(c
);
1000 void TreeFileIterator::implGetLanguageVectorFromPackage( ::std::vector
< OUString
> &rv
,
1001 const css::uno::Reference
< css::deployment::XPackage
>& xPackage
)
1004 OUString aExtensionPath
= xPackage
->getURL();
1005 const Sequence
< OUString
> aEntrySeq
= m_xSFA
->getFolderContents( aExtensionPath
, true );
1007 for( const OUString
& aEntry
: aEntrySeq
)
1009 if( m_xSFA
->isFolder( aEntry
) )
1011 sal_Int32 nLastSlash
= aEntry
.lastIndexOf( '/' );
1012 if( nLastSlash
!= -1 )
1014 OUString aPureEntry
= aEntry
.copy( nLastSlash
+ 1 );
1016 // Check language scheme
1017 int nLen
= aPureEntry
.getLength();
1018 const sal_Unicode
* pc
= aPureEntry
.getStr();
1019 bool bStartCanBeLanguage
= ( nLen
>= 2 && isLetter( pc
[0] ) && isLetter( pc
[1] ) );
1020 bool bIsLanguage
= bStartCanBeLanguage
&&
1021 ( nLen
== 2 || (nLen
== 5 && pc
[2] == '-' && isLetter( pc
[3] ) && isLetter( pc
[4] )) );
1023 rv
.push_back( aPureEntry
);
1030 OUString
TreeFileIterator::nextTreeFile( sal_Int32
& rnFileSize
)
1034 while( aRetFile
.isEmpty() && m_eState
!= IteratorState::EndReached
)
1038 case IteratorState::UserExtensions
:
1040 Reference
< deployment::XPackage
> xParentPackageBundle
;
1041 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextUserHelpPackage( xParentPackageBundle
);
1042 if( !xHelpPackage
.is() )
1045 aRetFile
= implGetTreeFileFromPackage( rnFileSize
, xHelpPackage
);
1049 case IteratorState::SharedExtensions
:
1051 Reference
< deployment::XPackage
> xParentPackageBundle
;
1052 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextSharedHelpPackage( xParentPackageBundle
);
1053 if( !xHelpPackage
.is() )
1056 aRetFile
= implGetTreeFileFromPackage( rnFileSize
, xHelpPackage
);
1059 case IteratorState::BundledExtensions
:
1061 Reference
< deployment::XPackage
> xParentPackageBundle
;
1062 Reference
< deployment::XPackage
> xHelpPackage
= implGetNextBundledHelpPackage( xParentPackageBundle
);
1063 if( !xHelpPackage
.is() )
1066 aRetFile
= implGetTreeFileFromPackage( rnFileSize
, xHelpPackage
);
1070 case IteratorState::EndReached
:
1071 OSL_FAIL( "DataBaseIterator::nextTreeFile(): Invalid case IteratorState::EndReached" );
1079 OUString
TreeFileIterator::expandURL( const OUString
& aURL
)
1081 static Reference
< util::XMacroExpander
> xMacroExpander
;
1082 static Reference
< uri::XUriReferenceFactory
> xFac
;
1084 osl::MutexGuard
aGuard( m_aMutex
);
1086 if( !xMacroExpander
.is() || !xFac
.is() )
1088 xFac
= uri::UriReferenceFactory::create( m_xContext
);
1090 xMacroExpander
= util::theMacroExpander::get(m_xContext
);
1093 OUString aRetURL
= aURL
;
1094 Reference
< uri::XUriReference
> uriRef
;
1097 uriRef
= xFac
->parse( aRetURL
);
1100 Reference
< uri::XVndSunStarExpandUrl
> sxUri( uriRef
, UNO_QUERY
);
1104 aRetURL
= sxUri
->expand( xMacroExpander
);
1110 OUString
TreeFileIterator::implGetTreeFileFromPackage
1111 ( sal_Int32
& rnFileSize
, const Reference
< deployment::XPackage
>& xPackage
)
1114 OUString aLanguage
= m_aLanguage
;
1115 for( sal_Int32 iPass
= 0 ; iPass
< 2 ; ++iPass
)
1117 aRetFile
= expandURL( xPackage
->getURL() + "/" + aLanguage
+ "/help.tree" );
1120 if( m_xSFA
->exists( aRetFile
) )
1123 ::std::vector
< OUString
> av
;
1124 implGetLanguageVectorFromPackage( av
, xPackage
);
1125 ::std::vector
< OUString
>::const_iterator pFound
= LanguageTag::getFallback( av
, m_aLanguage
);
1126 if( pFound
!= av
.end() )
1127 aLanguage
= *pFound
;
1132 if( m_xSFA
->exists( aRetFile
) )
1133 rnFileSize
= m_xSFA
->getSize( aRetFile
);
1140 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */