Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / ucb / source / core / ucbcmds.cxx
blobc4ed448d42ac446706a1afd7d468c83e3ca92b06
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 /**************************************************************************
22 TODO
23 **************************************************************************
25 *************************************************************************/
26 #include <osl/diagnose.h>
27 #include <comphelper/processfactory.hxx>
28 #include <cppuhelper/implbase1.hxx>
29 #include <cppuhelper/exc_hlp.hxx>
30 #include <rtl/ustring.h>
31 #include <rtl/ustring.hxx>
32 #include <com/sun/star/uno/XInterface.hpp>
33 #include <com/sun/star/beans/PropertyState.hpp>
34 #include <com/sun/star/beans/PropertyValue.hpp>
35 #include <com/sun/star/container/XChild.hpp>
36 #include <com/sun/star/beans/XPropertySetInfo.hpp>
37 #include <com/sun/star/io/Pipe.hpp>
38 #include <com/sun/star/io/XActiveDataSink.hpp>
39 #include <com/sun/star/io/XOutputStream.hpp>
40 #include <com/sun/star/io/XSeekable.hpp>
41 #include <com/sun/star/sdbc/XRow.hpp>
42 #include <com/sun/star/task/XInteractionHandler.hpp>
43 #include <com/sun/star/ucb/CommandEnvironment.hpp>
44 #include <com/sun/star/ucb/CommandFailedException.hpp>
45 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
46 #include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
47 #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
48 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
49 #include <com/sun/star/ucb/NameClash.hpp>
50 #include <com/sun/star/ucb/NameClashException.hpp>
51 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
52 #include <com/sun/star/ucb/OpenMode.hpp>
53 #include <com/sun/star/ucb/TransferInfo2.hpp>
54 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
55 #include <com/sun/star/ucb/XCommandInfo.hpp>
56 #include <com/sun/star/ucb/XContentAccess.hpp>
57 #include <com/sun/star/ucb/XContentCreator.hpp>
58 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
59 #include <com/sun/star/uno/Any.hxx>
60 #include <com/sun/star/uno/Sequence.hxx>
61 #include <ucbhelper/cancelcommandexecution.hxx>
62 #include <ucbhelper/simplenameclashresolverequest.hxx>
63 #include "ucbcmds.hxx"
64 #include "ucb.hxx"
66 using namespace com::sun::star;
68 namespace
73 // struct TransferCommandContext.
77 struct TransferCommandContext
79 uno::Reference< uno::XComponentContext > m_xContext;
80 uno::Reference< ucb::XCommandProcessor > xProcessor;
81 uno::Reference< ucb::XCommandEnvironment > xEnv;
82 uno::Reference< ucb::XCommandEnvironment > xOrigEnv;
83 ucb::GlobalTransferCommandArgument2 aArg;
85 TransferCommandContext(
86 const uno::Reference< uno::XComponentContext > & xContext,
87 const uno::Reference< ucb::XCommandProcessor > & rxProcessor,
88 const uno::Reference< ucb::XCommandEnvironment > & rxEnv,
89 const uno::Reference< ucb::XCommandEnvironment > & rxOrigEnv,
90 const ucb::GlobalTransferCommandArgument2 & rArg )
91 : m_xContext( xContext ), xProcessor( rxProcessor ), xEnv( rxEnv ),
92 xOrigEnv( rxOrigEnv ), aArg( rArg ) {}
97 // class InteractionHandlerProxy.
101 class InteractionHandlerProxy :
102 public cppu::WeakImplHelper1< task::XInteractionHandler >
104 uno::Reference< task::XInteractionHandler > m_xOrig;
106 public:
107 InteractionHandlerProxy(
108 const uno::Reference< task::XInteractionHandler > & xOrig )
109 : m_xOrig( xOrig ) {}
111 // XInteractionHandler methods.
112 virtual void SAL_CALL handle(
113 const uno::Reference< task::XInteractionRequest >& Request )
114 throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
118 // virtual
119 void SAL_CALL InteractionHandlerProxy::handle(
120 const uno::Reference< task::XInteractionRequest >& Request )
121 throw ( uno::RuntimeException, std::exception )
123 if ( !m_xOrig.is() )
124 return;
126 // Filter unwanted requests by just not handling them.
127 uno::Any aRequest = Request->getRequest();
129 // "transfer"
130 ucb::InteractiveBadTransferURLException aBadTransferURLEx;
131 if ( aRequest >>= aBadTransferURLEx )
133 return;
135 else
137 // "transfer"
138 ucb::UnsupportedNameClashException aUnsupportedNameClashEx;
139 if ( aRequest >>= aUnsupportedNameClashEx )
141 if ( aUnsupportedNameClashEx.NameClash
142 != ucb::NameClash::ERROR )
143 return;
145 else
147 // "insert"
148 ucb::NameClashException aNameClashEx;
149 if ( aRequest >>= aNameClashEx )
151 return;
153 else
155 // "transfer"
156 ucb::UnsupportedCommandException aUnsupportedCommandEx;
157 if ( aRequest >>= aUnsupportedCommandEx )
159 return;
165 // not filtered; let the original handler do the work.
166 m_xOrig->handle( Request );
171 // class ActiveDataSink.
175 class ActiveDataSink : public cppu::WeakImplHelper1< io::XActiveDataSink >
177 uno::Reference< io::XInputStream > m_xStream;
179 public:
180 // XActiveDataSink methods.
181 virtual void SAL_CALL setInputStream(
182 const uno::Reference< io::XInputStream >& aStream )
183 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
184 virtual uno::Reference< io::XInputStream > SAL_CALL getInputStream()
185 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
189 // virtual
190 void SAL_CALL ActiveDataSink::setInputStream(
191 const uno::Reference< io::XInputStream >& aStream )
192 throw( uno::RuntimeException, std::exception )
194 m_xStream = aStream;
198 // virtual
199 uno::Reference< io::XInputStream > SAL_CALL ActiveDataSink::getInputStream()
200 throw( uno::RuntimeException, std::exception )
202 return m_xStream;
207 // class CommandProcessorInfo.
211 class CommandProcessorInfo :
212 public cppu::WeakImplHelper1< ucb::XCommandInfo >
214 uno::Sequence< ucb::CommandInfo > * m_pInfo;
216 public:
217 CommandProcessorInfo();
218 virtual ~CommandProcessorInfo();
220 // XCommandInfo methods
221 virtual uno::Sequence< ucb::CommandInfo > SAL_CALL getCommands()
222 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
223 virtual ucb::CommandInfo SAL_CALL
224 getCommandInfoByName( const OUString& Name )
225 throw( ucb::UnsupportedCommandException, uno::RuntimeException, std::exception ) SAL_OVERRIDE;
226 virtual ucb::CommandInfo SAL_CALL
227 getCommandInfoByHandle( sal_Int32 Handle )
228 throw( ucb::UnsupportedCommandException, uno::RuntimeException, std::exception ) SAL_OVERRIDE;
229 virtual sal_Bool SAL_CALL hasCommandByName( const OUString& Name )
230 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
231 virtual sal_Bool SAL_CALL hasCommandByHandle( sal_Int32 Handle )
232 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
236 CommandProcessorInfo::CommandProcessorInfo()
238 m_pInfo = new uno::Sequence< ucb::CommandInfo >( 2 );
240 (*m_pInfo)[ 0 ]
241 = ucb::CommandInfo(
242 OUString( GETCOMMANDINFO_NAME ), // Name
243 GETCOMMANDINFO_HANDLE, // Handle
244 getCppuVoidType() ); // ArgType
245 (*m_pInfo)[ 1 ]
246 = ucb::CommandInfo(
247 OUString( GLOBALTRANSFER_NAME ), // Name
248 GLOBALTRANSFER_HANDLE, // Handle
249 cppu::UnoType<ucb::GlobalTransferCommandArgument>::get() ); // ArgType
250 (*m_pInfo)[ 2 ]
251 = ucb::CommandInfo(
252 OUString( CHECKIN_NAME ), // Name
253 CHECKIN_HANDLE, // Handle
254 cppu::UnoType<ucb::CheckinArgument>::get() ); // ArgType
258 // virtual
259 CommandProcessorInfo::~CommandProcessorInfo()
261 delete m_pInfo;
265 // virtual
266 uno::Sequence< ucb::CommandInfo > SAL_CALL
267 CommandProcessorInfo::getCommands()
268 throw( uno::RuntimeException, std::exception )
270 return uno::Sequence< ucb::CommandInfo >( *m_pInfo );
274 // virtual
275 ucb::CommandInfo SAL_CALL
276 CommandProcessorInfo::getCommandInfoByName( const OUString& Name )
277 throw( ucb::UnsupportedCommandException, uno::RuntimeException, std::exception )
279 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
281 if ( (*m_pInfo)[ n ].Name == Name )
282 return ucb::CommandInfo( (*m_pInfo)[ n ] );
285 throw ucb::UnsupportedCommandException();
289 // virtual
290 ucb::CommandInfo SAL_CALL
291 CommandProcessorInfo::getCommandInfoByHandle( sal_Int32 Handle )
292 throw( ucb::UnsupportedCommandException, uno::RuntimeException, std::exception )
294 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
296 if ( (*m_pInfo)[ n ].Handle == Handle )
297 return ucb::CommandInfo( (*m_pInfo)[ n ] );
300 throw ucb::UnsupportedCommandException();
304 // virtual
305 sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByName(
306 const OUString& Name )
307 throw( uno::RuntimeException, std::exception )
309 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
311 if ( (*m_pInfo)[ n ].Name == Name )
312 return sal_True;
315 return sal_False;
319 // virtual
320 sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByHandle( sal_Int32 Handle )
321 throw( uno::RuntimeException, std::exception )
323 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
325 if ( (*m_pInfo)[ n ].Handle == Handle )
326 return sal_True;
329 return sal_False;
336 OUString createDesiredName(
337 const OUString & rSourceURL, const OUString & rNewTitle )
339 OUString aName( rNewTitle );
340 if ( aName.isEmpty() )
342 // calculate name using source URL
344 // @@@ It's not guaranteed that slashes contained in the URL are
345 // actually path separators. This depends on the fact whether the
346 // URL is hierarchical. Only then the slashes are path separators.
347 // Therefore this algorithm is not guaranteed to work! But, ATM
348 // I don't know a better solution. It would have been better to
349 // have a member for the clashing name in
350 // UnsupportedNameClashException...
352 sal_Int32 nLastSlash = rSourceURL.lastIndexOf( '/' );
353 bool bTrailingSlash = false;
354 if ( nLastSlash == rSourceURL.getLength() - 1 )
356 nLastSlash = rSourceURL.lastIndexOf( '/', nLastSlash );
357 bTrailingSlash = true;
360 if ( nLastSlash != -1 )
362 if ( bTrailingSlash )
363 aName = rSourceURL.copy(
364 nLastSlash + 1,
365 rSourceURL.getLength() - nLastSlash - 2 );
366 else
367 aName = rSourceURL.copy( nLastSlash + 1 );
369 else
371 aName = rSourceURL;
374 // query, fragment present?
375 sal_Int32 nPos = aName.indexOf( '?' );
376 if ( nPos == -1 )
377 nPos = aName.indexOf( '#' );
379 if ( nPos != -1 )
380 aName = aName.copy( 0, nPos );
382 return OUString( aName );
385 OUString createDesiredName(
386 const ucb::GlobalTransferCommandArgument & rArg )
388 return createDesiredName( rArg.SourceURL, rArg.NewTitle );
391 OUString createDesiredName(
392 const ucb::TransferInfo & rArg )
394 return createDesiredName( rArg.SourceURL, rArg.NewTitle );
398 enum NameClashContinuation { NOT_HANDLED, ABORT, OVERWRITE, NEW_NAME, UNKNOWN };
400 NameClashContinuation interactiveNameClashResolve(
401 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
402 const OUString & rTargetURL,
403 const OUString & rClashingName,
404 /* [out] */ uno::Any & rException,
405 /* [out] */ OUString & rNewName )
407 rtl::Reference< ucbhelper::SimpleNameClashResolveRequest > xRequest(
408 new ucbhelper::SimpleNameClashResolveRequest(
409 rTargetURL, // target folder URL
410 rClashingName, // clashing name
411 OUString(), // no proposal for new name
412 true /* bSupportsOverwriteData */ ) );
414 rException = xRequest->getRequest();
415 if ( xEnv.is() )
417 uno::Reference< task::XInteractionHandler > xIH
418 = xEnv->getInteractionHandler();
419 if ( xIH.is() )
422 xIH->handle( xRequest.get() );
424 rtl::Reference< ucbhelper::InteractionContinuation >
425 xSelection( xRequest->getSelection() );
427 if ( xSelection.is() )
429 // Handler handled the request.
430 uno::Reference< task::XInteractionAbort > xAbort(
431 xSelection.get(), uno::UNO_QUERY );
432 if ( xAbort.is() )
434 // Abort.
435 return ABORT;
437 else
439 uno::Reference<
440 ucb::XInteractionReplaceExistingData >
441 xReplace(
442 xSelection.get(), uno::UNO_QUERY );
443 if ( xReplace.is() )
445 // Try again: Replace existing data.
446 return OVERWRITE;
448 else
450 uno::Reference<
451 ucb::XInteractionSupplyName >
452 xSupplyName(
453 xSelection.get(), uno::UNO_QUERY );
454 if ( xSupplyName.is() )
456 // Try again: Use new name.
457 rNewName = xRequest->getNewName();
458 return NEW_NAME;
460 else
462 OSL_FAIL( "Unknown interaction continuation!" );
463 return UNKNOWN;
470 return NOT_HANDLED;
474 bool setTitle(
475 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessor,
476 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
477 const OUString & rNewTitle )
478 throw( uno::RuntimeException )
482 uno::Sequence< beans::PropertyValue > aPropValues( 1 );
483 aPropValues[ 0 ].Name = "Title";
484 aPropValues[ 0 ].Handle = -1;
485 aPropValues[ 0 ].Value = uno::makeAny( rNewTitle );
487 ucb::Command aSetPropsCommand(
488 OUString( "setPropertyValues" ),
490 uno::makeAny( aPropValues ) );
492 uno::Any aResult
493 = xCommandProcessor->execute( aSetPropsCommand, 0, xEnv );
495 uno::Sequence< uno::Any > aErrors;
496 aResult >>= aErrors;
498 OSL_ENSURE( aErrors.getLength() == 1,
499 "getPropertyValues return value invalid!" );
501 if ( aErrors[ 0 ].hasValue() )
503 // error occurred.
504 OSL_FAIL( "error setting Title property!" );
505 return false;
508 catch ( uno::RuntimeException const & )
510 throw;
512 catch ( uno::Exception const & )
514 return false;
517 return true;
521 uno::Reference< ucb::XContent > createNew(
522 const TransferCommandContext & rContext,
523 const uno::Reference< ucb::XContent > & xTarget,
524 bool bSourceIsFolder,
525 bool bSourceIsDocument,
526 bool bSourceIsLink )
527 throw( uno::Exception )
531 // (1) Obtain creatable types from target.
535 // First, try it using "CreatabeleContentsInfo" property and
536 // "createNewContent" command -> the "new" way.
538 uno::Reference< ucb::XCommandProcessor > xCommandProcessorT(
539 xTarget, uno::UNO_QUERY );
540 if ( !xCommandProcessorT.is() )
542 uno::Any aProps
543 = uno::makeAny(beans::PropertyValue(
544 OUString( "Folder"),
546 uno::makeAny(rContext.aArg.TargetURL),
547 beans::PropertyState_DIRECT_VALUE));
548 ucbhelper::cancelCommandExecution(
549 ucb::IOErrorCode_CANT_CREATE,
550 uno::Sequence< uno::Any >(&aProps, 1),
551 rContext.xOrigEnv,
552 OUString("Target is no XCommandProcessor!"),
553 rContext.xProcessor );
554 // Unreachable
557 uno::Sequence< beans::Property > aPropsToObtain( 1 );
558 aPropsToObtain[ 0 ].Name = "CreatableContentsInfo";
559 aPropsToObtain[ 0 ].Handle = -1;
561 ucb::Command aGetPropsCommand(
562 OUString("getPropertyValues"),
564 uno::makeAny( aPropsToObtain ) );
566 uno::Reference< sdbc::XRow > xRow;
567 xCommandProcessorT->execute( aGetPropsCommand, 0, rContext.xEnv ) >>= xRow;
569 uno::Sequence< ucb::ContentInfo > aTypesInfo;
570 bool bGotTypesInfo = false;
572 if ( xRow.is() )
574 uno::Any aValue = xRow->getObject(
575 1, uno::Reference< container::XNameAccess >() );
576 if ( aValue.hasValue() && ( aValue >>= aTypesInfo ) )
578 bGotTypesInfo = true;
582 uno::Reference< ucb::XContentCreator > xCreator;
584 if ( !bGotTypesInfo )
586 // Second, try it using XContentCreator interface -> the "old" way (not
587 // providing the chance to supply an XCommandEnvironment.
589 xCreator.set( xTarget, uno::UNO_QUERY );
591 if ( !xCreator.is() )
593 uno::Any aProps
594 = uno::makeAny(beans::PropertyValue(
595 OUString( "Folder"),
597 uno::makeAny(rContext.aArg.TargetURL),
598 beans::PropertyState_DIRECT_VALUE));
599 ucbhelper::cancelCommandExecution(
600 ucb::IOErrorCode_CANT_CREATE,
601 uno::Sequence< uno::Any >(&aProps, 1),
602 rContext.xOrigEnv,
603 OUString("Target is no XContentCreator!"),
604 rContext.xProcessor );
605 // Unreachable
608 aTypesInfo = xCreator->queryCreatableContentsInfo();
611 sal_Int32 nCount = aTypesInfo.getLength();
612 if ( !nCount )
614 uno::Any aProps
615 = uno::makeAny(beans::PropertyValue(
616 OUString("Folder"),
618 uno::makeAny(rContext.aArg.TargetURL),
619 beans::PropertyState_DIRECT_VALUE));
620 ucbhelper::cancelCommandExecution(
621 ucb::IOErrorCode_CANT_CREATE,
622 uno::Sequence< uno::Any >(&aProps, 1),
623 rContext.xOrigEnv,
624 OUString("No types creatable!"),
625 rContext.xProcessor );
626 // Unreachable
631 // (2) Try to find a matching target type for the source object.
635 uno::Reference< ucb::XContent > xNew;
636 for ( sal_Int32 n = 0; n < nCount; ++n )
638 sal_Int32 nAttribs = aTypesInfo[ n ].Attributes;
639 bool bMatch = false;
641 if ( rContext.aArg.Operation == ucb::TransferCommandOperation_LINK )
643 // Create link
645 if ( nAttribs & ucb::ContentInfoAttribute::KIND_LINK )
647 // Match!
648 bMatch = true;
651 else if ( ( rContext.aArg.Operation
652 == ucb::TransferCommandOperation_COPY ) ||
653 ( rContext.aArg.Operation
654 == ucb::TransferCommandOperation_MOVE ) )
656 // Copy / Move
658 // Is source a link? Create link in target folder then.
659 if ( bSourceIsLink )
661 if ( nAttribs & ucb::ContentInfoAttribute::KIND_LINK )
663 // Match!
664 bMatch = true;
667 else
669 // (not a and not b) or (a and b)
670 // not( a or b) or (a and b)
672 if ( ( !!bSourceIsFolder ==
673 !!( nAttribs
674 & ucb::ContentInfoAttribute::KIND_FOLDER ) )
676 ( !!bSourceIsDocument ==
677 !!( nAttribs
678 & ucb::ContentInfoAttribute::KIND_DOCUMENT ) )
681 // Match!
682 bMatch = true;
686 else
688 ucbhelper::cancelCommandExecution(
689 uno::makeAny( lang::IllegalArgumentException(
690 OUString( "Unknown transfer operation!" ),
691 rContext.xProcessor,
692 -1 ) ),
693 rContext.xOrigEnv );
694 // Unreachable
697 if ( bMatch )
701 // (3) Create a new, empty object of matched type.
705 if ( !xCreator.is() )
707 // First, try it using "CreatabeleContentsInfo" property and
708 // "createNewContent" command -> the "new" way.
709 ucb::Command aCreateNewCommand(
710 OUString("createNewContent"),
712 uno::makeAny( aTypesInfo[ n ] ) );
714 xCommandProcessorT->execute( aCreateNewCommand, 0, rContext.xEnv )
715 >>= xNew;
717 else
719 // Second, try it using XContentCreator interface -> the "old"
720 // way (not providing the chance to supply an XCommandEnvironment.
722 xNew = xCreator->createNewContent( aTypesInfo[ n ] );
725 if ( !xNew.is() )
727 uno::Any aProps
728 = uno::makeAny(
729 beans::PropertyValue(
730 OUString( "Folder"),
732 uno::makeAny(rContext.aArg.TargetURL),
733 beans::PropertyState_DIRECT_VALUE));
734 ucbhelper::cancelCommandExecution(
735 ucb::IOErrorCode_CANT_CREATE,
736 uno::Sequence< uno::Any >(&aProps, 1),
737 rContext.xOrigEnv,
738 OUString( "createNewContent failed!" ),
739 rContext.xProcessor );
740 // Unreachable
742 break; // escape from 'for' loop
744 } // for
746 return xNew;
750 void transferProperties(
751 const TransferCommandContext & rContext,
752 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS,
753 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorN )
754 throw( uno::Exception )
756 ucb::Command aGetPropertySetInfoCommand(
757 OUString("getPropertySetInfo"),
759 uno::Any() );
761 uno::Reference< beans::XPropertySetInfo > xInfo;
762 xCommandProcessorS->execute( aGetPropertySetInfoCommand, 0, rContext.xEnv )
763 >>= xInfo;
765 if ( !xInfo.is() )
767 uno::Any aProps
768 = uno::makeAny(beans::PropertyValue(
769 OUString( "Uri"),
771 uno::makeAny(rContext.aArg.SourceURL),
772 beans::PropertyState_DIRECT_VALUE));
773 ucbhelper::cancelCommandExecution(
774 ucb::IOErrorCode_CANT_READ,
775 uno::Sequence< uno::Any >(&aProps, 1),
776 rContext.xOrigEnv,
777 OUString( "Unable to get propertyset info from source object!" ),
778 rContext.xProcessor );
779 // Unreachable
782 uno::Sequence< beans::Property > aAllProps = xInfo->getProperties();
784 ucb::Command aGetPropsCommand1(
785 OUString("getPropertyValues"),
787 uno::makeAny( aAllProps ) );
789 uno::Reference< sdbc::XRow > xRow1;
790 xCommandProcessorS->execute(
791 aGetPropsCommand1, 0, rContext.xEnv ) >>= xRow1;
793 if ( !xRow1.is() )
795 uno::Any aProps
796 = uno::makeAny(beans::PropertyValue(
797 OUString( "Uri"),
799 uno::makeAny(rContext.aArg.SourceURL),
800 beans::PropertyState_DIRECT_VALUE));
801 ucbhelper::cancelCommandExecution(
802 ucb::IOErrorCode_CANT_READ,
803 uno::Sequence< uno::Any >(&aProps, 1),
804 rContext.xOrigEnv,
805 OUString( "Unable to get properties from source object!" ),
806 rContext.xProcessor );
807 // Unreachable
810 // Assemble data structure for setPropertyValues command.
812 // Note: Make room for additional Title and TargetURL too. -> + 2
813 uno::Sequence< beans::PropertyValue > aPropValues(
814 aAllProps.getLength() + 2 );
816 bool bHasTitle = rContext.aArg.NewTitle.isEmpty();
817 bool bHasTargetURL = ( rContext.aArg.Operation
818 != ucb::TransferCommandOperation_LINK );
820 sal_Int32 nWritePos = 0;
821 for ( sal_Int32 m = 0; m < aAllProps.getLength(); ++m )
823 const beans::Property & rCurrProp = aAllProps[ m ];
824 beans::PropertyValue & rCurrValue = aPropValues[ nWritePos ];
826 uno::Any aValue;
828 if ( rCurrProp.Name.equalsAscii( "Title" ) )
830 // Supply new title, if given.
831 if ( !bHasTitle )
833 bHasTitle = true;
834 aValue <<= rContext.aArg.NewTitle;
837 else if ( rCurrProp.Name.equalsAscii( "TargetURL" ) )
839 // Supply source URL as link target for the new link to create.
840 if ( !bHasTargetURL )
842 bHasTargetURL = true;
843 aValue <<= rContext.aArg.SourceURL;
847 if ( !aValue.hasValue() )
851 aValue = xRow1->getObject(
852 m + 1, uno::Reference< container::XNameAccess >() );
854 catch ( sdbc::SQLException const & )
856 // Argh! But try to bring things to an end. Perhaps the
857 // mad property is not really important...
861 if ( aValue.hasValue() )
863 rCurrValue.Name = rCurrProp.Name;
864 rCurrValue.Handle = rCurrProp.Handle;
865 rCurrValue.Value = aValue;
866 // rCurrValue.State =
868 nWritePos++;
872 // Title needed, but not set yet?
873 if ( !bHasTitle && !rContext.aArg.NewTitle.isEmpty() )
875 aPropValues[ nWritePos ].Name = "Title";
876 aPropValues[ nWritePos ].Handle = -1;
877 aPropValues[ nWritePos ].Value <<= rContext.aArg.NewTitle;
879 nWritePos++;
882 // TargetURL needed, but not set yet?
883 if ( !bHasTargetURL && ( rContext.aArg.Operation
884 == ucb::TransferCommandOperation_LINK ) )
886 aPropValues[ nWritePos ].Name = "TargetURL";
887 aPropValues[ nWritePos ].Handle = -1;
888 aPropValues[ nWritePos ].Value <<= rContext.aArg.SourceURL;
890 nWritePos++;
893 aPropValues.realloc( nWritePos );
895 // Set properties at new object.
897 ucb::Command aSetPropsCommand(
898 OUString("setPropertyValues"),
900 uno::makeAny( aPropValues ) );
902 xCommandProcessorN->execute( aSetPropsCommand, 0, rContext.xEnv );
904 // @@@ What to do with source props that are not supported by the
905 // new object? addProperty ???
909 uno::Reference< io::XInputStream > getInputStream(
910 const TransferCommandContext & rContext,
911 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
912 throw( uno::Exception )
914 uno::Reference< io::XInputStream > xInputStream;
918 // (1) Try to get data as XInputStream via XActiveDataSink.
924 uno::Reference< io::XActiveDataSink > xSink = new ActiveDataSink;
926 ucb::OpenCommandArgument2 aArg;
927 aArg.Mode = ucb::OpenMode::DOCUMENT;
928 aArg.Priority = 0; // unused
929 aArg.Sink = xSink;
930 aArg.Properties = uno::Sequence< beans::Property >( 0 ); // unused
932 ucb::Command aOpenCommand(
933 OUString("open"),
935 uno::makeAny( aArg ) );
937 xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
938 xInputStream = xSink->getInputStream();
940 catch ( uno::RuntimeException const & )
942 throw;
944 catch ( uno::Exception const & )
946 // will be handled below.
949 if ( !xInputStream.is() )
953 // (2) Try to get data via XOutputStream.
959 uno::Reference< io::XOutputStream > xOutputStream( io::Pipe::create(rContext.m_xContext), uno::UNO_QUERY_THROW );
961 ucb::OpenCommandArgument2 aArg;
962 aArg.Mode = ucb::OpenMode::DOCUMENT;
963 aArg.Priority = 0; // unused
964 aArg.Sink = xOutputStream;
965 aArg.Properties = uno::Sequence< beans::Property >( 0 );
967 ucb::Command aOpenCommand(
968 OUString("open"),
970 uno::makeAny( aArg ) );
972 xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
974 xInputStream = uno::Reference< io::XInputStream >(
975 xOutputStream, uno::UNO_QUERY );
977 catch ( uno::RuntimeException const & )
979 throw;
981 catch ( uno::Exception const & )
983 OSL_FAIL( "unable to get input stream from document!" );
987 return xInputStream;
991 uno::Reference< sdbc::XResultSet > getResultSet(
992 const TransferCommandContext & rContext,
993 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
994 throw( uno::Exception )
996 uno::Reference< sdbc::XResultSet > xResultSet;
998 uno::Sequence< beans::Property > aProps( 3 );
1000 aProps[ 0 ].Name = "IsFolder";
1001 aProps[ 0 ].Handle = -1; /* unknown */
1002 aProps[ 1 ].Name = "IsDocument";
1003 aProps[ 1 ].Handle = -1; /* unknown */
1004 aProps[ 2 ].Name = "TargetURL";
1005 aProps[ 2 ].Handle = -1; /* unknown */
1007 ucb::OpenCommandArgument2 aArg;
1008 aArg.Mode = ucb::OpenMode::ALL;
1009 aArg.Priority = 0; // unused
1010 aArg.Sink = 0;
1011 aArg.Properties = aProps;
1013 ucb::Command aOpenCommand( OUString("open"),
1015 uno::makeAny( aArg ) );
1018 uno::Reference< ucb::XDynamicResultSet > xSet;
1019 xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv ) >>= xSet;
1021 if ( xSet.is() )
1022 xResultSet = xSet->getStaticResultSet();
1024 catch ( uno::RuntimeException const & )
1026 throw;
1028 catch ( uno::Exception const & )
1030 OSL_FAIL( "unable to get result set from folder!" );
1033 return xResultSet;
1037 void handleNameClashRename(
1038 const TransferCommandContext & rContext,
1039 const uno::Reference< ucb::XContent > & xNew,
1040 const uno::Reference<
1041 ucb::XCommandProcessor > & xCommandProcessorN,
1042 const uno::Reference<
1043 ucb::XCommandProcessor > & xCommandProcessorS,
1044 /* [inout] */ uno::Reference< io::XInputStream > & xInputStream )
1045 throw( uno::Exception )
1047 sal_Int32 nTry = 0;
1049 // Obtain old title.
1050 uno::Sequence< beans::Property > aProps( 1 );
1051 aProps[ 0 ].Name = "Title";
1052 aProps[ 0 ].Handle = -1;
1054 ucb::Command aGetPropsCommand(
1055 OUString("getPropertyValues"),
1057 uno::makeAny( aProps ) );
1059 uno::Reference< sdbc::XRow > xRow;
1060 xCommandProcessorN->execute( aGetPropsCommand, 0, rContext.xEnv ) >>= xRow;
1062 if ( !xRow.is() )
1064 uno::Any aProps2
1065 = uno::makeAny(
1066 beans::PropertyValue(
1067 OUString( "Uri" ),
1069 uno::makeAny(
1070 xNew->getIdentifier()->getContentIdentifier() ),
1071 beans::PropertyState_DIRECT_VALUE ) );
1072 ucbhelper::cancelCommandExecution(
1073 ucb::IOErrorCode_CANT_READ,
1074 uno::Sequence< uno::Any >( &aProps2, 1 ),
1075 rContext.xOrigEnv,
1076 OUString( "Unable to get properties from new object!" ),
1077 rContext.xProcessor );
1078 // Unreachable
1081 OUString aOldTitle = xRow->getString( 1 );
1082 if ( aOldTitle.isEmpty() )
1084 ucbhelper::cancelCommandExecution(
1085 uno::makeAny( beans::UnknownPropertyException(
1086 OUString( "Unable to get property 'Title' from new object!" ),
1087 rContext.xProcessor ) ),
1088 rContext.xOrigEnv );
1089 // Unreachable
1092 // Some pseudo-intelligence for not destroying file extensions.
1093 OUString aOldTitlePre;
1094 OUString aOldTitlePost;
1095 sal_Int32 nPos = aOldTitle.lastIndexOf( '.' );
1096 if ( nPos != -1 )
1098 aOldTitlePre = aOldTitle.copy( 0, nPos );
1099 aOldTitlePost = aOldTitle.copy( nPos );
1101 else
1102 aOldTitlePre = aOldTitle;
1104 if ( nPos > 0 )
1105 aOldTitlePre += "_";
1107 bool bContinue = true;
1110 nTry++;
1112 OUString aNewTitle = aOldTitlePre;
1113 aNewTitle += OUString::number( nTry );
1114 aNewTitle += aOldTitlePost;
1116 // Set new title
1117 setTitle( xCommandProcessorN, rContext.xEnv, aNewTitle );
1119 // Retry inserting the content.
1122 // Previous try may have read from stream. Seek to begin (if
1123 // optional interface XSeekable is supported) or get a new stream.
1124 if ( xInputStream.is() )
1126 uno::Reference< io::XSeekable > xSeekable(
1127 xInputStream, uno::UNO_QUERY );
1128 if ( xSeekable.is() )
1132 xSeekable->seek( 0 );
1134 catch ( lang::IllegalArgumentException const & )
1136 xInputStream.clear();
1138 catch ( io::IOException const & )
1140 xInputStream.clear();
1143 else
1144 xInputStream.clear();
1146 if ( !xInputStream.is() )
1148 xInputStream
1149 = getInputStream( rContext, xCommandProcessorS );
1150 if ( !xInputStream.is() )
1152 uno::Any aProps2
1153 = uno::makeAny(
1154 beans::PropertyValue(
1155 OUString( "Uri" ),
1157 uno::makeAny(
1158 xNew->getIdentifier()->
1159 getContentIdentifier() ),
1160 beans::PropertyState_DIRECT_VALUE ) );
1161 ucbhelper::cancelCommandExecution(
1162 ucb::IOErrorCode_CANT_READ,
1163 uno::Sequence< uno::Any >( &aProps2, 1 ),
1164 rContext.xOrigEnv,
1165 OUString( "Got no data stream from source!" ),
1166 rContext.xProcessor );
1167 // Unreachable
1172 ucb::InsertCommandArgument2 aArg;
1173 aArg.Data = xInputStream;
1174 aArg.ReplaceExisting = sal_False;
1176 ucb::Command aInsertCommand(
1177 OUString("insert"),
1179 uno::makeAny( aArg ) );
1181 xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
1183 // Success!
1184 bContinue = false;
1186 catch ( uno::RuntimeException const & )
1188 throw;
1190 catch ( uno::Exception const & )
1194 while ( bContinue && ( nTry < 50 ) );
1196 if ( nTry == 50 )
1198 ucbhelper::cancelCommandExecution(
1199 uno::makeAny(
1200 ucb::UnsupportedNameClashException(
1201 OUString( "Unable to resolve name clash!" ),
1202 rContext.xProcessor,
1203 ucb::NameClash::RENAME ) ),
1204 rContext.xOrigEnv );
1205 // Unreachable
1210 void globalTransfer_(
1211 const TransferCommandContext & rContext,
1212 const uno::Reference< ucb::XContent > & xSource,
1213 const uno::Reference< ucb::XContent > & xTarget,
1214 const uno::Reference< sdbc::XRow > & xSourceProps )
1215 throw( uno::Exception )
1217 // IsFolder: property is required.
1218 bool bSourceIsFolder = xSourceProps->getBoolean( 1 );
1219 if ( !bSourceIsFolder && xSourceProps->wasNull() )
1221 ucbhelper::cancelCommandExecution(
1222 uno::makeAny( beans::UnknownPropertyException(
1223 OUString( "Unable to get property 'IsFolder' "
1224 "from source object!" ),
1225 rContext.xProcessor ) ),
1226 rContext.xOrigEnv );
1227 // Unreachable
1230 // IsDocument: property is required.
1231 bool bSourceIsDocument = xSourceProps->getBoolean( 2 );
1232 if ( !bSourceIsDocument && xSourceProps->wasNull() )
1234 ucbhelper::cancelCommandExecution(
1235 uno::makeAny( beans::UnknownPropertyException(
1236 OUString( "Unable to get property 'IsDocument' "
1237 "from source object!" ),
1238 rContext.xProcessor ) ),
1239 rContext.xOrigEnv );
1240 // Unreachable
1243 // TargetURL: property is optional.
1244 bool bSourceIsLink = !xSourceProps->getString( 3 ).isEmpty();
1248 // (1) Try to find a matching target type for the source object and
1249 // create a new, empty object of that type.
1253 uno::Reference< ucb::XContent > xNew = createNew( rContext,
1254 xTarget,
1255 bSourceIsFolder,
1256 bSourceIsDocument,
1257 bSourceIsLink );
1258 if ( !xNew.is() )
1260 uno::Any aProps
1261 = uno::makeAny(beans::PropertyValue(
1262 OUString( "Folder"),
1264 uno::makeAny(rContext.aArg.TargetURL),
1265 beans::PropertyState_DIRECT_VALUE));
1266 ucbhelper::cancelCommandExecution(
1267 ucb::IOErrorCode_CANT_CREATE,
1268 uno::Sequence< uno::Any >(&aProps, 1),
1269 rContext.xOrigEnv,
1270 OUString( "No matching content type at target!" ),
1271 rContext.xProcessor );
1272 // Unreachable
1277 // (2) Transfer property values from source to new object.
1281 uno::Reference< ucb::XCommandProcessor > xCommandProcessorN(
1282 xNew, uno::UNO_QUERY );
1283 if ( !xCommandProcessorN.is() )
1285 uno::Any aProps
1286 = uno::makeAny(beans::PropertyValue(
1287 OUString( "Uri"),
1289 uno::makeAny(
1290 xNew->getIdentifier()->
1291 getContentIdentifier()),
1292 beans::PropertyState_DIRECT_VALUE));
1293 ucbhelper::cancelCommandExecution(
1294 ucb::IOErrorCode_CANT_WRITE,
1295 uno::Sequence< uno::Any >(&aProps, 1),
1296 rContext.xOrigEnv,
1297 OUString( "New content is not a XCommandProcessor!" ),
1298 rContext.xProcessor );
1299 // Unreachable
1302 // Obtain all properties from source.
1304 uno::Reference< ucb::XCommandProcessor > xCommandProcessorS(
1305 xSource, uno::UNO_QUERY );
1306 if ( !xCommandProcessorS.is() )
1308 uno::Any aProps
1309 = uno::makeAny(beans::PropertyValue(
1310 OUString( "Uri"),
1312 uno::makeAny(rContext.aArg.SourceURL),
1313 beans::PropertyState_DIRECT_VALUE));
1314 ucbhelper::cancelCommandExecution(
1315 ucb::IOErrorCode_CANT_READ,
1316 uno::Sequence< uno::Any >(&aProps, 1),
1317 rContext.xOrigEnv,
1318 OUString( "Source content is not a XCommandProcessor!" ),
1319 rContext.xProcessor );
1320 // Unreachable
1323 transferProperties( rContext, xCommandProcessorS, xCommandProcessorN );
1327 // (3) Try to obtain a data stream from source.
1331 uno::Reference< io::XInputStream > xInputStream;
1333 if ( bSourceIsDocument && ( rContext.aArg.Operation
1334 != ucb::TransferCommandOperation_LINK ) )
1335 xInputStream = getInputStream( rContext, xCommandProcessorS );
1339 // (4) Try to obtain a resultset (children) from source.
1343 uno::Reference< sdbc::XResultSet > xResultSet;
1345 if ( bSourceIsFolder && ( rContext.aArg.Operation
1346 != ucb::TransferCommandOperation_LINK ) )
1347 xResultSet = getResultSet( rContext, xCommandProcessorS );
1351 // (5) Insert (store) new content.
1355 ucb::InsertCommandArgument2 aArg;
1356 aArg.Data = xInputStream;
1357 aArg.MimeType = rContext.aArg.MimeType;
1358 aArg.DocumentId = rContext.aArg.DocumentId;
1360 switch ( rContext.aArg.NameClash )
1362 case ucb::NameClash::OVERWRITE:
1363 aArg.ReplaceExisting = sal_True;
1364 break;
1366 case ucb::NameClash::ERROR:
1367 case ucb::NameClash::RENAME:
1368 case ucb::NameClash::KEEP: // deprecated
1369 case ucb::NameClash::ASK:
1370 aArg.ReplaceExisting = sal_False;
1371 break;
1373 default:
1374 aArg.ReplaceExisting = sal_False;
1375 OSL_FAIL( "Unknown nameclash directive!" );
1376 break;
1379 OUString aDesiredName = createDesiredName( rContext.aArg );
1381 bool bRetry;
1384 bRetry = false;
1388 ucb::Command aInsertCommand(
1389 OUString("insert"),
1391 uno::makeAny( aArg ) );
1393 xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
1395 catch ( ucb::UnsupportedNameClashException const & exc )
1397 OSL_ENSURE( !aArg.ReplaceExisting,
1398 "BUG: UnsupportedNameClashException not allowed here!" );
1400 if (exc.NameClash != ucb::NameClash::ERROR) {
1401 OSL_FAIL( "BUG: NameClash::ERROR expected!" );
1404 // No chance to solve name clashes, because I'm not able to detect
1405 // whether there is one.
1406 throw ucb::UnsupportedNameClashException(
1407 OUString(
1408 "Unable to resolve name clashes, no chance to detect "
1409 "that there is one!" ),
1410 rContext.xProcessor,
1411 rContext.aArg.NameClash );
1413 catch ( ucb::NameClashException const & )
1415 // The 'insert' command throws a NameClashException if the parameter
1416 // ReplaceExisting of the command's argument was set to false and
1417 // there exists a resource with a clashing name in the target folder
1418 // of the operation.
1420 // 'insert' command has no direct support for name clashes other
1421 // than ERROR ( ReplaceExisting == false ) and OVERWRITE
1422 // ( ReplaceExisting == true ). So we have to implement the
1423 // other name clash handling directives on top of the content.
1425 // @@@ 'insert' command should be extended that it accepts a
1426 // name clash handling directive, exactly like 'transfer' command.
1428 switch ( rContext.aArg.NameClash )
1430 case ucb::NameClash::OVERWRITE:
1432 ucbhelper::cancelCommandExecution(
1433 uno::makeAny(
1434 ucb::UnsupportedNameClashException(
1435 OUString(
1436 "BUG: insert + replace == true MUST NOT "
1437 "throw NameClashException." ),
1438 rContext.xProcessor,
1439 rContext.aArg.NameClash ) ),
1440 rContext.xOrigEnv );
1441 // Unreachable
1444 case ucb::NameClash::ERROR:
1445 throw;
1447 case ucb::NameClash::RENAME:
1449 // "invent" a new valid title.
1450 handleNameClashRename( rContext,
1451 xNew,
1452 xCommandProcessorN,
1453 xCommandProcessorS,
1454 xInputStream );
1455 break;
1458 case ucb::NameClash::ASK:
1460 uno::Any aExc;
1461 OUString aNewTitle;
1462 NameClashContinuation eCont
1463 = interactiveNameClashResolve(
1464 rContext.xOrigEnv, // always use original environment!
1465 rContext.aArg.TargetURL, // target folder URL
1466 aDesiredName,
1467 aExc,
1468 aNewTitle );
1470 switch ( eCont )
1472 case NOT_HANDLED:
1473 // Not handled.
1474 cppu::throwException( aExc );
1475 // break;
1477 case UNKNOWN:
1478 // Handled, but not clear, how...
1479 // fall-thru intended.
1481 case ABORT:
1482 throw ucb::CommandFailedException(
1483 OUString(
1484 "abort requested via interaction "
1485 "handler" ),
1486 uno::Reference< uno::XInterface >(),
1487 aExc );
1488 // break;
1490 case OVERWRITE:
1491 OSL_ENSURE( aArg.ReplaceExisting == sal_False,
1492 "Hu? ReplaceExisting already true?"
1494 aArg.ReplaceExisting = sal_True;
1495 bRetry = true;
1496 break;
1498 case NEW_NAME:
1500 // set new name -> set "Title" property...
1501 if ( setTitle( xCommandProcessorN,
1502 rContext.xEnv,
1503 aNewTitle ) )
1505 // remember suggested title...
1506 aDesiredName = aNewTitle;
1508 // ... and try again.
1509 bRetry = true;
1511 else
1513 // error setting title. Abort.
1514 throw ucb::CommandFailedException(
1515 OUString( "error setting Title property!" ),
1516 uno::Reference< uno::XInterface >(),
1517 aExc );
1519 break;
1523 OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
1525 break;
1527 case ucb::NameClash::KEEP: // deprecated
1528 default:
1530 ucbhelper::cancelCommandExecution(
1531 uno::makeAny(
1532 ucb::UnsupportedNameClashException(
1533 OUString(
1534 "default action, don't know how to "
1535 "handle name clash" ),
1536 rContext.xProcessor,
1537 rContext.aArg.NameClash ) ),
1538 rContext.xOrigEnv );
1539 // Unreachable
1544 while ( bRetry );
1548 // (6) Process children of source.
1552 if ( xResultSet.is() )
1556 // Iterate over children...
1558 uno::Reference< sdbc::XRow > xChildRow(
1559 xResultSet, uno::UNO_QUERY );
1561 if ( !xChildRow.is() )
1563 uno::Any aProps
1564 = uno::makeAny(
1565 beans::PropertyValue(
1566 OUString( "Uri"),
1568 uno::makeAny(rContext.aArg.SourceURL),
1569 beans::PropertyState_DIRECT_VALUE));
1570 ucbhelper::cancelCommandExecution(
1571 ucb::IOErrorCode_CANT_READ,
1572 uno::Sequence< uno::Any >(&aProps, 1),
1573 rContext.xOrigEnv,
1574 OUString( "Unable to get properties from children of source!" ),
1575 rContext.xProcessor );
1576 // Unreachable
1579 uno::Reference< ucb::XContentAccess > xChildAccess(
1580 xResultSet, uno::UNO_QUERY );
1582 if ( !xChildAccess.is() )
1584 uno::Any aProps
1585 = uno::makeAny(
1586 beans::PropertyValue(
1587 OUString( "Uri"),
1589 uno::makeAny(rContext.aArg.SourceURL),
1590 beans::PropertyState_DIRECT_VALUE));
1591 ucbhelper::cancelCommandExecution(
1592 ucb::IOErrorCode_CANT_READ,
1593 uno::Sequence< uno::Any >(&aProps, 1),
1594 rContext.xOrigEnv,
1595 OUString( "Unable to get children of source!" ),
1596 rContext.xProcessor );
1597 // Unreachable
1600 if ( xResultSet->first() )
1602 ucb::GlobalTransferCommandArgument2 aTransArg(
1603 rContext.aArg.Operation,
1604 OUString(), // SourceURL; filled later
1605 xNew->getIdentifier()
1606 ->getContentIdentifier(), // TargetURL
1607 OUString(), // NewTitle;
1608 rContext.aArg.NameClash,
1609 rContext.aArg.MimeType,
1610 rContext.aArg.DocumentId);
1612 TransferCommandContext aSubCtx(
1613 rContext.m_xContext,
1614 rContext.xProcessor,
1615 rContext.xEnv,
1616 rContext.xOrigEnv,
1617 aTransArg );
1620 uno::Reference< ucb::XContent > xChild
1621 = xChildAccess->queryContent();
1622 if ( xChild.is() )
1624 // Recursion!
1626 aSubCtx.aArg.SourceURL
1627 = xChild->getIdentifier()->getContentIdentifier();
1629 globalTransfer_( aSubCtx,
1630 xChild,
1631 xNew,
1632 xChildRow );
1635 while ( xResultSet->next() );
1638 catch ( sdbc::SQLException const & )
1643 try {
1644 uno::Reference< ucb::XCommandProcessor > xcp(
1645 xTarget, uno::UNO_QUERY );
1647 uno::Any aAny;
1648 uno::Reference< ucb::XCommandInfo > xci;
1649 if(xcp.is())
1650 aAny =
1651 xcp->execute(
1652 ucb::Command(
1653 OUString("getCommandInfo"),
1655 uno::Any()),
1657 rContext.xEnv );
1659 const OUString cmdName("flush");
1660 if((aAny >>= xci) && xci->hasCommandByName(cmdName))
1661 xcp->execute(
1662 ucb::Command(
1663 cmdName,
1665 uno::Any()) ,
1667 rContext.xEnv );
1669 catch( uno::Exception const & )
1674 } /* namescpace */
1678 // UniversalContentBroker implementation ( XCommandProcessor commands ).
1682 uno::Reference< ucb::XCommandInfo >
1683 UniversalContentBroker::getCommandInfo()
1685 return uno::Reference< ucb::XCommandInfo >( new CommandProcessorInfo() );
1689 void UniversalContentBroker::globalTransfer(
1690 const ucb::GlobalTransferCommandArgument2 & rArg,
1691 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1692 throw( uno::Exception )
1694 // Use own command environment with own interaction handler intercepting
1695 // some interaction requests that shall not be handled by the user-supplied
1696 // interaction handler.
1697 uno::Reference< ucb::XCommandEnvironment > xLocalEnv;
1698 if (xEnv.is())
1700 xLocalEnv.set( ucb::CommandEnvironment::create(
1701 m_xContext,
1702 new InteractionHandlerProxy( xEnv->getInteractionHandler() ),
1703 xEnv->getProgressHandler() ) );
1708 // (1) Try to transfer the content using 'transfer' command.
1712 uno::Reference< ucb::XContent > xTarget;
1713 uno::Reference< ucb::XContentIdentifier > xId
1714 = createContentIdentifier( rArg.TargetURL );
1715 if ( xId.is() )
1719 xTarget = queryContent( xId );
1721 catch ( ucb::IllegalIdentifierException const & )
1726 if ( !xTarget.is() )
1728 uno::Any aProps
1729 = uno::makeAny(beans::PropertyValue(
1730 OUString( "Uri"),
1732 uno::makeAny(rArg.TargetURL),
1733 beans::PropertyState_DIRECT_VALUE));
1734 ucbhelper::cancelCommandExecution(
1735 ucb::IOErrorCode_CANT_READ,
1736 uno::Sequence< uno::Any >(&aProps, 1),
1737 xEnv,
1738 OUString( "Can't instanciate target object!" ),
1739 this );
1740 // Unreachable
1743 if ( ( rArg.Operation == ucb::TransferCommandOperation_COPY ) ||
1744 ( rArg.Operation == ucb::TransferCommandOperation_MOVE ) )
1746 uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
1747 xTarget, uno::UNO_QUERY );
1748 if ( !xCommandProcessor.is() )
1750 uno::Any aProps
1751 = uno::makeAny(
1752 beans::PropertyValue(
1753 OUString( "Uri"),
1755 uno::makeAny(rArg.TargetURL),
1756 beans::PropertyState_DIRECT_VALUE));
1757 ucbhelper::cancelCommandExecution(
1758 ucb::IOErrorCode_CANT_READ,
1759 uno::Sequence< uno::Any >(&aProps, 1),
1760 xEnv,
1761 OUString( "Target content is not a XCommandProcessor!" ),
1762 this );
1763 // Unreachable
1766 ucb::TransferInfo2 aTransferArg(
1767 ( rArg.Operation
1768 == ucb::TransferCommandOperation_MOVE ), // MoveData
1769 rArg.SourceURL,
1770 rArg.NewTitle,
1771 rArg.NameClash,
1772 rArg.MimeType );
1774 bool bRetry;
1777 bRetry = false;
1781 ucb::Command aCommand(
1782 OUString( "transfer" ), // Name
1783 -1, // Handle
1784 uno::makeAny( aTransferArg ) ); // Argument
1786 xCommandProcessor->execute( aCommand, 0, xLocalEnv );
1788 // Command succeeded. We're done.
1789 return;
1791 catch ( ucb::InteractiveBadTransferURLException const & )
1793 // Source URL is not supported by target. Try to transfer
1794 // the content "manually".
1796 catch ( ucb::UnsupportedCommandException const & )
1798 // 'transfer' command is not supported by commandprocessor.
1799 // Try to transfer manually.
1801 catch ( ucb::UnsupportedNameClashException const & exc )
1803 OSL_ENSURE( aTransferArg.NameClash == exc.NameClash,
1804 "nameclash mismatch!" );
1805 if ( exc.NameClash == ucb::NameClash::ASK )
1807 // Try to detect a name clash by invoking "transfer" with
1808 // NameClash::ERROR.
1811 ucb::TransferInfo2 aTransferArg1(
1812 aTransferArg.MoveData,
1813 aTransferArg.SourceURL,
1814 aTransferArg.NewTitle,
1815 ucb::NameClash::ERROR,
1816 aTransferArg.MimeType );
1818 ucb::Command aCommand1(
1819 OUString("transfer"),
1821 uno::makeAny( aTransferArg1 ) );
1823 xCommandProcessor->execute( aCommand1, 0, xLocalEnv );
1825 // Command succeeded. We're done.
1826 return;
1828 catch ( ucb::UnsupportedNameClashException const & )
1830 // No chance to solve name clashes, because I'm not
1831 // able to detect whether there is one.
1832 throw exc; // Not just 'throw;'!
1834 catch ( ucb::NameClashException const & )
1836 // There's a clash. Use interaction handler to solve it.
1838 uno::Any aExc;
1839 OUString aNewTitle;
1840 NameClashContinuation eCont
1841 = interactiveNameClashResolve(
1842 xEnv, // always use original environment!
1843 rArg.TargetURL, // target folder URL
1844 createDesiredName(
1845 aTransferArg ), // clashing name
1846 aExc,
1847 aNewTitle );
1849 switch ( eCont )
1851 case NOT_HANDLED:
1852 // Not handled.
1853 cppu::throwException( aExc );
1854 // break;
1856 case UNKNOWN:
1857 // Handled, but not clear, how...
1858 // fall-thru intended.
1860 case ABORT:
1861 throw ucb::CommandFailedException(
1862 OUString(
1863 "abort requested via interaction "
1864 "handler" ),
1865 uno::Reference< uno::XInterface >(),
1866 aExc );
1867 // break;
1869 case OVERWRITE:
1870 aTransferArg.NameClash
1871 = ucb::NameClash::OVERWRITE;
1872 bRetry = true;
1873 break;
1875 case NEW_NAME:
1876 aTransferArg.NewTitle = aNewTitle;
1877 bRetry = true;
1878 break;
1881 OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
1884 else
1886 throw;
1890 while ( bRetry );
1895 // (2) Try to transfer the content "manually".
1899 uno::Reference< ucb::XContent > xSource;
1902 uno::Reference< ucb::XContentIdentifier > xId2
1903 = createContentIdentifier( rArg.SourceURL );
1904 if ( xId2.is() )
1905 xSource = queryContent( xId2 );
1907 catch ( ucb::IllegalIdentifierException const & )
1909 // Error handling via "if ( !xSource.is() )" below.
1912 if ( !xSource.is() )
1914 uno::Any aProps
1915 = uno::makeAny(beans::PropertyValue(
1916 OUString( "Uri"),
1918 uno::makeAny(rArg.SourceURL),
1919 beans::PropertyState_DIRECT_VALUE));
1920 ucbhelper::cancelCommandExecution(
1921 ucb::IOErrorCode_CANT_READ,
1922 uno::Sequence< uno::Any >(&aProps, 1),
1923 xEnv,
1924 OUString( "Can't instanciate source object!" ),
1925 this );
1926 // Unreachable
1929 uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
1930 xSource, uno::UNO_QUERY );
1931 if ( !xCommandProcessor.is() )
1933 uno::Any aProps
1934 = uno::makeAny(beans::PropertyValue(
1935 OUString( "Uri"),
1937 uno::makeAny(rArg.SourceURL),
1938 beans::PropertyState_DIRECT_VALUE));
1939 ucbhelper::cancelCommandExecution(
1940 ucb::IOErrorCode_CANT_READ,
1941 uno::Sequence< uno::Any >(&aProps, 1),
1942 xEnv,
1943 OUString( "Source content is not a XCommandProcessor!" ),
1944 this );
1945 // Unreachable
1948 // Obtain interesting property values from source...
1950 uno::Sequence< beans::Property > aProps( 4 );
1952 aProps[ 0 ].Name = "IsFolder";
1953 aProps[ 0 ].Handle = -1; /* unknown */
1954 aProps[ 1 ].Name = "IsDocument";
1955 aProps[ 1 ].Handle = -1; /* unknown */
1956 aProps[ 2 ].Name = "TargetURL";
1957 aProps[ 2 ].Handle = -1; /* unknown */
1958 aProps[ 3 ].Name = "BaseURI";
1959 aProps[ 3 ].Handle = -1; /* unknown */
1961 ucb::Command aGetPropsCommand(
1962 OUString("getPropertyValues"),
1964 uno::makeAny( aProps ) );
1966 uno::Reference< sdbc::XRow > xRow;
1967 xCommandProcessor->execute( aGetPropsCommand, 0, xLocalEnv ) >>= xRow;
1969 if ( !xRow.is() )
1971 uno::Any aProps2
1972 = uno::makeAny(beans::PropertyValue(
1973 OUString( "Uri"),
1975 uno::makeAny(rArg.SourceURL),
1976 beans::PropertyState_DIRECT_VALUE));
1977 ucbhelper::cancelCommandExecution(
1978 ucb::IOErrorCode_CANT_READ,
1979 uno::Sequence< uno::Any >(&aProps2, 1),
1980 xEnv,
1981 OUString( "Unable to get properties from source object!" ),
1982 this );
1983 // Unreachable
1986 TransferCommandContext aTransferCtx(
1987 m_xContext, this, xLocalEnv, xEnv, rArg );
1989 if ( rArg.NewTitle.isEmpty() )
1991 // BaseURI: property is optional.
1992 OUString aBaseURI( xRow->getString( 4 ) );
1993 if ( !aBaseURI.isEmpty() )
1995 aTransferCtx.aArg.NewTitle
1996 = createDesiredName( aBaseURI, OUString() );
2000 // Do it!
2001 globalTransfer_( aTransferCtx, xSource, xTarget, xRow );
2005 // (3) Delete source, if operation is MOVE.
2009 if ( rArg.Operation == ucb::TransferCommandOperation_MOVE )
2013 ucb::Command aCommand(
2014 OUString("delete"), // Name
2015 -1, // Handle
2016 uno::makeAny( true ) ); // Argument
2018 xCommandProcessor->execute( aCommand, 0, xLocalEnv );
2020 catch ( uno::Exception const & )
2022 OSL_FAIL( "Cannot delete source object!" );
2023 throw;
2028 uno::Any UniversalContentBroker::checkIn( const ucb::CheckinArgument& rArg,
2029 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) throw ( uno::Exception )
2031 uno::Any aRet;
2032 // Use own command environment with own interaction handler intercepting
2033 // some interaction requests that shall not be handled by the user-supplied
2034 // interaction handler.
2035 uno::Reference< ucb::XCommandEnvironment > xLocalEnv;
2036 if (xEnv.is())
2038 xLocalEnv.set( ucb::CommandEnvironment::create(
2039 m_xContext,
2040 new InteractionHandlerProxy( xEnv->getInteractionHandler() ),
2041 xEnv->getProgressHandler() ) );
2044 uno::Reference< ucb::XContent > xTarget;
2045 uno::Reference< ucb::XContentIdentifier > xId
2046 = createContentIdentifier( rArg.TargetURL );
2047 if ( xId.is() )
2051 xTarget = queryContent( xId );
2053 catch ( ucb::IllegalIdentifierException const & )
2058 if ( !xTarget.is() )
2060 uno::Any aProps
2061 = uno::makeAny(beans::PropertyValue(
2062 OUString( "Uri" ), -1,
2063 uno::makeAny( rArg.TargetURL ),
2064 beans::PropertyState_DIRECT_VALUE ) );
2065 ucbhelper::cancelCommandExecution(
2066 ucb::IOErrorCode_CANT_READ,
2067 uno::Sequence< uno::Any >( &aProps, 1 ),
2068 xEnv,
2069 OUString( "Can't instanciate target object!" ),
2070 this );
2071 // Unreachable
2074 uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
2075 xTarget, uno::UNO_QUERY );
2076 if ( !xCommandProcessor.is() )
2078 uno::Any aProps
2079 = uno::makeAny(
2080 beans::PropertyValue(
2081 OUString( "Uri" ), -1,
2082 uno::makeAny( rArg.TargetURL ),
2083 beans::PropertyState_DIRECT_VALUE ) );
2084 ucbhelper::cancelCommandExecution(
2085 ucb::IOErrorCode_CANT_READ,
2086 uno::Sequence< uno::Any >( &aProps, 1 ),
2087 xEnv,
2088 OUString( "Target content is not a XCommandProcessor!" ),
2089 this );
2090 // Unreachable
2095 ucb::Command aCommand(
2096 OUString( "checkin" ), -1,
2097 uno::makeAny( rArg ) );
2099 aRet = xCommandProcessor->execute( aCommand, 0, xLocalEnv );
2101 catch ( ucb::UnsupportedCommandException const & )
2103 // 'checkin' command is not supported by commandprocessor:
2104 // ignore.
2106 return aRet;
2109 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */