blob: f615c78fc8b71075bbf0d4a9d8f18fcee7c34342 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_ucb.hxx"
/**************************************************************************
TODO
**************************************************************************
*************************************************************************/
#include <osl/diagnose.h>
#include <cppuhelper/implbase1.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <rtl/ustring.h>
#include <rtl/ustring.hxx>
#include <com/sun/star/uno/XInterface.hpp>
#include <com/sun/star/beans/PropertyState.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/io/XActiveDataSink.hpp>
#include <com/sun/star/io/XOutputStream.hpp>
#include <com/sun/star/io/XSeekable.hpp>
#include <com/sun/star/sdbc/XRow.hpp>
#include <com/sun/star/task/XInteractionHandler.hpp>
#include <com/sun/star/ucb/CommandEnvironment.hpp>
#include <com/sun/star/ucb/CommandFailedException.hpp>
#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
#include <com/sun/star/ucb/GlobalTransferCommandArgument.hpp>
#include <com/sun/star/ucb/InsertCommandArgument.hpp>
#include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
#include <com/sun/star/ucb/NameClash.hpp>
#include <com/sun/star/ucb/NameClashException.hpp>
#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
#include <com/sun/star/ucb/OpenMode.hpp>
#include <com/sun/star/ucb/TransferInfo.hpp>
#include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
#include <com/sun/star/ucb/XCommandInfo.hpp>
#include <com/sun/star/ucb/XContentAccess.hpp>
#include <com/sun/star/ucb/XContentCreator.hpp>
#include <com/sun/star/ucb/XDynamicResultSet.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Sequence.hxx>
#include <ucbhelper/cancelcommandexecution.hxx>
#include <ucbhelper/simplenameclashresolverequest.hxx>
#include "ucbcmds.hxx"
#include "ucb.hxx"
using namespace com::sun::star;
namespace
{
//=========================================================================
//
// struct TransferCommandContext.
//
//=========================================================================
struct TransferCommandContext
{
uno::Reference< lang::XMultiServiceFactory > xSMgr;
uno::Reference< ucb::XCommandProcessor > xProcessor;
uno::Reference< ucb::XCommandEnvironment > xEnv;
uno::Reference< ucb::XCommandEnvironment > xOrigEnv;
ucb::GlobalTransferCommandArgument aArg;
TransferCommandContext(
const uno::Reference< lang::XMultiServiceFactory > & rxSMgr,
const uno::Reference< ucb::XCommandProcessor > & rxProcessor,
const uno::Reference< ucb::XCommandEnvironment > & rxEnv,
const uno::Reference< ucb::XCommandEnvironment > & rxOrigEnv,
const ucb::GlobalTransferCommandArgument & rArg )
: xSMgr( rxSMgr ), xProcessor( rxProcessor ), xEnv( rxEnv ),
xOrigEnv( rxOrigEnv ), aArg( rArg ) {}
};
//=========================================================================
//
// class InteractionHandlerProxy.
//
//=========================================================================
class InteractionHandlerProxy :
public cppu::WeakImplHelper1< task::XInteractionHandler >
{
uno::Reference< task::XInteractionHandler > m_xOrig;
public:
InteractionHandlerProxy(
const uno::Reference< task::XInteractionHandler > & xOrig )
: m_xOrig( xOrig ) {}
// XInteractionHandler methods.
virtual void SAL_CALL handle(
const uno::Reference< task::XInteractionRequest >& Request )
throw ( uno::RuntimeException );
};
//=========================================================================
// virtual
void SAL_CALL InteractionHandlerProxy::handle(
const uno::Reference< task::XInteractionRequest >& Request )
throw ( uno::RuntimeException )
{
if ( !m_xOrig.is() )
return;
// Filter unwanted requests by just not handling them.
uno::Any aRequest = Request->getRequest();
// "transfer"
ucb::InteractiveBadTransferURLException aBadTransferURLEx;
if ( aRequest >>= aBadTransferURLEx )
{
return;
}
else
{
// "transfer"
ucb::UnsupportedNameClashException aUnsupportedNameClashEx;
if ( aRequest >>= aUnsupportedNameClashEx )
{
if ( aUnsupportedNameClashEx.NameClash
!= ucb::NameClash::ERROR )
return;
}
else
{
// "insert"
ucb::NameClashException aNameClashEx;
if ( aRequest >>= aNameClashEx )
{
return;
}
else
{
// "transfer"
ucb::UnsupportedCommandException aUnsupportedCommandEx;
if ( aRequest >>= aUnsupportedCommandEx )
{
return;
}
}
}
}
// not filtered; let the original handler do the work.
m_xOrig->handle( Request );
}
//=========================================================================
//
// class ActiveDataSink.
//
//=========================================================================
class ActiveDataSink : public cppu::WeakImplHelper1< io::XActiveDataSink >
{
uno::Reference< io::XInputStream > m_xStream;
public:
// XActiveDataSink methods.
virtual void SAL_CALL setInputStream(
const uno::Reference< io::XInputStream >& aStream )
throw( uno::RuntimeException );
virtual uno::Reference< io::XInputStream > SAL_CALL getInputStream()
throw( uno::RuntimeException );
};
//=========================================================================
// virtual
void SAL_CALL ActiveDataSink::setInputStream(
const uno::Reference< io::XInputStream >& aStream )
throw( uno::RuntimeException )
{
m_xStream = aStream;
}
//=========================================================================
// virtual
uno::Reference< io::XInputStream > SAL_CALL ActiveDataSink::getInputStream()
throw( uno::RuntimeException )
{
return m_xStream;
}
//=========================================================================
//
// class CommandProcessorInfo.
//
//=========================================================================
class CommandProcessorInfo :
public cppu::WeakImplHelper1< ucb::XCommandInfo >
{
uno::Sequence< ucb::CommandInfo > * m_pInfo;
public:
CommandProcessorInfo();
virtual ~CommandProcessorInfo();
// XCommandInfo methods
virtual uno::Sequence< ucb::CommandInfo > SAL_CALL getCommands()
throw( uno::RuntimeException );
virtual ucb::CommandInfo SAL_CALL
getCommandInfoByName( const rtl::OUString& Name )
throw( ucb::UnsupportedCommandException, uno::RuntimeException );
virtual ucb::CommandInfo SAL_CALL
getCommandInfoByHandle( sal_Int32 Handle )
throw( ucb::UnsupportedCommandException, uno::RuntimeException );
virtual sal_Bool SAL_CALL hasCommandByName( const rtl::OUString& Name )
throw( uno::RuntimeException );
virtual sal_Bool SAL_CALL hasCommandByHandle( sal_Int32 Handle )
throw( uno::RuntimeException );
};
//=========================================================================
CommandProcessorInfo::CommandProcessorInfo()
{
m_pInfo = new uno::Sequence< ucb::CommandInfo >( 2 );
(*m_pInfo)[ 0 ]
= ucb::CommandInfo(
rtl::OUString::createFromAscii( GETCOMMANDINFO_NAME ), // Name
GETCOMMANDINFO_HANDLE, // Handle
getCppuVoidType() ); // ArgType
(*m_pInfo)[ 1 ]
= ucb::CommandInfo(
rtl::OUString::createFromAscii( GLOBALTRANSFER_NAME ), // Name
GLOBALTRANSFER_HANDLE, // Handle
getCppuType(
static_cast<
ucb::GlobalTransferCommandArgument * >( 0 ) ) ); // ArgType
}
//=========================================================================
// virtual
CommandProcessorInfo::~CommandProcessorInfo()
{
delete m_pInfo;
}
//=========================================================================
// virtual
uno::Sequence< ucb::CommandInfo > SAL_CALL
CommandProcessorInfo::getCommands()
throw( uno::RuntimeException )
{
return uno::Sequence< ucb::CommandInfo >( *m_pInfo );
}
//=========================================================================
// virtual
ucb::CommandInfo SAL_CALL
CommandProcessorInfo::getCommandInfoByName( const rtl::OUString& Name )
throw( ucb::UnsupportedCommandException, uno::RuntimeException )
{
for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
{
if ( (*m_pInfo)[ n ].Name == Name )
return ucb::CommandInfo( (*m_pInfo)[ n ] );
}
throw ucb::UnsupportedCommandException();
}
//=========================================================================
// virtual
ucb::CommandInfo SAL_CALL
CommandProcessorInfo::getCommandInfoByHandle( sal_Int32 Handle )
throw( ucb::UnsupportedCommandException, uno::RuntimeException )
{
for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
{
if ( (*m_pInfo)[ n ].Handle == Handle )
return ucb::CommandInfo( (*m_pInfo)[ n ] );
}
throw ucb::UnsupportedCommandException();
}
//=========================================================================
// virtual
sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByName(
const rtl::OUString& Name )
throw( uno::RuntimeException )
{
for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
{
if ( (*m_pInfo)[ n ].Name == Name )
return sal_True;
}
return sal_False;
}
//=========================================================================
// virtual
sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByHandle( sal_Int32 Handle )
throw( uno::RuntimeException )
{
for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
{
if ( (*m_pInfo)[ n ].Handle == Handle )
return sal_True;
}
return sal_False;
}
//=========================================================================
//=========================================================================
//=========================================================================
rtl::OUString createDesiredName(
const rtl::OUString & rSourceURL, const rtl::OUString & rNewTitle )
{
rtl::OUString aName( rNewTitle );
if ( aName.getLength() == 0 )
{
// calculate name using source URL
// @@@ It's not guaranteed that slashes contained in the URL are
// actually path separators. This depends on the fact whether the
// URL is hierarchical. Only then the slashes are path separators.
// Therefore this algorithm is not guaranteed to work! But, ATM
// I don't know a better solution. It would have been better to
// have a member for the clashing name in
// UnsupportedNameClashException...
sal_Int32 nLastSlash = rSourceURL.lastIndexOf( '/' );
bool bTrailingSlash = false;
if ( nLastSlash == rSourceURL.getLength() - 1 )
{
nLastSlash = rSourceURL.lastIndexOf( '/', nLastSlash );
bTrailingSlash = true;
}
if ( nLastSlash != -1 )
{
if ( bTrailingSlash )
aName = rSourceURL.copy(
nLastSlash + 1,
rSourceURL.getLength() - nLastSlash - 2 );
else
aName = rSourceURL.copy( nLastSlash + 1 );
}
else
{
aName = rSourceURL;
}
// query, fragment present?
sal_Int32 nPos = aName.indexOf( '?' );
if ( nPos == -1 )
nPos = aName.indexOf( '#' );
if ( nPos != -1 )
aName = aName.copy( 0, nPos );
}
return rtl::OUString( aName );
}
rtl::OUString createDesiredName(
const ucb::GlobalTransferCommandArgument & rArg )
{
return createDesiredName( rArg.SourceURL, rArg.NewTitle );
}
rtl::OUString createDesiredName(
const ucb::TransferInfo & rArg )
{
return createDesiredName( rArg.SourceURL, rArg.NewTitle );
}
//=========================================================================
enum NameClashContinuation { NOT_HANDLED, ABORT, OVERWRITE, NEW_NAME, UNKNOWN };
NameClashContinuation interactiveNameClashResolve(
const uno::Reference< ucb::XCommandEnvironment > & xEnv,
const rtl::OUString & rTargetURL,
const rtl::OUString & rClashingName,
/* [out] */ uno::Any & rException,
/* [out] */ rtl::OUString & rNewName )
{
rtl::Reference< ucbhelper::SimpleNameClashResolveRequest > xRequest(
new ucbhelper::SimpleNameClashResolveRequest(
rTargetURL, // target folder URL
rClashingName, // clashing name
rtl::OUString(), // no proposal for new name
sal_True /* bSupportsOverwriteData */ ) );
rException = xRequest->getRequest();
if ( xEnv.is() )
{
uno::Reference< task::XInteractionHandler > xIH
= xEnv->getInteractionHandler();
if ( xIH.is() )
{
xIH->handle( xRequest.get() );
rtl::Reference< ucbhelper::InteractionContinuation >
xSelection( xRequest->getSelection() );
if ( xSelection.is() )
{
// Handler handled the request.
uno::Reference< task::XInteractionAbort > xAbort(
xSelection.get(), uno::UNO_QUERY );
if ( xAbort.is() )
{
// Abort.
return ABORT;
}
else
{
uno::Reference<
ucb::XInteractionReplaceExistingData >
xReplace(
xSelection.get(), uno::UNO_QUERY );
if ( xReplace.is() )
{
// Try again: Replace existing data.
return OVERWRITE;
}
else
{
uno::Reference<
ucb::XInteractionSupplyName >
xSupplyName(
xSelection.get(), uno::UNO_QUERY );
if ( xSupplyName.is() )
{
// Try again: Use new name.
rNewName = xRequest->getNewName();
return NEW_NAME;
}
else
{
OSL_ENSURE( sal_False,
"Unknown interaction continuation!" );
return UNKNOWN;
}
}
}
}
}
}
return NOT_HANDLED;
}
//=========================================================================
bool setTitle(
const uno::Reference< ucb::XCommandProcessor > & xCommandProcessor,
const uno::Reference< ucb::XCommandEnvironment > & xEnv,
const rtl::OUString & rNewTitle )
throw( uno::RuntimeException )
{
try
{
uno::Sequence< beans::PropertyValue > aPropValues( 1 );
aPropValues[ 0 ].Name
= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) );
aPropValues[ 0 ].Handle = -1;
aPropValues[ 0 ].Value = uno::makeAny( rNewTitle );
ucb::Command aSetPropsCommand(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "setPropertyValues" ) ),
-1,
uno::makeAny( aPropValues ) );
uno::Any aResult
= xCommandProcessor->execute( aSetPropsCommand, 0, xEnv );
uno::Sequence< uno::Any > aErrors;
aResult >>= aErrors;
OSL_ENSURE( aErrors.getLength() == 1,
"getPropertyValues return value invalid!" );
if ( aErrors[ 0 ].hasValue() )
{
// error occured.
OSL_ENSURE( sal_False, "error setting Title property!" );
return false;
}
}
catch ( uno::RuntimeException const & )
{
throw;
}
catch ( uno::Exception const & )
{
return false;
}
return true;
}
//=========================================================================
uno::Reference< ucb::XContent > createNew(
const TransferCommandContext & rContext,
const uno::Reference< ucb::XContent > & xTarget,
sal_Bool bSourceIsFolder,
sal_Bool bSourceIsDocument,
sal_Bool bSourceIsLink )
throw( uno::Exception )
{
//////////////////////////////////////////////////////////////////////
//
// (1) Obtain creatable types from target.
//
//////////////////////////////////////////////////////////////////////
// First, try it using "CreatabeleContentsInfo" property and
// "createNewContent" command -> the "new" way.
uno::Reference< ucb::XCommandProcessor > xCommandProcessorT(
xTarget, uno::UNO_QUERY );
if ( !xCommandProcessorT.is() )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Folder")),
-1,
uno::makeAny(rContext.aArg.TargetURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_CREATE,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii( "Target is no XCommandProcessor!" ),
rContext.xProcessor );
// Unreachable
}
uno::Sequence< beans::Property > aPropsToObtain( 1 );
aPropsToObtain[ 0 ].Name
= rtl::OUString::createFromAscii( "CreatableContentsInfo" );
aPropsToObtain[ 0 ].Handle
= -1;
ucb::Command aGetPropsCommand(
rtl::OUString::createFromAscii( "getPropertyValues" ),
-1,
uno::makeAny( aPropsToObtain ) );
uno::Reference< sdbc::XRow > xRow;
xCommandProcessorT->execute( aGetPropsCommand, 0, rContext.xEnv ) >>= xRow;
uno::Sequence< ucb::ContentInfo > aTypesInfo;
bool bGotTypesInfo = false;
if ( xRow.is() )
{
uno::Any aValue = xRow->getObject(
1, uno::Reference< container::XNameAccess >() );
if ( aValue.hasValue() && ( aValue >>= aTypesInfo ) )
{
bGotTypesInfo = true;
}
}
uno::Reference< ucb::XContentCreator > xCreator;
if ( !bGotTypesInfo )
{
// Second, try it using XContentCreator interface -> the "old" way (not
// providing the chance to supply an XCommandEnvironment.
xCreator.set( xTarget, uno::UNO_QUERY );
if ( !xCreator.is() )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Folder")),
-1,
uno::makeAny(rContext.aArg.TargetURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_CREATE,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii( "Target is no XContentCreator!" ),
rContext.xProcessor );
// Unreachable
}
aTypesInfo = xCreator->queryCreatableContentsInfo();
}
sal_Int32 nCount = aTypesInfo.getLength();
if ( !nCount )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Folder")),
-1,
uno::makeAny(rContext.aArg.TargetURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_CREATE,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii( "No types creatable!" ),
rContext.xProcessor );
// Unreachable
}
//////////////////////////////////////////////////////////////////////
//
// (2) Try to find a matching target type for the source object.
//
//////////////////////////////////////////////////////////////////////
uno::Reference< ucb::XContent > xNew;
for ( sal_Int32 n = 0; n < nCount; ++n )
{
sal_Int32 nAttribs = aTypesInfo[ n ].Attributes;
sal_Bool bMatch = sal_False;
if ( rContext.aArg.Operation == ucb::TransferCommandOperation_LINK )
{
// Create link
if ( nAttribs & ucb::ContentInfoAttribute::KIND_LINK )
{
// Match!
bMatch = sal_True;
}
}
else if ( ( rContext.aArg.Operation
== ucb::TransferCommandOperation_COPY ) ||
( rContext.aArg.Operation
== ucb::TransferCommandOperation_MOVE ) )
{
// Copy / Move
// Is source a link? Create link in target folder then.
if ( bSourceIsLink )
{
if ( nAttribs & ucb::ContentInfoAttribute::KIND_LINK )
{
// Match!
bMatch = sal_True;
}
}
else
{
// (not a and not b) or (a and b)
// not( a or b) or (a and b)
//
if ( ( !!bSourceIsFolder ==
!!( nAttribs
& ucb::ContentInfoAttribute::KIND_FOLDER ) )
&&
( !!bSourceIsDocument ==
!!( nAttribs
& ucb::ContentInfoAttribute::KIND_DOCUMENT ) )
)
{
// Match!
bMatch = sal_True;
}
}
}
else
{
ucbhelper::cancelCommandExecution(
uno::makeAny( lang::IllegalArgumentException(
rtl::OUString::createFromAscii(
"Unknown transfer operation!" ),
rContext.xProcessor,
-1 ) ),
rContext.xOrigEnv );
// Unreachable
}
if ( bMatch )
{
//////////////////////////////////////////////////////////////
//
// (3) Create a new, empty object of matched type.
//
//////////////////////////////////////////////////////////////
if ( !xCreator.is() )
{
// First, try it using "CreatabeleContentsInfo" property and
// "createNewContent" command -> the "new" way.
ucb::Command aCreateNewCommand(
rtl::OUString::createFromAscii( "createNewContent" ),
-1,
uno::makeAny( aTypesInfo[ n ] ) );
xCommandProcessorT->execute( aCreateNewCommand, 0, rContext.xEnv )
>>= xNew;
}
else
{
// Second, try it using XContentCreator interface -> the "old"
// way (not providing the chance to supply an XCommandEnvironment.
xNew = xCreator->createNewContent( aTypesInfo[ n ] );
}
if ( !xNew.is() )
{
uno::Any aProps
= uno::makeAny(
beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Folder")),
-1,
uno::makeAny(rContext.aArg.TargetURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_CREATE,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii(
"createNewContent failed!" ),
rContext.xProcessor );
// Unreachable
}
break; // escape from 'for' loop
}
} // for
return xNew;
}
//=========================================================================
void transferProperties(
const TransferCommandContext & rContext,
const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS,
const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorN )
throw( uno::Exception )
{
ucb::Command aGetPropertySetInfoCommand(
rtl::OUString::createFromAscii( "getPropertySetInfo" ),
-1,
uno::Any() );
uno::Reference< beans::XPropertySetInfo > xInfo;
xCommandProcessorS->execute( aGetPropertySetInfoCommand, 0, rContext.xEnv )
>>= xInfo;
if ( !xInfo.is() )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(rContext.aArg.SourceURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii(
"Unable to get propertyset info from source object!" ),
rContext.xProcessor );
// Unreachable
}
uno::Sequence< beans::Property > aAllProps = xInfo->getProperties();
ucb::Command aGetPropsCommand1(
rtl::OUString::createFromAscii( "getPropertyValues" ),
-1,
uno::makeAny( aAllProps ) );
uno::Reference< sdbc::XRow > xRow1;
xCommandProcessorS->execute(
aGetPropsCommand1, 0, rContext.xEnv ) >>= xRow1;
if ( !xRow1.is() )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(rContext.aArg.SourceURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii(
"Unable to get properties from source object!" ),
rContext.xProcessor );
// Unreachable
}
// Assemble data structure for setPropertyValues command.
// Note: Make room for additional Title and TargetURL too. -> + 2
uno::Sequence< beans::PropertyValue > aPropValues(
aAllProps.getLength() + 2 );
sal_Bool bHasTitle = ( rContext.aArg.NewTitle.getLength() == 0 );
sal_Bool bHasTargetURL = ( rContext.aArg.Operation
!= ucb::TransferCommandOperation_LINK );
sal_Int32 nWritePos = 0;
for ( sal_Int32 m = 0; m < aAllProps.getLength(); ++m )
{
const beans::Property & rCurrProp = aAllProps[ m ];
beans::PropertyValue & rCurrValue = aPropValues[ nWritePos ];
uno::Any aValue;
if ( rCurrProp.Name.compareToAscii( "Title" ) == 0 )
{
// Supply new title, if given.
if ( !bHasTitle )
{
bHasTitle = sal_True;
aValue <<= rContext.aArg.NewTitle;
}
}
else if ( rCurrProp.Name.compareToAscii( "TargetURL" ) == 0 )
{
// Supply source URL as link target for the new link to create.
if ( !bHasTargetURL )
{
bHasTargetURL = sal_True;
aValue <<= rContext.aArg.SourceURL;
}
}
if ( !aValue.hasValue() )
{
try
{
aValue = xRow1->getObject(
m + 1, uno::Reference< container::XNameAccess >() );
}
catch ( sdbc::SQLException const & )
{
// Argh! But try to bring things to an end. Perhaps the
// mad property is not really important...
}
}
if ( aValue.hasValue() )
{
rCurrValue.Name = rCurrProp.Name;
rCurrValue.Handle = rCurrProp.Handle;
rCurrValue.Value = aValue;
// rCurrValue.State =
nWritePos++;
}
}
// Title needed, but not set yet?
if ( !bHasTitle && ( rContext.aArg.NewTitle.getLength() > 0 ) )
{
aPropValues[ nWritePos ].Name
= rtl::OUString::createFromAscii( "Title" );
aPropValues[ nWritePos ].Handle = -1;
aPropValues[ nWritePos ].Value <<= rContext.aArg.NewTitle;
nWritePos++;
}
// TargetURL needed, but not set yet?
if ( !bHasTargetURL && ( rContext.aArg.Operation
== ucb::TransferCommandOperation_LINK ) )
{
aPropValues[ nWritePos ].Name
= rtl::OUString::createFromAscii( "TargetURL" );
aPropValues[ nWritePos ].Handle = -1;
aPropValues[ nWritePos ].Value <<= rContext.aArg.SourceURL;
nWritePos++;
}
aPropValues.realloc( nWritePos );
// Set properties at new object.
ucb::Command aSetPropsCommand(
rtl::OUString::createFromAscii( "setPropertyValues" ),
-1,
uno::makeAny( aPropValues ) );
xCommandProcessorN->execute( aSetPropsCommand, 0, rContext.xEnv );
// @@@ What to do with source props that are not supported by the
// new object? addProperty ???
}
//=========================================================================
uno::Reference< io::XInputStream > getInputStream(
const TransferCommandContext & rContext,
const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
throw( uno::Exception )
{
uno::Reference< io::XInputStream > xInputStream;
//////////////////////////////////////////////////////////////////////
//
// (1) Try to get data as XInputStream via XActiveDataSink.
//
//////////////////////////////////////////////////////////////////////
try
{
uno::Reference< io::XActiveDataSink > xSink = new ActiveDataSink;
ucb::OpenCommandArgument2 aArg;
aArg.Mode = ucb::OpenMode::DOCUMENT;
aArg.Priority = 0; // unused
aArg.Sink = xSink;
aArg.Properties = uno::Sequence< beans::Property >( 0 ); // unused
ucb::Command aOpenCommand(
rtl::OUString::createFromAscii( "open" ),
-1,
uno::makeAny( aArg ) );
xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
xInputStream = xSink->getInputStream();
}
catch ( uno::RuntimeException const & )
{
throw;
}
catch ( uno::Exception const & )
{
// will be handled below.
}
if ( !xInputStream.is() )
{
//////////////////////////////////////////////////////////////////
//
// (2) Try to get data via XOutputStream.
//
//////////////////////////////////////////////////////////////////
try
{
uno::Reference< io::XOutputStream > xOutputStream(
rContext.xSMgr->createInstance(
rtl::OUString::createFromAscii( "com.sun.star.io.Pipe" ) ),
uno::UNO_QUERY );
if ( xOutputStream.is() )
{
ucb::OpenCommandArgument2 aArg;
aArg.Mode = ucb::OpenMode::DOCUMENT;
aArg.Priority = 0; // unused
aArg.Sink = xOutputStream;
aArg.Properties = uno::Sequence< beans::Property >( 0 );
ucb::Command aOpenCommand(
rtl::OUString::createFromAscii( "open" ),
-1,
uno::makeAny( aArg ) );
xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
xInputStream = uno::Reference< io::XInputStream >(
xOutputStream, uno::UNO_QUERY );
}
}
catch ( uno::RuntimeException const & )
{
throw;
}
catch ( uno::Exception const & )
{
OSL_ENSURE( sal_False, "unable to get input stream from document!" );
}
}
return xInputStream;
}
//=========================================================================
uno::Reference< sdbc::XResultSet > getResultSet(
const TransferCommandContext & rContext,
const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
throw( uno::Exception )
{
uno::Reference< sdbc::XResultSet > xResultSet;
uno::Sequence< beans::Property > aProps( 3 );
aProps[ 0 ].Name = rtl::OUString::createFromAscii( "IsFolder" );
aProps[ 0 ].Handle = -1; /* unknown */
aProps[ 1 ].Name = rtl::OUString::createFromAscii( "IsDocument" );
aProps[ 1 ].Handle = -1; /* unknown */
aProps[ 2 ].Name = rtl::OUString::createFromAscii( "TargetURL" );
aProps[ 2 ].Handle = -1; /* unknown */
ucb::OpenCommandArgument2 aArg;
aArg.Mode = ucb::OpenMode::ALL;
aArg.Priority = 0; // unused
aArg.Sink = 0;
aArg.Properties = aProps;
ucb::Command aOpenCommand( rtl::OUString::createFromAscii( "open" ),
-1,
uno::makeAny( aArg ) );
try
{
uno::Reference< ucb::XDynamicResultSet > xSet;
xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv ) >>= xSet;
if ( xSet.is() )
xResultSet = xSet->getStaticResultSet();
}
catch ( uno::RuntimeException const & )
{
throw;
}
catch ( uno::Exception const & )
{
OSL_ENSURE( sal_False, "unable to get result set from folder!" );
}
return xResultSet;
}
//=========================================================================
void handleNameClashRename(
const TransferCommandContext & rContext,
const uno::Reference< ucb::XContent > & xNew,
const uno::Reference<
ucb::XCommandProcessor > & xCommandProcessorN,
const uno::Reference<
ucb::XCommandProcessor > & xCommandProcessorS,
/* [inout] */ uno::Reference< io::XInputStream > & xInputStream )
throw( uno::Exception )
{
sal_Int32 nTry = 0;
// Obtain old title.
uno::Sequence< beans::Property > aProps( 1 );
aProps[ 0 ].Name = rtl::OUString::createFromAscii( "Title" );
aProps[ 0 ].Handle = -1;
ucb::Command aGetPropsCommand(
rtl::OUString::createFromAscii( "getPropertyValues" ),
-1,
uno::makeAny( aProps ) );
uno::Reference< sdbc::XRow > xRow;
xCommandProcessorN->execute( aGetPropsCommand, 0, rContext.xEnv ) >>= xRow;
if ( !xRow.is() )
{
uno::Any aProps2
= uno::makeAny(
beans::PropertyValue(
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Uri" ) ),
-1,
uno::makeAny(
xNew->getIdentifier()->getContentIdentifier() ),
beans::PropertyState_DIRECT_VALUE ) );
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >( &aProps2, 1 ),
rContext.xOrigEnv,
rtl::OUString::createFromAscii(
"Unable to get properties from new object!" ),
rContext.xProcessor );
// Unreachable
}
rtl::OUString aOldTitle = xRow->getString( 1 );
if ( !aOldTitle.getLength() )
{
ucbhelper::cancelCommandExecution(
uno::makeAny( beans::UnknownPropertyException(
rtl::OUString::createFromAscii(
"Unable to get property 'Title' "
"from new object!" ),
rContext.xProcessor ) ),
rContext.xOrigEnv );
// Unreachable
}
// Some pseudo-intelligence for not destroying file extensions.
rtl::OUString aOldTitlePre;
rtl::OUString aOldTitlePost;
sal_Int32 nPos = aOldTitle.lastIndexOf( '.' );
if ( nPos != -1 )
{
aOldTitlePre = aOldTitle.copy( 0, nPos );
aOldTitlePost = aOldTitle.copy( nPos );
}
else
aOldTitlePre = aOldTitle;
if ( nPos > 0 )
aOldTitlePre += rtl::OUString::createFromAscii( "_" );
sal_Bool bContinue = sal_True;
do
{
nTry++;
rtl::OUString aNewTitle = aOldTitlePre;
aNewTitle += rtl::OUString::valueOf( nTry );
aNewTitle += aOldTitlePost;
// Set new title
setTitle( xCommandProcessorN, rContext.xEnv, aNewTitle );
// Retry inserting the content.
try
{
// Previous try may have read from stream. Seek to begin (if
// optional interface XSeekable is supported) or get a new stream.
if ( xInputStream.is() )
{
uno::Reference< io::XSeekable > xSeekable(
xInputStream, uno::UNO_QUERY );
if ( xSeekable.is() )
{
try
{
xSeekable->seek( 0 );
}
catch ( lang::IllegalArgumentException const & )
{
xInputStream.clear();
}
catch ( io::IOException const & )
{
xInputStream.clear();
}
}
else
xInputStream.clear();
if ( !xInputStream.is() )
{
xInputStream
= getInputStream( rContext, xCommandProcessorS );
if ( !xInputStream.is() )
{
uno::Any aProps2
= uno::makeAny(
beans::PropertyValue(
rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM( "Uri" ) ),
-1,
uno::makeAny(
xNew->getIdentifier()->
getContentIdentifier() ),
beans::PropertyState_DIRECT_VALUE ) );
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >( &aProps2, 1 ),
rContext.xOrigEnv,
rtl::OUString::createFromAscii(
"Got no data stream from source!" ),
rContext.xProcessor );
// Unreachable
}
}
}
ucb::InsertCommandArgument aArg;
aArg.Data = xInputStream;
aArg.ReplaceExisting = sal_False;
ucb::Command aInsertCommand(
rtl::OUString::createFromAscii( "insert" ),
-1,
uno::makeAny( aArg ) );
xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
// Success!
bContinue = sal_False;
}
catch ( uno::RuntimeException const & )
{
throw;
}
catch ( uno::Exception const & )
{
}
}
while ( bContinue && ( nTry < 50 ) );
if ( nTry == 50 )
{
ucbhelper::cancelCommandExecution(
uno::makeAny(
ucb::UnsupportedNameClashException(
rtl::OUString::createFromAscii(
"Unable to resolve name clash!" ),
rContext.xProcessor,
ucb::NameClash::RENAME ) ),
rContext.xOrigEnv );
// Unreachable
}
}
//=========================================================================
void globalTransfer_(
const TransferCommandContext & rContext,
const uno::Reference< ucb::XContent > & xSource,
const uno::Reference< ucb::XContent > & xTarget,
const uno::Reference< sdbc::XRow > & xSourceProps )
throw( uno::Exception )
{
// IsFolder: property is required.
sal_Bool bSourceIsFolder = xSourceProps->getBoolean( 1 );
if ( !bSourceIsFolder && xSourceProps->wasNull() )
{
ucbhelper::cancelCommandExecution(
uno::makeAny( beans::UnknownPropertyException(
rtl::OUString::createFromAscii(
"Unable to get property 'IsFolder' "
"from source object!" ),
rContext.xProcessor ) ),
rContext.xOrigEnv );
// Unreachable
}
// IsDocument: property is required.
sal_Bool bSourceIsDocument = xSourceProps->getBoolean( 2 );
if ( !bSourceIsDocument && xSourceProps->wasNull() )
{
ucbhelper::cancelCommandExecution(
uno::makeAny( beans::UnknownPropertyException(
rtl::OUString::createFromAscii(
"Unable to get property 'IsDocument' "
"from source object!" ),
rContext.xProcessor ) ),
rContext.xOrigEnv );
// Unreachable
}
// TargetURL: property is optional.
sal_Bool bSourceIsLink = ( xSourceProps->getString( 3 ).getLength() > 0 );
//////////////////////////////////////////////////////////////////////
//
// (1) Try to find a matching target type for the source object and
// create a new, empty object of that type.
//
//////////////////////////////////////////////////////////////////////
uno::Reference< ucb::XContent > xNew = createNew( rContext,
xTarget,
bSourceIsFolder,
bSourceIsDocument,
bSourceIsLink );
if ( !xNew.is() )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Folder")),
-1,
uno::makeAny(rContext.aArg.TargetURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_CREATE,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii(
"No matching content type at target!" ),
rContext.xProcessor );
// Unreachable
}
//////////////////////////////////////////////////////////////////////
//
// (2) Transfer property values from source to new object.
//
//////////////////////////////////////////////////////////////////////
uno::Reference< ucb::XCommandProcessor > xCommandProcessorN(
xNew, uno::UNO_QUERY );
if ( !xCommandProcessorN.is() )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(
xNew->getIdentifier()->
getContentIdentifier()),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_WRITE,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii(
"New content is not a XCommandProcessor!" ),
rContext.xProcessor );
// Unreachable
}
// Obtain all properties from source.
uno::Reference< ucb::XCommandProcessor > xCommandProcessorS(
xSource, uno::UNO_QUERY );
if ( !xCommandProcessorS.is() )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(rContext.aArg.SourceURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii(
"Source content is not a XCommandProcessor!" ),
rContext.xProcessor );
// Unreachable
}
transferProperties( rContext, xCommandProcessorS, xCommandProcessorN );
//////////////////////////////////////////////////////////////////////
//
// (3) Try to obtain a data stream from source.
//
//////////////////////////////////////////////////////////////////////
uno::Reference< io::XInputStream > xInputStream;
if ( bSourceIsDocument && ( rContext.aArg.Operation
!= ucb::TransferCommandOperation_LINK ) )
xInputStream = getInputStream( rContext, xCommandProcessorS );
//////////////////////////////////////////////////////////////////////
//
// (4) Try to obtain a resultset (children) from source.
//
//////////////////////////////////////////////////////////////////////
uno::Reference< sdbc::XResultSet > xResultSet;
if ( bSourceIsFolder && ( rContext.aArg.Operation
!= ucb::TransferCommandOperation_LINK ) )
xResultSet = getResultSet( rContext, xCommandProcessorS );
//////////////////////////////////////////////////////////////////////
//
// (5) Insert (store) new content.
//
//////////////////////////////////////////////////////////////////////
ucb::InsertCommandArgument aArg;
aArg.Data = xInputStream;
switch ( rContext.aArg.NameClash )
{
case ucb::NameClash::OVERWRITE:
aArg.ReplaceExisting = sal_True;
break;
case ucb::NameClash::ERROR:
case ucb::NameClash::RENAME:
case ucb::NameClash::KEEP: // deprecated
case ucb::NameClash::ASK:
aArg.ReplaceExisting = sal_False;
break;
default:
aArg.ReplaceExisting = sal_False;
OSL_ENSURE( sal_False, "Unknown nameclash directive!" );
break;
}
rtl::OUString aDesiredName = createDesiredName( rContext.aArg );
bool bRetry;
do
{
bRetry = false;
try
{
ucb::Command aInsertCommand(
rtl::OUString::createFromAscii( "insert" ),
-1,
uno::makeAny( aArg ) );
xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
}
catch ( ucb::UnsupportedNameClashException const & exc )
{
OSL_ENSURE( !aArg.ReplaceExisting,
"BUG: UnsupportedNameClashException not allowed here!" );
if (exc.NameClash != ucb::NameClash::ERROR) {
OSL_ENSURE( false, "BUG: NameClash::ERROR expected!" );
}
// No chance to solve name clashes, because I'm not able to detect
// whether there is one.
throw ucb::UnsupportedNameClashException(
rtl::OUString::createFromAscii(
"Unable to resolve name clashes, no chance to detect "
"that there is one!" ),
rContext.xProcessor,
rContext.aArg.NameClash );
}
catch ( ucb::NameClashException const & )
{
// The 'insert' command throws a NameClashException if the parameter
// ReplaceExisting of the command's argument was set to false and
// there exists a resource with a clashing name in the target folder
// of the operation.
// 'insert' command has no direct support for name clashes other
// than ERROR ( ReplaceExisting == false ) and OVERWRITE
// ( ReplaceExisting == true ). So we have to implement the
// other name clash handling directives on top of the content.
// @@@ 'insert' command should be extended that it accepts a
// name clash handling directive, exactly like 'transfer' command.
switch ( rContext.aArg.NameClash )
{
case ucb::NameClash::OVERWRITE:
{
ucbhelper::cancelCommandExecution(
uno::makeAny(
ucb::UnsupportedNameClashException(
rtl::OUString::createFromAscii(
"BUG: insert + replace == true MUST NOT "
"throw NameClashException." ),
rContext.xProcessor,
rContext.aArg.NameClash ) ),
rContext.xOrigEnv );
// Unreachable
}
case ucb::NameClash::ERROR:
throw;
case ucb::NameClash::RENAME:
{
// "invent" a new valid title.
handleNameClashRename( rContext,
xNew,
xCommandProcessorN,
xCommandProcessorS,
xInputStream );
break;
}
case ucb::NameClash::ASK:
{
uno::Any aExc;
rtl::OUString aNewTitle;
NameClashContinuation eCont
= interactiveNameClashResolve(
rContext.xOrigEnv, // always use original environment!
rContext.aArg.TargetURL, // target folder URL
aDesiredName,
aExc,
aNewTitle );
switch ( eCont )
{
case NOT_HANDLED:
// Not handled.
cppu::throwException( aExc );
// break;
case UNKNOWN:
// Handled, but not clear, how...
// fall-thru intended.
case ABORT:
throw ucb::CommandFailedException(
rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM(
"abort requested via interaction "
"handler" ) ),
uno::Reference< uno::XInterface >(),
aExc );
// break;
case OVERWRITE:
OSL_ENSURE( aArg.ReplaceExisting == sal_False,
"Hu? ReplaceExisting already true?"
);
aArg.ReplaceExisting = sal_True;
bRetry = true;
break;
case NEW_NAME:
{
// set new name -> set "Title" property...
if ( setTitle( xCommandProcessorN,
rContext.xEnv,
aNewTitle ) )
{
// remember suggested title...
aDesiredName = aNewTitle;
// ... and try again.
bRetry = true;
}
else
{
// error setting title. Abort.
throw ucb::CommandFailedException(
rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM(
"error setting Title property!"
) ),
uno::Reference< uno::XInterface >(),
aExc );
}
break;
}
}
OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
}
break;
case ucb::NameClash::KEEP: // deprecated
default:
{
ucbhelper::cancelCommandExecution(
uno::makeAny(
ucb::UnsupportedNameClashException(
rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM(
"default action, don't know how to "
"handle name clash" ) ),
rContext.xProcessor,
rContext.aArg.NameClash ) ),
rContext.xOrigEnv );
// Unreachable
}
}
}
}
while ( bRetry );
//////////////////////////////////////////////////////////////////////
//
// (6) Process children of source.
//
//////////////////////////////////////////////////////////////////////
if ( xResultSet.is() )
{
try
{
// Iterate over children...
uno::Reference< sdbc::XRow > xChildRow(
xResultSet, uno::UNO_QUERY );
if ( !xChildRow.is() )
{
uno::Any aProps
= uno::makeAny(
beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(rContext.aArg.SourceURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii(
"Unable to get properties from children of source!" ),
rContext.xProcessor );
// Unreachable
}
uno::Reference< ucb::XContentAccess > xChildAccess(
xResultSet, uno::UNO_QUERY );
if ( !xChildAccess.is() )
{
uno::Any aProps
= uno::makeAny(
beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(rContext.aArg.SourceURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >(&aProps, 1),
rContext.xOrigEnv,
rtl::OUString::createFromAscii(
"Unable to get children of source!" ),
rContext.xProcessor );
// Unreachable
}
if ( xResultSet->first() )
{
ucb::GlobalTransferCommandArgument aTransArg(
rContext.aArg.Operation, // Operation
rtl::OUString(), // SourceURL; filled later
xNew->getIdentifier()
->getContentIdentifier(), // TargetURL
rtl::OUString(), // NewTitle;
rContext.aArg.NameClash ); // NameClash
TransferCommandContext aSubCtx(
rContext.xSMgr,
rContext.xProcessor,
rContext.xEnv,
rContext.xOrigEnv,
aTransArg );
do
{
uno::Reference< ucb::XContent > xChild
= xChildAccess->queryContent();
if ( xChild.is() )
{
// Recursion!
aSubCtx.aArg.SourceURL
= xChild->getIdentifier()->getContentIdentifier();
globalTransfer_( aSubCtx,
xChild,
xNew,
xChildRow );
}
}
while ( xResultSet->next() );
}
}
catch ( sdbc::SQLException const & )
{
}
}
try {
uno::Reference< ucb::XCommandProcessor > xcp(
xTarget, uno::UNO_QUERY );
uno::Any aAny;
uno::Reference< ucb::XCommandInfo > xci;
if(xcp.is())
aAny =
xcp->execute(
ucb::Command(
rtl::OUString::createFromAscii("getCommandInfo"),
-1,
uno::Any()),
0,
rContext.xEnv );
const rtl::OUString cmdName =
rtl::OUString::createFromAscii("flush");
if((aAny >>= xci) && xci->hasCommandByName(cmdName))
xcp->execute(
ucb::Command(
cmdName,
-1,
uno::Any()) ,
0,
rContext.xEnv );
}
catch( uno::Exception const & )
{
}
}
} /* namescpace */
//=========================================================================
//
// UniversalContentBroker implementation ( XCommandProcessor commands ).
//
//=========================================================================
uno::Reference< ucb::XCommandInfo >
UniversalContentBroker::getCommandInfo()
{
return uno::Reference< ucb::XCommandInfo >( new CommandProcessorInfo() );
}
//=========================================================================
void UniversalContentBroker::globalTransfer(
const ucb::GlobalTransferCommandArgument & rArg,
const uno::Reference< ucb::XCommandEnvironment > & xEnv )
throw( uno::Exception )
{
// Use own command environment with own interaction handler intercepting
// some interaction requests that shall not be handled by the user-supplied
// interaction handler.
uno::Reference< ucb::XCommandEnvironment > xLocalEnv;
if (xEnv.is())
{
uno::Reference< beans::XPropertySet > const xProps(
m_xSMgr, uno::UNO_QUERY_THROW );
uno::Reference< uno::XComponentContext > xCtx;
xCtx.set( xProps->getPropertyValue(
rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ),
uno::UNO_QUERY_THROW );
xLocalEnv.set( ucb::CommandEnvironment::create(
xCtx,
new InteractionHandlerProxy( xEnv->getInteractionHandler() ),
xEnv->getProgressHandler() ) );
}
//////////////////////////////////////////////////////////////////////
//
// (1) Try to transfer the content using 'transfer' command.
//
//////////////////////////////////////////////////////////////////////
uno::Reference< ucb::XContent > xTarget;
uno::Reference< ucb::XContentIdentifier > xId
= createContentIdentifier( rArg.TargetURL );
if ( xId.is() )
{
try
{
xTarget = queryContent( xId );
}
catch ( ucb::IllegalIdentifierException const & )
{
}
}
if ( !xTarget.is() )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(rArg.TargetURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >(&aProps, 1),
xEnv,
rtl::OUString::createFromAscii(
"Can't instanciate target object!" ),
this );
// Unreachable
}
if ( ( rArg.Operation == ucb::TransferCommandOperation_COPY ) ||
( rArg.Operation == ucb::TransferCommandOperation_MOVE ) )
{
uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
xTarget, uno::UNO_QUERY );
if ( !xCommandProcessor.is() )
{
uno::Any aProps
= uno::makeAny(
beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(rArg.TargetURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >(&aProps, 1),
xEnv,
rtl::OUString::createFromAscii(
"Target content is not a XCommandProcessor!" ),
this );
// Unreachable
}
ucb::TransferInfo aTransferArg(
( rArg.Operation
== ucb::TransferCommandOperation_MOVE ), // MoveData
rArg.SourceURL, // SourceURL
rArg.NewTitle, // NewTitle
rArg.NameClash ); // NameClash
bool bRetry;
do
{
bRetry = false;
try
{
ucb::Command aCommand(
rtl::OUString::createFromAscii( "transfer" ), // Name
-1, // Handle
uno::makeAny( aTransferArg ) ); // Argument
xCommandProcessor->execute( aCommand, 0, xLocalEnv );
// Command succeeded. We're done.
return;
}
catch ( ucb::InteractiveBadTransferURLException const & )
{
// Source URL is not supported by target. Try to transfer
// the content "manually".
}
catch ( ucb::UnsupportedCommandException const & )
{
// 'transfer' command is not supported by commandprocessor.
// Try to transfer manually.
}
catch ( ucb::UnsupportedNameClashException const & exc )
{
OSL_ENSURE( aTransferArg.NameClash == exc.NameClash,
"nameclash mismatch!" );
if ( exc.NameClash == ucb::NameClash::ASK )
{
// Try to detect a name clash by invoking "transfer" with
// NameClash::ERROR.
try
{
ucb::TransferInfo aTransferArg1(
aTransferArg.MoveData,
aTransferArg.SourceURL,
aTransferArg.NewTitle,
ucb::NameClash::ERROR );
ucb::Command aCommand1(
rtl::OUString::createFromAscii( "transfer" ),
-1,
uno::makeAny( aTransferArg1 ) );
xCommandProcessor->execute( aCommand1, 0, xLocalEnv );
// Command succeeded. We're done.
return;
}
catch ( ucb::UnsupportedNameClashException const & )
{
// No chance to solve name clashes, because I'm not
// able to detect whether there is one.
throw exc; // Not just 'throw;'!
}
catch ( ucb::NameClashException const & )
{
// There's a clash. Use interaction handler to solve it.
uno::Any aExc;
rtl::OUString aNewTitle;
NameClashContinuation eCont
= interactiveNameClashResolve(
xEnv, // always use original environment!
rArg.TargetURL, // target folder URL
createDesiredName(
aTransferArg ), // clashing name
aExc,
aNewTitle );
switch ( eCont )
{
case NOT_HANDLED:
// Not handled.
cppu::throwException( aExc );
// break;
case UNKNOWN:
// Handled, but not clear, how...
// fall-thru intended.
case ABORT:
throw ucb::CommandFailedException(
rtl::OUString(
RTL_CONSTASCII_USTRINGPARAM(
"abort requested via interaction "
"handler" ) ),
uno::Reference< uno::XInterface >(),
aExc );
// break;
case OVERWRITE:
aTransferArg.NameClash
= ucb::NameClash::OVERWRITE;
bRetry = true;
break;
case NEW_NAME:
aTransferArg.NewTitle = aNewTitle;
bRetry = true;
break;
}
OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
}
}
else
{
throw;
}
}
}
while ( bRetry );
}
//////////////////////////////////////////////////////////////////////
//
// (2) Try to transfer the content "manually".
//
//////////////////////////////////////////////////////////////////////
uno::Reference< ucb::XContent > xSource;
try
{
uno::Reference< ucb::XContentIdentifier > xId2
= createContentIdentifier( rArg.SourceURL );
if ( xId2.is() )
xSource = queryContent( xId2 );
}
catch ( ucb::IllegalIdentifierException const & )
{
// Error handling via "if ( !xSource.is() )" below.
}
if ( !xSource.is() )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(rArg.SourceURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >(&aProps, 1),
xEnv,
rtl::OUString::createFromAscii(
"Can't instanciate source object!" ),
this );
// Unreachable
}
uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
xSource, uno::UNO_QUERY );
if ( !xCommandProcessor.is() )
{
uno::Any aProps
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(rArg.SourceURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >(&aProps, 1),
xEnv,
rtl::OUString::createFromAscii(
"Source content is not a XCommandProcessor!" ),
this );
// Unreachable
}
// Obtain interesting property values from source...
uno::Sequence< beans::Property > aProps( 4 );
aProps[ 0 ].Name = rtl::OUString::createFromAscii( "IsFolder" );
aProps[ 0 ].Handle = -1; /* unknown */
aProps[ 1 ].Name = rtl::OUString::createFromAscii( "IsDocument" );
aProps[ 1 ].Handle = -1; /* unknown */
aProps[ 2 ].Name = rtl::OUString::createFromAscii( "TargetURL" );
aProps[ 2 ].Handle = -1; /* unknown */
aProps[ 3 ].Name = rtl::OUString::createFromAscii( "BaseURI" );
aProps[ 3 ].Handle = -1; /* unknown */
ucb::Command aGetPropsCommand(
rtl::OUString::createFromAscii( "getPropertyValues" ),
-1,
uno::makeAny( aProps ) );
uno::Reference< sdbc::XRow > xRow;
xCommandProcessor->execute( aGetPropsCommand, 0, xLocalEnv ) >>= xRow;
if ( !xRow.is() )
{
uno::Any aProps2
= uno::makeAny(beans::PropertyValue(
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
"Uri")),
-1,
uno::makeAny(rArg.SourceURL),
beans::PropertyState_DIRECT_VALUE));
ucbhelper::cancelCommandExecution(
ucb::IOErrorCode_CANT_READ,
uno::Sequence< uno::Any >(&aProps2, 1),
xEnv,
rtl::OUString::createFromAscii(
"Unable to get properties from source object!" ),
this );
// Unreachable
}
TransferCommandContext aTransferCtx(
m_xSMgr, this, xLocalEnv, xEnv, rArg );
if ( rArg.NewTitle.getLength() == 0 )
{
// BaseURI: property is optional.
rtl::OUString aBaseURI( xRow->getString( 4 ) );
if ( aBaseURI.getLength() )
{
aTransferCtx.aArg.NewTitle
= createDesiredName( aBaseURI, rtl::OUString() );
}
}
// Do it!
globalTransfer_( aTransferCtx, xSource, xTarget, xRow );
//////////////////////////////////////////////////////////////////////
//
// (3) Delete source, if operation is MOVE.
//
//////////////////////////////////////////////////////////////////////
if ( rArg.Operation == ucb::TransferCommandOperation_MOVE )
{
try
{
ucb::Command aCommand(
rtl::OUString::createFromAscii( "delete" ), // Name
-1, // Handle
uno::makeAny( sal_Bool( sal_True ) ) ); // Argument
xCommandProcessor->execute( aCommand, 0, xLocalEnv );
}
catch ( uno::Exception const & )
{
OSL_ENSURE( sal_False, "Cannot delete source object!" );
throw;
}
}
}