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