diff options
Diffstat (limited to 'ucbhelper/source/client/content.cxx')
-rw-r--r-- | ucbhelper/source/client/content.cxx | 1359 |
1 files changed, 1359 insertions, 0 deletions
diff --git a/ucbhelper/source/client/content.cxx b/ucbhelper/source/client/content.cxx new file mode 100644 index 000000000..4eeeab200 --- /dev/null +++ b/ucbhelper/source/client/content.cxx @@ -0,0 +1,1359 @@ +/* -*- 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 <sal/config.h> + +#include <cassert> + +#include <o3tl/unreachable.hxx> +#include <osl/diagnose.h> +#include <mutex> +#include <sal/log.hxx> +#include <salhelper/simplereferenceobject.hxx> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/ucb/CheckinArgument.hpp> +#include <com/sun/star/ucb/ContentCreationError.hpp> +#include <com/sun/star/ucb/ContentCreationException.hpp> +#include <com/sun/star/ucb/IllegalIdentifierException.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/ucb/Command.hpp> +#include <com/sun/star/ucb/ContentAction.hpp> +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/ucb/XContentCreator.hpp> +#include <com/sun/star/ucb/XContentEventListener.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/ucb/SortedDynamicResultSetFactory.hpp> +#include <com/sun/star/ucb/UniversalContentBroker.hpp> +#include <com/sun/star/ucb/XUniversalContentBroker.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <ucbhelper/content.hxx> +#include <ucbhelper/activedatasink.hxx> +#include "activedatastreamer.hxx" +#include <ucbhelper/cancelcommandexecution.hxx> + +namespace com::sun::star::ucb { class XCommandEnvironment; } +namespace com::sun::star::ucb { class XContentProvider; } +namespace com::sun::star::sdbc { class XResultSet; } + +using namespace com::sun::star::container; +using namespace com::sun::star::beans; +using namespace com::sun::star::io; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::task; +using namespace com::sun::star::ucb; +using namespace com::sun::star::uno; + +namespace ucbhelper +{ + +namespace { + +class EmptyInputStream : public ::cppu::WeakImplHelper< XInputStream > +{ +public: + virtual sal_Int32 SAL_CALL readBytes( + Sequence< sal_Int8 > & data, sal_Int32 nBytesToRead ) override; + virtual sal_Int32 SAL_CALL readSomeBytes( + Sequence< sal_Int8 > & data, sal_Int32 nMaxBytesToRead ) override; + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override; + virtual sal_Int32 SAL_CALL available() override; + virtual void SAL_CALL closeInput() override; +}; + +} + +sal_Int32 EmptyInputStream::readBytes( + Sequence< sal_Int8 > & data, sal_Int32 ) +{ + data.realloc( 0 ); + return 0; +} + +sal_Int32 EmptyInputStream::readSomeBytes( + Sequence< sal_Int8 > & data, sal_Int32 ) +{ + data.realloc( 0 ); + return 0; +} + +void EmptyInputStream::skipBytes( sal_Int32 ) +{ +} + +sal_Int32 EmptyInputStream::available() +{ + return 0; +} + +void EmptyInputStream::closeInput() +{ +} + + + +namespace { + +class ContentEventListener_Impl : public cppu::OWeakObject, + public XContentEventListener +{ + Content_Impl& m_rContent; + +public: + explicit ContentEventListener_Impl( Content_Impl& rContent ) + : m_rContent( rContent ) {} + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XContentEventListener + virtual void SAL_CALL contentEvent( const ContentEvent& evt ) override; + + // XEventListener ( base of XContentEventListener ) + virtual void SAL_CALL disposing( const EventObject& Source ) override; +}; + +} + + + +class Content_Impl : public salhelper::SimpleReferenceObject +{ +friend ContentEventListener_Impl; + + mutable OUString m_aURL; + Reference< XComponentContext > m_xCtx; + Reference< XContent > m_xContent; + Reference< XCommandProcessor > m_xCommandProcessor; + Reference< XCommandEnvironment > m_xEnv; + Reference< XContentEventListener > m_xContentEventListener; + mutable std::mutex m_aMutex; + +private: + void reinit( const Reference< XContent >& xContent ); + void disposing(const EventObject& Source); + Reference< XContent > getContent_NoLock(); + const OUString& getURL_NoLock() const; + +public: + Content_Impl() {}; + Content_Impl( const Reference< XComponentContext >& rCtx, + const Reference< XContent >& rContent, + const Reference< XCommandEnvironment >& rEnv ); + + virtual ~Content_Impl() override; + + const OUString& getURL() const; + Reference< XContent > getContent(); + Reference< XCommandProcessor > getCommandProcessor(); + Reference< XComponentContext > const & getComponentContext() const + { assert(m_xCtx.is()); return m_xCtx; } + + Any executeCommand( const Command& rCommand ); + + inline const Reference< XCommandEnvironment >& getEnvironment() const; + inline void setEnvironment( + const Reference< XCommandEnvironment >& xNewEnv ); + + void inserted(); +}; + + +// Helpers. + +/// @throws ContentCreationException +/// @throws RuntimeException +static void ensureContentProviderForURL( const Reference< XUniversalContentBroker >& rBroker, + const OUString & rURL ) +{ + Reference< XContentProvider > xProv + = rBroker->queryContentProvider( rURL ); + if ( !xProv.is() ) + { + throw ContentCreationException( + "No Content Provider available for URL: " + rURL, + Reference< XInterface >(), + ContentCreationError_NO_CONTENT_PROVIDER ); + } +} + +/// @throws ContentCreationException +/// @throws RuntimeException +static Reference< XContentIdentifier > getContentIdentifierThrow( + const Reference< XUniversalContentBroker > & rBroker, + const OUString & rURL) +{ + Reference< XContentIdentifier > xId + = rBroker->createContentIdentifier( rURL ); + + if (!xId.is()) + { + ensureContentProviderForURL( rBroker, rURL ); + + throw ContentCreationException( + "Unable to create Content Identifier!", + Reference< XInterface >(), + ContentCreationError_IDENTIFIER_CREATION_FAILED ); + } + + return xId; +} + +/// @throws RuntimeException +static Reference< XContentIdentifier > getContentIdentifierNoThrow( + const Reference< XUniversalContentBroker > & rBroker, + const OUString & rURL) +{ + return rBroker->createContentIdentifier(rURL); +} + +/// @throws ContentCreationException +/// @throws RuntimeException +static Reference< XContent > getContentThrow( + const Reference< XUniversalContentBroker > & rBroker, + const Reference< XContentIdentifier > & xId) +{ + Reference< XContent > xContent; + OUString msg; + try + { + xContent = rBroker->queryContent( xId ); + } + catch ( IllegalIdentifierException const & e ) + { + msg = e.Message; + // handled below. + } + + if ( !xContent.is() ) + { + ensureContentProviderForURL( rBroker, xId->getContentIdentifier() ); + + throw ContentCreationException( + "Unable to create Content for <" + xId->getContentIdentifier() + ">: " + msg, + Reference< XInterface >(), + ContentCreationError_CONTENT_CREATION_FAILED ); + } + + return xContent; +} + +/// @throws RuntimeException +static Reference< XContent > getContentNoThrow( + const Reference< XUniversalContentBroker > & rBroker, + const Reference< XContentIdentifier > & xId) +{ + Reference< XContent > xContent; + try + { + xContent = rBroker->queryContent( xId ); + } + catch ( IllegalIdentifierException const & e ) + { + SAL_WARN("ucbhelper", "getContentNoThrow: " << e); + } + + return xContent; +} + + +// Content Implementation. + + +Content::Content() +: m_xImpl( new Content_Impl ) +{ +} + + +Content::Content( const OUString& rURL, + const Reference< XCommandEnvironment >& rEnv, + const Reference< XComponentContext >& rCtx ) +{ + Reference< XUniversalContentBroker > pBroker( + UniversalContentBroker::create( rCtx ) ); + + Reference< XContentIdentifier > xId + = getContentIdentifierThrow(pBroker, rURL); + + Reference< XContent > xContent = getContentThrow(pBroker, xId); + + m_xImpl = new Content_Impl( rCtx, xContent, rEnv ); +} + + +Content::Content( const Reference< XContent >& rContent, + const Reference< XCommandEnvironment >& rEnv, + const Reference< XComponentContext >& rCtx ) +{ + m_xImpl = new Content_Impl( rCtx, rContent, rEnv ); +} + + +Content::Content( const Content& rOther ) +{ + m_xImpl = rOther.m_xImpl; +} + +Content::Content( Content&& rOther ) noexcept +{ + m_xImpl = std::move(rOther.m_xImpl); +} + +// static +bool Content::create( const OUString& rURL, + const Reference< XCommandEnvironment >& rEnv, + const Reference< XComponentContext >& rCtx, + Content& rContent ) +{ + Reference< XUniversalContentBroker > pBroker( + UniversalContentBroker::create( rCtx ) ); + + Reference< XContentIdentifier > xId + = getContentIdentifierNoThrow(pBroker, rURL); + if ( !xId.is() ) + return false; + + Reference< XContent > xContent = getContentNoThrow(pBroker, xId); + if ( !xContent.is() ) + return false; + + rContent.m_xImpl + = new Content_Impl( rCtx, xContent, rEnv ); + + return true; +} + + +Content::~Content() +{ +} + + +Content& Content::operator=( const Content& rOther ) +{ + m_xImpl = rOther.m_xImpl; + return *this; +} + +Content& Content::operator=( Content&& rOther ) noexcept +{ + m_xImpl = std::move(rOther.m_xImpl); + return *this; +} + +Reference< XContent > Content::get() const +{ + return m_xImpl->getContent(); +} + + +const OUString& Content::getURL() const +{ + return m_xImpl->getURL(); +} + + +const Reference< XCommandEnvironment >& Content::getCommandEnvironment() const +{ + return m_xImpl->getEnvironment(); +} + + +void Content::setCommandEnvironment( + const Reference< XCommandEnvironment >& xNewEnv ) +{ + m_xImpl->setEnvironment( xNewEnv ); +} + + +Reference< XCommandInfo > Content::getCommands() +{ + Command aCommand; + aCommand.Name = "getCommandInfo"; + aCommand.Handle = -1; // n/a + aCommand.Argument = Any(); + + Any aResult = m_xImpl->executeCommand( aCommand ); + + Reference< XCommandInfo > xInfo; + aResult >>= xInfo; + return xInfo; +} + + +Reference< XPropertySetInfo > Content::getProperties() +{ + static constexpr OUStringLiteral sgetPropertySetInfo = u"getPropertySetInfo"; + Command aCommand; + aCommand.Name = sgetPropertySetInfo; + aCommand.Handle = -1; // n/a + aCommand.Argument = Any(); + + Any aResult = m_xImpl->executeCommand( aCommand ); + + Reference< XPropertySetInfo > xInfo; + aResult >>= xInfo; + return xInfo; +} + + +Any Content::getPropertyValue( const OUString& rPropertyName ) +{ + Sequence<OUString> aNames { rPropertyName }; + + Sequence< Any > aRet = getPropertyValues( aNames ); + return aRet.getConstArray()[ 0 ]; +} + + +Any Content::setPropertyValue( const OUString& rName, + const Any& rValue ) +{ + Sequence<OUString> aNames { rName }; + + Sequence< Any > aValues( 1 ); + aValues.getArray()[ 0 ] = rValue; + + Sequence< Any > aErrors = setPropertyValues( aNames, aValues ); + return aErrors.getConstArray()[ 0 ]; +} + + +Sequence< Any > Content::getPropertyValues( + const Sequence< OUString >& rPropertyNames ) +{ + Reference< XRow > xRow = getPropertyValuesInterface( rPropertyNames ); + + sal_Int32 nCount = rPropertyNames.getLength(); + Sequence< Any > aValues( nCount ); + + if ( xRow.is() ) + { + Any* pValues = aValues.getArray(); + + for ( sal_Int32 n = 0; n < nCount; ++n ) + pValues[ n ] = xRow->getObject( n + 1, Reference< XNameAccess >() ); + } + + return aValues; +} + + +Reference< XRow > Content::getPropertyValuesInterface( + const Sequence< OUString >& rPropertyNames ) +{ + sal_Int32 nCount = rPropertyNames.getLength(); + Sequence< Property > aProps( nCount ); + Property* pProps = aProps.getArray(); + + const OUString* pNames = rPropertyNames.getConstArray(); + + for ( sal_Int32 n = 0; n< nCount; ++n ) + { + Property& rProp = pProps[ n ]; + + rProp.Name = pNames[ n ]; + rProp.Handle = -1; // n/a +// rProp.Type = +// rProp.Attributes = ; + } + + static constexpr OUStringLiteral sgetPropertyValues = u"getPropertyValues"; + Command aCommand; + aCommand.Name = sgetPropertyValues; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aProps; + + Any aResult = m_xImpl->executeCommand( aCommand ); + + Reference< XRow > xRow; + aResult >>= xRow; + return xRow; +} + + +Sequence< Any > Content::setPropertyValues( + const Sequence< OUString >& rPropertyNames, + const Sequence< Any >& rValues ) +{ + if ( rPropertyNames.getLength() != rValues.getLength() ) + { + ucbhelper::cancelCommandExecution( + Any( IllegalArgumentException( + "Length of property names sequence and value " + "sequence are unequal!", + get(), + -1 ) ), + m_xImpl->getEnvironment() ); + // Unreachable + } + + sal_Int32 nCount = rValues.getLength(); + Sequence< PropertyValue > aProps( nCount ); + PropertyValue* pProps = aProps.getArray(); + + const OUString* pNames = rPropertyNames.getConstArray(); + const Any* pValues = rValues.getConstArray(); + + for ( sal_Int32 n = 0; n< nCount; ++n ) + { + PropertyValue& rProp = pProps[ n ]; + + rProp.Name = pNames[ n ]; + rProp.Handle = -1; // n/a + rProp.Value = pValues[ n ]; +// rProp.State = ; + } + + Command aCommand; + aCommand.Name = "setPropertyValues"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aProps; + + Any aResult = m_xImpl->executeCommand( aCommand ); + + Sequence< Any > aErrors; + aResult >>= aErrors; + return aErrors; +} + + +Any Content::executeCommand( const OUString& rCommandName, + const Any& rCommandArgument ) +{ + Command aCommand; + aCommand.Name = rCommandName; + aCommand.Handle = -1; // n/a + aCommand.Argument = rCommandArgument; + + return m_xImpl->executeCommand( aCommand ); +} + + +Any Content::createCursorAny( const Sequence< OUString >& rPropertyNames, + ResultSetInclude eMode ) +{ + sal_Int32 nCount = rPropertyNames.getLength(); + Sequence< Property > aProps( nCount ); + Property* pProps = aProps.getArray(); + const OUString* pNames = rPropertyNames.getConstArray(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + Property& rProp = pProps[ n ]; + rProp.Name = pNames[ n ]; + rProp.Handle = -1; // n/a + } + + OpenCommandArgument2 aArg; + aArg.Mode = ( eMode == INCLUDE_FOLDERS_ONLY ) + ? OpenMode::FOLDERS + : ( eMode == INCLUDE_DOCUMENTS_ONLY ) + ? OpenMode::DOCUMENTS : OpenMode::ALL; + aArg.Priority = 0; // unused + aArg.Sink.clear(); // unused + aArg.Properties = aProps; + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + return m_xImpl->executeCommand( aCommand ); +} + + +Reference< XResultSet > Content::createCursor( + const Sequence< OUString >& rPropertyNames, + ResultSetInclude eMode ) +{ + Any aCursorAny = createCursorAny( rPropertyNames, eMode ); + + Reference< XDynamicResultSet > xDynSet; + Reference< XResultSet > aResult; + + aCursorAny >>= xDynSet; + if ( xDynSet.is() ) + aResult = xDynSet->getStaticResultSet(); + + OSL_ENSURE( aResult.is(), "Content::createCursor - no cursor!" ); + + if ( !aResult.is() ) + { + // Former, the open command directly returned a XResultSet. + aCursorAny >>= aResult; + + OSL_ENSURE( !aResult.is(), + "Content::createCursor - open-Command must " + "return a Reference< XDynnamicResultSet >!" ); + } + + return aResult; +} + + +Reference< XDynamicResultSet > Content::createDynamicCursor( + const Sequence< OUString >& rPropertyNames, + ResultSetInclude eMode ) +{ + Reference< XDynamicResultSet > aResult; + createCursorAny( rPropertyNames, eMode ) >>= aResult; + + OSL_ENSURE( aResult.is(), "Content::createDynamicCursor - no cursor!" ); + + return aResult; +} + + +Reference< XResultSet > Content::createSortedCursor( + const Sequence< OUString >& rPropertyNames, + const Sequence< NumberedSortingInfo >& rSortInfo, + const Reference< XAnyCompareFactory >& rAnyCompareFactory, + ResultSetInclude eMode ) +{ + Reference< XResultSet > aResult; + Reference< XDynamicResultSet > aDynSet; + + Any aCursorAny = createCursorAny( rPropertyNames, eMode ); + + aCursorAny >>= aDynSet; + + if( aDynSet.is() ) + { + Reference< XDynamicResultSet > aDynResult; + + if( m_xImpl->getComponentContext().is() ) + { + Reference< XSortedDynamicResultSetFactory > aSortFactory = + SortedDynamicResultSetFactory::create( m_xImpl->getComponentContext()); + + aDynResult = aSortFactory->createSortedDynamicResultSet( aDynSet, + rSortInfo, + rAnyCompareFactory ); + } + + OSL_ENSURE( aDynResult.is(), "Content::createSortedCursor - no sorted cursor!" ); + + if( aDynResult.is() ) + aResult = aDynResult->getStaticResultSet(); + else + aResult = aDynSet->getStaticResultSet(); + } + + OSL_ENSURE( aResult.is(), "Content::createSortedCursor - no cursor!" ); + + if ( !aResult.is() ) + { + // Former, the open command directly returned a XResultSet. + aCursorAny >>= aResult; + + OSL_ENSURE( !aResult.is(), + "Content::createCursor - open-Command must " + "return a Reference< XDynnamicResultSet >!" ); + } + + return aResult; +} + + +Reference< XInputStream > Content::openStream() +{ + if ( !isDocument() ) + return Reference< XInputStream >(); + + Reference< XActiveDataSink > xSink = new ActiveDataSink; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT; + aArg.Priority = 0; // unused + aArg.Sink = xSink; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return xSink->getInputStream(); +} + + +Reference< XInputStream > Content::openStreamNoLock() +{ + if ( !isDocument() ) + return Reference< XInputStream >(); + + Reference< XActiveDataSink > xSink = new ActiveDataSink; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT_SHARE_DENY_NONE; + aArg.Priority = 0; // unused + aArg.Sink = xSink; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return xSink->getInputStream(); +} + + +Reference< XStream > Content::openWriteableStream() +{ + if ( !isDocument() ) + return Reference< XStream >(); + + Reference< XActiveDataStreamer > xStreamer = new ActiveDataStreamer; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT; + aArg.Priority = 0; // unused + aArg.Sink = xStreamer; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return xStreamer->getStream(); +} + + +Reference< XStream > Content::openWriteableStreamNoLock() +{ + if ( !isDocument() ) + return Reference< XStream >(); + + Reference< XActiveDataStreamer > xStreamer = new ActiveDataStreamer; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT_SHARE_DENY_NONE; + aArg.Priority = 0; // unused + aArg.Sink = xStreamer; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return xStreamer->getStream(); +} + + +bool Content::openStream( const Reference< XActiveDataSink >& rSink ) +{ + if ( !isDocument() ) + return false; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT; + aArg.Priority = 0; // unused + aArg.Sink = rSink; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return true; +} + + +bool Content::openStream( const Reference< XOutputStream >& rStream ) +{ + if ( !isDocument() ) + return false; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT; + aArg.Priority = 0; // unused + aArg.Sink = rStream; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return true; +} + + +void Content::writeStream( const Reference< XInputStream >& rStream, + bool bReplaceExisting ) +{ + InsertCommandArgument aArg; + aArg.Data = rStream.is() ? rStream : new EmptyInputStream; + aArg.ReplaceExisting = bReplaceExisting; + + Command aCommand; + aCommand.Name = "insert"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + m_xImpl->inserted(); +} + + +Sequence< ContentInfo > Content::queryCreatableContentsInfo() +{ + // First, try it using "CreatableContentsInfo" property -> the "new" way. + Sequence< ContentInfo > aInfo; + if ( getPropertyValue( + "CreatableContentsInfo" ) + >>= aInfo ) + return aInfo; + + // Second, try it using XContentCreator interface -> the "old" way (not + // providing the chance to supply an XCommandEnvironment. + Reference< XContentCreator > xCreator( m_xImpl->getContent(), UNO_QUERY ); + if ( xCreator.is() ) + aInfo = xCreator->queryCreatableContentsInfo(); + + return aInfo; +} + + +bool Content::insertNewContent( const OUString& rContentType, + const Sequence< OUString >& + rPropertyNames, + const Sequence< Any >& rPropertyValues, + Content& rNewContent ) +{ + return insertNewContent( rContentType, + rPropertyNames, + rPropertyValues, + new EmptyInputStream, + rNewContent ); +} + + +bool Content::insertNewContent( const OUString& rContentType, + const Sequence< OUString >& + rPropertyNames, + const Sequence< Any >& rPropertyValues, + const Reference< XInputStream >& rData, + Content& rNewContent ) +{ + if ( rContentType.isEmpty() ) + return false; + + // First, try it using "createNewContent" command -> the "new" way. + ContentInfo aInfo; + aInfo.Type = rContentType; + aInfo.Attributes = 0; + + Command aCommand; + aCommand.Name = "createNewContent"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aInfo; + + Reference< XContent > xNew; + try + { + m_xImpl->executeCommand( aCommand ) >>= xNew; + } + catch ( RuntimeException const & ) + { + throw; + } + catch ( Exception const & ) + { + } + + if ( !xNew.is() ) + { + // Second, try it using XContentCreator interface -> the "old" + // way (not providing the chance to supply an XCommandEnvironment. + Reference< XContentCreator > xCreator( m_xImpl->getContent(), UNO_QUERY ); + + if ( !xCreator.is() ) + return false; + + xNew = xCreator->createNewContent( aInfo ); + + if ( !xNew.is() ) + return false; + } + + Content aNewContent( + xNew, m_xImpl->getEnvironment(), m_xImpl->getComponentContext() ); + aNewContent.setPropertyValues( rPropertyNames, rPropertyValues ); + aNewContent.executeCommand( "insert", + Any( + InsertCommandArgument( + rData.is() ? rData : new EmptyInputStream, + false /* ReplaceExisting */ ) ) ); + aNewContent.m_xImpl->inserted(); + + rNewContent = aNewContent; + return true; +} + + +void Content::transferContent( const Content& rSourceContent, + InsertOperation eOperation, + const OUString & rTitle, + const sal_Int32 nNameClashAction, + const OUString & rMimeType, + bool bMajorVersion, + const OUString & rVersionComment, + OUString* pResultURL, + const OUString & rDocumentId ) const +{ + Reference< XUniversalContentBroker > pBroker( + UniversalContentBroker::create( m_xImpl->getComponentContext() ) ); + + // Execute command "globalTransfer" at UCB. + + TransferCommandOperation eTransOp = TransferCommandOperation(); + OUString sCommand( "globalTransfer" ); + bool bCheckIn = false; + switch ( eOperation ) + { + case InsertOperation::Copy: + eTransOp = TransferCommandOperation_COPY; + break; + + case InsertOperation::Move: + eTransOp = TransferCommandOperation_MOVE; + break; + + case InsertOperation::Checkin: + eTransOp = TransferCommandOperation_COPY; + sCommand = "checkin"; + bCheckIn = true; + break; + } + Command aCommand; + aCommand.Name = sCommand; + aCommand.Handle = -1; // n/a + + if ( !bCheckIn ) + { + GlobalTransferCommandArgument2 aTransferArg( + eTransOp, + rSourceContent.getURL(), // SourceURL + getURL(), // TargetFolderURL, + rTitle, + nNameClashAction, + rMimeType, + rDocumentId ); + aCommand.Argument <<= aTransferArg; + } + else + { + CheckinArgument aCheckinArg( bMajorVersion, rVersionComment, + rSourceContent.getURL(), getURL(), rTitle, rMimeType ); + aCommand.Argument <<= aCheckinArg; + } + + Any aRet = pBroker->execute( aCommand, 0, m_xImpl->getEnvironment() ); + if ( pResultURL != nullptr ) + aRet >>= *pResultURL; +} + + +bool Content::isFolder() +{ + bool bFolder = false; + if ( getPropertyValue("IsFolder") + >>= bFolder ) + return bFolder; + + ucbhelper::cancelCommandExecution( + Any( UnknownPropertyException( + "Unable to retrieve value of property 'IsFolder'!", + get() ) ), + m_xImpl->getEnvironment() ); + + O3TL_UNREACHABLE; +} + + +SAL_WNOUNREACHABLE_CODE_PUSH + +bool Content::isDocument() +{ + bool bDoc = false; + if ( getPropertyValue("IsDocument") + >>= bDoc ) + return bDoc; + + ucbhelper::cancelCommandExecution( + Any( UnknownPropertyException( + "Unable to retrieve value of property 'IsDocument'!", + get() ) ), + m_xImpl->getEnvironment() ); + + // Unreachable - cancelCommandExecution always throws an exception, + // But some compilers complain... + return false; +} + +SAL_WNOUNREACHABLE_CODE_POP + +void Content::lock() +{ + Command aCommand; + aCommand.Name = "lock"; + aCommand.Handle = -1; // n/a + + m_xImpl->executeCommand( aCommand ); + +} + +void Content::unlock() +{ + + Command aCommand; + aCommand.Name = "unlock"; + aCommand.Handle = -1; // n/a + + m_xImpl->executeCommand( aCommand ); + +} + + +// Content_Impl Implementation. + + +Content_Impl::Content_Impl( const Reference< XComponentContext >& rCtx, + const Reference< XContent >& rContent, + const Reference< XCommandEnvironment >& rEnv ) +: m_xCtx( rCtx ), + m_xContent( rContent ), + m_xEnv( rEnv ) +{ + assert(rCtx.is()); + if ( m_xContent.is() ) + { + m_xContentEventListener = new ContentEventListener_Impl( *this ); + m_xContent->addContentEventListener( m_xContentEventListener ); + +#if OSL_DEBUG_LEVEL > 0 + // Only done on demand in product version for performance reasons, + // but a nice debug helper. + getURL(); +#endif + } +} + + +void Content_Impl::reinit( const Reference< XContent >& xContent ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_xCommandProcessor = nullptr; + + // #92581# - Don't reset m_aURL!!! + + if ( m_xContent.is() ) + { + try + { + m_xContent->removeContentEventListener( m_xContentEventListener ); + } + catch ( RuntimeException const & ) + { + } + } + + if ( xContent.is() ) + { + m_xContent = xContent; + m_xContent->addContentEventListener( m_xContentEventListener ); + +#if OSL_DEBUG_LEVEL > 0 + // Only done on demand in product version for performance reasons, + // but a nice debug helper. + getURL_NoLock(); +#endif + } + else + { + // We need m_xContent's URL in order to be able to create the + // content object again if demanded ( --> Content_Impl::getContent() ) + getURL_NoLock(); + + m_xContent = nullptr; + } +} + + +// virtual +Content_Impl::~Content_Impl() +{ + if ( m_xContent.is() ) + { + try + { + m_xContent->removeContentEventListener( m_xContentEventListener ); + } + catch ( RuntimeException const & ) + { + } + } +} + + +void Content_Impl::disposing( const EventObject& Source ) +{ + Reference<XContent> xContent; + + { + std::unique_lock aGuard( m_aMutex ); + if(Source.Source != m_xContent) + return; + + xContent = m_xContent; + + m_aURL.clear(); + m_xCommandProcessor = nullptr; + m_xContent = nullptr; + } + + if ( xContent.is() ) + { + try + { + xContent->removeContentEventListener( m_xContentEventListener ); + } + catch ( RuntimeException const & ) + { + } + } +} + + +const OUString& Content_Impl::getURL() const +{ + if ( m_aURL.isEmpty() && m_xContent.is() ) + { + std::unique_lock aGuard( m_aMutex ); + + return getURL_NoLock(); + } + + return m_aURL; +} + +const OUString& Content_Impl::getURL_NoLock() const +{ + if ( m_aURL.isEmpty() && m_xContent.is() ) + { + Reference< XContentIdentifier > xId = m_xContent->getIdentifier(); + if ( xId.is() ) + m_aURL = xId->getContentIdentifier(); + } + + return m_aURL; +} + +Reference< XContent > Content_Impl::getContent() +{ + if ( !m_xContent.is() && !m_aURL.isEmpty() ) + { + std::unique_lock aGuard( m_aMutex ); + return getContent_NoLock(); + } + return m_xContent; +} + +Reference< XContent > Content_Impl::getContent_NoLock() +{ + if ( !m_xContent.is() && !m_aURL.isEmpty() ) + { + Reference< XUniversalContentBroker > pBroker( + UniversalContentBroker::create( getComponentContext() ) ); + + OSL_ENSURE( pBroker->queryContentProviders().hasElements(), + "Content Broker not configured (no providers)!" ); + + Reference< XContentIdentifier > xId + = pBroker->createContentIdentifier( m_aURL ); + + OSL_ENSURE( xId.is(), "No Content Identifier!" ); + + if ( xId.is() ) + { + try + { + m_xContent = pBroker->queryContent( xId ); + } + catch ( IllegalIdentifierException const & ) + { + } + + if ( m_xContent.is() ) + m_xContent->addContentEventListener( + m_xContentEventListener ); + } + } + + return m_xContent; +} + + +Reference< XCommandProcessor > Content_Impl::getCommandProcessor() +{ + if ( !m_xCommandProcessor.is() ) + { + std::unique_lock aGuard( m_aMutex ); + + if ( !m_xCommandProcessor.is() ) + m_xCommandProcessor.set( getContent_NoLock(), UNO_QUERY ); + } + + return m_xCommandProcessor; +} + + +Any Content_Impl::executeCommand( const Command& rCommand ) +{ + Reference< XCommandProcessor > xProc = getCommandProcessor(); + if ( !xProc.is() ) + return Any(); + + // Execute command + return xProc->execute( rCommand, 0, m_xEnv ); +} + + +inline const Reference< XCommandEnvironment >& + Content_Impl::getEnvironment() const +{ + return m_xEnv; +} + + +inline void Content_Impl::setEnvironment( + const Reference< XCommandEnvironment >& xNewEnv ) +{ + std::unique_lock aGuard( m_aMutex ); + m_xEnv = xNewEnv; +} + + +void Content_Impl::inserted() +{ + // URL might have changed during 'insert' => recalculate in next getURL() + std::unique_lock aGuard( m_aMutex ); + m_aURL.clear(); +} + + +// ContentEventListener_Impl Implementation. + + +// XInterface methods. + +void SAL_CALL ContentEventListener_Impl::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL ContentEventListener_Impl::release() + noexcept +{ + OWeakObject::release(); +} + +css::uno::Any SAL_CALL ContentEventListener_Impl::queryInterface( const css::uno::Type & rType ) +{ + css::uno::Any aRet = cppu::queryInterface( rType, + static_cast< XContentEventListener* >(this), + static_cast< XEventListener* >(this) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + +// XContentEventListener methods. + + +// virtual +void SAL_CALL ContentEventListener_Impl::contentEvent( const ContentEvent& evt ) +{ + if ( evt.Source != m_rContent.m_xContent ) + return; + + switch ( evt.Action ) + { + case ContentAction::DELETED: + m_rContent.reinit( Reference< XContent >() ); + break; + + case ContentAction::EXCHANGED: + m_rContent.reinit( evt.Content ); + break; + + default: + break; + } +} + + +// XEventListenr methods. + + +// virtual +void SAL_CALL ContentEventListener_Impl::disposing( const EventObject& Source ) +{ + m_rContent.disposing(Source); +} + +} /* namespace ucbhelper */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |