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