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 rtl::Reference<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 rtl::Reference<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  noexcept
158 {
159  ContentImplHelper::acquire();
160 }
161 
162 
163 // virtual
164 void SAL_CALL HierarchyContent::release()
165  noexcept
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 identity.
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 xRow;
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  auto aRetRange = asNonConstRange(aRet);
991  uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
992  sal_Int32 nChanged = 0;
993 
994  beans::PropertyChangeEvent aEvent;
995  aEvent.Source = static_cast< cppu::OWeakObject * >( this );
996  aEvent.Further = false;
997 // aEvent.PropertyName =
998  aEvent.PropertyHandle = -1;
999 // aEvent.OldValue =
1000 // aEvent.NewValue =
1001 
1002  const beans::PropertyValue* pValues = rValues.getConstArray();
1003  sal_Int32 nCount = rValues.getLength();
1004 
1005  uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1006  bool bTriedToGetAdditionalPropSet = false;
1007 
1008  bool bExchange = false;
1009  OUString aOldTitle;
1010  OUString aOldName;
1011  sal_Int32 nTitlePos = -1;
1012 
1013  for ( sal_Int32 n = 0; n < nCount; ++n )
1014  {
1015  const beans::PropertyValue& rValue = pValues[ n ];
1016 
1017  if ( rValue.Name == "ContentType" )
1018  {
1019  // Read-only property!
1020  aRetRange[ n ] <<= lang::IllegalAccessException(
1021  "Property is read-only!",
1022  static_cast< cppu::OWeakObject * >( this ) );
1023  }
1024  else if ( rValue.Name == "IsDocument" )
1025  {
1026  // Read-only property!
1027  aRetRange[ n ] <<= lang::IllegalAccessException(
1028  "Property is read-only!",
1029  static_cast< cppu::OWeakObject * >( this ) );
1030  }
1031  else if ( rValue.Name == "IsFolder" )
1032  {
1033  // Read-only property!
1034  aRetRange[ n ] <<= lang::IllegalAccessException(
1035  "Property is read-only!",
1036  static_cast< cppu::OWeakObject * >( this ) );
1037  }
1038  else if ( rValue.Name == "CreatableContentsInfo" )
1039  {
1040  // Read-only property!
1041  aRetRange[ n ] <<= lang::IllegalAccessException(
1042  "Property is read-only!",
1043  static_cast< cppu::OWeakObject * >( this ) );
1044  }
1045  else if ( rValue.Name == "Title" )
1046  {
1047  if ( isReadOnly() )
1048  {
1049  aRetRange[ n ] <<= lang::IllegalAccessException(
1050  "Property is read-only!",
1051  static_cast< cppu::OWeakObject * >( this ) );
1052  }
1053  else
1054  {
1055  OUString aNewValue;
1056  if ( rValue.Value >>= aNewValue )
1057  {
1058  // No empty titles!
1059  if ( !aNewValue.isEmpty() )
1060  {
1061  if ( aNewValue != m_aProps.getTitle() )
1062  {
1063  // modified title -> modified URL -> exchange !
1064  if ( m_eState == PERSISTENT )
1065  bExchange = true;
1066 
1067  aOldTitle = m_aProps.getTitle();
1068  aOldName = m_aProps.getName();
1069 
1070  m_aProps.setTitle( aNewValue );
1071  m_aProps.setName(
1073  aNewValue ) );
1074 
1075  // property change event will be set later...
1076 
1077  // remember position within sequence of values
1078  // (for error handling).
1079  nTitlePos = n;
1080  }
1081  }
1082  else
1083  {
1084  aRetRange[ n ] <<= lang::IllegalArgumentException(
1085  "Empty title not allowed!",
1086  static_cast< cppu::OWeakObject * >( this ),
1087  -1 );
1088  }
1089  }
1090  else
1091  {
1092  aRetRange[ n ] <<= beans::IllegalTypeException(
1093  "Property value has wrong type!",
1094  static_cast< cppu::OWeakObject * >( this ) );
1095  }
1096  }
1097  }
1098  else if ( rValue.Name == "TargetURL" )
1099  {
1100  if ( isReadOnly() )
1101  {
1102  aRetRange[ n ] <<= lang::IllegalAccessException(
1103  "Property is read-only!",
1104  static_cast< cppu::OWeakObject * >( this ) );
1105  }
1106  else
1107  {
1108  // TargetURL is only supported by links.
1109 
1110  if ( m_eKind == LINK )
1111  {
1112  OUString aNewValue;
1113  if ( rValue.Value >>= aNewValue )
1114  {
1115  // No empty target URL's!
1116  if ( !aNewValue.isEmpty() )
1117  {
1118  if ( aNewValue != m_aProps.getTargetURL() )
1119  {
1120  aEvent.PropertyName = rValue.Name;
1121  aEvent.OldValue <<= m_aProps.getTargetURL();
1122  aEvent.NewValue <<= aNewValue;
1123 
1124  aChanges.getArray()[ nChanged ] = aEvent;
1125 
1126  m_aProps.setTargetURL( aNewValue );
1127  nChanged++;
1128  }
1129  }
1130  else
1131  {
1132  aRetRange[ n ] <<= lang::IllegalArgumentException(
1133  "Empty target URL not allowed!",
1134  static_cast< cppu::OWeakObject * >( this ),
1135  -1 );
1136  }
1137  }
1138  else
1139  {
1140  aRetRange[ n ] <<= beans::IllegalTypeException(
1141  "Property value has wrong type!",
1142  static_cast< cppu::OWeakObject * >( this ) );
1143  }
1144  }
1145  else
1146  {
1147  aRetRange[ n ] <<= beans::UnknownPropertyException(
1148  "TargetURL only supported by links!",
1149  static_cast< cppu::OWeakObject * >( this ) );
1150  }
1151  }
1152  }
1153  else
1154  {
1155  // Not a Core Property! Maybe it's an Additional Core Property?!
1156 
1157  if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1158  {
1159  xAdditionalPropSet = getAdditionalPropertySet( false );
1160  bTriedToGetAdditionalPropSet = true;
1161  }
1162 
1163  if ( xAdditionalPropSet.is() )
1164  {
1165  try
1166  {
1167  uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1168  rValue.Name );
1169  if ( aOldValue != rValue.Value )
1170  {
1171  xAdditionalPropSet->setPropertyValue(
1172  rValue.Name, rValue.Value );
1173 
1174  aEvent.PropertyName = rValue.Name;
1175  aEvent.OldValue = aOldValue;
1176  aEvent.NewValue = rValue.Value;
1177 
1178  aChanges.getArray()[ nChanged ] = aEvent;
1179  nChanged++;
1180  }
1181  }
1182  catch ( beans::UnknownPropertyException const & e )
1183  {
1184  aRetRange[ n ] <<= e;
1185  }
1186  catch ( lang::WrappedTargetException const & e )
1187  {
1188  aRetRange[ n ] <<= e;
1189  }
1190  catch ( beans::PropertyVetoException const & e )
1191  {
1192  aRetRange[ n ] <<= e;
1193  }
1194  catch ( lang::IllegalArgumentException const & e )
1195  {
1196  aRetRange[ n ] <<= e;
1197  }
1198  }
1199  else
1200  {
1201  aRetRange[ n ] <<= uno::Exception(
1202  "No property set for storing the value!",
1203  static_cast< cppu::OWeakObject * >( this ) );
1204  }
1205  }
1206  }
1207 
1208  if ( bExchange )
1209  {
1210  uno::Reference< ucb::XContentIdentifier > xOldId
1211  = m_xIdentifier;
1212  uno::Reference< ucb::XContentIdentifier > xNewId
1213  = makeNewIdentifier( m_aProps.getTitle() );
1214 
1215  aGuard.clear();
1216  if ( exchangeIdentity( xNewId ) )
1217  {
1218  // Adapt persistent data.
1219  renameData( xOldId, xNewId );
1220 
1221  // Adapt Additional Core Properties.
1222  renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1223  xNewId->getContentIdentifier() );
1224  }
1225  else
1226  {
1227  // Roll-back.
1228  m_aProps.setTitle( aOldTitle );
1229  m_aProps.setName ( aOldName );
1230 
1231  aOldTitle.clear();
1232  aOldName.clear();
1233 
1234  // Set error .
1235  aRetRange[ nTitlePos ] <<= uno::Exception(
1236  "Exchange failed!",
1237  static_cast< cppu::OWeakObject * >( this ) );
1238  }
1239  aGuard.reset();
1240  }
1241 
1242  if ( !aOldTitle.isEmpty() )
1243  {
1244  aEvent.PropertyName = "Title";
1245  aEvent.OldValue <<= aOldTitle;
1246  aEvent.NewValue <<= m_aProps.getTitle();
1247 
1248  aChanges.getArray()[ nChanged ] = aEvent;
1249  nChanged++;
1250  }
1251 
1252  if ( nChanged > 0 )
1253  {
1254  // Save changes, if content was already made persistent.
1255  if ( !bExchange && ( m_eState == PERSISTENT ) )
1256  {
1257  if ( !storeData() )
1258  {
1259  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1260  {
1261  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1262  }));
1264  ucb::IOErrorCode_CANT_WRITE,
1265  aArgs,
1266  xEnv,
1267  "Cannot store persistent data!",
1268  this );
1269  // Unreachable
1270  }
1271  }
1272 
1273  aChanges.realloc( nChanged );
1274 
1275  aGuard.clear();
1276  notifyPropertiesChange( aChanges );
1277  }
1278 
1279  return aRet;
1280 }
1281 
1282 
1283 void HierarchyContent::insert( sal_Int32 nNameClashResolve,
1284  const uno::Reference<
1285  ucb::XCommandEnvironment > & xEnv )
1286 {
1287  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1288 
1289  // Am I the root folder?
1290  if ( m_eKind == ROOT )
1291  {
1293  uno::makeAny( ucb::UnsupportedCommandException(
1294  "Not supported by root folder!",
1295  static_cast< cppu::OWeakObject * >( this ) ) ),
1296  xEnv );
1297  // Unreachable
1298  }
1299 
1300  // Check, if all required properties were set.
1301  if ( m_aProps.getTitle().isEmpty() )
1302  {
1303  uno::Sequence<OUString> aProps { "Title" };
1305  uno::makeAny( ucb::MissingPropertiesException(
1306  OUString(),
1307  static_cast< cppu::OWeakObject * >( this ),
1308  aProps ) ),
1309  xEnv );
1310  // Unreachable
1311  }
1312 
1313  // Assemble new content identifier...
1314 
1315  uno::Reference< ucb::XContentIdentifier > xId
1316  = makeNewIdentifier( m_aProps.getTitle() );
1317 
1318  // Handle possible name clash...
1319 
1320  switch ( nNameClashResolve )
1321  {
1322  // fail.
1323  case ucb::NameClash::ERROR:
1324  if ( hasData( xId ) )
1325  {
1327  uno::makeAny(
1328  ucb::NameClashException(
1329  OUString(),
1330  static_cast< cppu::OWeakObject * >( this ),
1331  task::InteractionClassification_ERROR,
1332  m_aProps.getTitle() ) ),
1333  xEnv );
1334  // Unreachable
1335  }
1336  break;
1337 
1338  // replace existing object.
1339  case ucb::NameClash::OVERWRITE:
1340  break;
1341 
1342  // "invent" a new valid title.
1343  case ucb::NameClash::RENAME:
1344  if ( hasData( xId ) )
1345  {
1346  sal_Int32 nTry = 0;
1347 
1348  do
1349  {
1350  OUString aNewId = xId->getContentIdentifier() + "_";
1351  aNewId += OUString::number( ++nTry );
1352  xId = new ::ucbhelper::ContentIdentifier( aNewId );
1353  }
1354  while ( hasData( xId ) && ( nTry < 1000 ) );
1355 
1356  if ( nTry == 1000 )
1357  {
1359  uno::makeAny(
1360  ucb::UnsupportedNameClashException(
1361  "Unable to resolve name clash!",
1362  static_cast< cppu::OWeakObject * >( this ),
1363  nNameClashResolve ) ),
1364  xEnv );
1365  // Unreachable
1366  }
1367  else
1368  {
1369  OUString aNewTitle( m_aProps.getTitle() + "_" + OUString::number( nTry ) );
1370  m_aProps.setTitle( aNewTitle );
1371  }
1372  }
1373  break;
1374 
1375  case ucb::NameClash::KEEP: // deprecated
1376  case ucb::NameClash::ASK:
1377  default:
1378  if ( hasData( xId ) )
1379  {
1381  uno::makeAny(
1382  ucb::UnsupportedNameClashException(
1383  OUString(),
1384  static_cast< cppu::OWeakObject * >( this ),
1385  nNameClashResolve ) ),
1386  xEnv );
1387  // Unreachable
1388  }
1389  break;
1390  }
1391 
1392  // Identifier changed?
1393  bool bNewId = ( xId->getContentIdentifier()
1394  != m_xIdentifier->getContentIdentifier() );
1395  m_xIdentifier = xId;
1396 
1397  if ( !storeData() )
1398  {
1399  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1400  {
1401  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1402  }));
1404  ucb::IOErrorCode_CANT_WRITE,
1405  aArgs,
1406  xEnv,
1407  "Cannot store persistent data!",
1408  this );
1409  // Unreachable
1410  }
1411 
1412  m_eState = PERSISTENT;
1413 
1414  if ( bNewId )
1415  {
1416  aGuard.clear();
1417  inserted();
1418  }
1419 }
1420 
1421 
1422 void HierarchyContent::destroy( bool bDeletePhysical,
1423  const uno::Reference<
1424  ucb::XCommandEnvironment > & xEnv )
1425 {
1426  // @@@ take care about bDeletePhysical -> trashcan support
1427 
1428  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1429 
1430  uno::Reference< ucb::XContent > xThis = this;
1431 
1432  // Persistent?
1433  if ( m_eState != PERSISTENT )
1434  {
1436  uno::makeAny( ucb::UnsupportedCommandException(
1437  "Not persistent!",
1438  static_cast< cppu::OWeakObject * >( this ) ) ),
1439  xEnv );
1440  // Unreachable
1441  }
1442 
1443  // Am I the root folder?
1444  if ( m_eKind == ROOT )
1445  {
1447  uno::makeAny( ucb::UnsupportedCommandException(
1448  "Not supported by root folder!",
1449  static_cast< cppu::OWeakObject * >( this ) ) ),
1450  xEnv );
1451  // Unreachable
1452  }
1453 
1454  m_eState = DEAD;
1455 
1456  aGuard.clear();
1457  deleted();
1458 
1459  if ( m_eKind == FOLDER )
1460  {
1461  // Process instantiated children...
1462 
1463  HierarchyContentRefVector aChildren;
1464  queryChildren( aChildren );
1465 
1466  for ( auto & child : aChildren)
1467  {
1468  child->destroy( bDeletePhysical, xEnv );
1469  }
1470  }
1471 }
1472 
1473 
1474 void HierarchyContent::transfer(
1475  const ucb::TransferInfo& rInfo,
1476  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1477 {
1478  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1479 
1480  // Persistent?
1481  if ( m_eState != PERSISTENT )
1482  {
1484  uno::makeAny( ucb::UnsupportedCommandException(
1485  "Not persistent!",
1486  static_cast< cppu::OWeakObject * >( this ) ) ),
1487  xEnv );
1488  // Unreachable
1489  }
1490 
1491  // Is source a hierarchy content?
1492  if ( !rInfo.SourceURL.startsWith( HIERARCHY_URL_SCHEME ":/" ) )
1493  {
1495  uno::makeAny( ucb::InteractiveBadTransferURLException(
1496  OUString(),
1497  static_cast< cppu::OWeakObject * >( this ) ) ),
1498  xEnv );
1499  // Unreachable
1500  }
1501 
1502  // Is source not a parent of me / not me?
1503  OUString aId = m_xIdentifier->getContentIdentifier();
1504  sal_Int32 nPos = aId.lastIndexOf( '/' );
1505  if ( nPos != ( aId.getLength() - 1 ) )
1506  {
1507  // No trailing slash found. Append.
1508  aId += "/";
1509  }
1510 
1511  if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1512  {
1513  if ( aId.startsWith( rInfo.SourceURL ) )
1514  {
1515  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1516  {
1517  {"Uri", uno::Any(rInfo.SourceURL)}
1518  }));
1520  ucb::IOErrorCode_RECURSIVE,
1521  aArgs,
1522  xEnv,
1523  "Target is equal to or is a child of source!",
1524  this );
1525  // Unreachable
1526  }
1527  }
1528 
1529 
1530  // 0) Obtain content object for source.
1531 
1532 
1533  uno::Reference< ucb::XContentIdentifier > xId
1534  = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
1535 
1536  // Note: The static cast is okay here, because its sure that
1537  // m_xProvider is always the HierarchyContentProvider.
1539 
1540  try
1541  {
1542  xSource = static_cast< HierarchyContent * >(
1543  m_xProvider->queryContent( xId ).get() );
1544  }
1545  catch ( ucb::IllegalIdentifierException const & )
1546  {
1547  // queryContent
1548  }
1549 
1550  if ( !xSource.is() )
1551  {
1552  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1553  {
1554  {"Uri", uno::Any(xId->getContentIdentifier())}
1555  }));
1557  ucb::IOErrorCode_CANT_READ,
1558  aArgs,
1559  xEnv,
1560  "Cannot instantiate source object!",
1561  this );
1562  // Unreachable
1563  }
1564 
1565 
1566  // 1) Create new child content.
1567 
1568 
1569  OUString aType = xSource->isFolder()
1570  ? OUString( HIERARCHY_FOLDER_CONTENT_TYPE )
1571  : OUString( HIERARCHY_LINK_CONTENT_TYPE );
1572  ucb::ContentInfo aContentInfo;
1573  aContentInfo.Type = aType;
1574  aContentInfo.Attributes = 0;
1575 
1576  // Note: The static cast is okay here, because its sure that
1577  // createNewContent always creates a HierarchyContent.
1579  = static_cast< HierarchyContent * >(
1580  createNewContent( aContentInfo ).get() );
1581  if ( !xTarget.is() )
1582  {
1583  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1584  {
1585  {"Folder", uno::Any(aId)}
1586  }));
1588  ucb::IOErrorCode_CANT_CREATE,
1589  aArgs,
1590  xEnv,
1591  "XContentCreator::createNewContent failed!",
1592  this );
1593  // Unreachable
1594  }
1595 
1596 
1597  // 2) Copy data from source content to child content.
1598 
1599 
1600  uno::Sequence< beans::Property > aSourceProps
1601  = xSource->getPropertySetInfo( xEnv )->getProperties();
1602  sal_Int32 nCount = aSourceProps.getLength();
1603 
1604  if ( nCount )
1605  {
1606  bool bHadTitle = rInfo.NewTitle.isEmpty();
1607 
1608  // Get all source values.
1609  uno::Reference< sdbc::XRow > xRow
1610  = xSource->getPropertyValues( aSourceProps );
1611 
1612  uno::Sequence< beans::PropertyValue > aValues( nCount );
1613  beans::PropertyValue* pValues = aValues.getArray();
1614 
1615  const beans::Property* pProps = aSourceProps.getConstArray();
1616  for ( sal_Int32 n = 0; n < nCount; ++n )
1617  {
1618  const beans::Property& rProp = pProps[ n ];
1619  beans::PropertyValue& rValue = pValues[ n ];
1620 
1621  rValue.Name = rProp.Name;
1622  rValue.Handle = rProp.Handle;
1623 
1624  if ( !bHadTitle && rProp.Name == "Title" )
1625  {
1626  // Set new title instead of original.
1627  bHadTitle = true;
1628  rValue.Value <<= rInfo.NewTitle;
1629  }
1630  else
1631  rValue.Value = xRow->getObject(
1632  n + 1,
1633  uno::Reference< container::XNameAccess >() );
1634 
1635  rValue.State = beans::PropertyState_DIRECT_VALUE;
1636 
1637  if ( rProp.Attributes & beans::PropertyAttribute::REMOVABLE )
1638  {
1639  // Add Additional Core Property.
1640  try
1641  {
1642  xTarget->addProperty( rProp.Name,
1643  rProp.Attributes,
1644  rValue.Value );
1645  }
1646  catch ( beans::PropertyExistException const & )
1647  {
1648  }
1649  catch ( beans::IllegalTypeException const & )
1650  {
1651  }
1652  catch ( lang::IllegalArgumentException const & )
1653  {
1654  }
1655  }
1656  }
1657 
1658  // Set target values.
1659  xTarget->setPropertyValues( aValues, xEnv );
1660  }
1661 
1662 
1663  // 3) Commit (insert) child.
1664 
1665 
1666  xTarget->insert( rInfo.NameClash, xEnv );
1667 
1668 
1669  // 4) Transfer (copy) children of source.
1670 
1671 
1672  if ( xSource->isFolder() )
1673  {
1674  HierarchyEntry aFolder(
1675  m_xContext, m_pProvider, xId->getContentIdentifier() );
1677 
1678  while ( aFolder.next( it ) )
1679  {
1680  const HierarchyEntryData& rResult = *it;
1681 
1682  OUString aChildId = xId->getContentIdentifier();
1683  if ( ( aChildId.lastIndexOf( '/' ) + 1 ) != aChildId.getLength() )
1684  aChildId += "/";
1685 
1686  aChildId += rResult.getName();
1687 
1688  ucb::TransferInfo aInfo;
1689  aInfo.MoveData = false;
1690  aInfo.NewTitle.clear();
1691  aInfo.SourceURL = aChildId;
1692  aInfo.NameClash = rInfo.NameClash;
1693 
1694  // Transfer child to target.
1695  xTarget->transfer( aInfo, xEnv );
1696  }
1697  }
1698 
1699 
1700  // 5) Destroy source ( when moving only ) .
1701 
1702 
1703  if ( !rInfo.MoveData )
1704  return;
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 // HierarchyContentProperties Implementation.
1730 
1731 
1732 uno::Sequence< ucb::ContentInfo >
1733 HierarchyContentProperties::getCreatableContentsInfo() const
1734 {
1735  if ( getIsFolder() )
1736  {
1737  uno::Sequence< ucb::ContentInfo > aSeq( 2 );
1738 
1739  // Folder.
1740  aSeq.getArray()[ 0 ].Type = HIERARCHY_FOLDER_CONTENT_TYPE;
1741  aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
1742 
1743  uno::Sequence< beans::Property > aFolderProps( 1 );
1744  aFolderProps.getArray()[ 0 ] = beans::Property(
1745  "Title",
1746  -1,
1748  beans::PropertyAttribute::BOUND );
1749  aSeq.getArray()[ 0 ].Properties = aFolderProps;
1750 
1751  // Link.
1752  aSeq.getArray()[ 1 ].Type = HIERARCHY_LINK_CONTENT_TYPE;
1753  aSeq.getArray()[ 1 ].Attributes = ucb::ContentInfoAttribute::KIND_LINK;
1754 
1755  uno::Sequence< beans::Property > aLinkProps( 2 );
1756  aLinkProps.getArray()[ 0 ] = beans::Property(
1757  "Title",
1758  -1,
1760  beans::PropertyAttribute::BOUND );
1761  aLinkProps.getArray()[ 1 ] = beans::Property(
1762  "TargetURL",
1763  -1,
1765  beans::PropertyAttribute::BOUND );
1766  aSeq.getArray()[ 1 ].Properties = aLinkProps;
1767 
1768  return aSeq;
1769  }
1770  else
1771  {
1772  return uno::Sequence< ucb::ContentInfo >( 0 );
1773  }
1774 }
1775 
1776 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Type
URL aURL
bool hasValue()
std::vector< ContentImplHelperRef > ContentRefList
Reference< XRow > xRow
uno::Sequence< beans::Property > m_aProps
sal_Int32 findValue(const css::uno::Sequence< T1 > &_rList, const T2 &_rValue)
std::vector< HierarchyContentRef > HierarchyContentRefVector
Reference< XInterface > xTarget
sal_Int64 n
bool setData(const HierarchyEntryData &rData)
OUString encodeSegment(const OUString &rSegment)
Definition: urihelper.hxx:29
PropertiesInfo aProperties
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(const OUString &rKey, bool bCreate)
int nCount
std::mutex m_aMutex
Reference< deployment::XPackageRegistry > create(Reference< deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, Reference< XComponentContext > const &xComponentContext)
XTYPEPROVIDER_COMMON_IMPL(Content)
constexpr OUStringLiteral aData
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
constexpr OUStringLiteral HIERARCHY_FOLDER_CONTENT_TYPE
const OUString & getName() const
const PropertyValue * pValues
constexpr OUStringLiteral HIERARCHY_LINK_CONTENT_TYPE
bool move(const OUString &rNewURL, const HierarchyEntryData &rData)
#define CPPU_TYPE_REF(T)
css::uno::Sequence< css::ucb::ContentInfo > getCreatableContentsInfo() const
Sequence< sal_Int8 > aSeq
css::uno::Sequence< css::uno::Type > SAL_CALL getTypes()
Reference< XComponentContext > m_xContext
constexpr OUStringLiteral HIERARCHY_URL_SCHEME
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
AnyEventRef aEvent
sal_uInt16 nPos
Reference< XContentIdentifier > xId
OUString aId