Files
libreoffice/sfx2/source/doc/doctempl.cxx
Noel Grandin 2e0d1719f2 fdo#46808, Add service factory method to ucb::AnyCompareFactory
Change-Id: I18774fabdaf27376898ed661be21a72c6f52410d
2013-01-09 08:08:12 +02:00

1811 lines
51 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <limits.h>
#include <com/sun/star/uno/Any.h>
#include <osl/mutex.hxx>
#include <osl/thread.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <unotools/localedatawrapper.hxx>
#include <unotools/pathoptions.hxx>
#include <tools/resary.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/Desktop.hpp>
#include <com/sun/star/frame/XComponentLoader.hpp>
#include <com/sun/star/frame/DocumentTemplates.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/AnyCompareFactory.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 <sfx2/templatelocnames.hrc>
#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 TITLE "Title"
#define TARGET_URL "TargetURL"
#define TARGET_DIR_URL "TargetDirURL"
#define COMMAND_TRANSFER "transfer"
#define SERVICENAME_DOCINFO "com.sun.star.document.DocumentProperties"
//========================================================================
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;
};
}
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;
const OUString& GetTitle() const { return maTitle; }
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;
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::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_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::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();
}
//------------------------------------------------------------------------
::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, comphelper::getProcessComponentContext(), aTemplate ) )
{
OUString aPropName( TARGET_URL );
getTextProperty_Impl( aTemplate, aPropName, aResult );
aResult = SvtPathOptions().SubstituteVariable( aResult );
}
return aResult;
}
//------------------------------------------------------------------------
/** Convert a resource string - a template name - to its localised pair if it exists.
@param nSourceResIds
Resource ID where the list of original en-US template names begin.
@param nDestResIds
Resource ID where the list of localised template names begin.
@param nCount
The number of names that have been localised.
@param rString
Name to be translated.
@return
The localised pair of rString or rString if the former does not exist.
*/
OUString SfxDocumentTemplates::ConvertResourceString (
int nSourceResIds, int nDestResIds, int nCount, const OUString& rString )
{
for( int i = 0; i < nCount; ++i )
{
if( rString == SFX2_RESSTR(nSourceResIds + i))
return SFX2_RESSTR(nDestResIds + i);
}
return rString;
}
//------------------------------------------------------------------------
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 )
{
SAL_WARN( "sfx2.doc", "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.isEmpty() )
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, comphelper::getProcessComponentContext() );
TransferInfo aTransferInfo;
aTransferInfo.MoveData = sal_False;
aTransferInfo.SourceURL = pSource->GetTargetURL();
aTransferInfo.NewTitle = aTitle;
aTransferInfo.NameClash = NameClash::OVERWRITE;
Any aArg = makeAny( aTransferInfo );
OUString aCmd( 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
{
uno::Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );;
Sequence< PropertyValue > aArgs( 1 );
aArgs[0].Name = ::rtl::OUString("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("_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.isEmpty() )
{
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, comphelper::getProcessComponentContext(), aTemplCont ) )
{
OUString aTemplName;
OUString aPropName( 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&)>
*/
{
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&)>
*/
{
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::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();
}
// -----------------------------------------------------------------------
DocTempl_EntryData_Impl::DocTempl_EntryData_Impl( RegionData_Impl* pParent,
const OUString& rTitle )
{
mpParent = pParent;
maTitle = SfxDocumentTemplates::ConvertResourceString(
STR_TEMPLATE_NAME1_DEF, STR_TEMPLATE_NAME1, NUM_TEMPLATE_NAMES, rTitle );
mbIsOwner = sal_False;
mbDidConvert= sal_False;
}
// -----------------------------------------------------------------------
int DocTempl_EntryData_Impl::Compare( const OUString& rTitle ) const
{
return maTitle.compareTo( rTitle );
}
// -----------------------------------------------------------------------
const OUString& DocTempl_EntryData_Impl::GetHierarchyURL()
{
if ( maOwnURL.isEmpty() )
{
INetURLObject aTemplateObj( GetParent()->GetHierarchyURL() );
aTemplateObj.insertName( GetTitle(), false,
INetURLObject::LAST_SEGMENT, true,
INetURLObject::ENCODE_ALL );
maOwnURL = aTemplateObj.GetMainURL( INetURLObject::NO_DECODE );
DBG_ASSERT( !maOwnURL.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
}
return maOwnURL;
}
// -----------------------------------------------------------------------
const OUString& DocTempl_EntryData_Impl::GetTargetURL()
{
if ( maTargetURL.isEmpty() )
{
uno::Reference< XCommandEnvironment > aCmdEnv;
Content aRegion;
if ( Content::create( GetHierarchyURL(), aCmdEnv, comphelper::getProcessComponentContext(), aRegion ) )
{
OUString aPropName( TARGET_URL );
getTextProperty_Impl( aRegion, aPropName, maTargetURL );
}
else
{
SAL_WARN( "sfx2.doc", "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.isEmpty() )
{
INetURLObject aRegionObj( GetParent()->GetRootURL() );
aRegionObj.insertName( GetTitle(), false,
INetURLObject::LAST_SEGMENT, true,
INetURLObject::ENCODE_ALL );
maOwnURL = aRegionObj.GetMainURL( INetURLObject::NO_DECODE );
DBG_ASSERT( !maOwnURL.isEmpty(), "GetHierarchyURL(): Could not create URL!" );
}
return maOwnURL;
}
// -----------------------------------------------------------------------
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::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(TITLE );
aProps[1] = OUString(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(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, comphelper::getProcessComponentContext() );
AddRegion( aTitle, aContent );
}
}
catch ( Exception& ) {}
}
}
// ------------------------------------------------------------------------
sal_Bool SfxDocTemplate_Impl::Construct( )
{
::osl::MutexGuard aGuard( maMutex );
if ( mbConstructed )
return sal_True;
uno::Reference< XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
uno::Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
OUString aService( SERVICENAME_DOCINFO );
uno::Reference< XPersist > xInfo( xFactory->createInstance( aService ), UNO_QUERY );
mxInfo = xInfo;
mxTemplates = frame::DocumentTemplates::create(xContext);
uno::Reference< XLocalizable > xLocalizable( mxTemplates, UNO_QUERY );
m_rCompareFactory = AnyCompareFactory::createWithLocale(xContext, xLocalizable->getLocale());
uno::Reference < XContent > aRootContent = mxTemplates->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, comphelper::getProcessComponentContext() );
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, comphelper::getProcessComponentContext() );
Clear();
CreateFromHierarchy( aTemplRoot );
}
}
// -----------------------------------------------------------------------
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, comphelper::getProcessComponentContext() );
CreateFromHierarchy( aTemplRoot );
}
}
catch( const Exception& )
{
SAL_WARN( "sfx2.doc", "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( TITLE );
Any aValue = aPropSet->getPropertyValue( aPropName );
aValue >>= aTitle;
}
}
catch ( IOException& ) {}
catch ( UnknownPropertyException& ) {}
catch ( Exception& ) {}
}
if ( aTitle.isEmpty() )
{
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, whether 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: */