LibreOffice Module ucb (master) 1
hierarchycontent.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21/**************************************************************************
22 TODO
23 **************************************************************************
24
25 - optimize transfer command. "Move" should be implementable much more
26 efficient!
27
28 **************************************************************************
29
30 - Root Folder vs. 'normal' Folder
31 - root doesn't support command 'delete'
32 - root doesn't support command 'insert'
33 - root needs not created via XContentCreator - queryContent with root
34 folder id ( HIERARCHY_ROOT_FOLDER_URL ) always returns a value != 0
35 - root has no parent.
36
37 *************************************************************************/
38#include <osl/diagnose.h>
39
40#include <rtl/ustring.hxx>
41#include <com/sun/star/beans/IllegalTypeException.hpp>
42#include <com/sun/star/beans/PropertyAttribute.hpp>
43#include <com/sun/star/beans/PropertyExistException.hpp>
44#include <com/sun/star/beans/PropertyState.hpp>
45#include <com/sun/star/lang/IllegalAccessException.hpp>
46#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
47#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
48#include <com/sun/star/ucb/InsertCommandArgument.hpp>
49#include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
50#include <com/sun/star/ucb/MissingPropertiesException.hpp>
51#include <com/sun/star/ucb/NameClash.hpp>
52#include <com/sun/star/ucb/NameClashException.hpp>
53#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
54#include <com/sun/star/ucb/TransferInfo.hpp>
55#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
56#include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
57#include <com/sun/star/ucb/XCommandInfo.hpp>
58#include <com/sun/star/ucb/XPersistentPropertySet.hpp>
59#include <com/sun/star/uno/Any.hxx>
60#include <com/sun/star/uno/Sequence.hxx>
67#include <ucbhelper/macros.hxx>
68#include <utility>
69#include "hierarchycontent.hxx"
70#include "hierarchyprovider.hxx"
71#include "dynamicresultset.hxx"
72#include "hierarchyuri.hxx"
73
74#include "../inc/urihelper.hxx"
75
76using namespace com::sun::star;
77using namespace hierarchy_ucp;
78
79
80// HierarchyContent Implementation.
81
82
83// static ( "virtual" ctor )
84rtl::Reference<HierarchyContent> HierarchyContent::create(
85 const uno::Reference< uno::XComponentContext >& rxContext,
86 HierarchyContentProvider* pProvider,
87 const uno::Reference< ucb::XContentIdentifier >& Identifier )
88{
89 // Fail, if content does not exist.
91 if ( !loadData( rxContext, pProvider, Identifier, aProps ) )
92 return nullptr;
93
94 return new HierarchyContent( rxContext, pProvider, Identifier, std::move(aProps) );
95}
96
97
98// static ( "virtual" ctor )
100 const uno::Reference< uno::XComponentContext >& rxContext,
101 HierarchyContentProvider* pProvider,
102 const uno::Reference< ucb::XContentIdentifier >& Identifier,
103 const ucb::ContentInfo& Info )
104{
105 if ( Info.Type.isEmpty() )
106 return nullptr;
107
109 return nullptr;
110
111 return new HierarchyContent( rxContext, pProvider, Identifier, Info );
112}
113
114
116 const uno::Reference< uno::XComponentContext >& rxContext,
117 HierarchyContentProvider* pProvider,
118 const uno::Reference< ucb::XContentIdentifier >& Identifier,
120: ContentImplHelper( rxContext, pProvider, Identifier ),
121 m_aProps(std::move( aProps )),
122 m_eState( PERSISTENT ),
123 m_pProvider( pProvider ),
124 m_bCheckedReadOnly( false ),
125 m_bIsReadOnly( true )
126{
127 setKind( Identifier );
128}
129
130
131HierarchyContent::HierarchyContent(
132 const uno::Reference< uno::XComponentContext >& rxContext,
133 HierarchyContentProvider* pProvider,
134 const uno::Reference< ucb::XContentIdentifier >& Identifier,
135 const ucb::ContentInfo& Info )
136 : ContentImplHelper( rxContext, pProvider, Identifier ),
138 m_eState( TRANSIENT ),
139 m_pProvider( pProvider ),
140 m_bCheckedReadOnly( false ),
141 m_bIsReadOnly( true )
142{
143 setKind( Identifier );
144}
145
146
147// virtual
148HierarchyContent::~HierarchyContent()
149{
150}
151
152
153// XInterface methods.
154
155
156// virtual
158 noexcept
159{
160 ContentImplHelper::acquire();
161}
162
163
164// virtual
166 noexcept
167{
168 ContentImplHelper::release();
169}
170
171
172// virtual
174{
175 uno::Any aRet = ContentImplHelper::queryInterface( rType );
176
177 if ( !aRet.hasValue() )
178 {
179 // Note: isReadOnly may be relative expensive. So avoid calling it
180 // unless it is really necessary.
182 rType, static_cast< ucb::XContentCreator * >( this ) );
183 if ( aRet.hasValue() )
184 {
185 if ( !isFolder() || isReadOnly() )
186 return uno::Any();
187 }
188 }
189
190 return aRet;
191}
192
193
194// XTypeProvider methods.
195
196
198
199
200// virtual
201uno::Sequence< uno::Type > SAL_CALL HierarchyContent::getTypes()
202{
203 if ( isFolder() && !isReadOnly() )
204 {
205 static cppu::OTypeCollection s_aFolderTypes(
206 CPPU_TYPE_REF( lang::XTypeProvider ),
207 CPPU_TYPE_REF( lang::XServiceInfo ),
208 CPPU_TYPE_REF( lang::XComponent ),
209 CPPU_TYPE_REF( ucb::XContent ),
210 CPPU_TYPE_REF( ucb::XCommandProcessor ),
211 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
212 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
213 CPPU_TYPE_REF( beans::XPropertyContainer ),
214 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
215 CPPU_TYPE_REF( container::XChild ),
216 CPPU_TYPE_REF( ucb::XContentCreator ) );
217
218
219 return s_aFolderTypes.getTypes();
220 }
221 else
222 {
223 static cppu::OTypeCollection s_aDocumentTypes(
224 CPPU_TYPE_REF( lang::XTypeProvider ),
225 CPPU_TYPE_REF( lang::XServiceInfo ),
226 CPPU_TYPE_REF( lang::XComponent ),
227 CPPU_TYPE_REF( ucb::XContent ),
228 CPPU_TYPE_REF( ucb::XCommandProcessor ),
229 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
230 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
231 CPPU_TYPE_REF( beans::XPropertyContainer ),
232 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
233 CPPU_TYPE_REF( container::XChild ) );
234
235 return s_aDocumentTypes.getTypes();
236 }
237}
238
239
240// XServiceInfo methods.
241
242
243// virtual
245{
246 return "com.sun.star.comp.ucb.HierarchyContent";
247}
248
249
250// virtual
251uno::Sequence< OUString > SAL_CALL
253{
254 uno::Sequence< OUString > aSNS( 1 );
255
256 if ( m_eKind == LINK )
257 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.HierarchyLinkContent";
258 else if ( m_eKind == FOLDER )
259 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.HierarchyFolderContent";
260 else
261 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.HierarchyRootFolderContent";
262
263 return aSNS;
264}
265
266
267// XContent methods.
268
269
270// virtual
272{
273 return m_aProps.getContentType();
274}
275
276
277// virtual
278uno::Reference< ucb::XContentIdentifier > SAL_CALL
280{
281 // Transient?
282 if ( m_eState == TRANSIENT )
283 {
284 // Transient contents have no identifier.
285 return uno::Reference< ucb::XContentIdentifier >();
286 }
287
288 return ContentImplHelper::getIdentifier();
289}
290
291
292// XCommandProcessor methods.
293
294
295// virtual
297 const ucb::Command& aCommand,
298 sal_Int32 /*CommandId*/,
299 const uno::Reference< ucb::XCommandEnvironment >& Environment )
300{
301 uno::Any aRet;
302
303 if ( aCommand.Name == "getPropertyValues" )
304 {
305
306 // getPropertyValues
307
308
309 uno::Sequence< beans::Property > Properties;
310 if ( !( aCommand.Argument >>= Properties ) )
311 {
313 uno::Any( lang::IllegalArgumentException(
314 "Wrong argument type!",
315 static_cast< cppu::OWeakObject * >( this ),
316 -1 ) ),
317 Environment );
318 // Unreachable
319 }
320
321 aRet <<= getPropertyValues( Properties );
322 }
323 else if ( aCommand.Name == "setPropertyValues" )
324 {
325
326 // setPropertyValues
327
328
329 uno::Sequence< beans::PropertyValue > aProperties;
330 if ( !( aCommand.Argument >>= aProperties ) )
331 {
333 uno::Any( lang::IllegalArgumentException(
334 "Wrong argument type!",
335 static_cast< cppu::OWeakObject * >( this ),
336 -1 ) ),
337 Environment );
338 // Unreachable
339 }
340
341 if ( !aProperties.hasElements() )
342 {
344 uno::Any( lang::IllegalArgumentException(
345 "No properties!",
346 static_cast< cppu::OWeakObject * >( this ),
347 -1 ) ),
348 Environment );
349 // Unreachable
350 }
351
353 }
354 else if ( aCommand.Name == "getPropertySetInfo" )
355 {
356
357 // getPropertySetInfo
358
359
361 }
362 else if ( aCommand.Name == "getCommandInfo" )
363 {
364
365 // getCommandInfo
366
367
368 aRet <<= getCommandInfo( Environment );
369 }
370 else if ( aCommand.Name == "open" && isFolder() )
371 {
372
373 // open command for a folder content
374
375
376 ucb::OpenCommandArgument2 aOpenCommand;
377 if ( !( aCommand.Argument >>= aOpenCommand ) )
378 {
380 uno::Any( lang::IllegalArgumentException(
381 "Wrong argument type!",
382 static_cast< cppu::OWeakObject * >( this ),
383 -1 ) ),
384 Environment );
385 // Unreachable
386 }
387
388 uno::Reference< ucb::XDynamicResultSet > xSet
389 = new DynamicResultSet( m_xContext, this, aOpenCommand );
390 aRet <<= xSet;
391 }
392 else if ( aCommand.Name == "insert" && ( m_eKind != ROOT ) && !isReadOnly() )
393 {
394
395 // insert
396 // ( Not available at root folder )
397
398
399 ucb::InsertCommandArgument aArg;
400 if ( !( aCommand.Argument >>= aArg ) )
401 {
403 uno::Any( lang::IllegalArgumentException(
404 "Wrong argument type!",
405 static_cast< cppu::OWeakObject * >( this ),
406 -1 ) ),
407 Environment );
408 // Unreachable
409 }
410
411 sal_Int32 nNameClash = aArg.ReplaceExisting
412 ? ucb::NameClash::OVERWRITE
413 : ucb::NameClash::ERROR;
414 insert( nNameClash, Environment );
415 }
416 else if ( aCommand.Name == "delete" && ( m_eKind != ROOT ) && !isReadOnly() )
417 {
418
419 // delete
420 // ( Not available at root folder )
421
422
423 bool bDeletePhysical = false;
424 aCommand.Argument >>= bDeletePhysical;
425 destroy( bDeletePhysical, Environment );
426
427 // Remove own and all children's persistent data.
428 if ( !removeData() )
429 {
430 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
431 {
432 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
433 }));
435 ucb::IOErrorCode_CANT_WRITE,
436 aArgs,
438 "Cannot remove persistent data!",
439 this );
440 // Unreachable
441 }
442
443 // Remove own and all children's Additional Core Properties.
445 }
446 else if ( aCommand.Name == "transfer" && isFolder() && !isReadOnly() )
447 {
448
449 // transfer
450 // ( Not available at link objects )
451
452
453 ucb::TransferInfo aInfo;
454 if ( !( aCommand.Argument >>= aInfo ) )
455 {
456 OSL_FAIL( "Wrong argument type!" );
458 uno::Any( lang::IllegalArgumentException(
459 "Wrong argument type!",
460 static_cast< cppu::OWeakObject * >( this ),
461 -1 ) ),
462 Environment );
463 // Unreachable
464 }
465
466 transfer( aInfo, Environment );
467 }
468 else if ( aCommand.Name == "createNewContent" && isFolder() && !isReadOnly() )
469 {
470
471 // createNewContent
472 // ( Not available at link objects )
473
474
475 ucb::ContentInfo aInfo;
476 if ( !( aCommand.Argument >>= aInfo ) )
477 {
478 OSL_FAIL( "Wrong argument type!" );
480 uno::Any( lang::IllegalArgumentException(
481 "Wrong argument type!",
482 static_cast< cppu::OWeakObject * >( this ),
483 -1 ) ),
484 Environment );
485 // Unreachable
486 }
487
488 aRet <<= createNewContent( aInfo );
489 }
490 else
491 {
492
493 // Unsupported command
494
495
497 uno::Any( ucb::UnsupportedCommandException(
498 OUString(),
499 static_cast< cppu::OWeakObject * >( this ) ) ),
500 Environment );
501 // Unreachable
502 }
503
504 return aRet;
505}
506
507
508// virtual
509void SAL_CALL HierarchyContent::abort( sal_Int32 /*CommandId*/ )
510{
511 // @@@ Generally, no action takes much time...
512}
513
514
515// XContentCreator methods.
516
517
518// virtual
519uno::Sequence< ucb::ContentInfo > SAL_CALL
521{
523}
524
525
526// virtual
527uno::Reference< ucb::XContent > SAL_CALL
528HierarchyContent::createNewContent( const ucb::ContentInfo& Info )
529{
530 if ( isFolder() )
531 {
532 osl::Guard< osl::Mutex > aGuard( m_aMutex );
533
534 if ( Info.Type.isEmpty() )
535 return uno::Reference< ucb::XContent >();
536
537 bool bCreateFolder = Info.Type == HIERARCHY_FOLDER_CONTENT_TYPE;
538
539 if ( !bCreateFolder && Info.Type != HIERARCHY_LINK_CONTENT_TYPE )
540 return uno::Reference< ucb::XContent >();
541
542 OUString aURL = m_xIdentifier->getContentIdentifier();
543
544 OSL_ENSURE( !aURL.isEmpty(),
545 "HierarchyContent::createNewContent - empty identifier!" );
546
547 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
548 aURL += "/";
549
550 if ( bCreateFolder )
551 aURL += "New_Folder";
552 else
553 aURL += "New_Link";
554
555 uno::Reference< ucb::XContentIdentifier > xId
556 = new ::ucbhelper::ContentIdentifier( aURL );
557
558 return create( m_xContext, m_pProvider, xId, Info );
559 }
560 else
561 {
562 OSL_FAIL( "createNewContent called on non-folder object!" );
563 return uno::Reference< ucb::XContent >();
564 }
565}
566
567
568// virtual
570{
571 HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
572 return aUri.getParentUri();
573}
574
575
576//static
578 const uno::Reference< uno::XComponentContext >& rxContext,
579 HierarchyContentProvider* pProvider,
580 const uno::Reference< ucb::XContentIdentifier >& Identifier )
581{
582 OUString aURL = Identifier->getContentIdentifier();
583
584 // Am I a root folder?
585 HierarchyUri aUri( aURL );
586 if ( aUri.isRootFolder() )
587 {
588 // hasData must always return 'true' for root folder
589 // even if no persistent data exist!!!
590 return true;
591 }
592
593 return HierarchyEntry( rxContext, pProvider, aURL ).hasData();
594}
595
596
597//static
599 const uno::Reference< uno::XComponentContext >& rxContext,
600 HierarchyContentProvider* pProvider,
601 const uno::Reference< ucb::XContentIdentifier >& Identifier,
603{
604 OUString aURL = Identifier->getContentIdentifier();
605
606 // Am I a root folder?
607 HierarchyUri aUri( aURL );
608 if ( aUri.isRootFolder() )
609 {
611 }
612 else
613 {
614 HierarchyEntry aEntry( rxContext, pProvider, aURL );
616 if ( !aEntry.getData( aData ) )
617 return false;
618
620 }
621 return true;
622}
623
624
626{
627 HierarchyEntry aEntry(
628 m_xContext, m_pProvider, m_xIdentifier->getContentIdentifier() );
629 return aEntry.setData( m_aProps.getHierarchyEntryData() );
630}
631
632
634 const uno::Reference< ucb::XContentIdentifier >& xOldId,
635 const uno::Reference< ucb::XContentIdentifier >& xNewId )
636{
637 HierarchyEntry aEntry(
638 m_xContext, m_pProvider, xOldId->getContentIdentifier() );
639 aEntry.move( xNewId->getContentIdentifier(),
641}
642
643
645{
646 HierarchyEntry aEntry(
647 m_xContext, m_pProvider, m_xIdentifier->getContentIdentifier() );
648 return aEntry.remove();
649}
650
651
653 const uno::Reference< ucb::XContentIdentifier >& Identifier )
654{
655 if ( m_aProps.getIsFolder() )
656 {
657 // Am I a root folder?
658 HierarchyUri aUri( Identifier->getContentIdentifier() );
659 if ( aUri.isRootFolder() )
660 m_eKind = ROOT;
661 else
662 m_eKind = FOLDER;
663 }
664 else
665 m_eKind = LINK;
666}
667
668
670{
671 if ( !m_bCheckedReadOnly )
672 {
673 osl::Guard< osl::Mutex > aGuard( m_aMutex );
674 if ( !m_bCheckedReadOnly )
675 {
676 m_bCheckedReadOnly = true;
677 m_bIsReadOnly = true;
678
679 HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
680 uno::Reference< lang::XMultiServiceFactory > xConfigProv
682 if ( xConfigProv.is() )
683 {
684 uno::Sequence< OUString > aNames
685 = xConfigProv->getAvailableServiceNames();
686 m_bIsReadOnly = comphelper::findValue(aNames, "com.sun.star.ucb.HierarchyDataReadWriteAccess") == -1;
687 }
688 }
689 }
690
691 return m_bIsReadOnly;
692}
693
694
695uno::Reference< ucb::XContentIdentifier >
696HierarchyContent::makeNewIdentifier( const OUString& rTitle )
697{
698 osl::Guard< osl::Mutex > aGuard( m_aMutex );
699
700 // Assemble new content identifier...
701 HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
702 OUString aNewURL = aUri.getParentUri() + "/";
703 aNewURL += ::ucb_impl::urihelper::encodeSegment( rTitle );
704
705 return uno::Reference< ucb::XContentIdentifier >(
706 new ::ucbhelper::ContentIdentifier( aNewURL ) );
707}
708
709
711{
712 if ( ( m_eKind != FOLDER ) && ( m_eKind != ROOT ) )
713 return;
714
715 // Obtain a list with a snapshot of all currently instantiated contents
716 // from provider and extract the contents which are direct children
717 // of this content.
718
719 ::ucbhelper::ContentRefList aAllContents;
720 m_xProvider->queryExistingContents( aAllContents );
721
722 OUString aURL = m_xIdentifier->getContentIdentifier();
723 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
724
725 if ( nURLPos != ( aURL.getLength() - 1 ) )
726 {
727 // No trailing slash found. Append.
728 aURL += "/";
729 }
730
731 sal_Int32 nLen = aURL.getLength();
732
733 for ( const auto& rContent : aAllContents )
734 {
735 ::ucbhelper::ContentImplHelperRef xChild = rContent;
736 OUString aChildURL
737 = xChild->getIdentifier()->getContentIdentifier();
738
739 // Is aURL a prefix of aChildURL?
740 if ( ( aChildURL.getLength() > nLen ) &&
741 ( aChildURL.startsWith( aURL ) ) )
742 {
743 sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
744
745 if ( ( nPos == -1 ) ||
746 ( nPos == ( aChildURL.getLength() - 1 ) ) )
747 {
748 // No further slashes/ only a final slash. It's a child!
749 rChildren.emplace_back(
750 static_cast< HierarchyContent * >( xChild.get() ) );
751 }
752 }
753 }
754}
755
756
758 const uno::Reference< ucb::XContentIdentifier >& xNewId )
759{
760 if ( !xNewId.is() )
761 return false;
762
763 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
764
765 uno::Reference< ucb::XContent > xThis = this;
766
767 // Already persistent?
768 if ( m_eState != PERSISTENT )
769 {
770 OSL_FAIL( "HierarchyContent::exchangeIdentity - Not persistent!" );
771 return false;
772 }
773
774 // Am I the root folder?
775 if ( m_eKind == ROOT )
776 {
777 OSL_FAIL( "HierarchyContent::exchangeIdentity - "
778 "Not supported by root folder!" );
779 return false;
780 }
781
782 // Exchange own identity.
783
784 // Fail, if a content with given id already exists.
785 if ( !hasData( xNewId ) )
786 {
787 OUString aOldURL = m_xIdentifier->getContentIdentifier();
788
789 aGuard.clear();
790 if ( exchange( xNewId ) )
791 {
792 if ( m_eKind == FOLDER )
793 {
794 // Process instantiated children...
795
797 queryChildren( aChildren );
798
799 for ( const auto& rChild : aChildren )
800 {
801 HierarchyContentRef xChild = rChild;
802
803 // Create new content identifier for the child...
804 uno::Reference< ucb::XContentIdentifier > xOldChildId
805 = xChild->getIdentifier();
806 OUString aOldChildURL
807 = xOldChildId->getContentIdentifier();
808 OUString aNewChildURL
809 = aOldChildURL.replaceAt(
810 0,
811 aOldURL.getLength(),
812 xNewId->getContentIdentifier() );
813 uno::Reference< ucb::XContentIdentifier > xNewChildId
814 = new ::ucbhelper::ContentIdentifier( aNewChildURL );
815
816 if ( !xChild->exchangeIdentity( xNewChildId ) )
817 return false;
818 }
819 }
820 return true;
821 }
822 }
823
824 OSL_FAIL( "HierarchyContent::exchangeIdentity - "
825 "Panic! Cannot exchange identity!" );
826 return false;
827}
828
829
830// static
831uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues(
832 const uno::Reference< uno::XComponentContext >& rxContext,
833 const uno::Sequence< beans::Property >& rProperties,
834 const HierarchyContentProperties& rData,
835 HierarchyContentProvider* pProvider,
836 const OUString& rContentId )
837{
838 // Note: Empty sequence means "get values of all supported properties".
839
841 = new ::ucbhelper::PropertyValueSet( rxContext );
842
843 if ( rProperties.hasElements() )
844 {
845 uno::Reference< beans::XPropertySet > xAdditionalPropSet;
846 bool bTriedToGetAdditionalPropSet = false;
847
848 for ( const beans::Property& rProp : rProperties )
849 {
850 // Process Core properties.
851
852 if ( rProp.Name == "ContentType" )
853 {
854 xRow->appendString ( rProp, rData.getContentType() );
855 }
856 else if ( rProp.Name == "Title" )
857 {
858 xRow->appendString ( rProp, rData.getTitle() );
859 }
860 else if ( rProp.Name == "IsDocument" )
861 {
862 xRow->appendBoolean( rProp, rData.getIsDocument() );
863 }
864 else if ( rProp.Name == "IsFolder" )
865 {
866 xRow->appendBoolean( rProp, rData.getIsFolder() );
867 }
868 else if ( rProp.Name == "CreatableContentsInfo" )
869 {
870 xRow->appendObject(
871 rProp, uno::Any( rData.getCreatableContentsInfo() ) );
872 }
873 else if ( rProp.Name == "TargetURL" )
874 {
875 // TargetURL is only supported by links.
876
877 if ( rData.getIsDocument() )
878 xRow->appendString( rProp, rData.getTargetURL() );
879 else
880 xRow->appendVoid( rProp );
881 }
882 else
883 {
884 // Not a Core Property! Maybe it's an Additional Core Property?!
885
886 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
887 {
888 xAdditionalPropSet =
889 pProvider->getAdditionalPropertySet( rContentId,
890 false );
891 bTriedToGetAdditionalPropSet = true;
892 }
893
894 if ( xAdditionalPropSet.is() )
895 {
896 if ( !xRow->appendPropertySetValue(
897 xAdditionalPropSet,
898 rProp ) )
899 {
900 // Append empty entry.
901 xRow->appendVoid( rProp );
902 }
903 }
904 else
905 {
906 // Append empty entry.
907 xRow->appendVoid( rProp );
908 }
909 }
910 }
911 }
912 else
913 {
914 // Append all Core Properties.
915 xRow->appendString (
916 beans::Property( "ContentType",
917 -1,
919 beans::PropertyAttribute::BOUND
920 | beans::PropertyAttribute::READONLY ),
921 rData.getContentType() );
922 xRow->appendString (
923 beans::Property( "Title",
924 -1,
926 // @@@ Might actually be read-only!
927 beans::PropertyAttribute::BOUND ),
928 rData.getTitle() );
929 xRow->appendBoolean(
930 beans::Property( "IsDocument",
931 -1,
933 beans::PropertyAttribute::BOUND
934 | beans::PropertyAttribute::READONLY ),
935 rData.getIsDocument() );
936 xRow->appendBoolean(
937 beans::Property( "IsFolder",
938 -1,
940 beans::PropertyAttribute::BOUND
941 | beans::PropertyAttribute::READONLY ),
942 rData.getIsFolder() );
943
944 if ( rData.getIsDocument() )
945 xRow->appendString(
946 beans::Property( "TargetURL",
947 -1,
949 // @@@ Might actually be read-only!
950 beans::PropertyAttribute::BOUND ),
951 rData.getTargetURL() );
952 xRow->appendObject(
953 beans::Property(
954 "CreatableContentsInfo",
955 -1,
956 cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
957 beans::PropertyAttribute::BOUND
958 | beans::PropertyAttribute::READONLY ),
960
961 // Append all Additional Core Properties.
962
963 uno::Reference< beans::XPropertySet > xSet =
964 pProvider->getAdditionalPropertySet( rContentId, false );
965 xRow->appendPropertySet( xSet );
966 }
967
968 return xRow;
969}
970
971
972uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues(
973 const uno::Sequence< beans::Property >& rProperties )
974{
975 osl::Guard< osl::Mutex > aGuard( m_aMutex );
977 rProperties,
978 m_aProps,
980 m_xIdentifier->getContentIdentifier() );
981}
982
983
984uno::Sequence< uno::Any > HierarchyContent::setPropertyValues(
985 const uno::Sequence< beans::PropertyValue >& rValues,
986 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
987{
988 osl::ResettableGuard< osl::Mutex > aGuard( m_aMutex );
989
990 uno::Sequence< uno::Any > aRet( rValues.getLength() );
991 auto aRetRange = asNonConstRange(aRet);
992 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
993 sal_Int32 nChanged = 0;
994
995 beans::PropertyChangeEvent aEvent;
996 aEvent.Source = static_cast< cppu::OWeakObject * >( this );
997 aEvent.Further = false;
998// aEvent.PropertyName =
999 aEvent.PropertyHandle = -1;
1000// aEvent.OldValue =
1001// aEvent.NewValue =
1002
1003 const beans::PropertyValue* pValues = rValues.getConstArray();
1004 sal_Int32 nCount = rValues.getLength();
1005
1006 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1007 bool bTriedToGetAdditionalPropSet = false;
1008
1009 bool bExchange = false;
1010 OUString aOldTitle;
1011 OUString aOldName;
1012 sal_Int32 nTitlePos = -1;
1013
1014 for ( sal_Int32 n = 0; n < nCount; ++n )
1015 {
1016 const beans::PropertyValue& rValue = pValues[ n ];
1017
1018 if ( rValue.Name == "ContentType" )
1019 {
1020 // Read-only property!
1021 aRetRange[ n ] <<= lang::IllegalAccessException(
1022 "Property is read-only!",
1023 static_cast< cppu::OWeakObject * >( this ) );
1024 }
1025 else if ( rValue.Name == "IsDocument" )
1026 {
1027 // Read-only property!
1028 aRetRange[ n ] <<= lang::IllegalAccessException(
1029 "Property is read-only!",
1030 static_cast< cppu::OWeakObject * >( this ) );
1031 }
1032 else if ( rValue.Name == "IsFolder" )
1033 {
1034 // Read-only property!
1035 aRetRange[ n ] <<= lang::IllegalAccessException(
1036 "Property is read-only!",
1037 static_cast< cppu::OWeakObject * >( this ) );
1038 }
1039 else if ( rValue.Name == "CreatableContentsInfo" )
1040 {
1041 // Read-only property!
1042 aRetRange[ n ] <<= lang::IllegalAccessException(
1043 "Property is read-only!",
1044 static_cast< cppu::OWeakObject * >( this ) );
1045 }
1046 else if ( rValue.Name == "Title" )
1047 {
1048 if ( isReadOnly() )
1049 {
1050 aRetRange[ n ] <<= lang::IllegalAccessException(
1051 "Property is read-only!",
1052 static_cast< cppu::OWeakObject * >( this ) );
1053 }
1054 else
1055 {
1056 OUString aNewValue;
1057 if ( rValue.Value >>= aNewValue )
1058 {
1059 // No empty titles!
1060 if ( !aNewValue.isEmpty() )
1061 {
1062 if ( aNewValue != m_aProps.getTitle() )
1063 {
1064 // modified title -> modified URL -> exchange !
1065 if ( m_eState == PERSISTENT )
1066 bExchange = true;
1067
1068 aOldTitle = m_aProps.getTitle();
1069 aOldName = m_aProps.getName();
1070
1071 m_aProps.setTitle( aNewValue );
1074 aNewValue ) );
1075
1076 // property change event will be set later...
1077
1078 // remember position within sequence of values
1079 // (for error handling).
1080 nTitlePos = n;
1081 }
1082 }
1083 else
1084 {
1085 aRetRange[ n ] <<= lang::IllegalArgumentException(
1086 "Empty title not allowed!",
1087 static_cast< cppu::OWeakObject * >( this ),
1088 -1 );
1089 }
1090 }
1091 else
1092 {
1093 aRetRange[ n ] <<= beans::IllegalTypeException(
1094 "Property value has wrong type!",
1095 static_cast< cppu::OWeakObject * >( this ) );
1096 }
1097 }
1098 }
1099 else if ( rValue.Name == "TargetURL" )
1100 {
1101 if ( isReadOnly() )
1102 {
1103 aRetRange[ n ] <<= lang::IllegalAccessException(
1104 "Property is read-only!",
1105 static_cast< cppu::OWeakObject * >( this ) );
1106 }
1107 else
1108 {
1109 // TargetURL is only supported by links.
1110
1111 if ( m_eKind == LINK )
1112 {
1113 OUString aNewValue;
1114 if ( rValue.Value >>= aNewValue )
1115 {
1116 // No empty target URL's!
1117 if ( !aNewValue.isEmpty() )
1118 {
1119 if ( aNewValue != m_aProps.getTargetURL() )
1120 {
1121 aEvent.PropertyName = rValue.Name;
1122 aEvent.OldValue <<= m_aProps.getTargetURL();
1123 aEvent.NewValue <<= aNewValue;
1124
1125 aChanges.getArray()[ nChanged ] = aEvent;
1126
1127 m_aProps.setTargetURL( aNewValue );
1128 nChanged++;
1129 }
1130 }
1131 else
1132 {
1133 aRetRange[ n ] <<= lang::IllegalArgumentException(
1134 "Empty target URL not allowed!",
1135 static_cast< cppu::OWeakObject * >( this ),
1136 -1 );
1137 }
1138 }
1139 else
1140 {
1141 aRetRange[ n ] <<= beans::IllegalTypeException(
1142 "Property value has wrong type!",
1143 static_cast< cppu::OWeakObject * >( this ) );
1144 }
1145 }
1146 else
1147 {
1148 aRetRange[ n ] <<= beans::UnknownPropertyException(
1149 "TargetURL only supported by links!",
1150 static_cast< cppu::OWeakObject * >( this ) );
1151 }
1152 }
1153 }
1154 else
1155 {
1156 // Not a Core Property! Maybe it's an Additional Core Property?!
1157
1158 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1159 {
1160 xAdditionalPropSet = getAdditionalPropertySet( false );
1161 bTriedToGetAdditionalPropSet = true;
1162 }
1163
1164 if ( xAdditionalPropSet.is() )
1165 {
1166 try
1167 {
1168 uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1169 rValue.Name );
1170 if ( aOldValue != rValue.Value )
1171 {
1172 xAdditionalPropSet->setPropertyValue(
1173 rValue.Name, rValue.Value );
1174
1175 aEvent.PropertyName = rValue.Name;
1176 aEvent.OldValue = aOldValue;
1177 aEvent.NewValue = rValue.Value;
1178
1179 aChanges.getArray()[ nChanged ] = aEvent;
1180 nChanged++;
1181 }
1182 }
1183 catch ( beans::UnknownPropertyException const & e )
1184 {
1185 aRetRange[ n ] <<= e;
1186 }
1187 catch ( lang::WrappedTargetException const & e )
1188 {
1189 aRetRange[ n ] <<= e;
1190 }
1191 catch ( beans::PropertyVetoException const & e )
1192 {
1193 aRetRange[ n ] <<= e;
1194 }
1195 catch ( lang::IllegalArgumentException const & e )
1196 {
1197 aRetRange[ n ] <<= e;
1198 }
1199 }
1200 else
1201 {
1202 aRetRange[ n ] <<= uno::Exception(
1203 "No property set for storing the value!",
1204 static_cast< cppu::OWeakObject * >( this ) );
1205 }
1206 }
1207 }
1208
1209 if ( bExchange )
1210 {
1211 uno::Reference< ucb::XContentIdentifier > xOldId
1212 = m_xIdentifier;
1213 uno::Reference< ucb::XContentIdentifier > xNewId
1215
1216 aGuard.clear();
1217 if ( exchangeIdentity( xNewId ) )
1218 {
1219 // Adapt persistent data.
1220 renameData( xOldId, xNewId );
1221
1222 // Adapt Additional Core Properties.
1223 renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1224 xNewId->getContentIdentifier() );
1225 }
1226 else
1227 {
1228 // Roll-back.
1229 m_aProps.setTitle( aOldTitle );
1230 m_aProps.setName ( aOldName );
1231
1232 aOldTitle.clear();
1233 aOldName.clear();
1234
1235 // Set error .
1236 aRetRange[ nTitlePos ] <<= uno::Exception(
1237 "Exchange failed!",
1238 static_cast< cppu::OWeakObject * >( this ) );
1239 }
1240 aGuard.reset();
1241 }
1242
1243 if ( !aOldTitle.isEmpty() )
1244 {
1245 aEvent.PropertyName = "Title";
1246 aEvent.OldValue <<= aOldTitle;
1247 aEvent.NewValue <<= m_aProps.getTitle();
1248
1249 aChanges.getArray()[ nChanged ] = aEvent;
1250 nChanged++;
1251 }
1252
1253 if ( nChanged > 0 )
1254 {
1255 // Save changes, if content was already made persistent.
1256 if ( !bExchange && ( m_eState == PERSISTENT ) )
1257 {
1258 if ( !storeData() )
1259 {
1260 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1261 {
1262 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1263 }));
1265 ucb::IOErrorCode_CANT_WRITE,
1266 aArgs,
1267 xEnv,
1268 "Cannot store persistent data!",
1269 this );
1270 // Unreachable
1271 }
1272 }
1273
1274 aChanges.realloc( nChanged );
1275
1276 aGuard.clear();
1277 notifyPropertiesChange( aChanges );
1278 }
1279
1280 return aRet;
1281}
1282
1283
1284void HierarchyContent::insert( sal_Int32 nNameClashResolve,
1285 const uno::Reference<
1286 ucb::XCommandEnvironment > & xEnv )
1287{
1288 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1289
1290 // Am I the root folder?
1291 if ( m_eKind == ROOT )
1292 {
1294 uno::Any( ucb::UnsupportedCommandException(
1295 "Not supported by root folder!",
1296 static_cast< cppu::OWeakObject * >( this ) ) ),
1297 xEnv );
1298 // Unreachable
1299 }
1300
1301 // Check, if all required properties were set.
1302 if ( m_aProps.getTitle().isEmpty() )
1303 {
1304 uno::Sequence<OUString> aProps { "Title" };
1306 uno::Any( ucb::MissingPropertiesException(
1307 OUString(),
1308 static_cast< cppu::OWeakObject * >( this ),
1309 aProps ) ),
1310 xEnv );
1311 // Unreachable
1312 }
1313
1314 // Assemble new content identifier...
1315
1316 uno::Reference< ucb::XContentIdentifier > xId
1318
1319 // Handle possible name clash...
1320
1321 switch ( nNameClashResolve )
1322 {
1323 // fail.
1324 case ucb::NameClash::ERROR:
1325 if ( hasData( xId ) )
1326 {
1328 uno::Any(
1329 ucb::NameClashException(
1330 OUString(),
1331 static_cast< cppu::OWeakObject * >( this ),
1332 task::InteractionClassification_ERROR,
1333 m_aProps.getTitle() ) ),
1334 xEnv );
1335 // Unreachable
1336 }
1337 break;
1338
1339 // replace existing object.
1340 case ucb::NameClash::OVERWRITE:
1341 break;
1342
1343 // "invent" a new valid title.
1344 case ucb::NameClash::RENAME:
1345 if ( hasData( xId ) )
1346 {
1347 sal_Int32 nTry = 0;
1348
1349 do
1350 {
1351 OUString aNewId = xId->getContentIdentifier() + "_";
1352 aNewId += OUString::number( ++nTry );
1353 xId = new ::ucbhelper::ContentIdentifier( aNewId );
1354 }
1355 while ( hasData( xId ) && ( nTry < 1000 ) );
1356
1357 if ( nTry == 1000 )
1358 {
1360 uno::Any(
1361 ucb::UnsupportedNameClashException(
1362 "Unable to resolve name clash!",
1363 static_cast< cppu::OWeakObject * >( this ),
1364 nNameClashResolve ) ),
1365 xEnv );
1366 // Unreachable
1367 }
1368 else
1369 {
1370 OUString aNewTitle( m_aProps.getTitle() + "_" + OUString::number( nTry ) );
1371 m_aProps.setTitle( aNewTitle );
1372 }
1373 }
1374 break;
1375
1376 case ucb::NameClash::KEEP: // deprecated
1377 case ucb::NameClash::ASK:
1378 default:
1379 if ( hasData( xId ) )
1380 {
1382 uno::Any(
1383 ucb::UnsupportedNameClashException(
1384 OUString(),
1385 static_cast< cppu::OWeakObject * >( this ),
1386 nNameClashResolve ) ),
1387 xEnv );
1388 // Unreachable
1389 }
1390 break;
1391 }
1392
1393 // Identifier changed?
1394 bool bNewId = ( xId->getContentIdentifier()
1395 != m_xIdentifier->getContentIdentifier() );
1396 m_xIdentifier = xId;
1397
1398 if ( !storeData() )
1399 {
1400 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1401 {
1402 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1403 }));
1405 ucb::IOErrorCode_CANT_WRITE,
1406 aArgs,
1407 xEnv,
1408 "Cannot store persistent data!",
1409 this );
1410 // Unreachable
1411 }
1412
1414
1415 if ( bNewId )
1416 {
1417 aGuard.clear();
1418 inserted();
1419 }
1420}
1421
1422
1423void HierarchyContent::destroy( bool bDeletePhysical,
1424 const uno::Reference<
1425 ucb::XCommandEnvironment > & xEnv )
1426{
1427 // @@@ take care about bDeletePhysical -> trashcan support
1428
1429 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1430
1431 uno::Reference< ucb::XContent > xThis = this;
1432
1433 // Persistent?
1434 if ( m_eState != PERSISTENT )
1435 {
1437 uno::Any( ucb::UnsupportedCommandException(
1438 "Not persistent!",
1439 static_cast< cppu::OWeakObject * >( this ) ) ),
1440 xEnv );
1441 // Unreachable
1442 }
1443
1444 // Am I the root folder?
1445 if ( m_eKind == ROOT )
1446 {
1448 uno::Any( ucb::UnsupportedCommandException(
1449 "Not supported by root folder!",
1450 static_cast< cppu::OWeakObject * >( this ) ) ),
1451 xEnv );
1452 // Unreachable
1453 }
1454
1455 m_eState = DEAD;
1456
1457 aGuard.clear();
1458 deleted();
1459
1460 if ( m_eKind == FOLDER )
1461 {
1462 // Process instantiated children...
1463
1464 HierarchyContentRefVector aChildren;
1465 queryChildren( aChildren );
1466
1467 for ( auto & child : aChildren)
1468 {
1469 child->destroy( bDeletePhysical, xEnv );
1470 }
1471 }
1472}
1473
1474
1476 const ucb::TransferInfo& rInfo,
1477 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1478{
1479 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1480
1481 // Persistent?
1482 if ( m_eState != PERSISTENT )
1483 {
1485 uno::Any( ucb::UnsupportedCommandException(
1486 "Not persistent!",
1487 static_cast< cppu::OWeakObject * >( this ) ) ),
1488 xEnv );
1489 // Unreachable
1490 }
1491
1492 // Is source a hierarchy content?
1493 if ( !rInfo.SourceURL.startsWith( HIERARCHY_URL_SCHEME ":/" ) )
1494 {
1496 uno::Any( ucb::InteractiveBadTransferURLException(
1497 OUString(),
1498 static_cast< cppu::OWeakObject * >( this ) ) ),
1499 xEnv );
1500 // Unreachable
1501 }
1502
1503 // Is source not a parent of me / not me?
1504 OUString aId = m_xIdentifier->getContentIdentifier();
1505 sal_Int32 nPos = aId.lastIndexOf( '/' );
1506 if ( nPos != ( aId.getLength() - 1 ) )
1507 {
1508 // No trailing slash found. Append.
1509 aId += "/";
1510 }
1511
1512 if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1513 {
1514 if ( aId.startsWith( rInfo.SourceURL ) )
1515 {
1516 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1517 {
1518 {"Uri", uno::Any(rInfo.SourceURL)}
1519 }));
1521 ucb::IOErrorCode_RECURSIVE,
1522 aArgs,
1523 xEnv,
1524 "Target is equal to or is a child of source!",
1525 this );
1526 // Unreachable
1527 }
1528 }
1529
1530
1531 // 0) Obtain content object for source.
1532
1533
1534 uno::Reference< ucb::XContentIdentifier > xId
1535 = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
1536
1537 // Note: The static cast is okay here, because its sure that
1538 // m_xProvider is always the HierarchyContentProvider.
1540
1541 try
1542 {
1543 xSource = static_cast< HierarchyContent * >(
1544 m_xProvider->queryContent( xId ).get() );
1545 }
1546 catch ( ucb::IllegalIdentifierException const & )
1547 {
1548 // queryContent
1549 }
1550
1551 if ( !xSource.is() )
1552 {
1553 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1554 {
1555 {"Uri", uno::Any(xId->getContentIdentifier())}
1556 }));
1558 ucb::IOErrorCode_CANT_READ,
1559 aArgs,
1560 xEnv,
1561 "Cannot instantiate source object!",
1562 this );
1563 // Unreachable
1564 }
1565
1566
1567 // 1) Create new child content.
1568
1569
1570 OUString aType = xSource->isFolder()
1571 ? OUString( HIERARCHY_FOLDER_CONTENT_TYPE )
1572 : OUString( HIERARCHY_LINK_CONTENT_TYPE );
1573 ucb::ContentInfo aContentInfo;
1574 aContentInfo.Type = aType;
1575 aContentInfo.Attributes = 0;
1576
1577 // Note: The static cast is okay here, because its sure that
1578 // createNewContent always creates a HierarchyContent.
1580 = static_cast< HierarchyContent * >(
1581 createNewContent( aContentInfo ).get() );
1582 if ( !xTarget.is() )
1583 {
1584 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1585 {
1586 {"Folder", uno::Any(aId)}
1587 }));
1589 ucb::IOErrorCode_CANT_CREATE,
1590 aArgs,
1591 xEnv,
1592 "XContentCreator::createNewContent failed!",
1593 this );
1594 // Unreachable
1595 }
1596
1597
1598 // 2) Copy data from source content to child content.
1599
1600
1601 uno::Sequence< beans::Property > aSourceProps
1602 = xSource->getPropertySetInfo( xEnv )->getProperties();
1603 sal_Int32 nCount = aSourceProps.getLength();
1604
1605 if ( nCount )
1606 {
1607 bool bHadTitle = rInfo.NewTitle.isEmpty();
1608
1609 // Get all source values.
1610 uno::Reference< sdbc::XRow > xRow
1611 = xSource->getPropertyValues( aSourceProps );
1612
1613 uno::Sequence< beans::PropertyValue > aValues( nCount );
1614 beans::PropertyValue* pValues = aValues.getArray();
1615
1616 const beans::Property* pProps = aSourceProps.getConstArray();
1617 for ( sal_Int32 n = 0; n < nCount; ++n )
1618 {
1619 const beans::Property& rProp = pProps[ n ];
1620 beans::PropertyValue& rValue = pValues[ n ];
1621
1622 rValue.Name = rProp.Name;
1623 rValue.Handle = rProp.Handle;
1624
1625 if ( !bHadTitle && rProp.Name == "Title" )
1626 {
1627 // Set new title instead of original.
1628 bHadTitle = true;
1629 rValue.Value <<= rInfo.NewTitle;
1630 }
1631 else
1632 rValue.Value = xRow->getObject(
1633 n + 1,
1634 uno::Reference< container::XNameAccess >() );
1635
1636 rValue.State = beans::PropertyState_DIRECT_VALUE;
1637
1638 if ( rProp.Attributes & beans::PropertyAttribute::REMOVABLE )
1639 {
1640 // Add Additional Core Property.
1641 try
1642 {
1643 xTarget->addProperty( rProp.Name,
1644 rProp.Attributes,
1645 rValue.Value );
1646 }
1647 catch ( beans::PropertyExistException const & )
1648 {
1649 }
1650 catch ( beans::IllegalTypeException const & )
1651 {
1652 }
1653 catch ( lang::IllegalArgumentException const & )
1654 {
1655 }
1656 }
1657 }
1658
1659 // Set target values.
1660 xTarget->setPropertyValues( aValues, xEnv );
1661 }
1662
1663
1664 // 3) Commit (insert) child.
1665
1666
1667 xTarget->insert( rInfo.NameClash, xEnv );
1668
1669
1670 // 4) Transfer (copy) children of source.
1671
1672
1673 if ( xSource->isFolder() )
1674 {
1675 HierarchyEntry aFolder(
1676 m_xContext, m_pProvider, xId->getContentIdentifier() );
1678
1679 while ( aFolder.next( it ) )
1680 {
1681 const HierarchyEntryData& rResult = *it;
1682
1683 OUString aChildId = xId->getContentIdentifier();
1684 if ( ( aChildId.lastIndexOf( '/' ) + 1 ) != aChildId.getLength() )
1685 aChildId += "/";
1686
1687 aChildId += rResult.getName();
1688
1689 ucb::TransferInfo aInfo;
1690 aInfo.MoveData = false;
1691 aInfo.NewTitle.clear();
1692 aInfo.SourceURL = aChildId;
1693 aInfo.NameClash = rInfo.NameClash;
1694
1695 // Transfer child to target.
1696 xTarget->transfer( aInfo, xEnv );
1697 }
1698 }
1699
1700
1701 // 5) Destroy source ( when moving only ) .
1702
1703
1704 if ( !rInfo.MoveData )
1705 return;
1706
1707 xSource->destroy( true, xEnv );
1708
1709 // Remove all persistent data of source and its children.
1710 if ( !xSource->removeData() )
1711 {
1712 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1713 {
1714 {"Uri", uno::Any(xSource->m_xIdentifier->getContentIdentifier())}
1715 }));
1717 ucb::IOErrorCode_CANT_WRITE,
1718 aArgs,
1719 xEnv,
1720 "Cannot remove persistent data of source object!",
1721 this );
1722 // Unreachable
1723 }
1724
1725 // Remove own and all children's Additional Core Properties.
1726 xSource->removeAdditionalPropertySet();
1727}
1728
1729
1730// HierarchyContentProperties Implementation.
1731
1732
1733uno::Sequence< ucb::ContentInfo >
1735{
1736 if ( getIsFolder() )
1737 {
1738 uno::Sequence< ucb::ContentInfo > aSeq( 2 );
1739
1740 // Folder.
1741 aSeq.getArray()[ 0 ].Type = HIERARCHY_FOLDER_CONTENT_TYPE;
1742 aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
1743
1744 uno::Sequence< beans::Property > aFolderProps( 1 );
1745 aFolderProps.getArray()[ 0 ] = beans::Property(
1746 "Title",
1747 -1,
1749 beans::PropertyAttribute::BOUND );
1750 aSeq.getArray()[ 0 ].Properties = aFolderProps;
1751
1752 // Link.
1753 aSeq.getArray()[ 1 ].Type = HIERARCHY_LINK_CONTENT_TYPE;
1754 aSeq.getArray()[ 1 ].Attributes = ucb::ContentInfoAttribute::KIND_LINK;
1755
1756 uno::Sequence< beans::Property > aLinkProps( 2 );
1757 aLinkProps.getArray()[ 0 ] = beans::Property(
1758 "Title",
1759 -1,
1761 beans::PropertyAttribute::BOUND );
1762 aLinkProps.getArray()[ 1 ] = beans::Property(
1763 "TargetURL",
1764 -1,
1766 beans::PropertyAttribute::BOUND );
1767 aSeq.getArray()[ 1 ].Properties = aLinkProps;
1768
1769 return aSeq;
1770 }
1771 else
1772 {
1773 return uno::Sequence< ucb::ContentInfo >( 0 );
1774 }
1775}
1776
1777/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const PropertyValue * pValues
PropertiesInfo aProperties
AnyEventRef aEvent
css::uno::Sequence< css::uno::Type > SAL_CALL getTypes()
css::uno::Sequence< css::ucb::ContentInfo > getCreatableContentsInfo() const
const HierarchyEntryData & getHierarchyEntryData() const
css::uno::Reference< css::lang::XMultiServiceFactory > getConfigProvider(const OUString &rServiceSpecifier)
css::uno::Sequence< css::uno::Any > setPropertyValues(const css::uno::Sequence< css::beans::PropertyValue > &rValues, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
std::vector< HierarchyContentRef > HierarchyContentRefVector
void destroy(bool bDeletePhysical, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual OUString SAL_CALL getImplementationName() override
HierarchyContentProvider * m_pProvider
void renameData(const css::uno::Reference< css::ucb::XContentIdentifier > &xOldId, const css::uno::Reference< css::ucb::XContentIdentifier > &xNewId)
bool exchangeIdentity(const css::uno::Reference< css::ucb::XContentIdentifier > &xNewId)
virtual void SAL_CALL abort(sal_Int32 CommandId) override
virtual css::uno::Sequence< css::ucb::ContentInfo > SAL_CALL queryCreatableContentsInfo() override
void insert(sal_Int32 nNameClashResolve, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void setKind(const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier)
void transfer(const css::ucb::TransferInfo &rInfo, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual OUString getParentURL() override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
css::uno::Reference< css::sdbc::XRow > getPropertyValues(const css::uno::Sequence< css::beans::Property > &rProperties)
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL createNewContent(const css::ucb::ContentInfo &Info) override
virtual OUString SAL_CALL getContentType() override
static bool loadData(const css::uno::Reference< css::uno::XComponentContext > &rxContext, HierarchyContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier, HierarchyContentProperties &rProps)
virtual css::uno::Any SAL_CALL execute(const css::ucb::Command &aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment > &Environment) override
void queryChildren(HierarchyContentRefVector &rChildren)
virtual void SAL_CALL release() noexcept override
css::uno::Reference< css::ucb::XContentIdentifier > makeNewIdentifier(const OUString &rTitle)
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
HierarchyContent(const css::uno::Reference< css::uno::XComponentContext > &rxContext, HierarchyContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier, HierarchyContentProperties aProps)
HierarchyContentProperties m_aProps
static rtl::Reference< HierarchyContent > create(const css::uno::Reference< css::uno::XComponentContext > &rxContext, HierarchyContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier)
virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL getIdentifier() override
virtual void SAL_CALL acquire() noexcept override
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
static bool hasData(const css::uno::Reference< css::uno::XComponentContext > &rxContext, HierarchyContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier)
const OUString & getName() const
bool move(const OUString &rNewURL, const HierarchyEntryData &rData)
bool setData(const HierarchyEntryData &rData)
bool getData(HierarchyEntryData &rData)
const OUString & getService() const
const OUString & getParentUri() const
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(bool bCreate)
css::uno::Reference< css::ucb::XCommandInfo > getCommandInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
bool renameAdditionalPropertySet(const OUString &rOldKey, const OUString &rNewKey)
rtl::Reference< ContentProviderImplHelper > m_xProvider
bool exchange(const css::uno::Reference< css::ucb::XContentIdentifier > &rNewId)
css::uno::Reference< css::beans::XPropertySetInfo > getPropertySetInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
css::uno::Reference< css::ucb::XContentIdentifier > m_xIdentifier
css::uno::Reference< css::uno::XComponentContext > m_xContext
void notifyPropertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent > &evt) const
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(const OUString &rKey, bool bCreate)
int nCount
URL aURL
Reference< XInterface > xTarget
XTYPEPROVIDER_COMMON_IMPL(HierarchyContent)
constexpr OUStringLiteral HIERARCHY_URL_SCHEME
sal_Int64 n
sal_uInt16 nPos
Sequence< sal_Int8 > aSeq
#define CPPU_TYPE_REF(T)
constexpr OUStringLiteral aData
sal_Int32 findValue(const css::uno::Sequence< T1 > &_rList, const T2 &_rValue)
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
Type
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
Info
constexpr OUStringLiteral HIERARCHY_LINK_CONTENT_TYPE
constexpr OUStringLiteral HIERARCHY_FOLDER_CONTENT_TYPE
OUString encodeSegment(const OUString &rSegment)
Definition: urihelper.hxx:29
std::vector< ContentImplHelperRef > ContentRefList
void cancelCommandExecution(const uno::Any &rException, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
uno::Sequence< beans::Property > m_aProps
bool hasValue()
Object Value
OUString aCommand