diff options
Diffstat (limited to 'sfx2/source/doc/doctempl.cxx')
-rw-r--r-- | sfx2/source/doc/doctempl.cxx | 2599 |
1 files changed, 2599 insertions, 0 deletions
diff --git a/sfx2/source/doc/doctempl.cxx b/sfx2/source/doc/doctempl.cxx new file mode 100644 index 000000000000..d28d0e6c5c72 --- /dev/null +++ b/sfx2/source/doc/doctempl.cxx @@ -0,0 +1,2599 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 <limits.h> +#include <com/sun/star/uno/Any.h> +#include <osl/mutex.hxx> +#include <osl/thread.hxx> + +#include <tools/resary.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/pathoptions.hxx> +#include <tools/string.hxx> +#include <tools/urlobj.hxx> +#include <svtools/ehdl.hxx> +#include <svtools/sfxecode.hxx> +#include <comphelper/processfactory.hxx> +#include <ucbhelper/content.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/XDocumentTemplates.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XPersist.hpp> +#include <com/sun/star/lang/XLocalizable.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/ContentInfo.hpp> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/ucb/XAnyCompare.hpp> +#include <com/sun/star/ucb/NumberedSortingInfo.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> + +#include "sfxurlrelocator.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::document; +using namespace ::rtl; +using namespace ::ucbhelper; + + +#include <sfx2/doctempl.hxx> +#include <sfx2/docfac.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/objsh.hxx> +#include "sfxtypes.hxx" +#include <sfx2/app.hxx> +#include "sfx2/sfxresid.hxx" +#include "doc.hrc" +#include <sfx2/fcontnr.hxx> +#include <svtools/templatefoldercache.hxx> + +#include <comphelper/storagehelper.hxx> +#include <unotools/ucbhelper.hxx> + +#include <vector> +using ::std::vector; +using ::std::advance; + +//======================================================================== + +// #define DONT_USE_HIERARCHY + +#define TITLE "Title" +#define IS_FOLDER "IsFolder" +#define PROPERTY_TYPE "TypeDescription" +#define TARGET_URL "TargetURL" +#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 TARGET_DIR_URL "TargetDirURL" +#define COMMAND_DELETE "delete" +#define COMMAND_TRANSFER "transfer" + +#define STANDARD_FOLDER "standard" + +#define SERVICENAME_TYPEDETECTION "com.sun.star.document.TypeDetection" +#define TYPEDETECTION_PARAMETER "FileName" +#define SERVICENAME_DOCINFO "com.sun.star.document.DocumentProperties" +#define SERVICENAME_DOCTEMPLATES "com.sun.star.frame.DocumentTemplates" +#define SERVICENAME_DESKTOP "com.sun.star.frame.Desktop" + +//======================================================================== + +class RegionData_Impl; + +namespace DocTempl { + +class DocTempl_EntryData_Impl +{ + RegionData_Impl* mpParent; + + // the following member must be SfxObjectShellLock since it controlls that SfxObjectShell lifetime by design + // and users of this class expect it to be so. + SfxObjectShellLock mxObjShell; + + OUString maTitle; + OUString maOwnURL; + OUString maTargetURL; + sal_Bool mbIsOwner : 1; + sal_Bool mbDidConvert: 1; + +private: + RegionData_Impl* GetParent() const { return mpParent; } + +public: + DocTempl_EntryData_Impl( RegionData_Impl* pParent, + const OUString& rTitle ); + + const OUString& GetTitle() const { return maTitle; } + const OUString& GetTargetURL(); + const OUString& GetHierarchyURL(); + + void SetTitle( const OUString& rTitle ) { maTitle = rTitle; } + void SetTargetURL( const OUString& rURL ) { maTargetURL = rURL; } + void SetHierarchyURL( const OUString& rURL) { maOwnURL = rURL; } + + int Compare( const OUString& rTitle ) const; + + SfxObjectShellRef CreateObjectShell(); + sal_Bool DeleteObjectShell(); +}; + +} + +using namespace ::DocTempl; + +// ------------------------------------------------------------------------ + +class RegionData_Impl +{ + const SfxDocTemplate_Impl* mpParent; + vector< DocTempl_EntryData_Impl* > maEntries; + OUString maTitle; + OUString maOwnURL; + OUString maTargetURL; + +private: + size_t GetEntryPos( const OUString& rTitle, + sal_Bool& rFound ) const; + const SfxDocTemplate_Impl* GetParent() const { return mpParent; } + +public: + RegionData_Impl( const SfxDocTemplate_Impl* pParent, + const OUString& rTitle ); + ~RegionData_Impl(); + + void SetTargetURL( const OUString& rURL ) { maTargetURL = rURL; } + void SetHierarchyURL( const OUString& rURL) { maOwnURL = rURL; } + + DocTempl_EntryData_Impl* GetEntry( size_t nIndex ) const; + DocTempl_EntryData_Impl* GetEntry( const OUString& rName ) const; + DocTempl_EntryData_Impl* GetByTargetURL( const OUString& rName ) const; + + const OUString& GetTitle() const { return maTitle; } + const OUString& GetTargetURL(); + const OUString& GetHierarchyURL(); + + size_t GetCount() const; + + void SetTitle( const OUString& rTitle ) { maTitle = rTitle; } + + void AddEntry( const OUString& rTitle, + const OUString& rTargetURL, + size_t *pPos = NULL ); + void DeleteEntry( size_t nIndex ); + + int Compare( const OUString& rTitle ) const + { return maTitle.compareTo( rTitle ); } + int Compare( RegionData_Impl* pCompareWith ) const; +}; + +typedef vector< RegionData_Impl* > RegionList_Impl; + +// ------------------------------------------------------------------------ + +class SfxDocTemplate_Impl : public SvRefBase +{ + uno::Reference< XPersist > mxInfo; + uno::Reference< XDocumentTemplates > mxTemplates; + + ::osl::Mutex maMutex; + OUString maRootURL; + OUString maStandardGroup; + RegionList_Impl maRegions; + sal_Bool mbConstructed; + + uno::Reference< XAnyCompareFactory > m_rCompareFactory; + + // the following member is intended to prevent clearing of the global data when it is in use + // TODO/LATER: it still does not make the implementation complete thread-safe + sal_Int32 mnLockCounter; + +private: + void Clear(); + +public: + SfxDocTemplate_Impl(); + ~SfxDocTemplate_Impl(); + + void IncrementLock(); + void DecrementLock(); + + sal_Bool Construct( ); + void CreateFromHierarchy( Content &rTemplRoot ); + void ReInitFromComponent(); + void AddRegion( const OUString& rTitle, + Content& rContent ); + + void Rescan(); + + void DeleteRegion( size_t nIndex ); + + size_t GetRegionCount() const + { return maRegions.size(); } + RegionData_Impl* GetRegion( const OUString& rName ) const; + RegionData_Impl* GetRegion( size_t nIndex ) const; + void GetTemplates( Content& rTargetFolder, + Content& rParentFolder, + RegionData_Impl* pRegion ); + + size_t GetRegionPos( const OUString& rTitle, sal_Bool& rFound ) const; + + sal_Bool GetTitleFromURL( const OUString& rURL, OUString& aTitle ); + sal_Bool InsertRegion( RegionData_Impl *pData, size_t nPos = size_t(-1) ); + OUString GetRootURL() const { return maRootURL; } + + uno::Reference< XDocumentTemplates > getDocTemplates() { return mxTemplates; } +}; + +// ------------------------------------------------------------------------ + +class DocTemplLocker_Impl +{ + SfxDocTemplate_Impl& m_aDocTempl; +public: + DocTemplLocker_Impl( SfxDocTemplate_Impl& aDocTempl ) + : m_aDocTempl( aDocTempl ) + { + m_aDocTempl.IncrementLock(); + } + + ~DocTemplLocker_Impl() + { + m_aDocTempl.DecrementLock(); + } +}; + +// ------------------------------------------------------------------------ + +#ifndef SFX_DECL_DOCTEMPLATES_DEFINED +#define SFX_DECL_DOCTEMPLATES_DEFINED +SV_DECL_REF(SfxDocTemplate_Impl) +#endif + +SV_IMPL_REF(SfxDocTemplate_Impl) + +// ------------------------------------------------------------------------ + +SfxDocTemplate_Impl *gpTemplateData = 0; + +// ----------------------------------------------------------------------- + +static sal_Bool getTextProperty_Impl( Content& rContent, + const OUString& rPropName, + OUString& rPropValue ); + +//======================================================================== + +String SfxDocumentTemplates::GetFullRegionName +( + sal_uInt16 nIdx // Region Index +) const + +/* [Description] + + Returns the logical name of a region and its path + + [Return value] Reference to the Region name + +*/ + +{ + // First: find the RegionData for the index + String aName; + + DocTemplLocker_Impl aLocker( *pImp ); + + if ( pImp->Construct() ) + { + RegionData_Impl *pData1 = pImp->GetRegion( nIdx ); + + if ( pData1 ) + aName = pData1->GetTitle(); + + // --**-- here was some code which appended the path to the + // group if there was more than one with the same name. + // this should not happen anymore + } + + return aName; +} + +//------------------------------------------------------------------------ + +const String& SfxDocumentTemplates::GetRegionName +( + sal_uInt16 nIdx // Region Index +) const + +/* [Description] + + Returns the logical name of a region + + [Return value] + + const String& Reference to the Region name + +*/ +{ + static String maTmpString; + + DocTemplLocker_Impl aLocker( *pImp ); + + if ( pImp->Construct() ) + { + RegionData_Impl *pData = pImp->GetRegion( nIdx ); + + if ( pData ) + maTmpString = pData->GetTitle(); + else + maTmpString.Erase(); + } + else + maTmpString.Erase(); + + return maTmpString; +} + + +//------------------------------------------------------------------------ + +sal_uInt16 SfxDocumentTemplates::GetRegionNo +( + const String &rRegion // Region Name +) const + +/* [Description] + + Returns the Index for a logical Region Name. + + [Return value] + + sal_uInt16 Index of 'rRegion' or USHRT_MAX if unknown + +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return USHRT_MAX; + + sal_Bool bFound; + size_t nIndex = pImp->GetRegionPos( rRegion, bFound ); + + if ( bFound ) + return (sal_uInt16) nIndex; + else + return USHRT_MAX; +} + + +//------------------------------------------------------------------------ + +sal_uInt16 SfxDocumentTemplates::GetRegionCount() const + +/* [Description] + + Returns the number of Regions + + [Return value] + + sal_uInt16 Number of Regions +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return 0; + + sal_uIntPtr nCount = pImp->GetRegionCount(); + + return (sal_uInt16) nCount; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::IsRegionLoaded( sal_uInt16 nIdx ) const +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return sal_False; + + RegionData_Impl *pData = pImp->GetRegion( nIdx ); + + if ( pData ) + return sal_True; + else + return sal_False; +} + +//------------------------------------------------------------------------ + +sal_uInt16 SfxDocumentTemplates::GetCount +( + const String& rName /* Region Name, for which the entries + should be counted */ + +) const + +/* [Description] + + Number of entries in Region + + [Return value] + + sal_uInt16 Number of entries +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return 0; + + RegionData_Impl *pData = pImp->GetRegion( rName ); + sal_uIntPtr nCount = 0; + + if ( pData ) + nCount = pData->GetCount(); + + return (sal_uInt16) nCount; +} + +//------------------------------------------------------------------------ + +sal_uInt16 SfxDocumentTemplates::GetCount +( + sal_uInt16 nRegion /* Region index whose number is + to be determined */ + +) const + +/* [Description] + + Number of entries in Region + + [Return value] Number of entries +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return 0; + + RegionData_Impl *pData = pImp->GetRegion( nRegion ); + sal_uIntPtr nCount = 0; + + if ( pData ) + nCount = pData->GetCount(); + + return (sal_uInt16) nCount; +} + +//------------------------------------------------------------------------ + +const String& SfxDocumentTemplates::GetName +( + sal_uInt16 nRegion, // Region Index, in which the entry lies + sal_uInt16 nIdx // Index of the entry +) const + +/* [Description] + + Returns the logical name of an entry in Region + + [Return value] + + const String& Entry Name +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + static String maTmpString; + + if ( pImp->Construct() ) + { + DocTempl_EntryData_Impl *pEntry = NULL; + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + if ( pRegion ) + pEntry = pRegion->GetEntry( nIdx ); + + if ( pEntry ) + maTmpString = pEntry->GetTitle(); + else + maTmpString.Erase(); + } + else + maTmpString.Erase(); + + return maTmpString; +} + +//------------------------------------------------------------------------ + +String SfxDocumentTemplates::GetFileName +( + sal_uInt16 nRegion, // Region Index, in which the entry lies + sal_uInt16 nIdx // Index of the entry +) const + +/* [Description] + + Returns the file name of an entry in Region + + [Return value] File name of the entry +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return String(); + + DocTempl_EntryData_Impl *pEntry = NULL; + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + if ( pRegion ) + pEntry = pRegion->GetEntry( nIdx ); + + if ( pEntry ) + { + INetURLObject aURLObj( pEntry->GetTargetURL() ); + return aURLObj.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ); + } + else + return String(); +} + +//------------------------------------------------------------------------ + +String SfxDocumentTemplates::GetPath +( + sal_uInt16 nRegion, // Region Index, in which the entry lies + sal_uInt16 nIdx // Index of the entry +) const + +/* [Description] + + Returns the file name with full path to the file assigned to an entry + + [Return value] + + String File name with full path +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return String(); + + DocTempl_EntryData_Impl *pEntry = NULL; + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + if ( pRegion ) + pEntry = pRegion->GetEntry( nIdx ); + + if ( pEntry ) + return pEntry->GetTargetURL(); + else + return String(); +} + +//------------------------------------------------------------------------ + +String SfxDocumentTemplates::GetTemplatePath +( + sal_uInt16 nRegion, // Region Index, in which the entry lies + const String& rLongName // logical Entry Name +) const + +/* [Description] + + Returns the file name with full path to the file assigned to an entry + + [Return value] + + String File name with full path +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return String(); + + DocTempl_EntryData_Impl *pEntry = NULL; + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + if ( pRegion ) + pEntry = pRegion->GetEntry( rLongName ); + + if ( pEntry ) + return pEntry->GetTargetURL(); + else if ( pRegion ) + { + // a new template is going to be inserted, generate a new URL + // TODO/LATER: if the title is localized, use minimized URL in future + + // --**-- extension handling will become more complicated, because + // every new document type will have it's own extension + // e.g.: .stw or .stc instead of .vor + INetURLObject aURLObj( pRegion->GetTargetURL() ); + aURLObj.insertName( rLongName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + OUString aExtension = aURLObj.getExtension(); + + if ( ! aExtension.getLength() ) + aURLObj.setExtension( OUString( RTL_CONSTASCII_USTRINGPARAM( "vor" ) ) ); + + return aURLObj.GetMainURL( INetURLObject::NO_DECODE ); + } + else + return String(); +} + +//------------------------------------------------------------------------ + +String SfxDocumentTemplates::GetDefaultTemplatePath +( + const String& rLongName +) + +/* [Description] + + Returns the default location for templates + + [Return value] + + String Default location for templates +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return String(); + + // the first region in the list should always be the standard + // group + // --**-- perhaps we have to create it ??? + RegionData_Impl *pRegion = pImp->GetRegion( 0L ); + DocTempl_EntryData_Impl *pEntry = NULL; + + if ( pRegion ) + pEntry = pRegion->GetEntry( rLongName ); + + if ( pEntry ) + return pEntry->GetTargetURL(); + else if ( pRegion ) + { + // a new template is going to be inserted, generate a new URL + // TODO/LATER: if the title is localized, use minimized URL in future + + INetURLObject aURLObj( pRegion->GetTargetURL() ); + aURLObj.insertName( rLongName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + OUString aExtension = aURLObj.getExtension(); + + if ( ! aExtension.getLength() ) + aURLObj.setExtension( OUString( RTL_CONSTASCII_USTRINGPARAM( "vor" ) ) ); + + return aURLObj.GetMainURL( INetURLObject::NO_DECODE ); + } + else + return String(); + +} + +//------------------------------------------------------------------------ + +::rtl::OUString SfxDocumentTemplates::GetTemplateTargetURLFromComponent( const ::rtl::OUString& aGroupName, + const ::rtl::OUString& aTitle ) +{ + DocTemplLocker_Impl aLocker( *pImp ); + + INetURLObject aTemplateObj( pImp->GetRootURL() ); + + aTemplateObj.insertName( aGroupName, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + aTemplateObj.insertName( aTitle, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + + ::rtl::OUString aResult; + Content aTemplate; + uno::Reference< XCommandEnvironment > aCmdEnv; + if ( Content::create( aTemplateObj.GetMainURL( INetURLObject::NO_DECODE ), aCmdEnv, aTemplate ) ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + getTextProperty_Impl( aTemplate, aPropName, aResult ); + aResult = SvtPathOptions().SubstituteVariable( aResult ); + } + + return aResult; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::SaveDir +( +// SfxTemplateDir& rDir // Save Directory +) + +/* [Description] + + Saves the Directory rDir + + [Return value] + + sal_Bool sal_False, Write error + sal_True, Saved +*/ + +{ + return sal_True; +} + +//------------------------------------------------------------------------ + +void SfxDocumentTemplates::NewTemplate +( + sal_uInt16 nRegion, /* Region Index, in which the template + should be applied */ + + const String& rLongName, // logical name of the new template + const String& rFileName // File name of the new template +) + +/* [Description] + + Submit a new template in the administrative structures + overwriting a template of the same name is prevented (! Error message) +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return; + + DocTempl_EntryData_Impl *pEntry; + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + // do nothing if there is no region with that index + if ( !pRegion ) + return; + + pEntry = pRegion->GetEntry( rLongName ); + + // do nothing if there is already an entry with that name + if ( pEntry ) + return; + + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + + if ( xTemplates->addTemplate( pRegion->GetTitle(), rLongName, rFileName ) ) + pRegion->AddEntry( rLongName, rFileName ); +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::CopyOrMove +( + sal_uInt16 nTargetRegion, // Target Region Index + sal_uInt16 nTargetIdx, // Target position Index + sal_uInt16 nSourceRegion, // Source Region Index + sal_uInt16 nSourceIdx, /* Index to be copied / to moved template */ + sal_Bool bMove // Copy / Move +) + +/* [Description] + + Copy or move a document template + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxDocumentTemplates::Move(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)> + <SfxDocumentTemplates::Copy(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16)> +*/ + +{ + /* to perform a copy or move, we need to send a transfer command to + the destination folder with the URL of the source as parameter. + ( If the destination content doesn't support the transfer command, + we could try a copy ( and delete ) instead. ) + We need two transfers ( one for the real template and one for its + representation in the hierarchy ) + ... + */ + + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return sal_False; + + // Don't copy or move any folders + if( nSourceIdx == USHRT_MAX ) + return sal_False ; + + if ( nSourceRegion == nTargetRegion ) + { + DBG_ERRORFILE( "Don't know, what to do!" ); + return sal_False; + } + + RegionData_Impl *pSourceRgn = pImp->GetRegion( nSourceRegion ); + if ( !pSourceRgn ) + return sal_False; + + DocTempl_EntryData_Impl *pSource = pSourceRgn->GetEntry( nSourceIdx ); + if ( !pSource ) + return sal_False; + + RegionData_Impl *pTargetRgn = pImp->GetRegion( nTargetRegion ); + if ( !pTargetRgn ) + return sal_False; + + OUString aTitle = pSource->GetTitle(); + + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + + if ( xTemplates->addTemplate( pTargetRgn->GetTitle(), + aTitle, + pSource->GetTargetURL() ) ) + { + + INetURLObject aSourceObj( pSource->GetTargetURL() ); + + ::rtl::OUString aNewTargetURL = GetTemplateTargetURLFromComponent( pTargetRgn->GetTitle(), aTitle ); + if ( !aNewTargetURL.getLength() ) + return sal_False; + + if ( bMove ) + { + // --**-- delete the original file + sal_Bool bDeleted = xTemplates->removeTemplate( pSourceRgn->GetTitle(), + pSource->GetTitle() ); + if ( bDeleted ) + pSourceRgn->DeleteEntry( nSourceIdx ); + else + { + if ( xTemplates->removeTemplate( pTargetRgn->GetTitle(), aTitle ) ) + return sal_False; // will trigger tetry with copy instead of move + + // if it is not possible to remove just created template ( must be possible! ) + // it is better to report success here, since at least the copy has succeeded + // TODO/LATER: solve it more gracefully in future + } + } + + // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16 + size_t temp_nTargetIdx = nTargetIdx; + pTargetRgn->AddEntry( aTitle, aNewTargetURL, &temp_nTargetIdx ); + + return sal_True; + } + + // --**-- if the current file is opened, + // it must be re-opened afterwards. + + return sal_False; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::Move +( + sal_uInt16 nTargetRegion, // Target Region Index + sal_uInt16 nTargetIdx, // Target position Index + sal_uInt16 nSourceRegion, // Source Region Index + sal_uInt16 nSourceIdx /* Index to be copied / to moved template */ +) + +/* [Description] + + Moving a template + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)> +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + return CopyOrMove( nTargetRegion, nTargetIdx, + nSourceRegion, nSourceIdx, sal_True ); +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::Copy +( + sal_uInt16 nTargetRegion, // Target Region Index + sal_uInt16 nTargetIdx, // Target position Index + sal_uInt16 nSourceRegion, // Source Region Index + sal_uInt16 nSourceIdx /* Index to be copied / to moved template */ +) + +/* [Description] + + Copying a template + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxDocumentTemplates::CopyOrMove(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16,sal_Bool)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + return CopyOrMove( nTargetRegion, nTargetIdx, + nSourceRegion, nSourceIdx, sal_False ); +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::CopyTo +( + sal_uInt16 nRegion, // Region of the template to be exported + sal_uInt16 nIdx, // Index of the template to be exported + const String& rName /* File name under which the template is to + be created */ +) const + +/* [Description] + + Exporting a template into the file system + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxDocumentTemplates::CopyFrom(sal_uInt16,sal_uInt16,String&)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_False; + + RegionData_Impl *pSourceRgn = pImp->GetRegion( nRegion ); + if ( !pSourceRgn ) + return sal_False; + + DocTempl_EntryData_Impl *pSource = pSourceRgn->GetEntry( nIdx ); + if ( !pSource ) + return sal_False; + + INetURLObject aTargetURL( rName ); + + OUString aTitle( aTargetURL.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ) ); + aTargetURL.removeSegment(); + + OUString aParentURL = aTargetURL.GetMainURL( INetURLObject::NO_DECODE ); + + uno::Reference< XCommandEnvironment > aCmdEnv; + Content aTarget; + + try + { + aTarget = Content( aParentURL, aCmdEnv ); + + TransferInfo aTransferInfo; + aTransferInfo.MoveData = sal_False; + aTransferInfo.SourceURL = pSource->GetTargetURL(); + aTransferInfo.NewTitle = aTitle; + aTransferInfo.NameClash = NameClash::OVERWRITE; + + Any aArg = makeAny( aTransferInfo ); + OUString aCmd( RTL_CONSTASCII_USTRINGPARAM( COMMAND_TRANSFER ) ); + + aTarget.executeCommand( aCmd, aArg ); + } + catch ( ContentCreationException& ) + { return sal_False; } + catch ( Exception& ) + { return sal_False; } + + return sal_True; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::CopyFrom +( + sal_uInt16 nRegion, /* Region in which the template is to be + imported */ + sal_uInt16 nIdx, // Index of the new template in this Region + String& rName /* File name of the template to be imported + as an out parameter of the (automatically + generated from the file name) logical name + of the template */ +) + +/* [Description] + + Import a template from the file system + + [Return value] Sucess (sal_True) or serfpTargetDirectory->GetContent()); + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxDocumentTemplates::CopyTo(sal_uInt16,sal_uInt16,const String&)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_False; + + RegionData_Impl *pTargetRgn = pImp->GetRegion( nRegion ); + + if ( !pTargetRgn ) + return sal_False; + + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + if ( !xTemplates.is() ) + return sal_False; + + OUString aTitle; + sal_Bool bTemplateAdded = sal_False; + + if( pImp->GetTitleFromURL( rName, aTitle ) ) + { + bTemplateAdded = xTemplates->addTemplate( pTargetRgn->GetTitle(), aTitle, rName ); + } + else + { + OUString aService( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_DESKTOP ) ); + uno::Reference< XComponentLoader > xDesktop( ::comphelper::getProcessServiceFactory()->createInstance( aService ), + UNO_QUERY ); + + Sequence< PropertyValue > aArgs( 1 ); + aArgs[0].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Hidden")); + aArgs[0].Value <<= sal_True; + + INetURLObject aTemplURL( rName ); + uno::Reference< XDocumentPropertiesSupplier > xDocPropsSupplier; + uno::Reference< XStorable > xStorable; + try + { + xStorable = uno::Reference< XStorable >( + xDesktop->loadComponentFromURL( aTemplURL.GetMainURL(INetURLObject::NO_DECODE), + OUString(RTL_CONSTASCII_USTRINGPARAM("_blank")), + 0, + aArgs ), + UNO_QUERY ); + + xDocPropsSupplier = uno::Reference< XDocumentPropertiesSupplier >( + xStorable, UNO_QUERY ); + } + catch( Exception& ) + { + } + + if( xStorable.is() ) + { + // get Title from XDocumentPropertiesSupplier + if( xDocPropsSupplier.is() ) + { + uno::Reference< XDocumentProperties > xDocProps + = xDocPropsSupplier->getDocumentProperties(); + if (xDocProps.is() ) { + aTitle = xDocProps->getTitle(); + } + } + + if( ! aTitle.getLength() ) + { + INetURLObject aURL( aTemplURL ); + aURL.CutExtension(); + aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ); + } + + // write a template using XStorable interface + bTemplateAdded = xTemplates->storeTemplate( pTargetRgn->GetTitle(), aTitle, xStorable ); + } + } + + + if( bTemplateAdded ) + { + INetURLObject aTemplObj( pTargetRgn->GetHierarchyURL() ); + aTemplObj.insertName( aTitle, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + OUString aTemplURL = aTemplObj.GetMainURL( INetURLObject::NO_DECODE ); + + uno::Reference< XCommandEnvironment > aCmdEnv; + Content aTemplCont; + + if( Content::create( aTemplURL, aCmdEnv, aTemplCont ) ) + { + OUString aTemplName; + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + + if( getTextProperty_Impl( aTemplCont, aPropName, aTemplName ) ) + { + if ( nIdx == USHRT_MAX ) + nIdx = 0; + else + nIdx += 1; + + // todo: fix SfxDocumentTemplates to handle size_t instead of sal_uInt16 + size_t temp_nIdx = nIdx; + pTargetRgn->AddEntry( aTitle, aTemplName, &temp_nIdx ); + rName = aTitle; + return sal_True; + } + else + { + DBG_ASSERT( sal_False, "CopyFrom(): The content should contain target URL!" ); + } + } + else + { + DBG_ASSERT( sal_False, "CopyFrom(): The content just was created!" ); + } + } + + return sal_False; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::Delete +( + sal_uInt16 nRegion, // Region Index + sal_uInt16 nIdx /* Index of the entry or USHRT_MAX, + if a directory is meant. */ +) + +/* [Description] + + Deleting an entry or a directory + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxDocumentTemplates::InsertDir(const String&,sal_uInt16)> + <SfxDocumentTemplates::KillDir(SfxTemplateDir&)> + <SfxDocumentTemplates::SaveDir(SfxTemplateDir&)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + /* delete the template or folder in the hierarchy and in the + template folder by sending a delete command to the content. + Then remove the data from the lists + */ + if ( ! pImp->Construct() ) + return sal_False; + + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + + if ( !pRegion ) + return sal_False; + + sal_Bool bRet; + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + + if ( nIdx == USHRT_MAX ) + { + bRet = xTemplates->removeGroup( pRegion->GetTitle() ); + if ( bRet ) + pImp->DeleteRegion( nRegion ); + } + else + { + DocTempl_EntryData_Impl *pEntry = pRegion->GetEntry( nIdx ); + + if ( !pEntry ) + return sal_False; + + bRet = xTemplates->removeTemplate( pRegion->GetTitle(), + pEntry->GetTitle() ); + if( bRet ) + pRegion->DeleteEntry( nIdx ); + } + + return bRet; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::InsertDir +( + const String& rText, // the logical name of the new Region + sal_uInt16 nRegion // Region Index +) + +/* [Description] + + Insert an index + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxDocumentTemplates::KillDir(SfxTemplateDir&)> + <SfxDocumentTemplates::SaveDir(SfxTemplateDir&)> +*/ +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_False; + + RegionData_Impl *pRegion = pImp->GetRegion( rText ); + + if ( pRegion ) + return sal_False; + + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + + if ( xTemplates->addGroup( rText ) ) + { + RegionData_Impl* pNewRegion = new RegionData_Impl( pImp, rText ); + + if ( ! pImp->InsertRegion( pNewRegion, nRegion ) ) + { + delete pNewRegion; + return sal_False; + } + return sal_True; + } + + return sal_False; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::SetName +( + const String& rName, // Der zu setzende Name + sal_uInt16 nRegion, // Region Index + sal_uInt16 nIdx /* Index of the entry oder USHRT_MAX, + if a directory is meant. */ +) + +/* [Description] + + Change the name of an entry or a directory + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_False; + + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + DocTempl_EntryData_Impl *pEntry = NULL; + + if ( !pRegion ) + return sal_False; + + uno::Reference< XDocumentTemplates > xTemplates = pImp->getDocTemplates(); + OUString aEmpty; + + if ( nIdx == USHRT_MAX ) + { + if ( pRegion->GetTitle() == OUString( rName ) ) + return sal_True; + + // we have to rename a region + if ( xTemplates->renameGroup( pRegion->GetTitle(), rName ) ) + { + pRegion->SetTitle( rName ); + pRegion->SetTargetURL( aEmpty ); + pRegion->SetHierarchyURL( aEmpty ); + return sal_True; + } + } + else + { + pEntry = pRegion->GetEntry( nIdx ); + + if ( !pEntry ) + return sal_False; + + if ( pEntry->GetTitle() == OUString( rName ) ) + return sal_True; + + if ( xTemplates->renameTemplate( pRegion->GetTitle(), + pEntry->GetTitle(), + rName ) ) + { + pEntry->SetTitle( rName ); + pEntry->SetTargetURL( aEmpty ); + pEntry->SetHierarchyURL( aEmpty ); + return sal_True; + } + } + + return sal_False; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::Rescan() + +/* [Description] + + Comparison of administrative data with the current state on disk. + The logical name for which no file exists, will be removed from the + administrative structure. Files for which no record exists will be included. + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxTemplateDir::Scan(sal_Bool bDirectory, sal_Bool bSave)> + <SfxTemplateDir::Freshen(const SfxTemplateDir &rNew)> +*/ +{ + if ( !pImp->Construct() ) + return sal_False; + + pImp->Rescan(); + + return sal_True; +} + +//------------------------------------------------------------------------ + +SfxObjectShellRef SfxDocumentTemplates::CreateObjectShell +( + sal_uInt16 nRegion, // Region Index + sal_uInt16 nIdx // Index of the entry +) + +/* [Description] + + Access to the document shell of an entry + + [Return value] + + SfxObjectShellRef Referece to the ObjectShell + + [Cross-references] + + <SfxTemplateDirEntry::CreateObjectShell()> + <SfxDocumentTemplates::DeleteObjectShell(sal_uInt16, sal_uInt16)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( !pImp->Construct() ) + return NULL; + + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + DocTempl_EntryData_Impl *pEntry = NULL; + + if ( pRegion ) + pEntry = pRegion->GetEntry( nIdx ); + + if ( pEntry ) + return pEntry->CreateObjectShell(); + else + return NULL; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::DeleteObjectShell +( + sal_uInt16 nRegion, // Region Index + sal_uInt16 nIdx // Index of the entry +) + +/* [Description] + + Releasing the ObjectShell of an entry + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxTemplateDirEntry::DeleteObjectShell()> + <SfxDocumentTemplates::CreateObjectShell(sal_uInt16, sal_uInt16)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_True; + + RegionData_Impl *pRegion = pImp->GetRegion( nRegion ); + DocTempl_EntryData_Impl *pEntry = NULL; + + if ( pRegion ) + pEntry = pRegion->GetEntry( nIdx ); + + if ( pEntry ) + return pEntry->DeleteObjectShell(); + else + return sal_True; +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::GetFull +( + const String &rRegion, // Region Name + const String &rName, // Template Name + String &rPath // Out: Path + File name +) + +/* [Description] + + Returns Path + File name of the template specified by rRegion and rName. + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxDocumentTemplates::GetLogicNames(const String&,String&,String&)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + // We don't search for empty names! + if ( ! rName.Len() ) + return sal_False; + + if ( ! pImp->Construct() ) + return sal_False; + + DocTempl_EntryData_Impl* pEntry = NULL; + const sal_uInt16 nCount = GetRegionCount(); + + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + RegionData_Impl *pRegion = pImp->GetRegion( i ); + + if( pRegion && + ( !rRegion.Len() || ( rRegion == String( pRegion->GetTitle() ) ) ) ) + { + pEntry = pRegion->GetEntry( rName ); + + if ( pEntry ) + { + rPath = pEntry->GetTargetURL(); + break; + } + } + } + + return ( pEntry != NULL ); +} + +//------------------------------------------------------------------------ + +sal_Bool SfxDocumentTemplates::GetLogicNames +( + const String &rPath, // Full Path to the template + String &rRegion, // Out: Region name + String &rName // Out: Template name +) const + +/* [Description] + + Returns and logical path name to the template specified by rPath + + [Return value] + + sal_Bool sal_True, Action could be performed + sal_False, Action could not be performed + + [Cross-references] + + <SfxDocumentTemplates::GetFull(const String&,const String&,DirEntry&)> +*/ + +{ + DocTemplLocker_Impl aLocker( *pImp ); + + if ( ! pImp->Construct() ) + return sal_False; + + INetURLObject aFullPath; + + aFullPath.SetSmartProtocol( INET_PROT_FILE ); + aFullPath.SetURL( rPath ); + OUString aPath( aFullPath.GetMainURL( INetURLObject::NO_DECODE ) ); + + RegionData_Impl *pData = NULL; + DocTempl_EntryData_Impl *pEntry = NULL; + sal_Bool bFound = sal_False; + + sal_uIntPtr nCount = GetRegionCount(); + + for ( sal_uIntPtr i=0; !bFound && (i<nCount); i++ ) + { + pData = pImp->GetRegion( i ); + if ( pData ) + { + sal_uIntPtr nChildCount = pData->GetCount(); + + for ( sal_uIntPtr j=0; !bFound && (j<nChildCount); j++ ) + { + pEntry = pData->GetEntry( j ); + if ( pEntry->GetTargetURL() == aPath ) + { + bFound = sal_True; + } + } + } + } + + if ( bFound ) + { + rRegion = pData->GetTitle(); + rName = pEntry->GetTitle(); + } + + return bFound; +} + +//------------------------------------------------------------------------ + +SfxDocumentTemplates::SfxDocumentTemplates() + +/* [Description] + + Constructor +*/ +{ + if ( !gpTemplateData ) + gpTemplateData = new SfxDocTemplate_Impl; + + pImp = gpTemplateData; +} + +//------------------------------------------------------------------------- + +void SfxDocumentTemplates::Construct() + +// Delayed build-up of administrative data + +{ +} + +//------------------------------------------------------------------------ + +SfxDocumentTemplates::~SfxDocumentTemplates() + +/* [Description] + + Destructor + Release of administrative data +*/ + +{ + pImp = NULL; +} + +void SfxDocumentTemplates::Update( sal_Bool _bSmart ) +{ + if ( !_bSmart // don't be smart + || ::svt::TemplateFolderCache( sal_True ).needsUpdate() // update is really necessary + ) + { + if ( pImp->Construct() ) + pImp->Rescan(); + } +} + +void SfxDocumentTemplates::ReInitFromComponent() +{ + pImp->ReInitFromComponent(); +} + + +sal_Bool SfxDocumentTemplates::HasUserContents( sal_uInt16 nRegion, sal_uInt16 nIdx ) const +{ + DocTemplLocker_Impl aLocker( *pImp ); + + sal_Bool bResult = sal_False; + + RegionData_Impl* pRegion = pImp->GetRegion( nRegion ); + + if ( pRegion ) + { + ::rtl::OUString aRegionTargetURL = pRegion->GetTargetURL(); + if ( aRegionTargetURL.getLength() ) + { + sal_uInt16 nLen = 0; + sal_uInt16 nStartInd = 0; + + if( nIdx == USHRT_MAX ) + { + // this is a folder + // check whether there is at least one editable template + nLen = ( sal_uInt16 )pRegion->GetCount(); + nStartInd = 0; + if ( nLen == 0 ) + bResult = sal_True; // the writing part of empty folder with writing URL can be removed + } + else + { + // this is a template + // check whether the template is inserted by user + nLen = 1; + nStartInd = nIdx; + } + + for ( sal_uInt16 nInd = nStartInd; nInd < nStartInd + nLen; nInd++ ) + { + DocTempl_EntryData_Impl* pEntryData = pRegion->GetEntry( nInd ); + if ( pEntryData ) + { + ::rtl::OUString aEntryTargetURL = pEntryData->GetTargetURL(); + if ( aEntryTargetURL.getLength() + && ::utl::UCBContentHelper::IsSubPath( aRegionTargetURL, aEntryTargetURL ) ) + { + bResult = sal_True; + break; + } + } + } + } + } + + return bResult; +} + +// ----------------------------------------------------------------------- +DocTempl_EntryData_Impl::DocTempl_EntryData_Impl( RegionData_Impl* pParent, + const OUString& rTitle ) +{ + mpParent = pParent; + maTitle = rTitle; + mbIsOwner = sal_False; + mbDidConvert= sal_False; +} + +// ----------------------------------------------------------------------- +int DocTempl_EntryData_Impl::Compare( const OUString& rTitle ) const +{ + return maTitle.compareTo( rTitle ); +} + +//------------------------------------------------------------------------ +SfxObjectShellRef DocTempl_EntryData_Impl::CreateObjectShell() +{ + if( ! mxObjShell.Is() ) + { + mbIsOwner = sal_False; + sal_Bool bDum = sal_False; + SfxApplication *pSfxApp = SFX_APP(); + String aTargetURL = GetTargetURL(); + + mxObjShell = pSfxApp->DocAlreadyLoaded( aTargetURL, sal_True, bDum ); + + if( ! mxObjShell.Is() ) + { + mbIsOwner = sal_True; + SfxMedium *pMed=new SfxMedium( + aTargetURL,(STREAM_STD_READWRITE | STREAM_SHARE_DENYALL), sal_False, 0 ); + const SfxFilter* pFilter = NULL; + pMed->UseInteractionHandler(sal_True); + if( pSfxApp->GetFilterMatcher().GuessFilter( + *pMed, &pFilter, SFX_FILTER_TEMPLATE, 0 ) || + (pFilter && !pFilter->IsOwnFormat()) || + (pFilter && !pFilter->UsesStorage()) ) + { + SfxErrorContext aEc( ERRCTX_SFX_LOADTEMPLATE, + aTargetURL ); + delete pMed; + mbDidConvert=sal_True; + sal_uIntPtr lErr; + if ( mxObjShell.Is() ) { + lErr = pSfxApp->LoadTemplate( mxObjShell,aTargetURL); + if( lErr != ERRCODE_NONE ) + ErrorHandler::HandleError(lErr); + } + + } + else if (pFilter) + { + mbDidConvert=sal_False; + mxObjShell = SfxObjectShell::CreateObject( pFilter->GetServiceName(), SFX_CREATE_MODE_ORGANIZER ); + if ( mxObjShell.Is() ) + { + mxObjShell->DoInitNew(0); + // TODO/LATER: make sure that we don't use binary templates! + if( mxObjShell->LoadFrom( *pMed ) ) + { + mxObjShell->DoSaveCompleted( pMed ); + } + else + mxObjShell.Clear(); + } + } + } + } + + return (SfxObjectShellRef)(SfxObjectShell*) mxObjShell; +} + +//------------------------------------------------------------------------ +sal_Bool DocTempl_EntryData_Impl::DeleteObjectShell() +{ + sal_Bool bRet = sal_True; + + if ( mxObjShell.Is() ) + { + if( mxObjShell->IsModified() ) + { + // Here we also save, if the Template is being processed ... + bRet = sal_False; + + if ( mbIsOwner ) + { + if( mbDidConvert ) + { + bRet=mxObjShell->PreDoSaveAs_Impl( + GetTargetURL(), + mxObjShell->GetFactory().GetFilterContainer()->GetAnyFilter( SFX_FILTER_EXPORT | SFX_FILTER_IMPORT, SFX_FILTER_INTERNAL )->GetFilterName(), 0 ); + } + else + { + if( mxObjShell->Save() ) + { + uno::Reference< embed::XTransactedObject > xTransacted( mxObjShell->GetStorage(), uno::UNO_QUERY ); + DBG_ASSERT( xTransacted.is(), "Storage must implement XTransactedObject!\n" ); + if ( xTransacted.is() ) + { + try + { + xTransacted->commit(); + bRet = sal_True; + } + catch( uno::Exception& ) + { + } + } + } + } + } + } + + if( bRet ) + { + mxObjShell.Clear(); + } + } + return bRet; +} + +// ----------------------------------------------------------------------- +const OUString& DocTempl_EntryData_Impl::GetHierarchyURL() +{ + if ( !maOwnURL.getLength() ) + { + INetURLObject aTemplateObj( GetParent()->GetHierarchyURL() ); + + aTemplateObj.insertName( GetTitle(), false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + maOwnURL = aTemplateObj.GetMainURL( INetURLObject::NO_DECODE ); + DBG_ASSERT( maOwnURL.getLength(), "GetHierarchyURL(): Could not create URL!" ); + } + + return maOwnURL; +} + +// ----------------------------------------------------------------------- +const OUString& DocTempl_EntryData_Impl::GetTargetURL() +{ + if ( !maTargetURL.getLength() ) + { + uno::Reference< XCommandEnvironment > aCmdEnv; + Content aRegion; + + if ( Content::create( GetHierarchyURL(), aCmdEnv, aRegion ) ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_URL ) ); + + getTextProperty_Impl( aRegion, aPropName, maTargetURL ); + } + else + { + DBG_ERRORFILE( "GetTargetURL(): Could not create hierarchy content!" ); + } + } + + return maTargetURL; +} + +// ----------------------------------------------------------------------- +RegionData_Impl::RegionData_Impl( const SfxDocTemplate_Impl* pParent, + const OUString& rTitle ) +{ + maTitle = rTitle; + mpParent = pParent; +} + +// ----------------------------------------------------------------------- +RegionData_Impl::~RegionData_Impl() +{ + for ( size_t i = 0, n = maEntries.size(); i < n; ++i ) + delete maEntries[ i ]; + maEntries.clear(); +} + +// ----------------------------------------------------------------------- +size_t RegionData_Impl::GetEntryPos( const OUString& rTitle, sal_Bool& rFound ) const +{ +#if 1 // Don't use binary search today + size_t i; + size_t nCount = maEntries.size(); + + for ( i=0; i<nCount; i++ ) + { + DocTempl_EntryData_Impl *pData = maEntries[ i ]; + + if ( pData->Compare( rTitle ) == 0 ) + { + rFound = sal_True; + return i; + } + } + + rFound = sal_False; + return i; + +#else + // use binary search to find the correct position + // in the maEntries list + + int nCompVal = 1; + size_t nStart = 0; + size_t nEnd = maEntries.size() - 1; + size_t nMid; + + DocTempl_EntryData_Impl* pMid; + + rFound = sal_False; + + while ( nCompVal && ( nStart <= nEnd ) ) + { + nMid = ( nEnd - nStart ) / 2 + nStart; + pMid = maEntries[ nMid ]; + + nCompVal = pMid->Compare( rTitle ); + + if ( nCompVal < 0 ) // pMid < pData + nStart = nMid + 1; + else + nEnd = nMid - 1; + } + + if ( nCompVal == 0 ) + { + rFound = sal_True; + } + else + { + if ( nCompVal < 0 ) // pMid < pData + nMid++; + } + + return nMid; +#endif +} + +// ----------------------------------------------------------------------- +void RegionData_Impl::AddEntry( const OUString& rTitle, + const OUString& rTargetURL, + size_t *pPos ) +{ + INetURLObject aLinkObj( GetHierarchyURL() ); + aLinkObj.insertName( rTitle, false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + OUString aLinkURL = aLinkObj.GetMainURL( INetURLObject::NO_DECODE ); + + DocTempl_EntryData_Impl* pEntry; + sal_Bool bFound = sal_False; + size_t nPos = GetEntryPos( rTitle, bFound ); + + if ( bFound ) + { + pEntry = maEntries[ nPos ]; + } + else + { + if ( pPos ) + nPos = *pPos; + + pEntry = new DocTempl_EntryData_Impl( this, rTitle ); + pEntry->SetTargetURL( rTargetURL ); + pEntry->SetHierarchyURL( aLinkURL ); + if ( nPos < maEntries.size() ) { + vector< DocTempl_EntryData_Impl* >::iterator it = maEntries.begin(); + advance( it, nPos ); + maEntries.insert( it, pEntry ); + } + else + maEntries.push_back( pEntry ); + } +} + +// ----------------------------------------------------------------------- +size_t RegionData_Impl::GetCount() const +{ + return maEntries.size(); +} + +// ----------------------------------------------------------------------- +const OUString& RegionData_Impl::GetHierarchyURL() +{ + if ( !maOwnURL.getLength() ) + { + INetURLObject aRegionObj( GetParent()->GetRootURL() ); + + aRegionObj.insertName( GetTitle(), false, + INetURLObject::LAST_SEGMENT, true, + INetURLObject::ENCODE_ALL ); + + maOwnURL = aRegionObj.GetMainURL( INetURLObject::NO_DECODE ); + DBG_ASSERT( maOwnURL.getLength(), "GetHierarchyURL(): Could not create URL!" ); + } + + return maOwnURL; +} + +// ----------------------------------------------------------------------- +const OUString& RegionData_Impl::GetTargetURL() +{ + if ( !maTargetURL.getLength() ) + { + uno::Reference< XCommandEnvironment > aCmdEnv; + Content aRegion; + + if ( Content::create( GetHierarchyURL(), aCmdEnv, aRegion ) ) + { + OUString aPropName( RTL_CONSTASCII_USTRINGPARAM( TARGET_DIR_URL ) ); + + getTextProperty_Impl( aRegion, aPropName, maTargetURL ); + // The targeturl must be substituted: $(baseinsturl) (#i32656#) + maTargetURL = SvtPathOptions().SubstituteVariable( maTargetURL ); + } + else + { + DBG_ERRORFILE( "GetTargetURL(): Could not create hierarchy content!" ); + } + } + + return maTargetURL; +} + +// ----------------------------------------------------------------------- +DocTempl_EntryData_Impl* RegionData_Impl::GetEntry( const OUString& rName ) const +{ + sal_Bool bFound = sal_False; + long nPos = GetEntryPos( rName, bFound ); + + if ( bFound ) + return maEntries[ nPos ]; + else + return NULL; +} + +// ----------------------------------------------------------------------- +DocTempl_EntryData_Impl* RegionData_Impl::GetByTargetURL( const OUString& rName ) const +{ + for ( size_t i = 0, n = maEntries.size(); i < n; ++i ) + { + DocTempl_EntryData_Impl *pEntry = maEntries[ i ]; + if ( pEntry->GetTargetURL() == rName ) + return pEntry; + } + return NULL; +} + +// ----------------------------------------------------------------------- +DocTempl_EntryData_Impl* RegionData_Impl::GetEntry( size_t nIndex ) const +{ + if ( nIndex < maEntries.size() ) + return maEntries[ nIndex ]; + return NULL; +} + +// ----------------------------------------------------------------------- +void RegionData_Impl::DeleteEntry( size_t nIndex ) +{ + if ( nIndex < maEntries.size() ) + { + delete maEntries[ nIndex ]; + vector< DocTempl_EntryData_Impl*>::iterator it = maEntries.begin(); + advance( it, nIndex ); + maEntries.erase( it ); + } +} + +// ----------------------------------------------------------------------- +int RegionData_Impl::Compare( RegionData_Impl* pCompare ) const +{ + int nCompare = maTitle.compareTo( pCompare->maTitle ); + + return nCompare; +} + +// ----------------------------------------------------------------------- + +SfxDocTemplate_Impl::SfxDocTemplate_Impl() +: mbConstructed( sal_False ) +, mnLockCounter( 0 ) +{ +} + +// ----------------------------------------------------------------------- +SfxDocTemplate_Impl::~SfxDocTemplate_Impl() +{ + Clear(); + + gpTemplateData = NULL; +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::IncrementLock() +{ + ::osl::MutexGuard aGuard( maMutex ); + mnLockCounter++; +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::DecrementLock() +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mnLockCounter ) + mnLockCounter--; +} + +// ----------------------------------------------------------------------- +RegionData_Impl* SfxDocTemplate_Impl::GetRegion( size_t nIndex ) const +{ + if ( nIndex < maRegions.size() ) + return maRegions[ nIndex ]; + return NULL; +} + +// ----------------------------------------------------------------------- +RegionData_Impl* SfxDocTemplate_Impl::GetRegion( const OUString& rName ) + const +{ + for ( size_t i = 0, n = maRegions.size(); i < n; ++i ) + { + RegionData_Impl* pData = maRegions[ i ]; + if( pData->GetTitle() == rName ) + return pData; + } + return NULL; +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::DeleteRegion( size_t nIndex ) +{ + if ( nIndex < maRegions.size() ) + { + delete maRegions[ nIndex ]; + RegionList_Impl::iterator it = maRegions.begin(); + advance( it, nIndex ); + maRegions.erase( it ); + } +} + +// ----------------------------------------------------------------------- +/* AddRegion adds a Region to the RegionList +*/ +void SfxDocTemplate_Impl::AddRegion( const OUString& rTitle, + Content& rContent ) +{ + RegionData_Impl* pRegion; + pRegion = new RegionData_Impl( this, rTitle ); + + if ( ! InsertRegion( pRegion ) ) + { + delete pRegion; + return; + } + + // now get the content of the region + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(2); + aProps[0] = OUString(RTL_CONSTASCII_USTRINGPARAM( TITLE )); + aProps[1] = OUString(RTL_CONSTASCII_USTRINGPARAM( TARGET_URL )); + + try + { + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + Sequence< NumberedSortingInfo > aSortingInfo(1); + aSortingInfo.getArray()->ColumnIndex = 1; + aSortingInfo.getArray()->Ascending = sal_True; + xResultSet = rContent.createSortedCursor( aProps, aSortingInfo, m_rCompareFactory, 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 aTitle( xRow->getString( 1 ) ); + OUString aTargetDir( xRow->getString( 2 ) ); + + pRegion->AddEntry( aTitle, aTargetDir ); + } + } + catch ( Exception& ) {} + } +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::CreateFromHierarchy( Content &rTemplRoot ) +{ + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(1); + aProps[0] = OUString(RTL_CONSTASCII_USTRINGPARAM( TITLE )); + + try + { + ResultSetInclude eInclude = INCLUDE_FOLDERS_ONLY; + Sequence< NumberedSortingInfo > aSortingInfo(1); + aSortingInfo.getArray()->ColumnIndex = 1; + aSortingInfo.getArray()->Ascending = sal_True; + xResultSet = rTemplRoot.createSortedCursor( aProps, aSortingInfo, m_rCompareFactory, eInclude ); + } + catch ( Exception& ) {} + + if ( xResultSet.is() ) + { + uno::Reference< XCommandEnvironment > aCmdEnv; + uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + OUString aTitle( xRow->getString( 1 ) ); + + OUString aId = xContentAccess->queryContentIdentifierString(); + Content aContent = Content( aId, aCmdEnv ); + + AddRegion( aTitle, aContent ); + } + } + catch ( Exception& ) {} + } +} + +// ------------------------------------------------------------------------ +sal_Bool SfxDocTemplate_Impl::Construct( ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( mbConstructed ) + return sal_True; + + uno::Reference< XMultiServiceFactory > xFactory; + xFactory = ::comphelper::getProcessServiceFactory(); + + OUString aService( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_DOCINFO ) ); + uno::Reference< XPersist > xInfo( xFactory->createInstance( aService ), UNO_QUERY ); + mxInfo = xInfo; + + aService = OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICENAME_DOCTEMPLATES ) ); + uno::Reference< XDocumentTemplates > xTemplates( xFactory->createInstance( aService ), UNO_QUERY ); + + if ( xTemplates.is() ) + mxTemplates = xTemplates; + else + return sal_False; + + uno::Reference< XLocalizable > xLocalizable( xTemplates, UNO_QUERY ); + + Sequence< Any > aCompareArg(1); + *(aCompareArg.getArray()) <<= xLocalizable->getLocale();; + m_rCompareFactory = uno::Reference< XAnyCompareFactory >( + xFactory->createInstanceWithArguments( OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.AnyCompareFactory")), + aCompareArg ), + UNO_QUERY ); + + uno::Reference < XContent > aRootContent = xTemplates->getContent(); + uno::Reference < XCommandEnvironment > aCmdEnv; + + if ( ! aRootContent.is() ) + return sal_False; + + mbConstructed = sal_True; + maRootURL = aRootContent->getIdentifier()->getContentIdentifier(); + + ResStringArray aLongNames( SfxResId( TEMPLATE_LONG_NAMES_ARY ) ); + + if ( aLongNames.Count() ) + maStandardGroup = aLongNames.GetString( 0 ); + + Content aTemplRoot( aRootContent, aCmdEnv ); + CreateFromHierarchy( aTemplRoot ); + + return sal_True; +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::ReInitFromComponent() +{ + uno::Reference< XDocumentTemplates > xTemplates = getDocTemplates(); + if ( xTemplates.is() ) + { + uno::Reference < XContent > aRootContent = xTemplates->getContent(); + uno::Reference < XCommandEnvironment > aCmdEnv; + Content aTemplRoot( aRootContent, aCmdEnv ); + Clear(); + CreateFromHierarchy( aTemplRoot ); + } +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::GetTemplates( Content& rTargetFolder, + Content& /*rParentFolder*/, + RegionData_Impl* pRegion ) +{ + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(1); + + aProps[0] = OUString(RTL_CONSTASCII_USTRINGPARAM( TITLE )); + + try + { + ResultSetInclude eInclude = INCLUDE_DOCUMENTS_ONLY; + Sequence< NumberedSortingInfo > aSortingInfo(1); + aSortingInfo.getArray()->ColumnIndex = 1; + aSortingInfo.getArray()->Ascending = sal_True; + xResultSet = rTargetFolder.createSortedCursor( aProps, aSortingInfo, m_rCompareFactory, 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 aTitle( xRow->getString(1) ); + + if ( aTitle.compareToAscii( "sfx.tlx" ) == 0 ) + continue; + + OUString aId = xContentAccess->queryContentIdentifierString(); + + DocTempl_EntryData_Impl* pEntry = pRegion->GetByTargetURL( aId ); + + if ( ! pEntry ) + { + OUString aFullTitle; + if( !GetTitleFromURL( aId, aFullTitle ) ) + { + DBG_ERRORFILE( "GetTemplates(): template of alien format" ); + continue; + } + + if ( aFullTitle.getLength() ) + aTitle = aFullTitle; + + pRegion->AddEntry( aTitle, aId ); + } + } + } + catch ( Exception& ) {} + } +} + + +// ----------------------------------------------------------------------- +size_t SfxDocTemplate_Impl::GetRegionPos( const OUString& rTitle, sal_Bool& rFound ) const +{ + int nCompVal = 1; + size_t nStart = 0; + size_t nEnd = maRegions.size() - 1; + size_t nMid = 0; + + RegionData_Impl* pMid; + + while ( nCompVal && ( nStart <= nEnd ) ) + { + nMid = ( nEnd - nStart ) / 2 + nStart; + pMid = maRegions[ nMid ]; + + nCompVal = pMid->Compare( rTitle ); + + if ( nCompVal < 0 ) // pMid < pData + nStart = nMid + 1; + else + nEnd = nMid - 1; + } + + if ( nCompVal == 0 ) + rFound = sal_True; + else + { + if ( nCompVal < 0 ) // pMid < pData + nMid++; + + rFound = sal_False; + } + + return nMid; +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTemplate_Impl::InsertRegion( RegionData_Impl *pNew, size_t nPos ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + // return false (not inserted) if the entry already exists + for ( size_t i = 0, n = maRegions.size(); i < n; ++i ) + if ( maRegions[ i ]->Compare( pNew ) == 0 ) + return sal_False; + + size_t newPos = nPos; + if ( pNew->GetTitle() == maStandardGroup ) + newPos = 0; + + if ( newPos < maRegions.size() ) + { + RegionList_Impl::iterator it = maRegions.begin(); + advance( it, newPos ); + maRegions.insert( it, pNew ); + } + else + maRegions.push_back( pNew ); + + return sal_True; +} + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::Rescan() +{ + Clear(); + + try + { + uno::Reference< XDocumentTemplates > xTemplates = getDocTemplates(); + DBG_ASSERT( xTemplates.is(), "SfxDocTemplate_Impl::Rescan:invalid template instance!" ); + if ( xTemplates.is() ) + { + xTemplates->update(); + + uno::Reference < XContent > aRootContent = xTemplates->getContent(); + uno::Reference < XCommandEnvironment > aCmdEnv; + + Content aTemplRoot( aRootContent, aCmdEnv ); + CreateFromHierarchy( aTemplRoot ); + } + } + catch( const Exception& ) + { + DBG_ERRORFILE( "SfxDocTemplate_Impl::Rescan: caught an exception while doing the update!" ); + } +} + +// ----------------------------------------------------------------------- +sal_Bool SfxDocTemplate_Impl::GetTitleFromURL( const OUString& rURL, + OUString& aTitle ) +{ + if ( mxInfo.is() ) + { + try + { + mxInfo->read( 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; + } + } + catch ( IOException& ) {} + catch ( UnknownPropertyException& ) {} + catch ( Exception& ) {} + } + + if ( ! aTitle.getLength() ) + { + INetURLObject aURL( rURL ); + aURL.CutExtension(); + aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_WITH_CHARSET ); + } + + return sal_True; +} + + +// ----------------------------------------------------------------------- +void SfxDocTemplate_Impl::Clear() +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mnLockCounter ) + return; + + for ( size_t i = 0, n = maRegions.size(); i < n; ++i ) + delete maRegions[ i ]; + maRegions.clear(); +} + +// ----------------------------------------------------------------------- +sal_Bool getTextProperty_Impl( Content& rContent, + const OUString& rPropName, + OUString& 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 + Any aAnyValue; + + aAnyValue = rContent.getPropertyValue( rPropName ); + aAnyValue >>= rPropValue; + + if ( SfxURLRelocator_Impl::propertyCanContainOfficeDir( rPropName ) ) + { + SfxURLRelocator_Impl aRelocImpl( ::comphelper::getProcessServiceFactory() ); + aRelocImpl.makeAbsoluteURL( rPropValue ); + } + + bGotProperty = sal_True; + } + catch ( RuntimeException& ) {} + catch ( Exception& ) {} + + return bGotProperty; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |