diff options
Diffstat (limited to 'sfx2/source/doc/doctemplates.cxx')
-rw-r--r-- | sfx2/source/doc/doctemplates.cxx | 2898 |
1 files changed, 2898 insertions, 0 deletions
diff --git a/sfx2/source/doc/doctemplates.cxx b/sfx2/source/doc/doctemplates.cxx new file mode 100644 index 000000000000..b921f2d97f1f --- /dev/null +++ b/sfx2/source/doc/doctemplates.cxx @@ -0,0 +1,2898 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sfx2.hxx" + +#include "doctemplates.hxx" +#include <vos/mutex.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#ifndef _SV_RESARY_HXX +#include <tools/resary.hxx> +#endif +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <unotools/pathoptions.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/StringPair.hpp> +#include <com/sun/star/container/XContainerQuery.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> +#include <com/sun/star/document/XStandaloneDocumentInfo.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/ucb/NameClashException.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/frame/XModuleManager.hpp> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/util/XOfficeInstallationDirectories.hpp> + +#include <svtools/templatefoldercache.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/ucbhelper.hxx> + +#include "sfxresid.hxx" +#include "sfxurlrelocator.hxx" +#include "doctemplateslocal.hxx" +#include <sfx2/docfac.hxx> +#include <sfx2/docfile.hxx> +#include "doc.hrc" + +//----------------------------------------------------------------------------- + +//============================================================================= + +#define TEMPLATE_SERVICE_NAME "com.sun.star.frame.DocumentTemplates" +#define TEMPLATE_IMPLEMENTATION_NAME "com.sun.star.comp.sfx2.DocumentTemplates" + +#define SERVICENAME_TYPEDETECTION "com.sun.star.document.TypeDetection" +#define SERVICENAME_DOCINFO "com.sun.star.document.StandaloneDocumentInfo" + +#define TEMPLATE_ROOT_URL "vnd.sun.star.hier:/templates" +#define TITLE "Title" +#define IS_FOLDER "IsFolder" +#define IS_DOCUMENT "IsDocument" +#define TARGET_URL "TargetURL" +#define TEMPLATE_VERSION "TemplateComponentVersion" +#define TEMPLATE_VERSION_VALUE "2" +#define TYPE_FOLDER "application/vnd.sun.star.hier-folder" +#define TYPE_LINK "application/vnd.sun.star.hier-link" +#define TYPE_FSYS_FOLDER "application/vnd.sun.staroffice.fsys-folder" +#define TYPE_FSYS_FILE "application/vnd.sun.staroffice.fsys-file" + +#define PROPERTY_DIRLIST "DirectoryList" +#define PROPERTY_NEEDSUPDATE "NeedsUpdate" +#define PROPERTY_TYPE "TypeDescription" + +#define TARGET_DIR_URL "TargetDirURL" +#define COMMAND_DELETE "delete" +#define COMMAND_TRANSFER "transfer" + +#define STANDARD_FOLDER "standard" + +#define C_DELIM ';' + +//============================================================================= + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; + +using namespace ::rtl; +using namespace ::ucbhelper; +using namespace ::comphelper; + +//============================================================================= + +class WaitWindow_Impl : public WorkWindow +{ + Rectangle _aRect; + USHORT _nTextStyle; + String _aText; + + public: + WaitWindow_Impl(); + ~WaitWindow_Impl(); + virtual void Paint( const Rectangle& rRect ); +}; + +#define X_OFFSET 15 +#define Y_OFFSET 15 + +//============================================================================= + +struct NamePair_Impl +{ + OUString maShortName; + OUString maLongName; +}; + +DECLARE_LIST( NameList_Impl, NamePair_Impl* ) + +class Updater_Impl; +class GroupList_Impl; +class DocTemplates_EntryData_Impl; +class GroupData_Impl; + +//============================================================================= +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/ucb/XProgressHandler.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> + +class TplTaskEnvironment : public ::cppu::WeakImplHelper1< ucb::XCommandEnvironment > +{ + uno::Reference< task::XInteractionHandler > m_xInteractionHandler; + uno::Reference< ucb::XProgressHandler > m_xProgressHandler; + +public: + TplTaskEnvironment( const uno::Reference< task::XInteractionHandler>& rxInteractionHandler ) + : m_xInteractionHandler( rxInteractionHandler ) + {} + + virtual uno::Reference<task::XInteractionHandler> SAL_CALL getInteractionHandler() throw (uno::RuntimeException) + { return m_xInteractionHandler; } + + virtual uno::Reference<ucb::XProgressHandler> SAL_CALL getProgressHandler() throw (uno::RuntimeException) + { return m_xProgressHandler; } +}; + +class SfxDocTplService_Impl +{ + uno::Reference< XMultiServiceFactory > mxFactory; + uno::Reference< XCommandEnvironment > maCmdEnv; + uno::Reference< XStandaloneDocumentInfo > mxInfo; + uno::Reference< XTypeDetection > mxType; + + ::osl::Mutex maMutex; + Sequence< OUString > maTemplateDirs; + OUString maRootURL; + NameList_Impl maNames; + Locale maLocale; + Content maRootContent; + Updater_Impl* mpUpdater; + sal_Bool mbIsInitialized : 1; + sal_Bool mbLocaleSet : 1; + + SfxURLRelocator_Impl maRelocator; + + void init_Impl(); + void getDefaultLocale(); + void getDirList(); + void readFolderList(); + sal_Bool needsUpdate(); + OUString getLongName( const OUString& rShortName ); + sal_Bool setTitleForURL( const OUString& rURL, const OUString& aTitle ); + sal_Bool getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, sal_Bool& bDocHasTitle ); + + sal_Bool addEntry( Content& rParentFolder, + const OUString& rTitle, + const OUString& rTargetURL, + const OUString& rType ); + + sal_Bool createFolder( const OUString& rNewFolderURL, + sal_Bool bCreateParent, + sal_Bool bFsysFolder, + Content &rNewFolder ); + + sal_Bool CreateNewUniqueFolderWithPrefix( const ::rtl::OUString& aPath, + const ::rtl::OUString& aPrefix, + ::rtl::OUString& aNewFolderName, + ::rtl::OUString& aNewFolderURL, + Content& aNewFolder ); + ::rtl::OUString CreateNewUniqueFileWithPrefix( const ::rtl::OUString& aPath, + const ::rtl::OUString& aPrefix, + const ::rtl::OUString& aExt ); + + uno::Sequence< beans::StringPair > ReadUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath ); + sal_Bool UpdateUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aGroupName, + const ::rtl::OUString& aNewFolderName ); + sal_Bool ReplaceUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aFsysGroupName, + const ::rtl::OUString& aOldGroupName, + const ::rtl::OUString& aNewGroupName ); + sal_Bool RemoveUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aGroupName ); + sal_Bool WriteUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const uno::Sequence< beans::StringPair >& aUINames ); + + ::rtl::OUString CreateNewGroupFsys( const ::rtl::OUString& rGroupName, Content& aGroup ); + + sal_Bool removeContent( Content& rContent ); + sal_Bool removeContent( const OUString& rContentURL ); + + sal_Bool setProperty( Content& rContent, + const OUString& rPropName, + const Any& rPropValue ); + sal_Bool getProperty( Content& rContent, + const OUString& rPropName, + Any& rPropValue ); + + void createFromContent( GroupList_Impl& rList, + Content &rContent, + sal_Bool bHierarchy, + sal_Bool bWriteableContent = sal_False ); + void addHierGroup( GroupList_Impl& rList, + const OUString& rTitle, + const OUString& rOwnURL ); + void addFsysGroup( GroupList_Impl& rList, + const OUString& rTitle, + const OUString& rUITitle, + const OUString& rOwnURL, + sal_Bool bWriteableGroup = sal_False ); + void removeFromHierarchy( DocTemplates_EntryData_Impl *pData ); + void addToHierarchy( GroupData_Impl *pGroup, + DocTemplates_EntryData_Impl *pData ); + + void removeFromHierarchy( GroupData_Impl *pGroup ); + void addGroupToHierarchy( GroupData_Impl *pGroup ); + + void updateData( DocTemplates_EntryData_Impl *pData ); + +public: + SfxDocTplService_Impl( uno::Reference< XMultiServiceFactory > xFactory ); + ~SfxDocTplService_Impl(); + + sal_Bool init() { if ( !mbIsInitialized ) init_Impl(); return mbIsInitialized; } + Content getContent() { return maRootContent; } + + void setLocale( const Locale & rLocale ); + Locale getLocale(); + + sal_Bool storeTemplate( const OUString& rGroupName, + const OUString& rTemplateName, + const uno::Reference< XSTORABLE >& rStorable ); + + sal_Bool addTemplate( const OUString& rGroupName, + const OUString& rTemplateName, + const OUString& rSourceURL ); + sal_Bool removeTemplate( const OUString& rGroupName, + const OUString& rTemplateName ); + sal_Bool renameTemplate( const OUString& rGroupName, + const OUString& rOldName, + const OUString& rNewName ); + + sal_Bool addGroup( const OUString& rGroupName ); + sal_Bool removeGroup( const OUString& rGroupName ); + sal_Bool renameGroup( const OUString& rOldName, + const OUString& rNewName ); + + void update( sal_Bool bUpdateNow ); + void doUpdate(); + void finished() { mpUpdater = NULL; } +}; + +//============================================================================= + +class Updater_Impl : public ::vos::OThread +{ +private: + SfxDocTplService_Impl *mpDocTemplates; + +public: + Updater_Impl( SfxDocTplService_Impl* pTemplates ); + ~Updater_Impl(); + + virtual void SAL_CALL run(); + virtual void SAL_CALL onTerminated(); +}; + +//============================================================================= + +class DocTemplates_EntryData_Impl +{ + OUString maTitle; + OUString maType; + OUString maTargetURL; + OUString maHierarchyURL; + + sal_Bool mbInHierarchy : 1; + sal_Bool mbInUse : 1; + sal_Bool mbUpdateType : 1; + sal_Bool mbUpdateLink : 1; + +public: + DocTemplates_EntryData_Impl( const OUString& rTitle ); + + void setInUse() { mbInUse = sal_True; } + void setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; } + void setUpdateLink( sal_Bool bUpdateLink ) { mbUpdateLink = bUpdateLink; } + void setUpdateType( sal_Bool bUpdateType ) { mbUpdateType = bUpdateType; } + + sal_Bool getInUse() const { return mbInUse; } + sal_Bool getInHierarchy() const { return mbInHierarchy; } + sal_Bool getUpdateLink() const { return mbUpdateLink; } + sal_Bool getUpdateType() const { return mbUpdateType; } + + const OUString& getHierarchyURL() const { return maHierarchyURL; } + const OUString& getTargetURL() const { return maTargetURL; } + const OUString& getTitle() const { return maTitle; } + const OUString& getType() const { return maType; } + + void setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; } + void setTargetURL( const OUString& rURL ) { maTargetURL = rURL; } + void setType( const OUString& rType ) { maType = rType; } +}; + +//============================================================================= + +class GroupData_Impl +{ + DECLARE_LIST( EntryList_Impl, DocTemplates_EntryData_Impl* ) + EntryList_Impl maEntries; + OUString maTitle; + OUString maHierarchyURL; + OUString maTargetURL; + sal_Bool mbInUse : 1; + sal_Bool mbInHierarchy : 1; + +public: + GroupData_Impl( const OUString& rTitle ); + ~GroupData_Impl(); + + void setInUse() { mbInUse = sal_True; } + void setHierarchy( sal_Bool bInHierarchy ) { mbInHierarchy = bInHierarchy; } + void setHierarchyURL( const OUString& rURL ) { maHierarchyURL = rURL; } + void setTargetURL( const OUString& rURL ) { maTargetURL = rURL; } + + sal_Bool getInUse() { return mbInUse; } + sal_Bool getInHierarchy() { return mbInHierarchy; } + const OUString& getHierarchyURL() const { return maHierarchyURL; } + const OUString& getTargetURL() const { return maTargetURL; } + const OUString& getTitle() const { return maTitle; } + + DocTemplates_EntryData_Impl* addEntry( const OUString& rTitle, + const OUString& rTargetURL, + const OUString& rType, + const OUString& rHierURL ); + ULONG count() { return maEntries.Count(); } + DocTemplates_EntryData_Impl* getEntry( ULONG nPos ) { return maEntries.GetObject( nPos ); } +}; + +DECLARE_LIST( GroupList_Impl, GroupData_Impl* ) + +//============================================================================= +//============================================================================= +//============================================================================= + +//----------------------------------------------------------------------------- +// private SfxDocTplService_Impl +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::init_Impl() +{ + uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + if ( xFactory.is() ) + { + uno::Reference < task::XInteractionHandler > xInteractionHandler( xFactory->createInstance( DEFINE_CONST_UNICODE("com.sun.star.task.InteractionHandler") ), uno::UNO_QUERY ); + maCmdEnv = new TplTaskEnvironment( xInteractionHandler ); + } + + ::osl::ClearableMutexGuard aGuard( maMutex ); + sal_Bool bIsInitialized = sal_False; + sal_Bool bNeedsUpdate = sal_False; + + if ( !mbLocaleSet ) + getDefaultLocale(); + + // convert locale to string + OUString aLang = maLocale.Language; + aLang += String( '-' ); + aLang += maLocale.Country; + + // set maRootContent to the root of the templates hierarchy. Create the + // entry if necessary + + maRootURL = OUString( RTL_CONSTASCII_USTRINGPARAM( TEMPLATE_ROOT_URL ) ); + maRootURL += String( '/' ); + maRootURL += aLang; + + ::rtl::OUString aTemplVersPropName( RTL_CONSTASCII_USTRINGPARAM( TEMPLATE_VERSION ) ); + ::rtl::OUString aTemplVers( RTL_CONSTASCII_USTRINGPARAM( TEMPLATE_VERSION_VALUE ) ); + if ( Content::create( maRootURL, maCmdEnv, maRootContent ) ) + { + uno::Any aValue; + ::rtl::OUString aPropValue; + if ( getProperty( maRootContent, aTemplVersPropName, aValue ) + && ( aValue >>= aPropValue ) + && aPropValue.equals( aTemplVers ) ) + { + bIsInitialized = sal_True; + } + else + removeContent( maRootContent ); + } + + if ( !bIsInitialized ) + { + if ( createFolder( maRootURL, sal_True, sal_False, maRootContent ) + && setProperty( maRootContent, aTemplVersPropName, uno::makeAny( aTemplVers ) ) ) + bIsInitialized = sal_True; + + bNeedsUpdate = sal_True; + } + + if ( bIsInitialized ) + { + OUString aService( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_DOCINFO ) ); + try { + mxInfo = uno::Reference< XStandaloneDocumentInfo > ( + mxFactory->createInstance( aService ), UNO_QUERY ); + } catch (uno::RuntimeException &) { + OSL_ENSURE(false, "SfxDocTplService_Impl::init_Impl: " + "cannot create DocumentProperties service"); + } + + aService = OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_TYPEDETECTION ) ); + mxType = uno::Reference< XTypeDetection > ( mxFactory->createInstance( aService ), UNO_QUERY ); + + getDirList(); + readFolderList(); + + if ( bNeedsUpdate ) + { + aGuard.clear(); + ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() ); + + WaitWindow_Impl* pWin = new WaitWindow_Impl(); + + aSolarGuard.clear(); + ::osl::ClearableMutexGuard anotherGuard( maMutex ); + + update( sal_True ); + + anotherGuard.clear(); + ::vos::OGuard aSecondSolarGuard( Application::GetSolarMutex() ); + + delete pWin; + } + else if ( needsUpdate() ) + // the UI should be shown only on the first update + update( sal_True ); + } + else + { + DBG_ERRORFILE( "init_Impl(): Could not create root" ); + } + + mbIsInitialized = bIsInitialized; +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::getDefaultLocale() +{ + if ( !mbLocaleSet ) + { + ::osl::MutexGuard aGuard( maMutex ); + if ( !mbLocaleSet ) + { + rtl::OUString aLocale; + utl::ConfigManager::GetDirectConfigProperty( utl::ConfigManager::LOCALE ) + >>= aLocale; + + if ( aLocale.getLength() > 0 ) + { + sal_Int32 nPos = aLocale.indexOf( sal_Unicode( '-' ) ); + if ( nPos != -1 ) + { + maLocale.Language = aLocale.copy( 0, nPos ); + nPos = aLocale.indexOf( sal_Unicode( '_' ), nPos + 1 ); + if ( nPos != -1 ) + { + maLocale.Country + = aLocale.copy( maLocale.Language.getLength() + 1, + nPos - maLocale.Language.getLength() - 1 ); + maLocale.Variant + = aLocale.copy( nPos + 1 ); + } + else + { + maLocale.Country + = aLocale.copy( maLocale.Language.getLength() + 1 ); + } + } + + } + + mbLocaleSet = sal_True; + } + } +} + +// ----------------------------------------------------------------------- +void SfxDocTplService_Impl::readFolderList() +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + ResStringArray aShortNames( SfxResId( TEMPLATE_SHORT_NAMES_ARY ) ); + ResStringArray aLongNames( SfxResId( TEMPLATE_LONG_NAMES_ARY ) ); + + NamePair_Impl* pPair; + + USHORT nCount = (USHORT)( Min( aShortNames.Count(), aLongNames.Count() ) ); + + for ( USHORT i=0; i<nCount; i++ ) + { + pPair = new NamePair_Impl; + pPair->maShortName = aShortNames.GetString( i ); + pPair->maLongName = aLongNames.GetString( i ); + + maNames.Insert( pPair, LIST_APPEND ); + } +} + +// ----------------------------------------------------------------------- +OUString SfxDocTplService_Impl::getLongName( const OUString& rShortName ) +{ + OUString aRet; + NamePair_Impl *pPair = maNames.First(); + + while ( pPair ) + { + if ( pPair->maShortName == rShortName ) + { + aRet = pPair->maLongName; + break; + } + else + pPair = maNames.Next(); + } + + if ( !aRet.getLength() ) + aRet = rShortName; + + return aRet; +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::getDirList() +{ + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_DIRLIST ) ); + Any aValue; + + // Get the template dir list + // TODO/LATER: let use service, register listener + INetURLObject aURL; + String aDirs = SvtPathOptions().GetTemplatePath(); + USHORT nCount = aDirs.GetTokenCount( C_DELIM ); + + maTemplateDirs = Sequence< OUString >( nCount ); + + for ( USHORT i=0; i<nCount; i++ ) + { + aURL.SetSmartProtocol( INET_PROT_FILE ); + aURL.SetURL( aDirs.GetToken( i, C_DELIM ) ); + maTemplateDirs[i] = aURL.GetMainURL( INetURLObject::NO_DECODE ); + } + + aValue <<= maTemplateDirs; + + // Store the template dir list + setProperty( maRootContent, aPropName, aValue ); +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::needsUpdate() +{ + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_NEEDSUPDATE ) ); + sal_Bool bHasProperty = sal_False; + sal_Bool bNeedsUpdate = sal_True; + Any aValue; + + // Get the template dir list + bHasProperty = getProperty( maRootContent, aPropName, aValue ); + + if ( bHasProperty ) + aValue >>= bNeedsUpdate; + + // the old template component also checks this state, but it is initialized from this component + // so if this componend was already updated the old component does not need such an update + ::svt::TemplateFolderCache aTempCache; + if ( !bNeedsUpdate ) + bNeedsUpdate = aTempCache.needsUpdate(); + + if ( bNeedsUpdate ) + aTempCache.storeState(); + + return bNeedsUpdate; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::setTitleForURL( const OUString& rURL, const OUString& aTitle ) +{ + sal_Bool bResult = sal_False; + if ( mxInfo.is() ) + { + try + { + mxInfo->loadFromURL( rURL ); + uno::Reference< XPropertySet > xPropSet( mxInfo, UNO_QUERY_THROW ); + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + xPropSet->setPropertyValue( aPropName, uno::makeAny( aTitle ) ); + mxInfo->storeIntoURL( rURL ); + bResult = sal_True; + } + catch ( Exception& ) + { + } + } + + return bResult; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::getTitleFromURL( const OUString& rURL, OUString& aTitle, OUString& aType, sal_Bool& bDocHasTitle ) +{ + bDocHasTitle = sal_False; + + if ( mxInfo.is() ) + { + try + { + mxInfo->loadFromURL( rURL ); + } + catch ( Exception& ) + { + // the document is not a StarOffice document + return sal_False; + } + + try + { + uno::Reference< XPropertySet > aPropSet( mxInfo, UNO_QUERY ); + if ( aPropSet.is() ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + Any aValue = aPropSet->getPropertyValue( aPropName ); + aValue >>= aTitle; + + aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( "MIMEType" ) ); + aValue = aPropSet->getPropertyValue( aPropName ); + aValue >>= aType; + } + } + catch ( UnknownPropertyException& ) {} + catch ( Exception& ) {} + } + + if ( ! aType.getLength() && mxType.is() ) + { + ::rtl::OUString aDocType = mxType->queryTypeByURL( rURL ); + if ( aDocType.getLength() ) + try + { + uno::Reference< container::XNameAccess > xTypeDetection( mxType, uno::UNO_QUERY_THROW ); + SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aDocType ) ); + aType = aTypeProps.getUnpackedValueOrDefault( + ::rtl::OUString::createFromAscii( "MediaType" ), + ::rtl::OUString() ); + } + catch( uno::Exception& ) + {} + } + + if ( ! aTitle.getLength() ) + { + INetURLObject aURL( rURL ); + aURL.CutExtension(); + aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ); + } + else + bDocHasTitle = sal_True; + + return sal_True; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::addEntry( Content& rParentFolder, + const OUString& rTitle, + const OUString& rTargetURL, + const OUString& rType ) +{ + sal_Bool bAddedEntry = sal_False; + + INetURLObject aLinkObj( rParentFolder.getURL() ); + aLinkObj.insertName( rTitle, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + OUString aLinkURL = aLinkObj.GetMainURL( INetURLObject::NO_DECODE ); + + Content aLink; + + if ( ! Content::create( aLinkURL, maCmdEnv, aLink ) ) + { + Sequence< OUString > aNames(3); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_FOLDER ) ); + aNames[2] = OUString( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + + Sequence< Any > aValues(3); + aValues[0] = makeAny( rTitle ); + aValues[1] = makeAny( sal_Bool( sal_False ) ); + aValues[2] = makeAny( rTargetURL ); + + OUString aType( RTL_CONSTASCII_USTRINGPARAM( TYPE_LINK ) ); + OUString aAdditionalProp( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_TYPE ) ); + + try + { + rParentFolder.insertNewContent( aType, aNames, aValues, aLink ); + setProperty( aLink, aAdditionalProp, makeAny( rType ) ); + bAddedEntry = sal_True; + } + catch( Exception& ) + {} + } + return bAddedEntry; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::createFolder( const OUString& rNewFolderURL, + sal_Bool bCreateParent, + sal_Bool bFsysFolder, + Content &rNewFolder ) +{ + Content aParent; + sal_Bool bCreatedFolder = sal_False; + INetURLObject aParentURL( rNewFolderURL ); + OUString aFolderName = aParentURL.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ); + + // compute the parent folder url from the new folder url + // and remove the final slash, because Content::create doesn't + // like it + aParentURL.removeSegment(); + if ( aParentURL.getSegmentCount() >= 1 ) + aParentURL.removeFinalSlash(); + + // if the parent exists, we can continue with the creation of the + // new folder, we have to create the parent otherwise ( as long as + // bCreateParent is set to true ) + if ( Content::create( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), maCmdEnv, aParent ) ) + { + try + { + Sequence< OUString > aNames(2); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_FOLDER ) ); + + Sequence< Any > aValues(2); + aValues[0] = makeAny( aFolderName ); + aValues[1] = makeAny( sal_Bool( sal_True ) ); + + OUString aType; + + if ( bFsysFolder ) + aType = OUString( RTL_CONSTASCII_USTRINGPARAM( TYPE_FSYS_FOLDER ) ); + else + aType = OUString( RTL_CONSTASCII_USTRINGPARAM( TYPE_FOLDER ) ); + + aParent.insertNewContent( aType, aNames, aValues, rNewFolder ); + bCreatedFolder = sal_True; + } + catch( RuntimeException& ) + { + DBG_ERRORFILE( "createFolder(): got runtime exception" ); + } + catch( Exception& ) + { + DBG_ERRORFILE( "createFolder(): Could not create new folder" ); + } + } + else if ( bCreateParent ) + { + // if the parent doesn't exists and bCreateParent is set to true, + // we try to create the parent and if this was successful, we + // try to create the new folder again ( but this time, we set + // bCreateParent to false to avoid endless recusions ) + if ( ( aParentURL.getSegmentCount() >= 1 ) && + createFolder( aParentURL.GetMainURL( INetURLObject::NO_DECODE ), bCreateParent, bFsysFolder, aParent ) ) + { + bCreatedFolder = createFolder( rNewFolderURL, sal_False, bFsysFolder, rNewFolder ); + } + } + + return bCreatedFolder; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::CreateNewUniqueFolderWithPrefix( const ::rtl::OUString& aPath, + const ::rtl::OUString& aPrefix, + ::rtl::OUString& aNewFolderName, + ::rtl::OUString& aNewFolderURL, + Content& aNewFolder ) +{ + sal_Bool bCreated = sal_False; + INetURLObject aDirPath( aPath ); + + Content aParent; + if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), maCmdEnv, aParent ) ) + { + for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ ) + { + ::rtl::OUString aTryName = aPrefix; + if ( nInd ) + aTryName += ::rtl::OUString::valueOf( nInd ); + + try + { + Sequence< OUString > aNames(2); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_FOLDER ) ); + + Sequence< Any > aValues(2); + aValues[0] = makeAny( aTryName ); + aValues[1] = makeAny( sal_Bool( sal_True ) ); + + OUString aType( RTL_CONSTASCII_USTRINGPARAM( TYPE_FSYS_FOLDER ) ); + + bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFolder ); + } + catch( ucb::NameClashException& ) + { + // if there is already an element, retry + } + catch( Exception& ) + { + INetURLObject aObjPath( aDirPath ); + aObjPath.insertName( aTryName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + // if there is already an element, retry + // if there was another error, do not try any more + if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) ) + break; + } + + if ( bCreated ) + { + aNewFolderName = aTryName; + aNewFolderURL = aNewFolder.get()->getIdentifier()->getContentIdentifier(); + break; + } + } + } + + return bCreated; +} + +// ----------------------------------------------------------------------- +::rtl::OUString SfxDocTplService_Impl::CreateNewUniqueFileWithPrefix( const ::rtl::OUString& aPath, + const ::rtl::OUString& aPrefix, + const ::rtl::OUString& aExt ) +{ + ::rtl::OUString aNewFileURL; + INetURLObject aDirPath( aPath ); + + Content aParent; + + uno::Reference< XCommandEnvironment > aQuietEnv; + if ( Content::create( aDirPath.GetMainURL( INetURLObject::NO_DECODE ), aQuietEnv, aParent ) ) + { + for ( sal_Int32 nInd = 0; nInd < 32000; nInd++ ) + { + Content aNewFile; + sal_Bool bCreated = sal_False; + ::rtl::OUString aTryName = aPrefix; + if ( nInd ) + aTryName += ::rtl::OUString::valueOf( nInd ); + if ( aExt.toChar() != '.' ) + aTryName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) ); + aTryName += aExt; + + try + { + Sequence< OUString > aNames(2); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + aNames[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( IS_DOCUMENT ) ); + + Sequence< Any > aValues(2); + aValues[0] = makeAny( aTryName ); + aValues[1] = makeAny( sal_Bool( sal_True ) ); + + OUString aType( RTL_CONSTASCII_USTRINGPARAM( TYPE_FSYS_FILE ) ); + + bCreated = aParent.insertNewContent( aType, aNames, aValues, aNewFile ); + } + catch( ucb::NameClashException& ) + { + // if there is already an element, retry + } + catch( Exception& ) + { + INetURLObject aObjPath( aPath ); + aObjPath.insertName( aTryName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + // if there is already an element, retry + // if there was another error, do not try any more + if ( !::utl::UCBContentHelper::Exists( aObjPath.GetMainURL( INetURLObject::NO_DECODE ) ) ) + break; + } + + if ( bCreated ) + { + aNewFileURL = aNewFile.get()->getIdentifier()->getContentIdentifier(); + break; + } + } + } + + return aNewFileURL; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::removeContent( Content& rContent ) +{ + sal_Bool bRemoved = sal_False; + try + { + OUString aCmd( RTL_CONSTASCII_USTRINGPARAM( COMMAND_DELETE ) ); + Any aArg = makeAny( sal_Bool( sal_True ) ); + + rContent.executeCommand( aCmd, aArg ); + bRemoved = sal_True; + } + catch ( RuntimeException& ) {} + catch ( Exception& ) {} + + return bRemoved; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::removeContent( const OUString& rContentURL ) +{ + Content aContent; + + if ( Content::create( rContentURL, maCmdEnv, aContent ) ) + return removeContent( aContent ); + else + return sal_False; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::setProperty( Content& rContent, + const OUString& rPropName, + const Any& rPropValue ) +{ + sal_Bool bPropertySet = sal_False; + + // Store the property + try + { + Any aPropValue( rPropValue ); + uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties(); + + // check, wether or not the property exists, create it, when not + if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) ) + { + uno::Reference< XPropertyContainer > xProperties( rContent.get(), UNO_QUERY ); + if ( xProperties.is() ) + { + try + { + xProperties->addProperty( rPropName, PropertyAttribute::MAYBEVOID, rPropValue ); + } + catch( PropertyExistException& ) {} + catch( IllegalTypeException& ) { DBG_ERRORFILE( "IllegalTypeException" ); } + catch( IllegalArgumentException& ) { DBG_ERRORFILE( "IllegalArgumentException" ); } + } + } + + // To ensure a reloctable office installation, the path to the + // office installtion directory must never be stored directly. + if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) ) + { + OUString aValue; + if ( rPropValue >>= aValue ) + { + maRelocator.makeRelocatableURL( aValue ); + aPropValue = makeAny( aValue ); + } + else + { + Sequence< OUString > aValues; + if ( rPropValue >>= aValues ) + { + for ( sal_Int32 n = 0; n < aValues.getLength(); n++ ) + { + maRelocator.makeRelocatableURL( aValues[ n ] ); + } + aPropValue = makeAny( aValues ); + } + else + { + OSL_ENSURE( false, "Unsupported property value type" ); + } + } + } + + // now set the property + + rContent.setPropertyValue( rPropName, aPropValue ); + bPropertySet = sal_True; + } + catch ( RuntimeException& ) {} + catch ( Exception& ) {} + + return bPropertySet; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::getProperty( Content& rContent, + const OUString& rPropName, + Any& rPropValue ) +{ + sal_Bool bGotProperty = sal_False; + + // Get the property + try + { + uno::Reference< XPropertySetInfo > aPropInfo = rContent.getProperties(); + + // check, wether or not the property exists + if ( !aPropInfo.is() || !aPropInfo->hasPropertyByName( rPropName ) ) + { + return sal_False; + } + + // now get the property + + rPropValue = rContent.getPropertyValue( rPropName ); + + // To ensure a reloctable office installation, the path to the + // office installtion directory must never be stored directly. + if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) ) + { + OUString aValue; + if ( rPropValue >>= aValue ) + { + maRelocator.makeAbsoluteURL( aValue ); + rPropValue = makeAny( aValue ); + } + else + { + Sequence< OUString > aValues; + if ( rPropValue >>= aValues ) + { + for ( sal_Int32 n = 0; n < aValues.getLength(); n++ ) + { + maRelocator.makeAbsoluteURL( aValues[ n ] ); + } + rPropValue = makeAny( aValues ); + } + else + { + OSL_ENSURE( false, "Unsupported property value type" ); + } + } + } + + bGotProperty = sal_True; + } + catch ( RuntimeException& ) {} + catch ( Exception& ) {} + + return bGotProperty; +} + +// ----------------------------------------------------------------------- +// static +bool SfxURLRelocator_Impl::propertyCanContainOfficeDir( + const rtl::OUString & rPropName ) +{ + // Note: TargetURL is handled by UCB itself (because it is a property + // with a predefined semantic). Additional Core properties introduced + // be a client app must be handled by the client app itself, because + // the UCB does not know the semantics of those properties. + return ( rPropName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( TARGET_DIR_URL ) ) || + rPropName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( PROPERTY_DIRLIST ) ) ); +} + +//----------------------------------------------------------------------------- +// public SfxDocTplService_Impl +//----------------------------------------------------------------------------- + +SfxDocTplService_Impl::SfxDocTplService_Impl( uno::Reference< XMultiServiceFactory > xFactory ) +: maRelocator( xFactory ) +{ + mxFactory = xFactory; + mpUpdater = NULL; + mbIsInitialized = sal_False; + mbLocaleSet = sal_False; +} + +//----------------------------------------------------------------------------- +SfxDocTplService_Impl::~SfxDocTplService_Impl() +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mpUpdater ) + { + mpUpdater->kill(); + delete mpUpdater; + } +} + +//----------------------------------------------------------------------------- +Locale SfxDocTplService_Impl::getLocale() +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( !mbLocaleSet ) + getDefaultLocale(); + + return maLocale; +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::setLocale( const Locale &rLocale ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mbLocaleSet && + ( maLocale.Language != rLocale.Language ) && + ( maLocale.Country != rLocale.Country ) ) + mbIsInitialized = sal_False; + + maLocale = rLocale; + mbLocaleSet = sal_True; +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::update( sal_Bool bUpdateNow ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( bUpdateNow ) + doUpdate(); + else + { + mpUpdater = new Updater_Impl( this ); + mpUpdater->create(); + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::doUpdate() +{ + ::osl::MutexGuard aGuard( maMutex ); + + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_NEEDSUPDATE ) ); + Any aValue; + + aValue <<= sal_True; + setProperty( maRootContent, aPropName, aValue ); + + GroupList_Impl aGroupList; + + // get the entries from the hierarchy + createFromContent( aGroupList, maRootContent, sal_True ); + + // get the entries from the template directories + sal_Int32 nCountDir = maTemplateDirs.getLength(); + OUString* pDirs = maTemplateDirs.getArray(); + Content aDirContent; + + // the last directory in the list must be writable + sal_Bool bWriteableDirectory = sal_True; + + // the target folder might not exist, for this reason no interaction handler should be used + uno::Reference< XCommandEnvironment > aQuietEnv; + + while ( nCountDir ) + { + nCountDir--; + if ( Content::create( pDirs[ nCountDir ], aQuietEnv, aDirContent ) ) + { + createFromContent( aGroupList, aDirContent, sal_False, bWriteableDirectory ); + } + + bWriteableDirectory = sal_False; + } + + // now check the list + GroupData_Impl *pGroup = aGroupList.First(); + while ( pGroup ) + { + if ( pGroup->getInUse() ) + { + if ( pGroup->getInHierarchy() ) + { + Content aGroup; + if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) ) + setProperty( aGroup, + OUString( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ), + makeAny( pGroup->getTargetURL() ) ); + + ULONG nCount = pGroup->count(); + for ( ULONG i=0; i<nCount; i++ ) + { + DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i ); + if ( ! pData->getInUse() ) + { + if ( pData->getInHierarchy() ) + removeFromHierarchy( pData ); // delete entry in hierarchy + else + addToHierarchy( pGroup, pData ); // add entry to hierarchy + } + else if ( pData->getUpdateType() || + pData->getUpdateLink() ) + { + updateData( pData ); + } + } + } + else + { + addGroupToHierarchy( pGroup ); // add group to hierarchy + } + } + else + removeFromHierarchy( pGroup ); // delete group from hierarchy + + delete pGroup; + pGroup = aGroupList.Next(); + } + + aValue <<= sal_False; + setProperty( maRootContent, aPropName, aValue ); +} + +//----------------------------------------------------------------------------- +uno::Sequence< beans::StringPair > SfxDocTplService_Impl::ReadUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath ) +{ + INetURLObject aLocObj( aUserPath ); + aLocObj.insertName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "groupuinames.xml" ) ), false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + Content aLocContent; + + // TODO/LATER: Use hashmap in future + uno::Sequence< beans::StringPair > aUINames; + if ( Content::create( aLocObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference < ucb::XCommandEnvironment >(), aLocContent ) ) + { + try + { + uno::Reference< io::XInputStream > xLocStream = aLocContent.openStream(); + if ( xLocStream.is() ) + aUINames = DocTemplLocaleHelper::ReadGroupLocalizationSequence( xLocStream, mxFactory ); + } + catch( uno::Exception& ) + {} + } + + return aUINames; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::UpdateUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aGroupName, + const ::rtl::OUString& aNewFolderName ) +{ + uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath ); + sal_Int32 nLen = aUINames.getLength(); + + // it is possible that the name is used already, but it should be checked before + for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ ) + if ( aUINames[nInd].First.equals( aNewFolderName ) ) + return sal_False; + + aUINames.realloc( ++nLen ); + aUINames[nLen-1].First = aNewFolderName; + aUINames[nLen-1].Second = aGroupName; + + return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames ); +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::ReplaceUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aDefaultFsysGroupName, + const ::rtl::OUString& aOldGroupName, + const ::rtl::OUString& aNewGroupName ) +{ + uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath ); + sal_Int32 nLen = aUINames.getLength(); + + sal_Bool bChanged = sal_False; + for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ ) + if ( aUINames[nInd].Second.equals( aOldGroupName ) ) + { + aUINames[nInd].Second = aNewGroupName; + bChanged = sal_True; + } + + if ( !bChanged ) + { + aUINames.realloc( ++nLen ); + aUINames[nLen-1].First = aDefaultFsysGroupName; + aUINames[nLen-1].Second = aNewGroupName; + } + return WriteUINamesForTemplateDir_Impl( aUserPath, aUINames ); +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::RemoveUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const ::rtl::OUString& aGroupName ) +{ + uno::Sequence< beans::StringPair > aUINames = ReadUINamesForTemplateDir_Impl( aUserPath ); + sal_Int32 nLen = aUINames.getLength(); + uno::Sequence< beans::StringPair > aNewUINames( nLen ); + sal_Int32 nNewLen = 0; + + sal_Bool bChanged = sal_False; + for ( sal_Int32 nInd = 0; nInd < nLen; nInd++ ) + if ( aUINames[nInd].Second.equals( aGroupName ) ) + bChanged = sal_True; + else + { + nNewLen++; + aNewUINames[nNewLen-1].First = aUINames[nInd].First; + aNewUINames[nNewLen-1].Second = aUINames[nInd].Second; + } + + aNewUINames.realloc( nNewLen ); + + return bChanged ? WriteUINamesForTemplateDir_Impl( aUserPath, aNewUINames ) : sal_True; +} + + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::WriteUINamesForTemplateDir_Impl( const ::rtl::OUString& aUserPath, + const uno::Sequence< beans::StringPair >& aUINames ) +{ + sal_Bool bResult = sal_False; + try { + uno::Reference< beans::XPropertySet > xTempFile( + mxFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), + uno::UNO_QUERY_THROW ); + + ::rtl::OUString aTempURL; + uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) ); + aUrl >>= aTempURL; + + uno::Reference< io::XStream > xStream( xTempFile, uno::UNO_QUERY_THROW ); + uno::Reference< io::XOutputStream > xOutStream = xStream->getOutputStream(); + if ( !xOutStream.is() ) + throw uno::RuntimeException(); + + DocTemplLocaleHelper::WriteGroupLocalizationSequence( xOutStream, aUINames, mxFactory ); + try { + // the SAX writer might close the stream + xOutStream->closeOutput(); + } catch( uno::Exception& ) + {} + + Content aTargetContent( aUserPath, maCmdEnv ); + Content aSourceContent( aTempURL, maCmdEnv ); + aTargetContent.transferContent( aSourceContent, + InsertOperation_COPY, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "groupuinames.xml" ) ), + ucb::NameClash::OVERWRITE ); + bResult = sal_True; + } + catch ( uno::Exception& ) + { + } + + return bResult; +} + +//----------------------------------------------------------------------------- +::rtl::OUString SfxDocTplService_Impl::CreateNewGroupFsys( const ::rtl::OUString& rGroupName, Content& aGroup ) +{ + ::rtl::OUString aResultURL; + + if ( maTemplateDirs.getLength() ) + { + ::rtl::OUString aTargetPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ]; + + // create a new folder with the given name + Content aNewFolder; + ::rtl::OUString aNewFolderName; + + // the Fsys name instead of GroupName should be used, the groupuinames must be added also + if ( !CreateNewUniqueFolderWithPrefix( aTargetPath, + rGroupName, + aNewFolderName, + aResultURL, + aNewFolder ) + && !CreateNewUniqueFolderWithPrefix( aTargetPath, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserGroup" ) ), + aNewFolderName, + aResultURL, + aNewFolder ) ) + + return ::rtl::OUString(); + + if ( !UpdateUINamesForTemplateDir_Impl( aTargetPath, rGroupName, aNewFolderName ) ) + { + // we could not create the groupuinames for the folder, so we delete the group in the + // the folder and return + removeContent( aNewFolder ); + return ::rtl::OUString(); + } + + // Now set the target url for this group and we are done + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue = makeAny( aResultURL ); + + if ( ! setProperty( aGroup, aPropName, aValue ) ) + { + removeContent( aNewFolder ); + return ::rtl::OUString(); + } + } + + return aResultURL; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::addGroup( const OUString& rGroupName ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // Check, wether or not there is a group with this name + Content aNewGroup; + OUString aNewGroupURL; + INetURLObject aNewGroupObj( maRootURL ); + + aNewGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aNewGroupURL, maCmdEnv, aNewGroup ) || + ! createFolder( aNewGroupURL, sal_False, sal_False, aNewGroup ) ) + { + // if there already was a group with this name or the new group + // could not be created, we return here + return sal_False; + } + + // Get the user template path entry ( new group will always + // be added in the user template path ) + sal_Int32 nIndex; + OUString aUserPath; + + nIndex = maTemplateDirs.getLength(); + if ( nIndex ) + nIndex--; + else + return sal_False; // We don't know where to add the group + + aUserPath = maTemplateDirs[ nIndex ]; + + // create a new folder with the given name + Content aNewFolder; + OUString aNewFolderName; + OUString aNewFolderURL; + + // the Fsys name instead of GroupName should be used, the groupuinames must be added also + if ( !CreateNewUniqueFolderWithPrefix( aUserPath, + rGroupName, + aNewFolderName, + aNewFolderURL, + aNewFolder ) + && !CreateNewUniqueFolderWithPrefix( aUserPath, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserGroup" ) ), + aNewFolderName, + aNewFolderURL, + aNewFolder ) ) + { + // we could not create the folder, so we delete the group in the + // hierarchy and return + removeContent( aNewGroup ); + return sal_False; + } + + if ( !UpdateUINamesForTemplateDir_Impl( aUserPath, rGroupName, aNewFolderName ) ) + { + // we could not create the groupuinames for the folder, so we delete the group in the + // hierarchy, the folder and return + removeContent( aNewGroup ); + removeContent( aNewFolder ); + return sal_False; + } + + // Now set the target url for this group and we are done + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue = makeAny( aNewFolderURL ); + + if ( ! setProperty( aNewGroup, aPropName, aValue ) ) + { + removeContent( aNewGroup ); + removeContent( aNewFolder ); + return sal_False; + } + + return sal_True; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::removeGroup( const OUString& rGroupName ) +{ + // remove all the elements that have the prefix aTargetURL + // if the group does not have other elements remove it + + ::osl::MutexGuard aGuard( maMutex ); + + sal_Bool bResult = sal_False; + + // create the group url + INetURLObject aGroupObj( maRootURL ); + aGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + // Get the target url + Content aGroup; + OUString aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aGroupURL, maCmdEnv, aGroup ) ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue; + + OUString aGroupTargetURL; + if ( getProperty( aGroup, aPropName, aValue ) ) + aValue >>= aGroupTargetURL; + + if ( !aGroupTargetURL.getLength() ) + return sal_False; // nothing is allowed to be removed + + if ( !maTemplateDirs.getLength() ) + return sal_False; + ::rtl::OUString aGeneralTempPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ]; + + // check that the fs location is in writeble folder and this is not a "My templates" folder + INetURLObject aGroupParentFolder( aGroupTargetURL ); + if ( !aGroupParentFolder.removeSegment() + || !::utl::UCBContentHelper::IsSubPath( aGeneralTempPath, + aGroupParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) ) + return sal_False; + + // now get the content of the Group + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps( 1 ); + + aProps[0] = OUString::createFromAscii( TARGET_URL ); + + try + { + sal_Bool bHasNonRemovable = sal_False; + sal_Bool bHasShared = sal_False; + + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + xResultSet = aGroup.createCursor( aProps, eInclude ); + + if ( xResultSet.is() ) + { + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW ); + + while ( xResultSet->next() ) + { + OUString aTemplTargetURL( xRow->getString( 1 ) ); + OUString aHierURL = xContentAccess->queryContentIdentifierString(); + + if ( ::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) ) + { + // this is a user template, and it can be removed + if ( removeContent( aTemplTargetURL ) ) + removeContent( aHierURL ); + else + bHasNonRemovable = sal_True; + } + else + bHasShared = sal_True; + } + + if ( !bHasNonRemovable && !bHasShared ) + { + if ( removeContent( aGroupTargetURL ) + || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) ) + { + removeContent( aGroupURL ); + RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName ); + bResult = sal_True; // the operation is successful only if the whole group is removed + } + } + else if ( !bHasNonRemovable ) + { + if ( removeContent( aGroupTargetURL ) + || !::utl::UCBContentHelper::Exists( aGroupTargetURL ) ) + { + RemoveUINamesForTemplateDir_Impl( aGeneralTempPath, rGroupName ); + setProperty( aGroup, aPropName, uno::makeAny( ::rtl::OUString() ) ); + } + } + } + } + catch ( Exception& ) {} + } + + return bResult; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::renameGroup( const OUString& rOldName, + const OUString& rNewName ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // create the group url + Content aGroup; + INetURLObject aGroupObj( maRootURL ); + aGroupObj.insertName( rNewName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + OUString aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + // Check, if there is a group with the new name, return false + // if there is one. + if ( Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + aGroupObj.removeSegment(); + aGroupObj.insertName( rOldName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + // When there is no group with the old name, we can't rename it + if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + OUString aGroupTargetURL; + // there is no need to check whether target dir url is in target path, since if the target path is changed + // the target dir url should be already generated new + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue; + if ( getProperty( aGroup, aPropName, aValue ) ) + aValue >>= aGroupTargetURL; + + if ( !aGroupTargetURL.getLength() ) + return sal_False; + + if ( !maTemplateDirs.getLength() ) + return sal_False; + ::rtl::OUString aGeneralTempPath = maTemplateDirs[ maTemplateDirs.getLength() - 1 ]; + + // check that the fs location is in writeble folder and this is not a "My templates" folder + INetURLObject aGroupParentFolder( aGroupTargetURL ); + if ( !aGroupParentFolder.removeSegment() + || !::utl::UCBContentHelper::IsSubPath( aGeneralTempPath, + aGroupParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) ) + return sal_False; + + // check that the group can be renamed ( all the contents must be in target location ) + sal_Bool bCanBeRenamed = sal_False; + try + { + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps( 1 ); + + aProps[0] = OUString::createFromAscii( TARGET_URL ); + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + xResultSet = aGroup.createCursor( aProps, eInclude ); + + if ( xResultSet.is() ) + { + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY_THROW ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY_THROW ); + + while ( xResultSet->next() ) + { + OUString aTemplTargetURL( xRow->getString( 1 ) ); + + if ( !::utl::UCBContentHelper::IsSubPath( aGroupTargetURL, aTemplTargetURL ) ) + throw uno::Exception(); + } + + bCanBeRenamed = sal_True; + } + } + catch ( Exception& ) {} + + if ( bCanBeRenamed ) + { + INetURLObject aGroupTargetObj( aGroupTargetURL ); + ::rtl::OUString aFsysName = aGroupTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + + if ( aGroupTargetObj.removeSegment() + && ReplaceUINamesForTemplateDir_Impl( aGroupTargetObj.GetMainURL( INetURLObject::NO_DECODE ), + aFsysName, + rOldName, + rNewName ) ) + { + // rename the group in the hierarchy + OUString aTitleProp( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + Any aTitleValue; + aTitleValue <<= rNewName; + + return setProperty( aGroup, aTitleProp, aTitleValue ); + } + } + + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::storeTemplate( const OUString& rGroupName, + const OUString& rTemplateName, + const uno::Reference< XSTORABLE >& rStorable ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // Check, wether or not there is a group with this name + // Return false, if there is no group with the given name + Content aGroup, aTemplate, aTargetGroup, aTemplateToRemove; + OUString aGroupURL, aTemplateURL, aTemplateToRemoveTargetURL; + INetURLObject aGroupObj( maRootURL ); + sal_Bool bRemoveOldTemplateContent = sal_False; + ::rtl::OUString sDocServiceName; + + aGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + ::rtl::OUString aGroupTargetURL; + ::rtl::OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue; + if ( getProperty( aGroup, aPropName, aValue ) ) + aValue >>= aGroupTargetURL; + + + // Check, if there's a template with the given name in this group + // the target template should be overwritten if it is imported by user + // in case the template is installed by office installation of by an add-in + // it can not be replaced + aGroupObj.insertName( rTemplateName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aTemplateURL, maCmdEnv, aTemplateToRemove ) ) + { + OUString aTargetTemplPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + + bRemoveOldTemplateContent = sal_True; + if ( getProperty( aTemplateToRemove, aTargetTemplPropName, aValue ) ) + aValue >>= aTemplateToRemoveTargetURL; + + if ( !aGroupTargetURL.getLength() || !maTemplateDirs.getLength() + || (aTemplateToRemoveTargetURL.getLength() && !::utl::UCBContentHelper::IsSubPath( maTemplateDirs[ maTemplateDirs.getLength() - 1 ], aTemplateToRemoveTargetURL )) ) + return sal_False; // it is not allowed to remove the template + } + + try + { + uno::Reference< lang::XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + if ( !xFactory.is() ) + throw uno::RuntimeException(); + + // get document service name + uno::Reference< frame::XModuleManager > xModuleManager( + xFactory->createInstance( + ::rtl::OUString::createFromAscii( "com.sun.star.frame.ModuleManager" ) ), + uno::UNO_QUERY_THROW ); + sDocServiceName = xModuleManager->identify( uno::Reference< uno::XInterface >( rStorable, uno::UNO_QUERY ) ); + if ( !sDocServiceName.getLength() ) + throw uno::RuntimeException(); + + // get the actual filter name + ::rtl::OUString aFilterName; + + uno::Reference< lang::XMultiServiceFactory > xConfigProvider( + xFactory->createInstance( + ::rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationProvider" ) ), + uno::UNO_QUERY_THROW ); + + uno::Sequence< uno::Any > aArgs( 1 ); + beans::PropertyValue aPathProp; + aPathProp.Name = ::rtl::OUString::createFromAscii( "nodepath" ); + aPathProp.Value <<= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Setup/Office/Factories/" ) ); + aArgs[0] <<= aPathProp; + + uno::Reference< container::XNameAccess > xSOFConfig( + xConfigProvider->createInstanceWithArguments( + ::rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationAccess" ), + aArgs ), + uno::UNO_QUERY_THROW ); + + uno::Reference< container::XNameAccess > xApplConfig; + xSOFConfig->getByName( sDocServiceName ) >>= xApplConfig; + if ( !xApplConfig.is() ) + throw uno::RuntimeException(); + + xApplConfig->getByName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ooSetupFactoryActualTemplateFilter" ) ) ) >>= aFilterName; + if ( !aFilterName.getLength() ) + throw uno::RuntimeException(); + + // find the related type name + ::rtl::OUString aTypeName; + uno::Reference< container::XNameAccess > xFilterFactory( + xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ), + uno::UNO_QUERY_THROW ); + + uno::Sequence< beans::PropertyValue > aFilterData; + xFilterFactory->getByName( aFilterName ) >>= aFilterData; + for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ ) + if ( aFilterData[nInd].Name.equalsAscii( "Type" ) ) + aFilterData[nInd].Value >>= aTypeName; + + if ( !aTypeName.getLength() ) + throw uno::RuntimeException(); + + // find the mediatype and extension + uno::Reference< container::XNameAccess > xTypeDetection = + mxType.is() ? + uno::Reference< container::XNameAccess >( mxType, uno::UNO_QUERY_THROW ) : + uno::Reference< container::XNameAccess >( + xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.TypeDetection" ) ), + uno::UNO_QUERY_THROW ); + + SequenceAsHashMap aTypeProps( xTypeDetection->getByName( aTypeName ) ); + uno::Sequence< ::rtl::OUString > aAllExt = + aTypeProps.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "Extensions" ), Sequence< ::rtl::OUString >() ); + if ( !aAllExt.getLength() ) + throw uno::RuntimeException(); + + ::rtl::OUString aMediaType = aTypeProps.getUnpackedValueOrDefault( ::rtl::OUString::createFromAscii( "MediaType" ), ::rtl::OUString() ); + ::rtl::OUString aExt = aAllExt[0]; + + if ( !aMediaType.getLength() || !aExt.getLength() ) + throw uno::RuntimeException(); + + // construct destination url + if ( !aGroupTargetURL.getLength() ) + { + aGroupTargetURL = CreateNewGroupFsys( rGroupName, aGroup ); + + if ( !aGroupTargetURL.getLength() ) + throw uno::RuntimeException(); + } + + ::rtl::OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, rTemplateName, aExt ); + if ( !aNewTemplateTargetURL.getLength() ) + { + aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aGroupTargetURL, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserTemplate" ) ), aExt ); + + if ( !aNewTemplateTargetURL.getLength() ) + throw uno::RuntimeException(); + } + + // store template + uno::Sequence< PropertyValue > aStoreArgs( 2 ); + aStoreArgs[0].Name = ::rtl::OUString::createFromAscii( "FilterName" ); + aStoreArgs[0].Value <<= aFilterName; + aStoreArgs[1].Name = ::rtl::OUString::createFromAscii( "DocumentTitle" ); + aStoreArgs[1].Value <<= rTemplateName; + + ::rtl::OUString aCurrentDocumentURL = rStorable->getLocation(); + if( !SfxMedium::EqualURLs( aNewTemplateTargetURL, rStorable->getLocation() )) + rStorable->storeToURL( aNewTemplateTargetURL, aStoreArgs ); + else + rStorable->store(); + + // the storing was successful, now the old template with the same name can be removed if it existed + if ( aTemplateToRemoveTargetURL.getLength() ) + { + removeContent( aTemplateToRemoveTargetURL ); + + /* + * pb: #i79496# + * if the old template was the standard template + * it is necessary to change the standard template with the new file name + */ + String sStdTmplFile = SfxObjectFactory::GetStandardTemplate( sDocServiceName ); + if ( INetURLObject( sStdTmplFile ) == INetURLObject( aTemplateToRemoveTargetURL ) ) + { + SfxObjectFactory::SetStandardTemplate( sDocServiceName, aNewTemplateTargetURL ); + } + } + + if ( bRemoveOldTemplateContent ) + removeContent( aTemplateToRemove ); + + // add the template to hierarchy + return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aMediaType ); + } + catch( Exception& ) + { + // the template was not stored + return sal_False; + } +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::addTemplate( const OUString& rGroupName, + const OUString& rTemplateName, + const OUString& rSourceURL ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // Check, wether or not there is a group with this name + // Return false, if there is no group with the given name + Content aGroup, aTemplate, aTargetGroup; + OUString aGroupURL, aTemplateURL; + INetURLObject aGroupObj( maRootURL ); + + aGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + // Check, if there's a template with the given name in this group + // Return false, if there already is a template + aGroupObj.insertName( rTemplateName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) ) + return sal_False; + + // get the target url of the group + OUString aTargetURL; + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Any aValue; + + if ( getProperty( aGroup, aPropName, aValue ) ) + aValue >>= aTargetURL; + + if ( !aTargetURL.getLength() ) + { + aTargetURL = CreateNewGroupFsys( rGroupName, aGroup ); + + if ( !aTargetURL.getLength() ) + return sal_False; + } + + // Get the content type + OUString aTitle, aType, aTargetURL2, aFullName; + + // only StarOffice documents are acceptable + sal_Bool bDocHasTitle = sal_False; + if( !getTitleFromURL( rSourceURL, aTitle, aType, bDocHasTitle ) ) + return sal_False; + + INetURLObject aSourceObj( rSourceURL ); + if ( rTemplateName.equals( aTitle ) ) + { + ///////////////////////////////////////////////////// + // addTemplate will sometimes be called just to add an entry in the + // hierarchy; the target URL and the source URL will be the same in + // this scenario + // TODO/LATER: get rid of this old hack + + INetURLObject aTargetObj( aTargetURL ); + + aTargetObj.insertName( rTemplateName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTargetObj.setExtension( aSourceObj.getExtension() ); + + aTargetURL2 = aTargetObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( aTargetURL2 == rSourceURL ) + return addEntry( aGroup, rTemplateName, aTargetURL2, aType ); + } + + ///////////////////////////////////////////////////// + // copy the template into the new group (targeturl) + + INetURLObject aTmpURL( aSourceObj ); + aTmpURL.CutExtension(); + ::rtl::OUString aPattern = aTmpURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + + ::rtl::OUString aNewTemplateTargetURL = CreateNewUniqueFileWithPrefix( aTargetURL, aPattern, aSourceObj.getExtension() ); + INetURLObject aNewTemplateTargetObj( aNewTemplateTargetURL ); + ::rtl::OUString aNewTemplateTargetName = aNewTemplateTargetObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + if ( !aNewTemplateTargetURL.getLength() || !aNewTemplateTargetName.getLength() ) + return sal_False; + + // get access to source file + Content aSourceContent; + uno::Reference < ucb::XCommandEnvironment > xEnv; + INetURLObject aSourceURL( rSourceURL ); + if( ! Content::create( aSourceURL.GetMainURL( INetURLObject::NO_DECODE ), xEnv, aSourceContent ) ) + return sal_False; + + if( ! Content::create( aTargetURL, xEnv, aTargetGroup ) ) + return sal_False; + + // transfer source file + try + { + if( ! aTargetGroup.transferContent( aSourceContent, + InsertOperation_COPY, + aNewTemplateTargetName, + NameClash::OVERWRITE ) ) + return sal_False; + + // allow to edit the added template + Content aResultContent; + if ( Content::create( aNewTemplateTargetURL, xEnv, aResultContent ) ) + { + ::rtl::OUString aPropertyName( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ); + uno::Any aProperty; + sal_Bool bReadOnly = sal_False; + if ( getProperty( aResultContent, aPropertyName, aProperty ) && ( aProperty >>= bReadOnly ) && bReadOnly ) + setProperty( aResultContent, aPropertyName, uno::makeAny( (sal_Bool)sal_False ) ); + } + } + catch ( ContentCreationException& ) + { return sal_False; } + catch ( Exception& ) + { return sal_False; } + + + // either the document has title and it is the same as requested, or we have to set it + sal_Bool bCorrectTitle = ( bDocHasTitle && aTitle.equals( rTemplateName ) ); + if ( !bCorrectTitle ) + { + if ( !bDocHasTitle ) + { + INetURLObject aNewTmpObj( aNewTemplateTargetObj ); + aNewTmpObj.CutExtension(); + bCorrectTitle = ( aNewTmpObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).equals( rTemplateName ) ); + } + + if ( !bCorrectTitle ) + bCorrectTitle = setTitleForURL( aNewTemplateTargetURL, rTemplateName ); + } + + if ( bCorrectTitle ) + { + // create a new entry in the hierarchy + return addEntry( aGroup, rTemplateName, aNewTemplateTargetURL, aType ); + } + + // TODO/LATER: The user could be notified here that the renaming has failed + // create a new entry in the hierarchy + addEntry( aGroup, aTitle, aNewTemplateTargetURL, aType ); + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::removeTemplate( const OUString& rGroupName, + const OUString& rTemplateName ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // Check, wether or not there is a group with this name + // Return false, if there is no group with the given name + Content aGroup, aTemplate; + OUString aGroupURL, aTemplateURL; + INetURLObject aGroupObj( maRootURL ); + + aGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + // Check, if there's a template with the given name in this group + // Return false, if there is no template + aGroupObj.insertName( rTemplateName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( !Content::create( aTemplateURL, maCmdEnv, aTemplate ) ) + return sal_False; + + // get the target URL from the template + OUString aTargetURL; + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + Any aValue; + + if ( getProperty( aTemplate, aPropName, aValue ) ) + aValue >>= aTargetURL; + + // delete the target template + if ( aTargetURL.getLength() ) + { + if ( !maTemplateDirs.getLength() + || !::utl::UCBContentHelper::IsSubPath( maTemplateDirs[ maTemplateDirs.getLength() - 1 ], aTargetURL ) ) + return sal_False; + + removeContent( aTargetURL ); + } + + // delete the template entry + return removeContent( aTemplate ); +} + +//----------------------------------------------------------------------------- +sal_Bool SfxDocTplService_Impl::renameTemplate( const OUString& rGroupName, + const OUString& rOldName, + const OUString& rNewName ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // Check, wether or not there is a group with this name + // Return false, if there is no group with the given name + Content aGroup, aTemplate; + OUString aGroupURL, aTemplateURL; + INetURLObject aGroupObj( maRootURL ); + + aGroupObj.insertName( rGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aGroupURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( ! Content::create( aGroupURL, maCmdEnv, aGroup ) ) + return sal_False; + + // Check, if there's a template with the new name in this group + // Return false, if there is one + aGroupObj.insertName( rNewName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) ) + return sal_False; + + // Check, if there's a template with the old name in this group + // Return false, if there is no template + aGroupObj.removeSegment(); + aGroupObj.insertName( rOldName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( !Content::create( aTemplateURL, maCmdEnv, aTemplate ) ) + return sal_False; + + OUString aTemplateTargetURL; + OUString aTargetProp( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + Any aTargetValue; + + if ( getProperty( aTemplate, aTargetProp, aTargetValue ) ) + aTargetValue >>= aTemplateTargetURL; + + if ( !setTitleForURL( aTemplateTargetURL, rNewName ) ) + return sal_False; + + // rename the template entry in the cache + OUString aTitleProp( RTL_CONSTASCII_USTRINGPARAM( TITLE ) ); + Any aTitleValue; + aTitleValue <<= rNewName; + + return setProperty( aTemplate, aTitleProp, aTitleValue ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +SFX_IMPL_XSERVICEINFO( SfxDocTplService, TEMPLATE_SERVICE_NAME, TEMPLATE_IMPLEMENTATION_NAME ) +SFX_IMPL_SINGLEFACTORY( SfxDocTplService ) + +//----------------------------------------------------------------------------- +SfxDocTplService::SfxDocTplService( const uno::Reference< XMultiServiceFactory >& xFactory ) +{ + pImp = new SfxDocTplService_Impl( xFactory ); +} + +//----------------------------------------------------------------------------- + +SfxDocTplService::~SfxDocTplService() +{ + delete pImp; +} + +//----------------------------------------------------------------------------- +//--- XLocalizable --- +//----------------------------------------------------------------------------- + +Locale SAL_CALL SfxDocTplService::getLocale() + throw( RUNTIMEEXCEPTION ) +{ + return pImp->getLocale(); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL SfxDocTplService::setLocale( const Locale & rLocale ) + throw( RUNTIMEEXCEPTION ) +{ + pImp->setLocale( rLocale ); +} + +//----------------------------------------------------------------------------- +//--- XDocumentTemplates --- +//----------------------------------------------------------------------------- +uno::Reference< XCONTENT > SAL_CALL SfxDocTplService::getContent() + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->getContent().get(); + else + return NULL; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::storeTemplate( const OUString& GroupName, + const OUString& TemplateName, + const uno::Reference< XSTORABLE >& Storable ) + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->storeTemplate( GroupName, TemplateName, Storable ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::addTemplate( const OUString& rGroupName, + const OUString& rTemplateName, + const OUString& rSourceURL ) + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->addTemplate( rGroupName, rTemplateName, rSourceURL ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::removeTemplate( const OUString& rGroupName, + const OUString& rTemplateName ) + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->removeTemplate( rGroupName, rTemplateName ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::renameTemplate( const OUString& rGroupName, + const OUString& rOldName, + const OUString& rNewName ) + throw( RUNTIMEEXCEPTION ) +{ + if ( rOldName == rNewName ) + return sal_True; + + if ( pImp->init() ) + return pImp->renameTemplate( rGroupName, rOldName, rNewName ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::addGroup( const OUString& rGroupName ) + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->addGroup( rGroupName ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::removeGroup( const OUString& rGroupName ) + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + return pImp->removeGroup( rGroupName ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +sal_Bool SAL_CALL SfxDocTplService::renameGroup( const OUString& rOldName, + const OUString& rNewName ) + throw( RUNTIMEEXCEPTION ) +{ + if ( rOldName == rNewName ) + return sal_True; + + if ( pImp->init() ) + return pImp->renameGroup( rOldName, rNewName ); + else + return sal_False; +} + +//----------------------------------------------------------------------------- +void SAL_CALL SfxDocTplService::update() + throw( RUNTIMEEXCEPTION ) +{ + if ( pImp->init() ) + pImp->update( sal_True ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//------------------------------------------------------------------------ + +Updater_Impl::Updater_Impl( SfxDocTplService_Impl* pTemplates ) +{ + mpDocTemplates = pTemplates; +} + +//------------------------------------------------------------------------ +Updater_Impl::~Updater_Impl() +{ +} + +//------------------------------------------------------------------------ +void SAL_CALL Updater_Impl::run() +{ + mpDocTemplates->doUpdate(); +} + +//------------------------------------------------------------------------ +void SAL_CALL Updater_Impl::onTerminated() +{ + mpDocTemplates->finished(); + delete this; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +WaitWindow_Impl::WaitWindow_Impl() + : WorkWindow( NULL, WB_BORDER | WB_3DLOOK ) +{ + Rectangle aRect = Rectangle( 0, 0, 300, 30000 ); + _nTextStyle = TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE; + _aText = String( SfxResId( RID_CNT_STR_WAITING ) ); + _aRect = GetTextRect( aRect, _aText, _nTextStyle ); + aRect = _aRect; + aRect.Right() += 2*X_OFFSET; + aRect.Bottom() += 2*Y_OFFSET; + _aRect.SetPos( Point( X_OFFSET, Y_OFFSET ) ); + SetOutputSizePixel( aRect.GetSize() ); + Show(); + Update(); + Flush(); +} + +//----------------------------------------------------------------------------- +WaitWindow_Impl::~WaitWindow_Impl() +{ + Hide(); +} + +//----------------------------------------------------------------------------- +void WaitWindow_Impl::Paint( const Rectangle& /*rRect*/ ) +{ + DrawText( _aRect, _aText, _nTextStyle ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::addHierGroup( GroupList_Impl& rList, + const OUString& rTitle, + const OUString& rOwnURL ) +{ + // now get the content of the Group + Content aContent; + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(3); + + aProps[0] = OUString::createFromAscii( TITLE ); + aProps[1] = OUString::createFromAscii( TARGET_URL ); + aProps[2] = OUString::createFromAscii( PROPERTY_TYPE ); + + try + { + aContent = Content( rOwnURL, maCmdEnv ); + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + xResultSet = aContent.createCursor( aProps, eInclude ); + } + catch ( ContentCreationException& ) + { + DBG_ERRORFILE( "addHierGroup: ContentCreationException" ); + } + catch ( Exception& ) {} + + if ( xResultSet.is() ) + { + GroupData_Impl *pGroup = new GroupData_Impl( rTitle ); + pGroup->setHierarchy( sal_True ); + pGroup->setHierarchyURL( rOwnURL ); + rList.Insert( pGroup ); + + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + BOOL bUpdateType = sal_False; + DocTemplates_EntryData_Impl *pData; + + OUString aTitle( xRow->getString( 1 ) ); + OUString aTargetDir( xRow->getString( 2 ) ); + OUString aType( xRow->getString( 3 ) ); + OUString aHierURL = xContentAccess->queryContentIdentifierString(); + + if ( !aType.getLength() ) + { + OUString aTmpTitle; + + sal_Bool bDocHasTitle = sal_False; + if( !getTitleFromURL( aTargetDir, aTmpTitle, aType, bDocHasTitle ) ) + { + DBG_ERRORFILE( "addHierGroup(): template of alien format" ); + continue; + } + + if ( aType.getLength() ) + bUpdateType = sal_True; + } + + pData = pGroup->addEntry( aTitle, aTargetDir, aType, aHierURL ); + pData->setUpdateType( bUpdateType ); + } + } + catch ( Exception& ) {} + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::addFsysGroup( GroupList_Impl& rList, + const OUString& rTitle, + const OUString& rUITitle, + const OUString& rOwnURL, + sal_Bool bWriteableGroup ) +{ + ::rtl::OUString aTitle; + + if ( !rUITitle.getLength() ) + { + // reserved FS names that should not be used + if ( rTitle.compareToAscii( "wizard" ) == 0 ) + return; + else if ( rTitle.compareToAscii( "internal" ) == 0 ) + return; + + aTitle = getLongName( rTitle ); + } + else + aTitle = rUITitle; + + if ( !aTitle.getLength() ) + return; + + GroupData_Impl *pGroup = rList.First(); + + while ( pGroup && pGroup->getTitle() != aTitle ) + pGroup = rList.Next(); + + if ( !pGroup ) + { + pGroup = new GroupData_Impl( aTitle ); + rList.Insert( pGroup ); + } + + if ( bWriteableGroup ) + pGroup->setTargetURL( rOwnURL ); + + pGroup->setInUse(); + + // now get the content of the Group + Content aContent; + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(1); + aProps[0] = OUString::createFromAscii( TITLE ); + + try + { + // this method is only used during checking of the available template-folders + // that should happen quietly + uno::Reference< XCommandEnvironment > aQuietEnv; + aContent = Content( rOwnURL, aQuietEnv ); + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + xResultSet = aContent.createCursor( aProps, eInclude ); + } + catch ( Exception& ) {} + + if ( xResultSet.is() ) + { + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + OUString aChildTitle( xRow->getString( 1 ) ); + OUString aTargetURL = xContentAccess->queryContentIdentifierString(); + OUString aType; + OUString aHierURL; + + if ( aChildTitle.compareToAscii( "sfx.tlx" ) == 0 + || aChildTitle.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "groupuinames.xml" ) ) ) + continue; + + // only StarOffice templates are accepted + sal_Bool bDocHasTitle = sal_False; + if( !getTitleFromURL( aTargetURL, aChildTitle, aType, bDocHasTitle ) ) + continue; + + pGroup->addEntry( aChildTitle, aTargetURL, aType, aHierURL ); + } + } + catch ( Exception& ) {} + } +} + +// ----------------------------------------------------------------------- +void SfxDocTplService_Impl::createFromContent( GroupList_Impl& rList, + Content &rContent, + sal_Bool bHierarchy, + sal_Bool bWriteableContent ) +{ + OUString aTargetURL = rContent.get()->getIdentifier()->getContentIdentifier(); + + // when scanning the file system, we have to add the 'standard' group, too + if ( ! bHierarchy ) + { + OUString aUIStdTitle = getLongName( OUString( RTL_CONSTASCII_USTRINGPARAM( STANDARD_FOLDER ) ) ); + addFsysGroup( rList, ::rtl::OUString(), aUIStdTitle, aTargetURL, bWriteableContent ); + } + + // search for predefined UI names + INetURLObject aLayerObj( aTargetURL ); + + // TODO/LATER: Use hashmap in future + uno::Sequence< beans::StringPair > aUINames; + if ( !bHierarchy ) + aUINames = ReadUINamesForTemplateDir_Impl( aLayerObj.GetMainURL( INetURLObject::NO_DECODE ) ); + + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(1); + aProps[0] = OUString::createFromAscii( TITLE ); + + try + { + ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY; + xResultSet = rContent.createCursor( aProps, eInclude ); + } + catch ( Exception& ) {} + + if ( xResultSet.is() ) + { + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + // TODO/LATER: clarify the encoding of the Title + OUString aTitle( xRow->getString( 1 ) ); + OUString aTargetSubfolderURL( xContentAccess->queryContentIdentifierString() ); + + if ( bHierarchy ) + addHierGroup( rList, aTitle, aTargetSubfolderURL ); + else + { + ::rtl::OUString aUITitle; + for ( sal_Int32 nInd = 0; nInd < aUINames.getLength(); nInd++ ) + if ( aUINames[nInd].First.equals( aTitle ) ) + { + aUITitle = aUINames[nInd].Second; + break; + } + + addFsysGroup( rList, aTitle, aUITitle, aTargetSubfolderURL, bWriteableContent ); + } + } + } + catch ( Exception& ) {} + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::removeFromHierarchy( DocTemplates_EntryData_Impl *pData ) +{ + Content aTemplate; + + if ( Content::create( pData->getHierarchyURL(), maCmdEnv, aTemplate ) ) + { + removeContent( aTemplate ); + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::addToHierarchy( GroupData_Impl *pGroup, + DocTemplates_EntryData_Impl *pData ) +{ + Content aGroup, aTemplate; + + if ( ! Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) ) + return; + + // Check, if there's a template with the given name in this group + // Return if there is already a template + INetURLObject aGroupObj( pGroup->getHierarchyURL() ); + + aGroupObj.insertName( pData->getTitle(), false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + OUString aTemplateURL = aGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( Content::create( aTemplateURL, maCmdEnv, aTemplate ) ) + return; + + addEntry( aGroup, pData->getTitle(), + pData->getTargetURL(), + pData->getType() ); +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::updateData( DocTemplates_EntryData_Impl *pData ) +{ + Content aTemplate; + + if ( ! Content::create( pData->getHierarchyURL(), maCmdEnv, aTemplate ) ) + return; + + OUString aPropName; + + if ( pData->getUpdateType() ) + { + aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( PROPERTY_TYPE ) ); + setProperty( aTemplate, aPropName, makeAny( pData->getType() ) ); + } + + if ( pData->getUpdateLink() ) + { + aPropName = OUString( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + setProperty( aTemplate, aPropName, makeAny( pData->getTargetURL() ) ); + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::addGroupToHierarchy( GroupData_Impl *pGroup ) +{ + OUString aAdditionalProp( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + Content aGroup; + + INetURLObject aNewGroupObj( maRootURL ); + aNewGroupObj.insertName( pGroup->getTitle(), false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + OUString aNewGroupURL = aNewGroupObj.GetMainURL( INetURLObject::NO_DECODE ); + + if ( createFolder( aNewGroupURL, sal_False, sal_False, aGroup ) ) + { + setProperty( aGroup, aAdditionalProp, makeAny( pGroup->getTargetURL() ) ); + pGroup->setHierarchyURL( aNewGroupURL ); + + ULONG nCount = pGroup->count(); + for ( ULONG i=0; i<nCount; i++ ) + { + DocTemplates_EntryData_Impl *pData = pGroup->getEntry( i ); + addToHierarchy( pGroup, pData ); // add entry to hierarchy + } + } +} + +//----------------------------------------------------------------------------- +void SfxDocTplService_Impl::removeFromHierarchy( GroupData_Impl *pGroup ) +{ + Content aGroup; + + if ( Content::create( pGroup->getHierarchyURL(), maCmdEnv, aGroup ) ) + { + removeContent( aGroup ); + } +} + +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +GroupData_Impl::GroupData_Impl( const OUString& rTitle ) +{ + maTitle = rTitle; + mbInUse = sal_False; + mbInHierarchy = sal_False; +} + +// ----------------------------------------------------------------------- +GroupData_Impl::~GroupData_Impl() +{ + DocTemplates_EntryData_Impl *pData = maEntries.First(); + while ( pData ) + { + delete pData; + pData = maEntries.Next(); + } +} + +// ----------------------------------------------------------------------- +DocTemplates_EntryData_Impl* GroupData_Impl::addEntry( const OUString& rTitle, + const OUString& rTargetURL, + const OUString& rType, + const OUString& rHierURL ) +{ + DocTemplates_EntryData_Impl *pData = maEntries.First(); + + while ( pData && pData->getTitle() != rTitle ) + pData = maEntries.Next(); + + if ( !pData ) + { + pData = new DocTemplates_EntryData_Impl( rTitle ); + pData->setTargetURL( rTargetURL ); + pData->setType( rType ); + if ( rHierURL.getLength() ) + { + pData->setHierarchyURL( rHierURL ); + pData->setHierarchy( sal_True ); + } + maEntries.Insert( pData ); + } + else + { + if ( rHierURL.getLength() ) + { + pData->setHierarchyURL( rHierURL ); + pData->setHierarchy( sal_True ); + } + + if ( pData->getInHierarchy() ) + pData->setInUse(); + + if ( rTargetURL != pData->getTargetURL() ) + { + pData->setTargetURL( rTargetURL ); + pData->setUpdateLink( sal_True ); + } + } + + return pData; +} + +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +DocTemplates_EntryData_Impl::DocTemplates_EntryData_Impl( const OUString& rTitle ) +{ + maTitle = rTitle; + mbInUse = sal_False; + mbInHierarchy = sal_False; + mbUpdateType = sal_False; + mbUpdateLink = sal_False; +} + +// ----------------------------------------------------------------------- +SfxURLRelocator_Impl::SfxURLRelocator_Impl( uno::Reference< XMultiServiceFactory > xFactory ) +: mxFactory( xFactory ) +{ +} + +// ----------------------------------------------------------------------- +SfxURLRelocator_Impl::~SfxURLRelocator_Impl() +{ +} + +// ----------------------------------------------------------------------- +void SfxURLRelocator_Impl::initOfficeInstDirs() +{ + if ( !mxOfficeInstDirs.is() ) + { + osl::MutexGuard aGuard( maMutex ); + if ( !mxOfficeInstDirs.is() ) + { + OSL_ENSURE( mxFactory.is(), "No service manager!" ); + + uno::Reference< XComponentContext > xCtx; + uno::Reference< XPropertySet > xPropSet( mxFactory, UNO_QUERY ); + if ( xPropSet.is() ) + { + xPropSet->getPropertyValue( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ) + >>= xCtx; + } + + OSL_ENSURE( xCtx.is(), + "Unable to obtain component context from " + "service manager!" ); + + if ( xCtx.is() ) + { + xCtx->getValueByName( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "/singletons/" + "com.sun.star.util.theOfficeInstallationDirectories" ) ) ) + >>= mxOfficeInstDirs; + } + + OSL_ENSURE( mxOfficeInstDirs.is(), + "Unable to obtain office installation directory " + "singleton!" ); + } + } +} + +// ----------------------------------------------------------------------- +void SfxURLRelocator_Impl::makeRelocatableURL( rtl::OUString & rURL ) +{ + if ( rURL.getLength() > 0 ) + { + initOfficeInstDirs(); + rURL = mxOfficeInstDirs->makeRelocatableURL( rURL ); + } +} + +// ----------------------------------------------------------------------- +void SfxURLRelocator_Impl::makeAbsoluteURL( rtl::OUString & rURL ) +{ + if ( rURL.getLength() > 0 ) + { + initOfficeInstDirs(); + rURL = mxOfficeInstDirs->makeAbsoluteURL( rURL ); + } +} + + |