/* -*- 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 <rtl/uri.hxx>
#include <rtl/ustrbuf.hxx>
#include <rtl/ref.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <com/sun/star/lang/NoSupportException.hpp>
#include <com/sun/star/sdbc/SQLException.hpp>
#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
#include <com/sun/star/ucb/OpenMode.hpp>
#include <com/sun/star/beans/IllegalTypeException.hpp>
#include <com/sun/star/io/XActiveDataStreamer.hpp>
#include <com/sun/star/io/XOutputStream.hpp>
#include <com/sun/star/io/XActiveDataSink.hpp>
#include <com/sun/star/ucb/NameClash.hpp>
#include <comphelper/fileurl.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <utility>
#include "filglob.hxx"
#include "filid.hxx"
#include "filrow.hxx"
#include "bc.hxx"
#include "prov.hxx"
#include "filerror.hxx"
#include "filinsreq.hxx"
using namespace fileaccess;
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::ucb;
#if OSL_DEBUG_LEVEL > 0
#define THROW_WHERE SAL_WHERE
#else
#define THROW_WHERE ""
#endif
class fileaccess::PropertyListeners
{
typedef comphelper::OInterfaceContainerHelper4<beans::XPropertiesChangeListener> ContainerHelper;
std::unordered_map<OUString, ContainerHelper> m_aMap;
public:
void disposeAndClear(std::unique_lock<std::mutex>& rGuard, const lang::EventObject& rEvt)
{
// create a copy, because do not fire event in a guarded section
std::unordered_map<OUString, ContainerHelper> tempMap = std::move(m_aMap);
for (auto& rPair : tempMap)
rPair.second.disposeAndClear(rGuard, rEvt);
}
void addInterface(std::unique_lock<std::mutex>& rGuard, const OUString& rKey, const uno::Reference<beans::XPropertiesChangeListener>& rListener)
{
m_aMap[rKey].addInterface(rGuard, rListener);
}
void removeInterface(std::unique_lock<std::mutex>& rGuard, const OUString& rKey, const uno::Reference<beans::XPropertiesChangeListener>& rListener)
{
// search container with id rKey
auto iter = m_aMap.find(rKey);
// container found?
if (iter != m_aMap.end())
iter->second.removeInterface(rGuard, rListener);
}
std::vector< OUString > getContainedTypes(std::unique_lock<std::mutex>& rGuard) const
{
std::vector<OUString> aInterfaceTypes;
aInterfaceTypes.reserve(m_aMap.size());
for (const auto& rPair : m_aMap)
// are interfaces added to this container?
if (rPair.second.getLength(rGuard))
// yes, put the type in the array
aInterfaceTypes.push_back(rPair.first);
return aInterfaceTypes;
}
comphelper::OInterfaceContainerHelper4<beans::XPropertiesChangeListener>* getContainer(std::unique_lock<std::mutex>& , const OUString& rKey)
{
auto iter = m_aMap.find(rKey);
if (iter != m_aMap.end())
return &iter->second;
return nullptr;
}
};
/****************************************************************************************/
/* */
/* BaseContent */
/* */
/****************************************************************************************/
// Private Constructor for just inserted Contents
BaseContent::BaseContent( TaskManager* pMyShell,
OUString parentName,
bool bFolder )
: m_pMyShell( pMyShell ),
m_aUncPath(std::move( parentName )),
m_bFolder( bFolder ),
m_nState( JustInserted )
{
m_pMyShell->m_pProvider->acquire();
// No registering, since we have no name
}
// Constructor for full featured Contents
BaseContent::BaseContent( TaskManager* pMyShell,
const Reference< XContentIdentifier >& xContentIdentifier,
OUString aUncPath )
: m_pMyShell( pMyShell ),
m_xContentIdentifier( xContentIdentifier ),
m_aUncPath(std::move( aUncPath )),
m_bFolder( false ),
m_nState( FullFeatured )
{
m_pMyShell->m_pProvider->acquire();
m_pMyShell->registerNotifier( m_aUncPath,this );
m_pMyShell->insertDefaultProperties( m_aUncPath );
}
BaseContent::~BaseContent( )
{
if( ( m_nState & FullFeatured ) || ( m_nState & Deleted ) )
{
m_pMyShell->deregisterNotifier( m_aUncPath,this );
}
m_pMyShell->m_pProvider->release();
}
// XComponent
void SAL_CALL
BaseContent::addEventListener( const Reference< lang::XEventListener >& Listener )
{
std::unique_lock aGuard( m_aMutex );
m_aDisposeEventListeners.addInterface( aGuard, Listener );
}
void SAL_CALL
BaseContent::removeEventListener( const Reference< lang::XEventListener >& Listener )
{
std::unique_lock aGuard( m_aMutex );
m_aDisposeEventListeners.removeInterface( aGuard, Listener );
}
void SAL_CALL
BaseContent::dispose()
{
lang::EventObject aEvt;
aEvt.Source = static_cast< XContent* >( this );
std::unique_lock aGuard( m_aMutex );
std::unique_ptr<PropertyListeners> pPropertyListener = std::move(m_pPropertyListener);
m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt );
m_aContentEventListeners.disposeAndClear( aGuard, aEvt );
if( pPropertyListener )
pPropertyListener->disposeAndClear( aGuard, aEvt );
m_aPropertySetInfoChangeListeners.disposeAndClear( aGuard, aEvt );
}
// XServiceInfo
OUString SAL_CALL
BaseContent::getImplementationName()
{
return u"com.sun.star.comp.ucb.FileContent"_ustr;
}
sal_Bool SAL_CALL
BaseContent::supportsService( const OUString& ServiceName )
{
return cppu::supportsService( this, ServiceName );
}
Sequence< OUString > SAL_CALL
BaseContent::getSupportedServiceNames()
{
Sequence<OUString> ret { u"com.sun.star.ucb.FileContent"_ustr };
return ret;
}
// XCommandProcessor
sal_Int32 SAL_CALL
BaseContent::createCommandIdentifier()
{
return m_pMyShell->getCommandId();
}
void SAL_CALL
BaseContent::abort( sal_Int32 /*CommandId*/ )
{
}
Any SAL_CALL
BaseContent::execute( const Command& aCommand,
sal_Int32 CommandId,
const Reference< XCommandEnvironment >& Environment )
{
if( ! CommandId )
// A Command with commandid zero cannot be aborted
CommandId = createCommandIdentifier();
m_pMyShell->startTask( CommandId,
Environment );
Any aAny;
if (aCommand.Name == "getPropertySetInfo") // No exceptions
{
aAny <<= getPropertySetInfo();
}
else if (aCommand.Name == "getCommandInfo") // no exceptions
{
aAny <<= getCommandInfo();
}
else if ( aCommand.Name == "setPropertyValues" )
{
Sequence< beans::PropertyValue > sPropertyValues;
if( ! ( aCommand.Argument >>= sPropertyValues ) )
m_pMyShell->installError( CommandId,
TaskHandlerErr::WRONG_SETPROPERTYVALUES_ARGUMENT );
else
aAny <<= setPropertyValues( CommandId,sPropertyValues ); // calls endTask by itself
}
else if ( aCommand.Name == "getPropertyValues" )
{
Sequence< beans::Property > ListOfRequestedProperties;
if( ! ( aCommand.Argument >>= ListOfRequestedProperties ) )
m_pMyShell->installError( CommandId,
TaskHandlerErr::WRONG_GETPROPERTYVALUES_ARGUMENT );
else
aAny <<= getPropertyValues( CommandId,
ListOfRequestedProperties );
}
else if ( aCommand.Name == "open" )
{
OpenCommandArgument2 aOpenArgument;
if( ! ( aCommand.Argument >>= aOpenArgument ) )
m_pMyShell->installError( CommandId,
TaskHandlerErr::WRONG_OPEN_ARGUMENT );
else
{
Reference< XDynamicResultSet > result = open( CommandId,aOpenArgument );
if( result.is() )
aAny <<= result;
}
}
else if ( aCommand.Name == "delete" )
{
if( ! aCommand.Argument.has< bool >() )
m_pMyShell->installError( CommandId,
TaskHandlerErr::WRONG_DELETE_ARGUMENT );
else
deleteContent( CommandId );
}
else if ( aCommand.Name == "transfer" )
{
TransferInfo aTransferInfo;
if( ! ( aCommand.Argument >>= aTransferInfo ) )
m_pMyShell->installError( CommandId,
TaskHandlerErr::WRONG_TRANSFER_ARGUMENT );
else
transfer( CommandId, aTransferInfo );
}
else if ( aCommand.Name == "insert" )
{
InsertCommandArgument aInsertArgument;
if( ! ( aCommand.Argument >>= aInsertArgument ) )
m_pMyShell->installError( CommandId,
TaskHandlerErr::WRONG_INSERT_ARGUMENT );
else
insert( CommandId,aInsertArgument );
}
else if ( aCommand.Name == "getCasePreservingURL" )
{
Reference< sdbc::XRow > xRow = getPropertyValues( CommandId, { { u"CasePreservingURL"_ustr, -1, cppu::UnoType<sal_Bool>::get(), 0 } });
OUString CasePreservingURL = xRow->getString(1);
if(!xRow->wasNull())
aAny <<= CasePreservingURL;
}
else if ( aCommand.Name == "createNewContent" )
{
ucb::ContentInfo aArg;
if ( !( aCommand.Argument >>= aArg ) )
m_pMyShell->installError( CommandId,
TaskHandlerErr::WRONG_CREATENEWCONTENT_ARGUMENT );
else
aAny <<= createNewContent( aArg );
}
else
m_pMyShell->installError( CommandId,
TaskHandlerErr::UNSUPPORTED_COMMAND );
// This is the only function allowed to throw an exception
endTask( CommandId );
return aAny;
}
void SAL_CALL
BaseContent::addPropertiesChangeListener(
const Sequence< OUString >& PropertyNames,
const Reference< beans::XPropertiesChangeListener >& Listener )
{
if( ! Listener.is() )
return;
std::unique_lock aGuard( m_aMutex );
if( ! m_pPropertyListener )
m_pPropertyListener.reset( new PropertyListeners );
if( !PropertyNames.hasElements() )
m_pPropertyListener->addInterface( aGuard, OUString(),Listener );
else
{
Reference< beans::XPropertySetInfo > xProp = m_pMyShell->info_p( m_aUncPath );
for( const auto& rName : PropertyNames )
if( xProp->hasPropertyByName( rName ) )
m_pPropertyListener->addInterface( aGuard, rName,Listener );
}
}
void SAL_CALL
BaseContent::removePropertiesChangeListener( const Sequence< OUString >& PropertyNames,
const Reference< beans::XPropertiesChangeListener >& Listener )
{
if( ! Listener.is() )
return;
std::unique_lock aGuard( m_aMutex );
if( ! m_pPropertyListener )
return;
for( const auto& rName : PropertyNames )
m_pPropertyListener->removeInterface( aGuard, rName,Listener );
m_pPropertyListener->removeInterface( aGuard, OUString(), Listener );
}
// XContent
Reference< ucb::XContentIdentifier > SAL_CALL
BaseContent::getIdentifier()
{
return m_xContentIdentifier;
}
OUString SAL_CALL
BaseContent::getContentType()
{
if( !( m_nState & Deleted ) )
{
if( m_nState & JustInserted )
{
if ( m_bFolder )
return TaskManager::FolderContentType;
else
return TaskManager::FileContentType;
}
else
{
try
{
// Who am I ?
Reference< sdbc::XRow > xRow = getPropertyValues( -1, { { u"IsDocument"_ustr, -1, cppu::UnoType<sal_Bool>::get(), 0 } });
bool IsDocument = xRow->getBoolean( 1 );
if ( !xRow->wasNull() )
{
if ( IsDocument )
return TaskManager::FileContentType;
else
return TaskManager::FolderContentType;
}
else
{
OSL_FAIL( "BaseContent::getContentType - Property value was null!" );
}
}
catch (const sdbc::SQLException&)
{
TOOLS_WARN_EXCEPTION("ucb.ucp.file", "");
}
}
}
return OUString();
}
void SAL_CALL
BaseContent::addContentEventListener(
const Reference< XContentEventListener >& Listener )
{
std::unique_lock aGuard( m_aMutex );
m_aContentEventListeners.addInterface( aGuard, Listener );
}
void SAL_CALL
BaseContent::removeContentEventListener(
const Reference< XContentEventListener >& Listener )
{
std::unique_lock aGuard( m_aMutex );
m_aContentEventListeners.removeInterface( aGuard, Listener );
}
// XPropertyContainer
void SAL_CALL
BaseContent::addProperty(
const OUString& Name,
sal_Int16 Attributes,
const Any& DefaultValue )
{
if( ( m_nState & JustInserted ) || ( m_nState & Deleted ) || Name.isEmpty() )
{
throw lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
}
m_pMyShell->associate( m_aUncPath,Name,DefaultValue,Attributes );
}
void SAL_CALL
BaseContent::removeProperty( const OUString& Name )
{
if( m_nState & Deleted )
throw beans::UnknownPropertyException( Name );
m_pMyShell->deassociate( m_aUncPath, Name );
}
// XContentCreator
Sequence< ContentInfo > SAL_CALL
BaseContent::queryCreatableContentsInfo()
{
return TaskManager::queryCreatableContentsInfo();
}
Reference< XContent > SAL_CALL
BaseContent::createNewContent( const ContentInfo& Info )
{
// Check type.
if ( Info.Type.isEmpty() )
return Reference< XContent >();
bool bFolder = Info.Type == TaskManager::FolderContentType;
if ( !bFolder )
{
if ( Info.Type != TaskManager::FileContentType )
{
// Neither folder nor file to create!
return Reference< XContent >();
}
}
// Who am I ?
bool IsDocument = false;
try
{
Reference< sdbc::XRow > xRow = getPropertyValues( -1, { { u"IsDocument"_ustr, -1, cppu::UnoType<sal_Bool>::get(), 0 } });
IsDocument = xRow->getBoolean( 1 );
if ( xRow->wasNull() )
{
IsDocument = false;
// OSL_FAIL( // "BaseContent::createNewContent - Property value was null!" );
// return Reference< XContent >();
}
}
catch (const sdbc::SQLException&)
{
TOOLS_WARN_EXCEPTION("ucb.ucp.file", "");
return Reference< XContent >();
}
OUString dstUncPath;
if( IsDocument )
{
// KSO: Why is a document a XContentCreator? This is quite unusual.
dstUncPath = getParentName( m_aUncPath );
}
else
dstUncPath = m_aUncPath;
return new BaseContent( m_pMyShell, dstUncPath, bFolder );
}
// XPropertySetInfoChangeNotifier
void SAL_CALL
BaseContent::addPropertySetInfoChangeListener(
const Reference< beans::XPropertySetInfoChangeListener >& Listener )
{
std::unique_lock aGuard( m_aMutex );
m_aPropertySetInfoChangeListeners.addInterface( aGuard, Listener );
}
void SAL_CALL
BaseContent::removePropertySetInfoChangeListener(
const Reference< beans::XPropertySetInfoChangeListener >& Listener )
{
std::unique_lock aGuard( m_aMutex );
m_aPropertySetInfoChangeListeners.removeInterface( aGuard, Listener );
}
// XChild
Reference< XInterface > SAL_CALL
BaseContent::getParent()
{
OUString ParentUnq = getParentName( m_aUncPath );
OUString ParentUrl;
bool err = fileaccess::TaskManager::getUrlFromUnq( ParentUnq, ParentUrl );
if( err )
return Reference< XInterface >( nullptr );
rtl::Reference<FileContentIdentifier> Identifier = new FileContentIdentifier( ParentUnq );
try
{
return Reference<XInterface>( m_pMyShell->m_pProvider->queryContent( Identifier ), UNO_QUERY );
}
catch (const IllegalIdentifierException&)
{
return Reference< XInterface >();
}
}
void SAL_CALL
BaseContent::setParent(
const Reference< XInterface >& )
{
throw lang::NoSupportException( THROW_WHERE );
}
// Private Methods
Reference< XCommandInfo >
BaseContent::getCommandInfo()
{
if( m_nState & Deleted )
return Reference< XCommandInfo >();
return m_pMyShell->info_c();
}
Reference< beans::XPropertySetInfo >
BaseContent::getPropertySetInfo()
{
if( m_nState & Deleted )
return Reference< beans::XPropertySetInfo >();
return m_pMyShell->info_p( m_aUncPath );
}
Reference< sdbc::XRow >
BaseContent::getPropertyValues(
sal_Int32 nMyCommandIdentifier,
const Sequence< beans::Property >& PropertySet )
{
sal_Int32 nProps = PropertySet.getLength();
if ( !nProps )
return Reference< sdbc::XRow >();
if( m_nState & Deleted )
{
Sequence< Any > aValues( nProps );
return Reference< sdbc::XRow >( new XRow_impl( m_pMyShell, aValues ) );
}
if( m_nState & JustInserted )
{
Sequence< Any > aValues( nProps );
Any* pValues = aValues.getArray();
const beans::Property* pProps = PropertySet.getConstArray();
for ( sal_Int32 n = 0; n < nProps; ++n )
{
const beans::Property& rProp = pProps[ n ];
Any& rValue = pValues[ n ];
if ( rProp.Name == "ContentType" )
{
rValue <<= (m_bFolder ? TaskManager::FolderContentType
: TaskManager::FileContentType);
}
else if ( rProp.Name == "IsFolder" )
{
rValue <<= m_bFolder;
}
else if ( rProp.Name == "IsDocument" )
{
rValue <<= !m_bFolder;
}
}
return Reference< sdbc::XRow >(
new XRow_impl( m_pMyShell, aValues ) );
}
return m_pMyShell->getv( nMyCommandIdentifier,
m_aUncPath,
PropertySet );
}
Sequence< Any >
BaseContent::setPropertyValues(
sal_Int32 nMyCommandIdentifier,
const Sequence< beans::PropertyValue >& Values )
{
if( m_nState & Deleted )
{ // To do
return Sequence< Any >( Values.getLength() );
}
static constexpr OUString Title(u"Title"_ustr);
// Special handling for files which have to be inserted
if( m_nState & JustInserted )
{
for( const auto& rValue : Values )
{
if( rValue.Name == Title )
{
OUString NewTitle;
if( rValue.Value >>= NewTitle )
{
if ( m_nState & NameForInsertionSet )
{
// User wants to set another Title before "insert".
// m_aUncPath contains previous own URI.
sal_Int32 nLastSlash = m_aUncPath.lastIndexOf( '/' );
bool bTrailingSlash = false;
if ( nLastSlash == m_aUncPath.getLength() - 1 )
{
bTrailingSlash = true;
nLastSlash
= m_aUncPath.lastIndexOf( '/', nLastSlash );
}
OSL_ENSURE( nLastSlash != -1,
"BaseContent::setPropertyValues: "
"Invalid URL!" );
OUStringBuffer aBuf(
m_aUncPath.subView( 0, nLastSlash + 1 ) );
if ( !NewTitle.isEmpty() )
{
aBuf.append( NewTitle );
if ( bTrailingSlash )
aBuf.append( '/' );
}
else
{
m_nState &= ~NameForInsertionSet;
}
m_aUncPath = aBuf.makeStringAndClear();
}
else
{
if ( !NewTitle.isEmpty() )
{
// Initial Title before "insert".
// m_aUncPath contains parent's URI.
if( !m_aUncPath.endsWith( "/" ) )
m_aUncPath += "/";
m_aUncPath += rtl::Uri::encode( NewTitle,
rtl_UriCharClassPchar,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8 );
m_nState |= NameForInsertionSet;
}
}
}
}
}
return Sequence< Any >( Values.getLength() );
}
else
{
Sequence< Any > ret = m_pMyShell->setv( m_aUncPath, // Does not handle Title
Values );
auto retRange = asNonConstRange(ret);
// Special handling Title: Setting Title is equivalent to a renaming of the underlying file
for( sal_Int32 i = 0; i < Values.getLength(); ++i )
{
if( Values[i].Name != Title )
continue; // handled by setv
OUString NewTitle;
if( !( Values[i].Value >>= NewTitle ) )
{
retRange[i] <<= beans::IllegalTypeException( THROW_WHERE );
break;
}
else if( NewTitle.isEmpty() )
{
retRange[i] <<= lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
break;
}
OUString aDstName = getParentName( m_aUncPath );
if( !aDstName.endsWith("/") )
aDstName += "/";
aDstName += rtl::Uri::encode( NewTitle,
rtl_UriCharClassPchar,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8 );
m_pMyShell->move( nMyCommandIdentifier, // move notifies the children also;
m_aUncPath,
aDstName,
NameClash::KEEP );
try
{
endTask( nMyCommandIdentifier );
}
catch(const Exception& e)
{
retRange[i] <<= e;
}
// NameChanges come back through a ContentEvent
break; // only handling Title
} // end for
return ret;
}
}
Reference< XDynamicResultSet >
BaseContent::open(
sal_Int32 nMyCommandIdentifier,
const OpenCommandArgument2& aCommandArgument )
{
Reference< XDynamicResultSet > retValue;
if( m_nState & Deleted )
{
m_pMyShell->installError( nMyCommandIdentifier,
TaskHandlerErr::DELETED_STATE_IN_OPEN_COMMAND );
}
else if( m_nState & JustInserted )
{
m_pMyShell->installError( nMyCommandIdentifier,
TaskHandlerErr::INSERTED_STATE_IN_OPEN_COMMAND );
}
else
{
if( aCommandArgument.Mode == OpenMode::DOCUMENT ||
aCommandArgument.Mode == OpenMode::DOCUMENT_SHARE_DENY_NONE )
{
Reference< io::XOutputStream > outputStream( aCommandArgument.Sink,UNO_QUERY );
if( outputStream.is() )
{
m_pMyShell->page( nMyCommandIdentifier,
m_aUncPath,
outputStream );
}
bool bLock = ( aCommandArgument.Mode != OpenMode::DOCUMENT_SHARE_DENY_NONE );
Reference< io::XActiveDataSink > activeDataSink( aCommandArgument.Sink,UNO_QUERY );
if( activeDataSink.is() )
{
activeDataSink->setInputStream( m_pMyShell->open( nMyCommandIdentifier,
m_aUncPath,
bLock ) );
}
Reference< io::XActiveDataStreamer > activeDataStreamer( aCommandArgument.Sink,UNO_QUERY );
if( activeDataStreamer.is() )
{
activeDataStreamer->setStream( m_pMyShell->open_rw( nMyCommandIdentifier,
m_aUncPath,
bLock ) );
}
}
else if ( aCommandArgument.Mode == OpenMode::ALL ||
aCommandArgument.Mode == OpenMode::FOLDERS ||
aCommandArgument.Mode == OpenMode::DOCUMENTS )
{
retValue = m_pMyShell->ls( nMyCommandIdentifier,
m_aUncPath,
aCommandArgument.Mode,
aCommandArgument.Properties,
aCommandArgument.SortingInfo );
}
// else if( aCommandArgument.Mode ==
// OpenMode::DOCUMENT_SHARE_DENY_NONE ||
// aCommandArgument.Mode ==
// OpenMode::DOCUMENT_SHARE_DENY_WRITE )
// m_pMyShell->installError( nMyCommandIdentifier,
// TaskHandlerErr::UNSUPPORTED_OPEN_MODE,
// aCommandArgument.Mode);
else
m_pMyShell->installError( nMyCommandIdentifier,
TaskHandlerErr::UNSUPPORTED_OPEN_MODE,
aCommandArgument.Mode);
}
return retValue;
}
void
BaseContent::deleteContent( sal_Int32 nMyCommandIdentifier )
{
if( m_nState & Deleted )
return;
if( m_pMyShell->remove( nMyCommandIdentifier,m_aUncPath ) )
{
std::unique_lock aGuard( m_aMutex );
m_nState |= Deleted;
}
}
void
BaseContent::transfer( sal_Int32 nMyCommandIdentifier,
const TransferInfo& aTransferInfo )
{
if( m_nState & Deleted )
return;
if( !comphelper::isFileUrl(aTransferInfo.SourceURL) )
{
m_pMyShell->installError( nMyCommandIdentifier,
TaskHandlerErr::TRANSFER_INVALIDSCHEME );
return;
}
OUString srcUnc;
if( fileaccess::TaskManager::getUnqFromUrl( aTransferInfo.SourceURL,srcUnc ) )
{
m_pMyShell->installError( nMyCommandIdentifier,
TaskHandlerErr::TRANSFER_INVALIDURL );
return;
}
OUString srcUncPath = srcUnc;
// Determine the new title !
OUString NewTitle;
if( !aTransferInfo.NewTitle.isEmpty() )
NewTitle = rtl::Uri::encode( aTransferInfo.NewTitle,
rtl_UriCharClassPchar,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8 );
else
NewTitle = srcUncPath.copy( 1 + srcUncPath.lastIndexOf( '/' ) );
// Is destination a document or a folder ?
Reference< sdbc::XRow > xRow = getPropertyValues( nMyCommandIdentifier,{ { u"IsDocument"_ustr, -1, cppu::UnoType<sal_Bool>::get(), 0 } } );
bool IsDocument = xRow->getBoolean( 1 );
if( xRow->wasNull() )
{ // Destination file type could not be determined
m_pMyShell->installError( nMyCommandIdentifier,
TaskHandlerErr::TRANSFER_DESTFILETYPE );
return;
}
OUString dstUncPath;
if( IsDocument )
{ // as sibling
sal_Int32 lastSlash = m_aUncPath.lastIndexOf( '/' );
dstUncPath = m_aUncPath.copy(0,lastSlash );
}
else
// as child
dstUncPath = m_aUncPath;
dstUncPath += "/" + NewTitle;
sal_Int32 NameClash = aTransferInfo.NameClash;
if( aTransferInfo.MoveData )
m_pMyShell->move( nMyCommandIdentifier,srcUncPath,dstUncPath,NameClash );
else
m_pMyShell->copy( nMyCommandIdentifier,srcUncPath,dstUncPath,NameClash );
}
void BaseContent::insert( sal_Int32 nMyCommandIdentifier,
const InsertCommandArgument& aInsertArgument )
{
if( m_nState & FullFeatured )
{
m_pMyShell->write( nMyCommandIdentifier,
m_aUncPath,
aInsertArgument.ReplaceExisting,
aInsertArgument.Data );
return;
}
if( ! ( m_nState & JustInserted ) )
{
m_pMyShell->installError( nMyCommandIdentifier,
TaskHandlerErr::NOFRESHINSERT_IN_INSERT_COMMAND );
return;
}
// Inserts the content, which has the flag m_bIsFresh
if( ! (m_nState & NameForInsertionSet) )
{
m_pMyShell->installError( nMyCommandIdentifier,
TaskHandlerErr::NONAMESET_INSERT_COMMAND );
return;
}
// Inserting a document or a file?
bool bDocument = false;
Reference< sdbc::XRow > xRow = getPropertyValues( -1, { { u"IsDocument"_ustr, -1, cppu::UnoType<sal_Bool>::get(), 0 } });
bool contentTypeSet = true; // is set to false, if contentType not set
try
{
bDocument = xRow->getBoolean( 1 );
if( xRow->wasNull() )
contentTypeSet = false;
}
catch (const sdbc::SQLException&)
{
TOOLS_WARN_EXCEPTION("ucb.ucp.file", "");
contentTypeSet = false;
}
if( ! contentTypeSet )
{
m_pMyShell->installError( nMyCommandIdentifier,
TaskHandlerErr::NOCONTENTTYPE_INSERT_COMMAND );
return;
}
bool success = false;
if( bDocument )
success = m_pMyShell->mkfil( nMyCommandIdentifier,
m_aUncPath,
aInsertArgument.ReplaceExisting,
aInsertArgument.Data );
else
{
while( ! success )
{
success = m_pMyShell->mkdir( nMyCommandIdentifier,
m_aUncPath,
aInsertArgument.ReplaceExisting );
if( success )
break;
XInteractionRequestImpl aRequestImpl(
rtl::Uri::decode(
OUString(getTitle(m_aUncPath)),
rtl_UriDecodeWithCharset,
RTL_TEXTENCODING_UTF8),
getXWeak(),
m_pMyShell,nMyCommandIdentifier);
uno::Reference<task::XInteractionRequest> const& xReq(aRequestImpl.getRequest());
m_pMyShell->handleTask( nMyCommandIdentifier, xReq );
if (aRequestImpl.aborted() || aRequestImpl.newName().isEmpty())
// means aborting
break;
// determine new uncpath
m_pMyShell->clearError( nMyCommandIdentifier );
m_aUncPath = getParentName( m_aUncPath );
if( !m_aUncPath.endsWith( "/" ) )
m_aUncPath += "/";
m_aUncPath += rtl::Uri::encode( aRequestImpl.newName(),
rtl_UriCharClassPchar,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8 );
}
}
if ( ! success )
return;
m_xContentIdentifier.set( new FileContentIdentifier( m_aUncPath ) );
m_pMyShell->registerNotifier( m_aUncPath,this );
m_pMyShell->insertDefaultProperties( m_aUncPath );
std::unique_lock aGuard( m_aMutex );
m_nState = FullFeatured;
}
void BaseContent::endTask( sal_Int32 CommandId )
{
// This is the only function allowed to throw an exception
m_pMyShell->endTask( CommandId,m_aUncPath,this );
}
std::optional<ContentEventNotifier>
BaseContent::cDEL()
{
std::unique_lock aGuard( m_aMutex );
m_nState |= Deleted;
if( m_aContentEventListeners.getLength(aGuard) == 0 )
return {};
return ContentEventNotifier( m_pMyShell,
this,
m_xContentIdentifier,
m_aContentEventListeners.getElements(aGuard) );
}
std::optional<ContentEventNotifier>
BaseContent::cEXC( const OUString& aNewName )
{
std::unique_lock aGuard( m_aMutex );
Reference< XContentIdentifier > xOldRef = m_xContentIdentifier;
m_aUncPath = aNewName;
m_xContentIdentifier = new FileContentIdentifier( aNewName );
if( m_aContentEventListeners.getLength(aGuard) == 0 )
return {};
return ContentEventNotifier( m_pMyShell,
this,
m_xContentIdentifier,
xOldRef,
m_aContentEventListeners.getElements(aGuard) );
}
std::optional<ContentEventNotifier>
BaseContent::cCEL()
{
std::unique_lock aGuard( m_aMutex );
if( m_aContentEventListeners.getLength(aGuard) == 0 )
return {};
return ContentEventNotifier( m_pMyShell,
this,
m_xContentIdentifier,
m_aContentEventListeners.getElements(aGuard) );
}
std::optional<PropertySetInfoChangeNotifier>
BaseContent::cPSL()
{
std::unique_lock aGuard( m_aMutex );
if( m_aPropertySetInfoChangeListeners.getLength(aGuard) == 0 )
return {};
return PropertySetInfoChangeNotifier( this, m_aPropertySetInfoChangeListeners.getElements(aGuard) );
}
std::optional<PropertyChangeNotifier>
BaseContent::cPCL()
{
std::unique_lock aGuard( m_aMutex );
if (!m_pPropertyListener)
return {};
const std::vector< OUString > seqNames = m_pPropertyListener->getContainedTypes(aGuard);
if( seqNames.empty() )
return {};
ListenerMap listener;
for( const auto& rName : seqNames )
{
comphelper::OInterfaceContainerHelper4<beans::XPropertiesChangeListener>* pContainer = m_pPropertyListener->getContainer(aGuard, rName);
if (!pContainer)
continue;
listener[rName] = pContainer->getElements(aGuard);
}
return PropertyChangeNotifier( this, std::move(listener) );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'append' is required to be utilized.