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>
62 #include <comphelper/sequence.hxx>
67 #include <ucbhelper/macros.hxx>
68 #include "hierarchycontent.hxx"
69 #include "hierarchyprovider.hxx"
70 #include "dynamicresultset.hxx"
71 #include "hierarchyuri.hxx"
72 
73 #include "../inc/urihelper.hxx"
74 
75 using namespace com::sun::star;
76 using namespace hierarchy_ucp;
77 
78 
79 // HierarchyContent Implementation.
80 
81 
82 // static ( "virtual" ctor )
83 HierarchyContent* HierarchyContent::create(
84  const uno::Reference< uno::XComponentContext >& rxContext,
85  HierarchyContentProvider* pProvider,
86  const uno::Reference< ucb::XContentIdentifier >& Identifier )
87 {
88  // Fail, if content does not exist.
90  if ( !loadData( rxContext, pProvider, Identifier, aProps ) )
91  return nullptr;
92 
93  return new HierarchyContent( rxContext, pProvider, Identifier, aProps );
94 }
95 
96 
97 // static ( "virtual" ctor )
98 HierarchyContent* HierarchyContent::create(
99  const uno::Reference< uno::XComponentContext >& rxContext,
100  HierarchyContentProvider* pProvider,
101  const uno::Reference< ucb::XContentIdentifier >& Identifier,
102  const ucb::ContentInfo& Info )
103 {
104  if ( Info.Type.isEmpty() )
105  return nullptr;
106 
107  if ( Info.Type != HIERARCHY_FOLDER_CONTENT_TYPE && Info.Type != HIERARCHY_LINK_CONTENT_TYPE )
108  return nullptr;
109 
110  return new HierarchyContent( rxContext, pProvider, Identifier, Info );
111 }
112 
113 
114 HierarchyContent::HierarchyContent(
115  const uno::Reference< uno::XComponentContext >& rxContext,
116  HierarchyContentProvider* pProvider,
117  const uno::Reference< ucb::XContentIdentifier >& Identifier,
118  const HierarchyContentProperties& rProps )
119 : ContentImplHelper( rxContext, pProvider, Identifier ),
120  m_aProps( rProps ),
121  m_eState( PERSISTENT ),
122  m_pProvider( pProvider ),
123  m_bCheckedReadOnly( false ),
124  m_bIsReadOnly( true )
125 {
126  setKind( Identifier );
127 }
128 
129 
130 HierarchyContent::HierarchyContent(
131  const uno::Reference< uno::XComponentContext >& rxContext,
132  HierarchyContentProvider* pProvider,
133  const uno::Reference< ucb::XContentIdentifier >& Identifier,
134  const ucb::ContentInfo& Info )
135  : ContentImplHelper( rxContext, pProvider, Identifier ),
137  m_eState( TRANSIENT ),
138  m_pProvider( pProvider ),
139  m_bCheckedReadOnly( false ),
140  m_bIsReadOnly( true )
141 {
142  setKind( Identifier );
143 }
144 
145 
146 // virtual
147 HierarchyContent::~HierarchyContent()
148 {
149 }
150 
151 
152 // XInterface methods.
153 
154 
155 // virtual
156 void SAL_CALL HierarchyContent::acquire()
157  throw( )
158 {
159  ContentImplHelper::acquire();
160 }
161 
162 
163 // virtual
164 void SAL_CALL HierarchyContent::release()
165  throw( )
166 {
167  ContentImplHelper::release();
168 }
169 
170 
171 // virtual
172 uno::Any SAL_CALL HierarchyContent::queryInterface( const uno::Type & rType )
173 {
174  uno::Any aRet = ContentImplHelper::queryInterface( rType );
175 
176  if ( !aRet.hasValue() )
177  {
178  // Note: isReadOnly may be relative expensive. So avoid calling it
179  // unless it is really necessary.
180  aRet = cppu::queryInterface(
181  rType, static_cast< ucb::XContentCreator * >( this ) );
182  if ( aRet.hasValue() )
183  {
184  if ( !isFolder() || isReadOnly() )
185  return uno::Any();
186  }
187  }
188 
189  return aRet;
190 }
191 
192 
193 // XTypeProvider methods.
194 
195 
197 
198 
199 // virtual
200 uno::Sequence< uno::Type > SAL_CALL HierarchyContent::getTypes()
201 {
202  if ( isFolder() && !isReadOnly() )
203  {
204  static cppu::OTypeCollection s_aFolderTypes(
205  CPPU_TYPE_REF( lang::XTypeProvider ),
206  CPPU_TYPE_REF( lang::XServiceInfo ),
207  CPPU_TYPE_REF( lang::XComponent ),
208  CPPU_TYPE_REF( ucb::XContent ),
209  CPPU_TYPE_REF( ucb::XCommandProcessor ),
210  CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
211  CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
212  CPPU_TYPE_REF( beans::XPropertyContainer ),
213  CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
214  CPPU_TYPE_REF( container::XChild ),
215  CPPU_TYPE_REF( ucb::XContentCreator ) );
216 
217 
218  return s_aFolderTypes.getTypes();
219  }
220  else
221  {
222  static cppu::OTypeCollection s_aDocumentTypes(
223  CPPU_TYPE_REF( lang::XTypeProvider ),
224  CPPU_TYPE_REF( lang::XServiceInfo ),
225  CPPU_TYPE_REF( lang::XComponent ),
226  CPPU_TYPE_REF( ucb::XContent ),
227  CPPU_TYPE_REF( ucb::XCommandProcessor ),
228  CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
229  CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
230  CPPU_TYPE_REF( beans::XPropertyContainer ),
231  CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
232  CPPU_TYPE_REF( container::XChild ) );
233 
234  return s_aDocumentTypes.getTypes();
235  }
236 }
237 
238 
239 // XServiceInfo methods.
240 
241 
242 // virtual
243 OUString SAL_CALL HierarchyContent::getImplementationName()
244 {
245  return "com.sun.star.comp.ucb.HierarchyContent";
246 }
247 
248 
249 // virtual
250 uno::Sequence< OUString > SAL_CALL
251 HierarchyContent::getSupportedServiceNames()
252 {
253  uno::Sequence< OUString > aSNS( 1 );
254 
255  if ( m_eKind == LINK )
256  aSNS.getArray()[ 0 ] = "com.sun.star.ucb.HierarchyLinkContent";
257  else if ( m_eKind == FOLDER )
258  aSNS.getArray()[ 0 ] = "com.sun.star.ucb.HierarchyFolderContent";
259  else
260  aSNS.getArray()[ 0 ] = "com.sun.star.ucb.HierarchyRootFolderContent";
261 
262  return aSNS;
263 }
264 
265 
266 // XContent methods.
267 
268 
269 // virtual
270 OUString SAL_CALL HierarchyContent::getContentType()
271 {
272  return m_aProps.getContentType();
273 }
274 
275 
276 // virtual
277 uno::Reference< ucb::XContentIdentifier > SAL_CALL
278 HierarchyContent::getIdentifier()
279 {
280  // Transient?
281  if ( m_eState == TRANSIENT )
282  {
283  // Transient contents have no identifier.
284  return uno::Reference< ucb::XContentIdentifier >();
285  }
286 
287  return ContentImplHelper::getIdentifier();
288 }
289 
290 
291 // XCommandProcessor methods.
292 
293 
294 // virtual
295 uno::Any SAL_CALL HierarchyContent::execute(
296  const ucb::Command& aCommand,
297  sal_Int32 /*CommandId*/,
298  const uno::Reference< ucb::XCommandEnvironment >& Environment )
299 {
300  uno::Any aRet;
301 
302  if ( aCommand.Name == "getPropertyValues" )
303  {
304 
305  // getPropertyValues
306 
307 
308  uno::Sequence< beans::Property > Properties;
309  if ( !( aCommand.Argument >>= Properties ) )
310  {
312  uno::makeAny( lang::IllegalArgumentException(
313  "Wrong argument type!",
314  static_cast< cppu::OWeakObject * >( this ),
315  -1 ) ),
316  Environment );
317  // Unreachable
318  }
319 
320  aRet <<= getPropertyValues( Properties );
321  }
322  else if ( aCommand.Name == "setPropertyValues" )
323  {
324 
325  // setPropertyValues
326 
327 
328  uno::Sequence< beans::PropertyValue > aProperties;
329  if ( !( aCommand.Argument >>= aProperties ) )
330  {
332  uno::makeAny( lang::IllegalArgumentException(
333  "Wrong argument type!",
334  static_cast< cppu::OWeakObject * >( this ),
335  -1 ) ),
336  Environment );
337  // Unreachable
338  }
339 
340  if ( !aProperties.hasElements() )
341  {
343  uno::makeAny( lang::IllegalArgumentException(
344  "No properties!",
345  static_cast< cppu::OWeakObject * >( this ),
346  -1 ) ),
347  Environment );
348  // Unreachable
349  }
350 
351  aRet <<= setPropertyValues( aProperties, Environment );
352  }
353  else if ( aCommand.Name == "getPropertySetInfo" )
354  {
355 
356  // getPropertySetInfo
357 
358 
359  aRet <<= getPropertySetInfo( Environment );
360  }
361  else if ( aCommand.Name == "getCommandInfo" )
362  {
363 
364  // getCommandInfo
365 
366 
367  aRet <<= getCommandInfo( Environment );
368  }
369  else if ( aCommand.Name == "open" && isFolder() )
370  {
371 
372  // open command for a folder content
373 
374 
375  ucb::OpenCommandArgument2 aOpenCommand;
376  if ( !( aCommand.Argument >>= aOpenCommand ) )
377  {
379  uno::makeAny( lang::IllegalArgumentException(
380  "Wrong argument type!",
381  static_cast< cppu::OWeakObject * >( this ),
382  -1 ) ),
383  Environment );
384  // Unreachable
385  }
386 
387  uno::Reference< ucb::XDynamicResultSet > xSet
388  = new DynamicResultSet( m_xContext, this, aOpenCommand );
389  aRet <<= xSet;
390  }
391  else if ( aCommand.Name == "insert" && ( m_eKind != ROOT ) && !isReadOnly() )
392  {
393 
394  // insert
395  // ( Not available at root folder )
396 
397 
398  ucb::InsertCommandArgument aArg;
399  if ( !( aCommand.Argument >>= aArg ) )
400  {
402  uno::makeAny( lang::IllegalArgumentException(
403  "Wrong argument type!",
404  static_cast< cppu::OWeakObject * >( this ),
405  -1 ) ),
406  Environment );
407  // Unreachable
408  }
409 
410  sal_Int32 nNameClash = aArg.ReplaceExisting
411  ? ucb::NameClash::OVERWRITE
412  : ucb::NameClash::ERROR;
413  insert( nNameClash, Environment );
414  }
415  else if ( aCommand.Name == "delete" && ( m_eKind != ROOT ) && !isReadOnly() )
416  {
417 
418  // delete
419  // ( Not available at root folder )
420 
421 
422  bool bDeletePhysical = false;
423  aCommand.Argument >>= bDeletePhysical;
424  destroy( bDeletePhysical, Environment );
425 
426  // Remove own and all children's persistent data.
427  if ( !removeData() )
428  {
429  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
430  {
431  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
432  }));
434  ucb::IOErrorCode_CANT_WRITE,
435  aArgs,
436  Environment,
437  "Cannot remove persistent data!",
438  this );
439  // Unreachable
440  }
441 
442  // Remove own and all children's Additional Core Properties.
443  removeAdditionalPropertySet();
444  }
445  else if ( aCommand.Name == "transfer" && isFolder() && !isReadOnly() )
446  {
447 
448  // transfer
449  // ( Not available at link objects )
450 
451 
452  ucb::TransferInfo aInfo;
453  if ( !( aCommand.Argument >>= aInfo ) )
454  {
455  OSL_FAIL( "Wrong argument type!" );
457  uno::makeAny( lang::IllegalArgumentException(
458  "Wrong argument type!",
459  static_cast< cppu::OWeakObject * >( this ),
460  -1 ) ),
461  Environment );
462  // Unreachable
463  }
464 
465  transfer( aInfo, Environment );
466  }
467  else if ( aCommand.Name == "createNewContent" && isFolder() && !isReadOnly() )
468  {
469 
470  // createNewContent
471  // ( Not available at link objects )
472 
473 
474  ucb::ContentInfo aInfo;
475  if ( !( aCommand.Argument >>= aInfo ) )
476  {
477  OSL_FAIL( "Wrong argument type!" );
479  uno::makeAny( lang::IllegalArgumentException(
480  "Wrong argument type!",
481  static_cast< cppu::OWeakObject * >( this ),
482  -1 ) ),
483  Environment );
484  // Unreachable
485  }
486 
487  aRet <<= createNewContent( aInfo );
488  }
489  else
490  {
491 
492  // Unsupported command
493 
494 
496  uno::makeAny( ucb::UnsupportedCommandException(
497  OUString(),
498  static_cast< cppu::OWeakObject * >( this ) ) ),
499  Environment );
500  // Unreachable
501  }
502 
503  return aRet;
504 }
505 
506 
507 // virtual
508 void SAL_CALL HierarchyContent::abort( sal_Int32 /*CommandId*/ )
509 {
510  // @@@ Generally, no action takes much time...
511 }
512 
513 
514 // XContentCreator methods.
515 
516 
517 // virtual
518 uno::Sequence< ucb::ContentInfo > SAL_CALL
519 HierarchyContent::queryCreatableContentsInfo()
520 {
521  return m_aProps.getCreatableContentsInfo();
522 }
523 
524 
525 // virtual
526 uno::Reference< ucb::XContent > SAL_CALL
527 HierarchyContent::createNewContent( const ucb::ContentInfo& Info )
528 {
529  if ( isFolder() )
530  {
531  osl::Guard< osl::Mutex > aGuard( m_aMutex );
532 
533  if ( Info.Type.isEmpty() )
534  return uno::Reference< ucb::XContent >();
535 
536  bool bCreateFolder = Info.Type == HIERARCHY_FOLDER_CONTENT_TYPE;
537 
538  if ( !bCreateFolder && Info.Type != HIERARCHY_LINK_CONTENT_TYPE )
539  return uno::Reference< ucb::XContent >();
540 
541  OUString aURL = m_xIdentifier->getContentIdentifier();
542 
543  OSL_ENSURE( !aURL.isEmpty(),
544  "HierarchyContent::createNewContent - empty identifier!" );
545 
546  if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
547  aURL += "/";
548 
549  if ( bCreateFolder )
550  aURL += "New_Folder";
551  else
552  aURL += "New_Link";
553 
554  uno::Reference< ucb::XContentIdentifier > xId
555  = new ::ucbhelper::ContentIdentifier( aURL );
556 
557  return create( m_xContext, m_pProvider, xId, Info );
558  }
559  else
560  {
561  OSL_FAIL( "createNewContent called on non-folder object!" );
562  return uno::Reference< ucb::XContent >();
563  }
564 }
565 
566 
567 // virtual
568 OUString HierarchyContent::getParentURL()
569 {
570  HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
571  return aUri.getParentUri();
572 }
573 
574 
575 //static
576 bool HierarchyContent::hasData(
577  const uno::Reference< uno::XComponentContext >& rxContext,
578  HierarchyContentProvider* pProvider,
579  const uno::Reference< ucb::XContentIdentifier >& Identifier )
580 {
581  OUString aURL = Identifier->getContentIdentifier();
582 
583  // Am I a root folder?
584  HierarchyUri aUri( aURL );
585  if ( aUri.isRootFolder() )
586  {
587  // hasData must always return 'true' for root folder
588  // even if no persistent data exist!!!
589  return true;
590  }
591 
592  return HierarchyEntry( rxContext, pProvider, aURL ).hasData();
593 }
594 
595 
596 //static
597 bool HierarchyContent::loadData(
598  const uno::Reference< uno::XComponentContext >& rxContext,
599  HierarchyContentProvider* pProvider,
600  const uno::Reference< ucb::XContentIdentifier >& Identifier,
602 {
603  OUString aURL = Identifier->getContentIdentifier();
604 
605  // Am I a root folder?
606  HierarchyUri aUri( aURL );
607  if ( aUri.isRootFolder() )
608  {
610  }
611  else
612  {
613  HierarchyEntry aEntry( rxContext, pProvider, aURL );
615  if ( !aEntry.getData( aData ) )
616  return false;
617 
618  rProps = HierarchyContentProperties( aData );
619  }
620  return true;
621 }
622 
623 
624 bool HierarchyContent::storeData()
625 {
626  HierarchyEntry aEntry(
627  m_xContext, m_pProvider, m_xIdentifier->getContentIdentifier() );
628  return aEntry.setData( m_aProps.getHierarchyEntryData() );
629 }
630 
631 
632 void HierarchyContent::renameData(
633  const uno::Reference< ucb::XContentIdentifier >& xOldId,
634  const uno::Reference< ucb::XContentIdentifier >& xNewId )
635 {
636  HierarchyEntry aEntry(
637  m_xContext, m_pProvider, xOldId->getContentIdentifier() );
638  aEntry.move( xNewId->getContentIdentifier(),
639  m_aProps.getHierarchyEntryData() );
640 }
641 
642 
643 bool HierarchyContent::removeData()
644 {
645  HierarchyEntry aEntry(
646  m_xContext, m_pProvider, m_xIdentifier->getContentIdentifier() );
647  return aEntry.remove();
648 }
649 
650 
651 void HierarchyContent::setKind(
652  const uno::Reference< ucb::XContentIdentifier >& Identifier )
653 {
654  if ( m_aProps.getIsFolder() )
655  {
656  // Am I a root folder?
657  HierarchyUri aUri( Identifier->getContentIdentifier() );
658  if ( aUri.isRootFolder() )
659  m_eKind = ROOT;
660  else
661  m_eKind = FOLDER;
662  }
663  else
664  m_eKind = LINK;
665 }
666 
667 
668 bool HierarchyContent::isReadOnly()
669 {
670  if ( !m_bCheckedReadOnly )
671  {
672  osl::Guard< osl::Mutex > aGuard( m_aMutex );
673  if ( !m_bCheckedReadOnly )
674  {
675  m_bCheckedReadOnly = true;
676  m_bIsReadOnly = true;
677 
678  HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
679  uno::Reference< lang::XMultiServiceFactory > xConfigProv
680  = m_pProvider->getConfigProvider( aUri.getService() );
681  if ( xConfigProv.is() )
682  {
683  uno::Sequence< OUString > aNames
684  = xConfigProv->getAvailableServiceNames();
685  m_bIsReadOnly = comphelper::findValue(aNames, "com.sun.star.ucb.HierarchyDataReadWriteAccess") == -1;
686  }
687  }
688  }
689 
690  return m_bIsReadOnly;
691 }
692 
693 
694 uno::Reference< ucb::XContentIdentifier >
695 HierarchyContent::makeNewIdentifier( const OUString& rTitle )
696 {
697  osl::Guard< osl::Mutex > aGuard( m_aMutex );
698 
699  // Assemble new content identifier...
700  HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
701  OUString aNewURL = aUri.getParentUri() + "/";
702  aNewURL += ::ucb_impl::urihelper::encodeSegment( rTitle );
703 
704  return uno::Reference< ucb::XContentIdentifier >(
705  new ::ucbhelper::ContentIdentifier( aNewURL ) );
706 }
707 
708 
709 void HierarchyContent::queryChildren( HierarchyContentRefVector& rChildren )
710 {
711  if ( ( m_eKind != FOLDER ) && ( m_eKind != ROOT ) )
712  return;
713 
714  // Obtain a list with a snapshot of all currently instantiated contents
715  // from provider and extract the contents which are direct children
716  // of this content.
717 
718  ::ucbhelper::ContentRefList aAllContents;
719  m_xProvider->queryExistingContents( aAllContents );
720 
721  OUString aURL = m_xIdentifier->getContentIdentifier();
722  sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
723 
724  if ( nURLPos != ( aURL.getLength() - 1 ) )
725  {
726  // No trailing slash found. Append.
727  aURL += "/";
728  }
729 
730  sal_Int32 nLen = aURL.getLength();
731 
732  for ( const auto& rContent : aAllContents )
733  {
734  ::ucbhelper::ContentImplHelperRef xChild = rContent;
735  OUString aChildURL
736  = xChild->getIdentifier()->getContentIdentifier();
737 
738  // Is aURL a prefix of aChildURL?
739  if ( ( aChildURL.getLength() > nLen ) &&
740  ( aChildURL.startsWith( aURL ) ) )
741  {
742  sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
743 
744  if ( ( nPos == -1 ) ||
745  ( nPos == ( aChildURL.getLength() - 1 ) ) )
746  {
747  // No further slashes/ only a final slash. It's a child!
748  rChildren.emplace_back(
749  static_cast< HierarchyContent * >( xChild.get() ) );
750  }
751  }
752  }
753 }
754 
755 
756 bool HierarchyContent::exchangeIdentity(
757  const uno::Reference< ucb::XContentIdentifier >& xNewId )
758 {
759  if ( !xNewId.is() )
760  return false;
761 
762  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
763 
764  uno::Reference< ucb::XContent > xThis = this;
765 
766  // Already persistent?
767  if ( m_eState != PERSISTENT )
768  {
769  OSL_FAIL( "HierarchyContent::exchangeIdentity - Not persistent!" );
770  return false;
771  }
772 
773  // Am I the root folder?
774  if ( m_eKind == ROOT )
775  {
776  OSL_FAIL( "HierarchyContent::exchangeIdentity - "
777  "Not supported by root folder!" );
778  return false;
779  }
780 
781  // Exchange own identitity.
782 
783  // Fail, if a content with given id already exists.
784  if ( !hasData( xNewId ) )
785  {
786  OUString aOldURL = m_xIdentifier->getContentIdentifier();
787 
788  aGuard.clear();
789  if ( exchange( xNewId ) )
790  {
791  if ( m_eKind == FOLDER )
792  {
793  // Process instantiated children...
794 
795  HierarchyContentRefVector aChildren;
796  queryChildren( aChildren );
797 
798  for ( const auto& rChild : aChildren )
799  {
800  HierarchyContentRef xChild = rChild;
801 
802  // Create new content identifier for the child...
803  uno::Reference< ucb::XContentIdentifier > xOldChildId
804  = xChild->getIdentifier();
805  OUString aOldChildURL
806  = xOldChildId->getContentIdentifier();
807  OUString aNewChildURL
808  = aOldChildURL.replaceAt(
809  0,
810  aOldURL.getLength(),
811  xNewId->getContentIdentifier() );
812  uno::Reference< ucb::XContentIdentifier > xNewChildId
813  = new ::ucbhelper::ContentIdentifier( aNewChildURL );
814 
815  if ( !xChild->exchangeIdentity( xNewChildId ) )
816  return false;
817  }
818  }
819  return true;
820  }
821  }
822 
823  OSL_FAIL( "HierarchyContent::exchangeIdentity - "
824  "Panic! Cannot exchange identity!" );
825  return false;
826 }
827 
828 
829 // static
830 uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues(
831  const uno::Reference< uno::XComponentContext >& rxContext,
832  const uno::Sequence< beans::Property >& rProperties,
833  const HierarchyContentProperties& rData,
834  HierarchyContentProvider* pProvider,
835  const OUString& rContentId )
836 {
837  // Note: Empty sequence means "get values of all supported properties".
838 
840  = new ::ucbhelper::PropertyValueSet( rxContext );
841 
842  if ( rProperties.hasElements() )
843  {
844  uno::Reference< beans::XPropertySet > xAdditionalPropSet;
845  bool bTriedToGetAdditionalPropSet = false;
846 
847  for ( const beans::Property& rProp : rProperties )
848  {
849  // Process Core properties.
850 
851  if ( rProp.Name == "ContentType" )
852  {
853  xRow->appendString ( rProp, rData.getContentType() );
854  }
855  else if ( rProp.Name == "Title" )
856  {
857  xRow->appendString ( rProp, rData.getTitle() );
858  }
859  else if ( rProp.Name == "IsDocument" )
860  {
861  xRow->appendBoolean( rProp, rData.getIsDocument() );
862  }
863  else if ( rProp.Name == "IsFolder" )
864  {
865  xRow->appendBoolean( rProp, rData.getIsFolder() );
866  }
867  else if ( rProp.Name == "CreatableContentsInfo" )
868  {
869  xRow->appendObject(
870  rProp, uno::makeAny( rData.getCreatableContentsInfo() ) );
871  }
872  else if ( rProp.Name == "TargetURL" )
873  {
874  // TargetURL is only supported by links.
875 
876  if ( rData.getIsDocument() )
877  xRow->appendString( rProp, rData.getTargetURL() );
878  else
879  xRow->appendVoid( rProp );
880  }
881  else
882  {
883  // Not a Core Property! Maybe it's an Additional Core Property?!
884 
885  if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
886  {
887  xAdditionalPropSet =
888  pProvider->getAdditionalPropertySet( rContentId,
889  false );
890  bTriedToGetAdditionalPropSet = true;
891  }
892 
893  if ( xAdditionalPropSet.is() )
894  {
895  if ( !xRow->appendPropertySetValue(
896  xAdditionalPropSet,
897  rProp ) )
898  {
899  // Append empty entry.
900  xRow->appendVoid( rProp );
901  }
902  }
903  else
904  {
905  // Append empty entry.
906  xRow->appendVoid( rProp );
907  }
908  }
909  }
910  }
911  else
912  {
913  // Append all Core Properties.
914  xRow->appendString (
915  beans::Property( "ContentType",
916  -1,
918  beans::PropertyAttribute::BOUND
919  | beans::PropertyAttribute::READONLY ),
920  rData.getContentType() );
921  xRow->appendString (
922  beans::Property( "Title",
923  -1,
925  // @@@ Might actually be read-only!
926  beans::PropertyAttribute::BOUND ),
927  rData.getTitle() );
928  xRow->appendBoolean(
929  beans::Property( "IsDocument",
930  -1,
932  beans::PropertyAttribute::BOUND
933  | beans::PropertyAttribute::READONLY ),
934  rData.getIsDocument() );
935  xRow->appendBoolean(
936  beans::Property( "IsFolder",
937  -1,
939  beans::PropertyAttribute::BOUND
940  | beans::PropertyAttribute::READONLY ),
941  rData.getIsFolder() );
942 
943  if ( rData.getIsDocument() )
944  xRow->appendString(
945  beans::Property( "TargetURL",
946  -1,
948  // @@@ Might actually be read-only!
949  beans::PropertyAttribute::BOUND ),
950  rData.getTargetURL() );
951  xRow->appendObject(
952  beans::Property(
953  "CreatableContentsInfo",
954  -1,
955  cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
956  beans::PropertyAttribute::BOUND
957  | beans::PropertyAttribute::READONLY ),
958  uno::makeAny( rData.getCreatableContentsInfo() ) );
959 
960  // Append all Additional Core Properties.
961 
962  uno::Reference< beans::XPropertySet > xSet =
963  pProvider->getAdditionalPropertySet( rContentId, false );
964  xRow->appendPropertySet( xSet );
965  }
966 
967  return uno::Reference< sdbc::XRow >( xRow.get() );
968 }
969 
970 
971 uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues(
972  const uno::Sequence< beans::Property >& rProperties )
973 {
974  osl::Guard< osl::Mutex > aGuard( m_aMutex );
975  return getPropertyValues( m_xContext,
976  rProperties,
977  m_aProps,
978  m_pProvider,
979  m_xIdentifier->getContentIdentifier() );
980 }
981 
982 
983 uno::Sequence< uno::Any > HierarchyContent::setPropertyValues(
984  const uno::Sequence< beans::PropertyValue >& rValues,
985  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
986 {
987  osl::ResettableGuard< osl::Mutex > aGuard( m_aMutex );
988 
989  uno::Sequence< uno::Any > aRet( rValues.getLength() );
990  uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
991  sal_Int32 nChanged = 0;
992 
993  beans::PropertyChangeEvent aEvent;
994  aEvent.Source = static_cast< cppu::OWeakObject * >( this );
995  aEvent.Further = false;
996 // aEvent.PropertyName =
997  aEvent.PropertyHandle = -1;
998 // aEvent.OldValue =
999 // aEvent.NewValue =
1000 
1001  const beans::PropertyValue* pValues = rValues.getConstArray();
1002  sal_Int32 nCount = rValues.getLength();
1003 
1004  uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1005  bool bTriedToGetAdditionalPropSet = false;
1006 
1007  bool bExchange = false;
1008  OUString aOldTitle;
1009  OUString aOldName;
1010  sal_Int32 nTitlePos = -1;
1011 
1012  for ( sal_Int32 n = 0; n < nCount; ++n )
1013  {
1014  const beans::PropertyValue& rValue = pValues[ n ];
1015 
1016  if ( rValue.Name == "ContentType" )
1017  {
1018  // Read-only property!
1019  aRet[ n ] <<= lang::IllegalAccessException(
1020  "Property is read-only!",
1021  static_cast< cppu::OWeakObject * >( this ) );
1022  }
1023  else if ( rValue.Name == "IsDocument" )
1024  {
1025  // Read-only property!
1026  aRet[ n ] <<= lang::IllegalAccessException(
1027  "Property is read-only!",
1028  static_cast< cppu::OWeakObject * >( this ) );
1029  }
1030  else if ( rValue.Name == "IsFolder" )
1031  {
1032  // Read-only property!
1033  aRet[ n ] <<= lang::IllegalAccessException(
1034  "Property is read-only!",
1035  static_cast< cppu::OWeakObject * >( this ) );
1036  }
1037  else if ( rValue.Name == "CreatableContentsInfo" )
1038  {
1039  // Read-only property!
1040  aRet[ n ] <<= lang::IllegalAccessException(
1041  "Property is read-only!",
1042  static_cast< cppu::OWeakObject * >( this ) );
1043  }
1044  else if ( rValue.Name == "Title" )
1045  {
1046  if ( isReadOnly() )
1047  {
1048  aRet[ n ] <<= lang::IllegalAccessException(
1049  "Property is read-only!",
1050  static_cast< cppu::OWeakObject * >( this ) );
1051  }
1052  else
1053  {
1054  OUString aNewValue;
1055  if ( rValue.Value >>= aNewValue )
1056  {
1057  // No empty titles!
1058  if ( !aNewValue.isEmpty() )
1059  {
1060  if ( aNewValue != m_aProps.getTitle() )
1061  {
1062  // modified title -> modified URL -> exchange !
1063  if ( m_eState == PERSISTENT )
1064  bExchange = true;
1065 
1066  aOldTitle = m_aProps.getTitle();
1067  aOldName = m_aProps.getName();
1068 
1069  m_aProps.setTitle( aNewValue );
1070  m_aProps.setName(
1072  aNewValue ) );
1073 
1074  // property change event will be set later...
1075 
1076  // remember position within sequence of values
1077  // (for error handling).
1078  nTitlePos = n;
1079  }
1080  }
1081  else
1082  {
1083  aRet[ n ] <<= lang::IllegalArgumentException(
1084  "Empty title not allowed!",
1085  static_cast< cppu::OWeakObject * >( this ),
1086  -1 );
1087  }
1088  }
1089  else
1090  {
1091  aRet[ n ] <<= beans::IllegalTypeException(
1092  "Property value has wrong type!",
1093  static_cast< cppu::OWeakObject * >( this ) );
1094  }
1095  }
1096  }
1097  else if ( rValue.Name == "TargetURL" )
1098  {
1099  if ( isReadOnly() )
1100  {
1101  aRet[ n ] <<= lang::IllegalAccessException(
1102  "Property is read-only!",
1103  static_cast< cppu::OWeakObject * >( this ) );
1104  }
1105  else
1106  {
1107  // TargetURL is only supported by links.
1108 
1109  if ( m_eKind == LINK )
1110  {
1111  OUString aNewValue;
1112  if ( rValue.Value >>= aNewValue )
1113  {
1114  // No empty target URL's!
1115  if ( !aNewValue.isEmpty() )
1116  {
1117  if ( aNewValue != m_aProps.getTargetURL() )
1118  {
1119  aEvent.PropertyName = rValue.Name;
1120  aEvent.OldValue <<= m_aProps.getTargetURL();
1121  aEvent.NewValue <<= aNewValue;
1122 
1123  aChanges.getArray()[ nChanged ] = aEvent;
1124 
1125  m_aProps.setTargetURL( aNewValue );
1126  nChanged++;
1127  }
1128  }
1129  else
1130  {
1131  aRet[ n ] <<= lang::IllegalArgumentException(
1132  "Empty target URL not allowed!",
1133  static_cast< cppu::OWeakObject * >( this ),
1134  -1 );
1135  }
1136  }
1137  else
1138  {
1139  aRet[ n ] <<= beans::IllegalTypeException(
1140  "Property value has wrong type!",
1141  static_cast< cppu::OWeakObject * >( this ) );
1142  }
1143  }
1144  else
1145  {
1146  aRet[ n ] <<= beans::UnknownPropertyException(
1147  "TargetURL only supported by links!",
1148  static_cast< cppu::OWeakObject * >( this ) );
1149  }
1150  }
1151  }
1152  else
1153  {
1154  // Not a Core Property! Maybe it's an Additional Core Property?!
1155 
1156  if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1157  {
1158  xAdditionalPropSet = getAdditionalPropertySet( false );
1159  bTriedToGetAdditionalPropSet = true;
1160  }
1161 
1162  if ( xAdditionalPropSet.is() )
1163  {
1164  try
1165  {
1166  uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1167  rValue.Name );
1168  if ( aOldValue != rValue.Value )
1169  {
1170  xAdditionalPropSet->setPropertyValue(
1171  rValue.Name, rValue.Value );
1172 
1173  aEvent.PropertyName = rValue.Name;
1174  aEvent.OldValue = aOldValue;
1175  aEvent.NewValue = rValue.Value;
1176 
1177  aChanges.getArray()[ nChanged ] = aEvent;
1178  nChanged++;
1179  }
1180  }
1181  catch ( beans::UnknownPropertyException const & e )
1182  {
1183  aRet[ n ] <<= e;
1184  }
1185  catch ( lang::WrappedTargetException const & e )
1186  {
1187  aRet[ n ] <<= e;
1188  }
1189  catch ( beans::PropertyVetoException const & e )
1190  {
1191  aRet[ n ] <<= e;
1192  }
1193  catch ( lang::IllegalArgumentException const & e )
1194  {
1195  aRet[ n ] <<= e;
1196  }
1197  }
1198  else
1199  {
1200  aRet[ n ] <<= uno::Exception(
1201  "No property set for storing the value!",
1202  static_cast< cppu::OWeakObject * >( this ) );
1203  }
1204  }
1205  }
1206 
1207  if ( bExchange )
1208  {
1209  uno::Reference< ucb::XContentIdentifier > xOldId
1210  = m_xIdentifier;
1211  uno::Reference< ucb::XContentIdentifier > xNewId
1212  = makeNewIdentifier( m_aProps.getTitle() );
1213 
1214  aGuard.clear();
1215  if ( exchangeIdentity( xNewId ) )
1216  {
1217  // Adapt persistent data.
1218  renameData( xOldId, xNewId );
1219 
1220  // Adapt Additional Core Properties.
1221  renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1222  xNewId->getContentIdentifier() );
1223  }
1224  else
1225  {
1226  // Roll-back.
1227  m_aProps.setTitle( aOldTitle );
1228  m_aProps.setName ( aOldName );
1229 
1230  aOldTitle.clear();
1231  aOldName.clear();
1232 
1233  // Set error .
1234  aRet[ nTitlePos ] <<= uno::Exception(
1235  "Exchange failed!",
1236  static_cast< cppu::OWeakObject * >( this ) );
1237  }
1238  aGuard.reset();
1239  }
1240 
1241  if ( !aOldTitle.isEmpty() )
1242  {
1243  aEvent.PropertyName = "Title";
1244  aEvent.OldValue <<= aOldTitle;
1245  aEvent.NewValue <<= m_aProps.getTitle();
1246 
1247  aChanges.getArray()[ nChanged ] = aEvent;
1248  nChanged++;
1249  }
1250 
1251  if ( nChanged > 0 )
1252  {
1253  // Save changes, if content was already made persistent.
1254  if ( !bExchange && ( m_eState == PERSISTENT ) )
1255  {
1256  if ( !storeData() )
1257  {
1258  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1259  {
1260  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1261  }));
1263  ucb::IOErrorCode_CANT_WRITE,
1264  aArgs,
1265  xEnv,
1266  "Cannot store persistent data!",
1267  this );
1268  // Unreachable
1269  }
1270  }
1271 
1272  aChanges.realloc( nChanged );
1273 
1274  aGuard.clear();
1275  notifyPropertiesChange( aChanges );
1276  }
1277 
1278  return aRet;
1279 }
1280 
1281 
1282 void HierarchyContent::insert( sal_Int32 nNameClashResolve,
1283  const uno::Reference<
1284  ucb::XCommandEnvironment > & xEnv )
1285 {
1286  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1287 
1288  // Am I the root folder?
1289  if ( m_eKind == ROOT )
1290  {
1292  uno::makeAny( ucb::UnsupportedCommandException(
1293  "Not supported by root folder!",
1294  static_cast< cppu::OWeakObject * >( this ) ) ),
1295  xEnv );
1296  // Unreachable
1297  }
1298 
1299  // Check, if all required properties were set.
1300  if ( m_aProps.getTitle().isEmpty() )
1301  {
1302  uno::Sequence<OUString> aProps { "Title" };
1304  uno::makeAny( ucb::MissingPropertiesException(
1305  OUString(),
1306  static_cast< cppu::OWeakObject * >( this ),
1307  aProps ) ),
1308  xEnv );
1309  // Unreachable
1310  }
1311 
1312  // Assemble new content identifier...
1313 
1314  uno::Reference< ucb::XContentIdentifier > xId
1315  = makeNewIdentifier( m_aProps.getTitle() );
1316 
1317  // Handle possible name clash...
1318 
1319  switch ( nNameClashResolve )
1320  {
1321  // fail.
1322  case ucb::NameClash::ERROR:
1323  if ( hasData( xId ) )
1324  {
1326  uno::makeAny(
1327  ucb::NameClashException(
1328  OUString(),
1329  static_cast< cppu::OWeakObject * >( this ),
1330  task::InteractionClassification_ERROR,
1331  m_aProps.getTitle() ) ),
1332  xEnv );
1333  // Unreachable
1334  }
1335  break;
1336 
1337  // replace existing object.
1338  case ucb::NameClash::OVERWRITE:
1339  break;
1340 
1341  // "invent" a new valid title.
1342  case ucb::NameClash::RENAME:
1343  if ( hasData( xId ) )
1344  {
1345  sal_Int32 nTry = 0;
1346 
1347  do
1348  {
1349  OUString aNewId = xId->getContentIdentifier() + "_";
1350  aNewId += OUString::number( ++nTry );
1351  xId = new ::ucbhelper::ContentIdentifier( aNewId );
1352  }
1353  while ( hasData( xId ) && ( nTry < 1000 ) );
1354 
1355  if ( nTry == 1000 )
1356  {
1358  uno::makeAny(
1359  ucb::UnsupportedNameClashException(
1360  "Unable to resolve name clash!",
1361  static_cast< cppu::OWeakObject * >( this ),
1362  nNameClashResolve ) ),
1363  xEnv );
1364  // Unreachable
1365  }
1366  else
1367  {
1368  OUString aNewTitle( m_aProps.getTitle() );
1369  aNewTitle += "_" +
1370  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::makeAny(
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 
1413  m_eState = PERSISTENT;
1414 
1415  if ( bNewId )
1416  {
1417  aGuard.clear();
1418  inserted();
1419  }
1420 }
1421 
1422 
1423 void 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::makeAny( 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::makeAny( 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 
1475 void HierarchyContent::transfer(
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::makeAny( 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::makeAny( 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  {
1706  xSource->destroy( true, xEnv );
1707 
1708  // Remove all persistent data of source and its children.
1709  if ( !xSource->removeData() )
1710  {
1711  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1712  {
1713  {"Uri", uno::Any(xSource->m_xIdentifier->getContentIdentifier())}
1714  }));
1716  ucb::IOErrorCode_CANT_WRITE,
1717  aArgs,
1718  xEnv,
1719  "Cannot remove persistent data of source object!",
1720  this );
1721  // Unreachable
1722  }
1723 
1724  // Remove own and all children's Additional Core Properties.
1725  xSource->removeAdditionalPropertySet();
1726  }
1727 }
1728 
1729 
1730 // HierarchyContentProperties Implementation.
1731 
1732 
1733 uno::Sequence< ucb::ContentInfo >
1734 HierarchyContentProperties::getCreatableContentsInfo() const
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: */
Type
::osl::Mutex m_aMutex
bool hasValue()
std::vector< ContentImplHelperRef > ContentRefList
const char aData[]
sal_Int32 findValue(const css::uno::Sequence< T1 > &_rList, const T2 &_rValue)
std::vector< HierarchyContentRef > HierarchyContentRefVector
#define HIERARCHY_LINK_CONTENT_TYPE
bool setData(const HierarchyEntryData &rData)
OUString encodeSegment(const OUString &rSegment)
Definition: urihelper.hxx:30
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(const OUString &rKey, bool bCreate)
Reference< deployment::XPackageRegistry > create(Reference< deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, Reference< XComponentContext > const &xComponentContext)
XTYPEPROVIDER_COMMON_IMPL(Content)
#define HIERARCHY_FOLDER_CONTENT_TYPE
void cancelCommandExecution(const uno::Any &rException, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
const OUString & getParentUri() const
bool getData(HierarchyEntryData &rData)
DECL_LISTENERMULTIPLEXER_END void SAL_CALL inserted(::sal_Int32 ID) override
Object Value
const OUString & getName() const
bool move(const OUString &rNewURL, const HierarchyEntryData &rData)
#define CPPU_TYPE_REF(T)
css::uno::Sequence< css::ucb::ContentInfo > getCreatableContentsInfo() const
#define HIERARCHY_URL_SCHEME
css::uno::Sequence< css::uno::Type > SAL_CALL getTypes()
sal_Int32 nPos
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
const uno::Reference< uno::XComponentContext > m_xContext