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