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