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 52 : 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 52 : HierarchyContentProperties aProps;
92 52 : if ( !loadData( rxContext, pProvider, Identifier, aProps ) )
93 44 : return 0;
94 :
95 8 : return new HierarchyContent( rxContext, pProvider, Identifier, aProps );
96 : }
97 :
98 :
99 : // static ( "virtual" ctor )
100 28 : 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 28 : if ( Info.Type.isEmpty() )
107 0 : return 0;
108 :
109 28 : if ( Info.Type != HIERARCHY_FOLDER_CONTENT_TYPE && Info.Type != HIERARCHY_LINK_CONTENT_TYPE )
110 0 : return 0;
111 :
112 28 : return new HierarchyContent( rxContext, pProvider, Identifier, Info );
113 : }
114 :
115 :
116 8 : 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 8 : m_bIsReadOnly( true )
127 : {
128 8 : setKind( Identifier );
129 8 : }
130 :
131 :
132 28 : 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 28 : 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 56 : m_bIsReadOnly( true )
143 : {
144 28 : setKind( Identifier );
145 28 : }
146 :
147 :
148 : // virtual
149 72 : HierarchyContent::~HierarchyContent()
150 : {
151 72 : }
152 :
153 :
154 :
155 : // XInterface methods.
156 :
157 :
158 :
159 : // virtual
160 3038 : void SAL_CALL HierarchyContent::acquire()
161 : throw( )
162 : {
163 3038 : ContentImplHelper::acquire();
164 3038 : }
165 :
166 :
167 : // virtual
168 3038 : void SAL_CALL HierarchyContent::release()
169 : throw( )
170 : {
171 3038 : ContentImplHelper::release();
172 3038 : }
173 :
174 :
175 : // virtual
176 544 : uno::Any SAL_CALL HierarchyContent::queryInterface( const uno::Type & rType )
177 : throw ( uno::RuntimeException, std::exception )
178 : {
179 544 : uno::Any aRet = ContentImplHelper::queryInterface( rType );
180 :
181 544 : 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 544 : 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 126 : HierarchyContent::getIdentifier()
329 : throw( uno::RuntimeException, std::exception )
330 : {
331 : // Transient?
332 126 : if ( m_eState == TRANSIENT )
333 : {
334 : // Transient contents have no identifier.
335 0 : return uno::Reference< ucb::XContentIdentifier >();
336 : }
337 :
338 126 : return ContentImplHelper::getIdentifier();
339 : }
340 :
341 :
342 :
343 : // XCommandProcessor methods.
344 :
345 :
346 :
347 : // virtual
348 156 : 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 156 : uno::Any aRet;
357 :
358 156 : 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 156 : else if ( aCommand.Name == "setPropertyValues" )
379 : {
380 :
381 : // setPropertyValues
382 :
383 :
384 60 : uno::Sequence< beans::PropertyValue > aProperties;
385 60 : 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 60 : 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 60 : aRet <<= setPropertyValues( aProperties, Environment );
408 : }
409 96 : else if ( aCommand.Name == "getPropertySetInfo" )
410 : {
411 :
412 : // getPropertySetInfo
413 :
414 :
415 32 : aRet <<= getPropertySetInfo( Environment );
416 : }
417 64 : else if ( aCommand.Name == "getCommandInfo" )
418 : {
419 :
420 : // getCommandInfo
421 :
422 :
423 0 : aRet <<= getCommandInfo( Environment );
424 : }
425 64 : else if ( aCommand.Name == "open" && isFolder() )
426 : {
427 :
428 : // open command for a folder content
429 :
430 :
431 8 : ucb::OpenCommandArgument2 aOpenCommand;
432 8 : 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 16 : = new DynamicResultSet( m_xContext, this, aOpenCommand );
445 16 : aRet <<= xSet;
446 : }
447 56 : else if ( aCommand.Name == "insert" && ( m_eKind != ROOT ) && !isReadOnly() )
448 : {
449 :
450 : // insert
451 : // ( Not available at root folder )
452 :
453 :
454 28 : ucb::InsertCommandArgument aArg;
455 28 : 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 28 : : ucb::NameClash::ERROR;
469 28 : insert( nNameClash, Environment );
470 : }
471 28 : 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 28 : 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 28 : else if ( aCommand.Name == "createNewContent" && isFolder() && !isReadOnly() )
528 : {
529 :
530 : // createNewContent
531 : // ( Not available at link objects )
532 :
533 :
534 28 : ucb::ContentInfo aInfo;
535 28 : 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 28 : 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 156 : 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 28 : HierarchyContent::createNewContent( const ucb::ContentInfo& Info )
592 : throw( uno::RuntimeException, std::exception )
593 : {
594 28 : if ( isFolder() )
595 : {
596 28 : osl::Guard< osl::Mutex > aGuard( m_aMutex );
597 :
598 28 : if ( Info.Type.isEmpty() )
599 0 : return uno::Reference< ucb::XContent >();
600 :
601 28 : bool bCreateFolder = Info.Type == HIERARCHY_FOLDER_CONTENT_TYPE;
602 :
603 28 : if ( !bCreateFolder && Info.Type != HIERARCHY_LINK_CONTENT_TYPE )
604 0 : return uno::Reference< ucb::XContent >();
605 :
606 56 : OUString aURL = m_xIdentifier->getContentIdentifier();
607 :
608 : OSL_ENSURE( !aURL.isEmpty(),
609 : "HierarchyContent::createNewContent - empty identifier!" );
610 :
611 28 : if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
612 26 : aURL += "/";
613 :
614 28 : if ( bCreateFolder )
615 8 : aURL += "New_Folder";
616 : else
617 20 : aURL += "New_Link";
618 :
619 : uno::Reference< ucb::XContentIdentifier > xId
620 56 : = new ::ucbhelper::ContentIdentifier( aURL );
621 :
622 56 : 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 28 : OUString HierarchyContent::getParentURL()
634 : {
635 28 : HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
636 28 : return aUri.getParentUri();
637 : }
638 :
639 :
640 : //static
641 28 : bool HierarchyContent::hasData(
642 : const uno::Reference< uno::XComponentContext >& rxContext,
643 : HierarchyContentProvider* pProvider,
644 : const uno::Reference< ucb::XContentIdentifier >& Identifier )
645 : {
646 28 : OUString aURL = Identifier->getContentIdentifier();
647 :
648 : // Am I a root folder?
649 56 : HierarchyUri aUri( aURL );
650 28 : 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 56 : return HierarchyEntry( rxContext, pProvider, aURL ).hasData();
658 : }
659 :
660 :
661 : //static
662 52 : 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 52 : OUString aURL = Identifier->getContentIdentifier();
669 :
670 : // Am I a root folder?
671 104 : HierarchyUri aUri( aURL );
672 52 : if ( aUri.isRootFolder() )
673 : {
674 4 : rProps = HierarchyContentProperties( HierarchyEntryData::FOLDER );
675 : }
676 : else
677 : {
678 48 : HierarchyEntry aEntry( rxContext, pProvider, aURL );
679 52 : HierarchyEntryData aData;
680 48 : if ( !aEntry.getData( aData ) )
681 44 : return false;
682 :
683 8 : rProps = HierarchyContentProperties( aData );
684 : }
685 60 : return true;
686 : }
687 :
688 :
689 34 : bool HierarchyContent::storeData()
690 : {
691 : HierarchyEntry aEntry(
692 34 : m_xContext, m_pProvider, m_xIdentifier->getContentIdentifier() );
693 34 : 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 36 : void HierarchyContent::setKind(
717 : const uno::Reference< ucb::XContentIdentifier >& Identifier )
718 : {
719 36 : if ( m_aProps.getIsFolder() )
720 : {
721 : // Am I a root folder?
722 16 : HierarchyUri aUri( Identifier->getContentIdentifier() );
723 16 : if ( aUri.isRootFolder() )
724 4 : m_eKind = ROOT;
725 : else
726 12 : m_eKind = FOLDER;
727 : }
728 : else
729 20 : m_eKind = LINK;
730 36 : }
731 :
732 :
733 136 : bool HierarchyContent::isReadOnly()
734 : {
735 136 : if ( !m_bCheckedReadOnly )
736 : {
737 30 : osl::Guard< osl::Mutex > aGuard( m_aMutex );
738 30 : if ( !m_bCheckedReadOnly )
739 : {
740 30 : m_bCheckedReadOnly = true;
741 30 : m_bIsReadOnly = true;
742 :
743 30 : HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
744 : uno::Reference< lang::XMultiServiceFactory > xConfigProv
745 60 : = m_pProvider->getConfigProvider( aUri.getService() );
746 30 : if ( xConfigProv.is() )
747 : {
748 : uno::Sequence< OUString > aNames
749 30 : = xConfigProv->getAvailableServiceNames();
750 30 : sal_Int32 nCount = aNames.getLength();
751 60 : for ( sal_Int32 n = 0; n < nCount; ++n )
752 : {
753 60 : if ( aNames[ n ] == "com.sun.star.ucb.HierarchyDataReadWriteAccess" )
754 : {
755 30 : m_bIsReadOnly = false;
756 30 : break;
757 : }
758 30 : }
759 30 : }
760 30 : }
761 : }
762 :
763 136 : return m_bIsReadOnly;
764 : }
765 :
766 :
767 : uno::Reference< ucb::XContentIdentifier >
768 28 : HierarchyContent::makeNewIdentifier( const OUString& rTitle )
769 : {
770 28 : osl::Guard< osl::Mutex > aGuard( m_aMutex );
771 :
772 : // Assemble new content identifier...
773 56 : HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
774 56 : OUString aNewURL = aUri.getParentUri();
775 28 : aNewURL += "/";
776 28 : aNewURL += ::ucb_impl::urihelper::encodeSegment( rTitle );
777 :
778 : return uno::Reference< ucb::XContentIdentifier >(
779 56 : 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 24 : 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 24 : = new ::ucbhelper::PropertyValueSet( rxContext );
926 :
927 24 : sal_Int32 nCount = rProperties.getLength();
928 24 : if ( nCount )
929 : {
930 24 : uno::Reference< beans::XPropertySet > xAdditionalPropSet;
931 24 : bool bTriedToGetAdditionalPropSet = false;
932 :
933 24 : const beans::Property* pProps = rProperties.getConstArray();
934 68 : for ( sal_Int32 n = 0; n < nCount; ++n )
935 : {
936 44 : const beans::Property& rProp = pProps[ n ];
937 :
938 : // Process Core properties.
939 :
940 44 : if ( rProp.Name == "ContentType" )
941 : {
942 0 : xRow->appendString ( rProp, rData.getContentType() );
943 : }
944 44 : else if ( rProp.Name == "Title" )
945 : {
946 24 : xRow->appendString ( rProp, rData.getTitle() );
947 : }
948 20 : else if ( rProp.Name == "IsDocument" )
949 : {
950 0 : xRow->appendBoolean( rProp, rData.getIsDocument() );
951 : }
952 20 : else if ( rProp.Name == "IsFolder" )
953 : {
954 0 : xRow->appendBoolean( rProp, rData.getIsFolder() );
955 : }
956 20 : else if ( rProp.Name == "CreatableContentsInfo" )
957 : {
958 : xRow->appendObject(
959 0 : rProp, uno::makeAny( rData.getCreatableContentsInfo() ) );
960 : }
961 20 : else if ( rProp.Name == "TargetURL" )
962 : {
963 : // TargetURL is only supported by links.
964 :
965 20 : if ( rData.getIsDocument() )
966 20 : 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 24 : }
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 : getCppuBooleanType(),
1023 : beans::PropertyAttribute::BOUND
1024 : | beans::PropertyAttribute::READONLY ),
1025 0 : rData.getIsDocument() );
1026 : xRow->appendBoolean(
1027 : beans::Property( OUString("IsFolder"),
1028 : -1,
1029 0 : getCppuBooleanType(),
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 : getCppuType( static_cast< const uno::Sequence< ucb::ContentInfo > * >( 0 ) ),
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 24 : 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 60 : 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 60 : osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1081 :
1082 60 : uno::Sequence< uno::Any > aRet( rValues.getLength() );
1083 120 : uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1084 60 : sal_Int32 nChanged = 0;
1085 :
1086 120 : beans::PropertyChangeEvent aEvent;
1087 60 : aEvent.Source = static_cast< cppu::OWeakObject * >( this );
1088 60 : aEvent.Further = sal_False;
1089 : // aEvent.PropertyName =
1090 60 : aEvent.PropertyHandle = -1;
1091 : // aEvent.OldValue =
1092 : // aEvent.NewValue =
1093 :
1094 60 : const beans::PropertyValue* pValues = rValues.getConstArray();
1095 60 : sal_Int32 nCount = rValues.getLength();
1096 :
1097 120 : uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1098 60 : bool bTriedToGetAdditionalPropSet = false;
1099 :
1100 60 : bool bExchange = false;
1101 120 : OUString aOldTitle;
1102 120 : OUString aOldName;
1103 60 : sal_Int32 nTitlePos = -1;
1104 :
1105 168 : for ( sal_Int32 n = 0; n < nCount; ++n )
1106 : {
1107 108 : const beans::PropertyValue& rValue = pValues[ n ];
1108 :
1109 108 : 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 108 : 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 108 : else if ( rValue.Name == "IsFolder" )
1124 : {
1125 : // Read-only property!
1126 56 : aRet[ n ] <<= lang::IllegalAccessException(
1127 : OUString( "Property is read-only!" ),
1128 28 : static_cast< cppu::OWeakObject * >( this ) );
1129 : }
1130 80 : 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 80 : else if ( rValue.Name == "Title" )
1138 : {
1139 28 : 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 28 : OUString aNewValue;
1148 28 : if ( rValue.Value >>= aNewValue )
1149 : {
1150 : // No empty titles!
1151 28 : if ( !aNewValue.isEmpty() )
1152 : {
1153 28 : if ( aNewValue != m_aProps.getTitle() )
1154 : {
1155 : // modified title -> modified URL -> exchange !
1156 28 : if ( m_eState == PERSISTENT )
1157 0 : bExchange = true;
1158 :
1159 28 : aOldTitle = m_aProps.getTitle();
1160 28 : aOldName = m_aProps.getName();
1161 :
1162 28 : m_aProps.setTitle( aNewValue );
1163 : m_aProps.setName(
1164 : ::ucb_impl::urihelper::encodeSegment(
1165 28 : aNewValue ) );
1166 :
1167 : // property change event will be set later...
1168 :
1169 : // remember position within sequence of values
1170 : // (for error handling).
1171 28 : 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 28 : }
1188 : }
1189 : }
1190 52 : else if ( rValue.Name == "TargetURL" )
1191 : {
1192 20 : 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 20 : if ( m_eKind == LINK )
1203 : {
1204 20 : OUString aNewValue;
1205 20 : if ( rValue.Value >>= aNewValue )
1206 : {
1207 : // No empty target URL's!
1208 20 : if ( !aNewValue.isEmpty() )
1209 : {
1210 20 : if ( aNewValue != m_aProps.getTargetURL() )
1211 : {
1212 20 : aEvent.PropertyName = rValue.Name;
1213 : aEvent.OldValue
1214 20 : = uno::makeAny( m_aProps.getTargetURL() );
1215 : aEvent.NewValue
1216 20 : = uno::makeAny( aNewValue );
1217 :
1218 20 : aChanges.getArray()[ nChanged ] = aEvent;
1219 :
1220 20 : m_aProps.setTargetURL( aNewValue );
1221 20 : 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 20 : }
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 32 : if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1252 : {
1253 32 : xAdditionalPropSet = getAdditionalPropertySet( false );
1254 32 : bTriedToGetAdditionalPropSet = true;
1255 : }
1256 :
1257 32 : if ( xAdditionalPropSet.is() )
1258 : {
1259 : try
1260 : {
1261 32 : uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1262 32 : rValue.Name );
1263 32 : if ( aOldValue != rValue.Value )
1264 : {
1265 6 : xAdditionalPropSet->setPropertyValue(
1266 6 : rValue.Name, rValue.Value );
1267 :
1268 6 : aEvent.PropertyName = rValue.Name;
1269 6 : aEvent.OldValue = aOldValue;
1270 6 : aEvent.NewValue = rValue.Value;
1271 :
1272 6 : aChanges.getArray()[ nChanged ] = aEvent;
1273 6 : nChanged++;
1274 32 : }
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 60 : 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 = aOldName = "";
1327 :
1328 : // Set error .
1329 0 : aRet[ nTitlePos ] <<= uno::Exception(
1330 : OUString("Exchange failed!"),
1331 0 : static_cast< cppu::OWeakObject * >( this ) );
1332 0 : }
1333 : }
1334 :
1335 60 : if ( !aOldTitle.isEmpty() )
1336 : {
1337 0 : aEvent.PropertyName = "Title";
1338 0 : aEvent.OldValue = uno::makeAny( aOldTitle );
1339 0 : aEvent.NewValue = uno::makeAny( m_aProps.getTitle() );
1340 :
1341 0 : aChanges.getArray()[ nChanged ] = aEvent;
1342 0 : nChanged++;
1343 : }
1344 :
1345 60 : if ( nChanged > 0 )
1346 : {
1347 : // Save changes, if content was already made persistent.
1348 26 : if ( !bExchange && ( m_eState == PERSISTENT ) )
1349 : {
1350 6 : if ( !storeData() )
1351 : {
1352 : uno::Any aProps
1353 : = uno::makeAny(
1354 : beans::PropertyValue(
1355 : OUString( "Uri"),
1356 : -1,
1357 0 : uno::makeAny(m_xIdentifier->
1358 0 : getContentIdentifier()),
1359 0 : beans::PropertyState_DIRECT_VALUE));
1360 : ucbhelper::cancelCommandExecution(
1361 : ucb::IOErrorCode_CANT_WRITE,
1362 : uno::Sequence< uno::Any >(&aProps, 1),
1363 : xEnv,
1364 : OUString( "Cannot store persistent data!" ),
1365 0 : this );
1366 : // Unreachable
1367 : }
1368 : }
1369 :
1370 26 : aChanges.realloc( nChanged );
1371 :
1372 26 : aGuard.clear();
1373 26 : notifyPropertiesChange( aChanges );
1374 : }
1375 :
1376 120 : return aRet;
1377 : }
1378 :
1379 :
1380 28 : void HierarchyContent::insert( sal_Int32 nNameClashResolve,
1381 : const uno::Reference<
1382 : ucb::XCommandEnvironment > & xEnv )
1383 : throw( uno::Exception )
1384 : {
1385 28 : osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1386 :
1387 : // Am I the root folder?
1388 28 : if ( m_eKind == ROOT )
1389 : {
1390 : ucbhelper::cancelCommandExecution(
1391 : uno::makeAny( ucb::UnsupportedCommandException(
1392 : OUString( "Not supported by root folder!" ),
1393 : static_cast< cppu::OWeakObject * >( this ) ) ),
1394 0 : xEnv );
1395 : // Unreachable
1396 : }
1397 :
1398 : // Check, if all required properties were set.
1399 28 : if ( m_aProps.getTitle().isEmpty() )
1400 : {
1401 0 : uno::Sequence< OUString > aProps( 1 );
1402 0 : aProps[ 0 ] = "Title";
1403 : ucbhelper::cancelCommandExecution(
1404 : uno::makeAny( ucb::MissingPropertiesException(
1405 : OUString(),
1406 : static_cast< cppu::OWeakObject * >( this ),
1407 : aProps ) ),
1408 0 : xEnv );
1409 : // Unreachable
1410 : }
1411 :
1412 : // Assemble new content identifier...
1413 :
1414 : uno::Reference< ucb::XContentIdentifier > xId
1415 56 : = makeNewIdentifier( m_aProps.getTitle() );
1416 :
1417 : // Handle possible name clash...
1418 :
1419 28 : switch ( nNameClashResolve )
1420 : {
1421 : // fail.
1422 : case ucb::NameClash::ERROR:
1423 28 : if ( hasData( xId ) )
1424 : {
1425 : ucbhelper::cancelCommandExecution(
1426 : uno::makeAny(
1427 : ucb::NameClashException(
1428 : OUString(),
1429 : static_cast< cppu::OWeakObject * >( this ),
1430 : task::InteractionClassification_ERROR,
1431 0 : m_aProps.getTitle() ) ),
1432 0 : xEnv );
1433 : // Unreachable
1434 : }
1435 28 : break;
1436 :
1437 : // replace existing object.
1438 : case ucb::NameClash::OVERWRITE:
1439 0 : break;
1440 :
1441 : // "invent" a new valid title.
1442 : case ucb::NameClash::RENAME:
1443 0 : if ( hasData( xId ) )
1444 : {
1445 0 : sal_Int32 nTry = 0;
1446 :
1447 0 : do
1448 : {
1449 0 : OUString aNewId = xId->getContentIdentifier();
1450 0 : aNewId += "_";
1451 0 : aNewId += OUString::number( ++nTry );
1452 0 : xId = new ::ucbhelper::ContentIdentifier( aNewId );
1453 : }
1454 0 : while ( hasData( xId ) && ( nTry < 1000 ) );
1455 :
1456 0 : if ( nTry == 1000 )
1457 : {
1458 : ucbhelper::cancelCommandExecution(
1459 : uno::makeAny(
1460 : ucb::UnsupportedNameClashException(
1461 : OUString( "Unable to resolve name clash!" ),
1462 : static_cast< cppu::OWeakObject * >( this ),
1463 : nNameClashResolve ) ),
1464 0 : xEnv );
1465 : // Unreachable
1466 : }
1467 : else
1468 : {
1469 0 : OUString aNewTitle( m_aProps.getTitle() );
1470 0 : aNewTitle += "_";
1471 0 : aNewTitle += OUString::number( nTry );
1472 0 : m_aProps.setTitle( aNewTitle );
1473 : }
1474 : }
1475 0 : break;
1476 :
1477 : case ucb::NameClash::KEEP: // deprecated
1478 : case ucb::NameClash::ASK:
1479 : default:
1480 0 : if ( hasData( xId ) )
1481 : {
1482 : ucbhelper::cancelCommandExecution(
1483 : uno::makeAny(
1484 : ucb::UnsupportedNameClashException(
1485 : OUString(),
1486 : static_cast< cppu::OWeakObject * >( this ),
1487 : nNameClashResolve ) ),
1488 0 : xEnv );
1489 : // Unreachable
1490 : }
1491 0 : break;
1492 : }
1493 :
1494 : // Identifier changed?
1495 28 : bool bNewId = ( xId->getContentIdentifier()
1496 56 : != m_xIdentifier->getContentIdentifier() );
1497 28 : m_xIdentifier = xId;
1498 :
1499 28 : if ( !storeData() )
1500 : {
1501 : uno::Any aProps
1502 : = uno::makeAny(beans::PropertyValue(
1503 : OUString( "Uri"),
1504 : -1,
1505 0 : uno::makeAny(m_xIdentifier->
1506 0 : getContentIdentifier()),
1507 0 : beans::PropertyState_DIRECT_VALUE));
1508 : ucbhelper::cancelCommandExecution(
1509 : ucb::IOErrorCode_CANT_WRITE,
1510 : uno::Sequence< uno::Any >(&aProps, 1),
1511 : xEnv,
1512 : OUString("Cannot store persistent data!"),
1513 0 : this );
1514 : // Unreachable
1515 : }
1516 :
1517 28 : m_eState = PERSISTENT;
1518 :
1519 28 : if ( bNewId )
1520 : {
1521 28 : aGuard.clear();
1522 28 : inserted();
1523 28 : }
1524 28 : }
1525 :
1526 :
1527 0 : void HierarchyContent::destroy( bool bDeletePhysical,
1528 : const uno::Reference<
1529 : ucb::XCommandEnvironment > & xEnv )
1530 : throw( uno::Exception )
1531 : {
1532 : // @@@ take care about bDeletePhysical -> trashcan support
1533 :
1534 0 : osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1535 :
1536 0 : uno::Reference< ucb::XContent > xThis = this;
1537 :
1538 : // Persistent?
1539 0 : if ( m_eState != PERSISTENT )
1540 : {
1541 : ucbhelper::cancelCommandExecution(
1542 : uno::makeAny( ucb::UnsupportedCommandException(
1543 : OUString( "Not persistent!" ),
1544 : static_cast< cppu::OWeakObject * >( this ) ) ),
1545 0 : xEnv );
1546 : // Unreachable
1547 : }
1548 :
1549 : // Am I the root folder?
1550 0 : if ( m_eKind == ROOT )
1551 : {
1552 : ucbhelper::cancelCommandExecution(
1553 : uno::makeAny( ucb::UnsupportedCommandException(
1554 : OUString( "Not supported by root folder!" ),
1555 : static_cast< cppu::OWeakObject * >( this ) ) ),
1556 0 : xEnv );
1557 : // Unreachable
1558 : }
1559 :
1560 0 : m_eState = DEAD;
1561 :
1562 0 : aGuard.clear();
1563 0 : deleted();
1564 :
1565 0 : if ( m_eKind == FOLDER )
1566 : {
1567 : // Process instantiated children...
1568 :
1569 0 : HierarchyContentRefList aChildren;
1570 0 : queryChildren( aChildren );
1571 :
1572 0 : HierarchyContentRefList::const_iterator it = aChildren.begin();
1573 0 : HierarchyContentRefList::const_iterator end = aChildren.end();
1574 :
1575 0 : while ( it != end )
1576 : {
1577 0 : (*it)->destroy( bDeletePhysical, xEnv );
1578 0 : ++it;
1579 0 : }
1580 0 : }
1581 0 : }
1582 :
1583 :
1584 0 : void HierarchyContent::transfer(
1585 : const ucb::TransferInfo& rInfo,
1586 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1587 : throw( uno::Exception )
1588 : {
1589 0 : osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1590 :
1591 : // Persistent?
1592 0 : if ( m_eState != PERSISTENT )
1593 : {
1594 : ucbhelper::cancelCommandExecution(
1595 : uno::makeAny( ucb::UnsupportedCommandException(
1596 : OUString( "Not persistent!" ),
1597 : static_cast< cppu::OWeakObject * >( this ) ) ),
1598 0 : xEnv );
1599 : // Unreachable
1600 : }
1601 :
1602 : // Is source a hierarchy content?
1603 0 : if ( !rInfo.SourceURL.startsWith( HIERARCHY_URL_SCHEME ":/" ) )
1604 : {
1605 : ucbhelper::cancelCommandExecution(
1606 : uno::makeAny( ucb::InteractiveBadTransferURLException(
1607 : OUString(),
1608 : static_cast< cppu::OWeakObject * >( this ) ) ),
1609 0 : xEnv );
1610 : // Unreachable
1611 : }
1612 :
1613 : // Is source not a parent of me / not me?
1614 0 : OUString aId = m_xIdentifier->getContentIdentifier();
1615 0 : sal_Int32 nPos = aId.lastIndexOf( '/' );
1616 0 : if ( nPos != ( aId.getLength() - 1 ) )
1617 : {
1618 : // No trailing slash found. Append.
1619 0 : aId += "/";
1620 : }
1621 :
1622 0 : if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1623 : {
1624 0 : if ( aId.startsWith( rInfo.SourceURL ) )
1625 : {
1626 : uno::Any aProps
1627 : = uno::makeAny(beans::PropertyValue(
1628 : OUString( "Uri"),
1629 : -1,
1630 : uno::makeAny(rInfo.SourceURL),
1631 0 : beans::PropertyState_DIRECT_VALUE));
1632 : ucbhelper::cancelCommandExecution(
1633 : ucb::IOErrorCode_RECURSIVE,
1634 : uno::Sequence< uno::Any >(&aProps, 1),
1635 : xEnv,
1636 : OUString( "Target is equal to or is a child of source!" ),
1637 0 : this );
1638 : // Unreachable
1639 : }
1640 : }
1641 :
1642 :
1643 : // 0) Obtain content object for source.
1644 :
1645 :
1646 : uno::Reference< ucb::XContentIdentifier > xId
1647 0 : = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
1648 :
1649 : // Note: The static cast is okay here, because its sure that
1650 : // m_xProvider is always the HierarchyContentProvider.
1651 0 : rtl::Reference< HierarchyContent > xSource;
1652 :
1653 : try
1654 : {
1655 0 : xSource = static_cast< HierarchyContent * >(
1656 0 : m_xProvider->queryContent( xId ).get() );
1657 : }
1658 0 : catch ( ucb::IllegalIdentifierException const & )
1659 : {
1660 : // queryContent
1661 : }
1662 :
1663 0 : if ( !xSource.is() )
1664 : {
1665 : uno::Any aProps
1666 : = uno::makeAny(beans::PropertyValue(
1667 : OUString( "Uri"),
1668 : -1,
1669 0 : uno::makeAny(xId->getContentIdentifier()),
1670 0 : beans::PropertyState_DIRECT_VALUE));
1671 : ucbhelper::cancelCommandExecution(
1672 : ucb::IOErrorCode_CANT_READ,
1673 : uno::Sequence< uno::Any >(&aProps, 1),
1674 : xEnv,
1675 : OUString( "Cannot instanciate source object!" ),
1676 0 : this );
1677 : // Unreachable
1678 : }
1679 :
1680 :
1681 : // 1) Create new child content.
1682 :
1683 :
1684 0 : OUString aType = xSource->isFolder()
1685 : ? OUString( HIERARCHY_FOLDER_CONTENT_TYPE )
1686 0 : : OUString( HIERARCHY_LINK_CONTENT_TYPE );
1687 0 : ucb::ContentInfo aContentInfo;
1688 0 : aContentInfo.Type = aType;
1689 0 : aContentInfo.Attributes = 0;
1690 :
1691 : // Note: The static cast is okay here, because its sure that
1692 : // createNewContent always creates a HierarchyContent.
1693 : rtl::Reference< HierarchyContent > xTarget
1694 : = static_cast< HierarchyContent * >(
1695 0 : createNewContent( aContentInfo ).get() );
1696 0 : if ( !xTarget.is() )
1697 : {
1698 : uno::Any aProps
1699 : = uno::makeAny(beans::PropertyValue(
1700 : OUString( "Folder"),
1701 : -1,
1702 : uno::makeAny(aId),
1703 0 : beans::PropertyState_DIRECT_VALUE));
1704 : ucbhelper::cancelCommandExecution(
1705 : ucb::IOErrorCode_CANT_CREATE,
1706 : uno::Sequence< uno::Any >(&aProps, 1),
1707 : xEnv,
1708 : OUString( "XContentCreator::createNewContent failed!" ),
1709 0 : this );
1710 : // Unreachable
1711 : }
1712 :
1713 :
1714 : // 2) Copy data from source content to child content.
1715 :
1716 :
1717 : uno::Sequence< beans::Property > aSourceProps
1718 0 : = xSource->getPropertySetInfo( xEnv )->getProperties();
1719 0 : sal_Int32 nCount = aSourceProps.getLength();
1720 :
1721 0 : if ( nCount )
1722 : {
1723 0 : bool bHadTitle = rInfo.NewTitle.isEmpty();
1724 :
1725 : // Get all source values.
1726 : uno::Reference< sdbc::XRow > xRow
1727 0 : = xSource->getPropertyValues( aSourceProps );
1728 :
1729 0 : uno::Sequence< beans::PropertyValue > aValues( nCount );
1730 0 : beans::PropertyValue* pValues = aValues.getArray();
1731 :
1732 0 : const beans::Property* pProps = aSourceProps.getConstArray();
1733 0 : for ( sal_Int32 n = 0; n < nCount; ++n )
1734 : {
1735 0 : const beans::Property& rProp = pProps[ n ];
1736 0 : beans::PropertyValue& rValue = pValues[ n ];
1737 :
1738 0 : rValue.Name = rProp.Name;
1739 0 : rValue.Handle = rProp.Handle;
1740 :
1741 0 : if ( !bHadTitle && rProp.Name == "Title" )
1742 : {
1743 : // Set new title instead of original.
1744 0 : bHadTitle = true;
1745 0 : rValue.Value <<= rInfo.NewTitle;
1746 : }
1747 : else
1748 0 : rValue.Value = xRow->getObject(
1749 : n + 1,
1750 0 : uno::Reference< container::XNameAccess >() );
1751 :
1752 0 : rValue.State = beans::PropertyState_DIRECT_VALUE;
1753 :
1754 0 : if ( rProp.Attributes & beans::PropertyAttribute::REMOVABLE )
1755 : {
1756 : // Add Additional Core Property.
1757 : try
1758 : {
1759 0 : xTarget->addProperty( rProp.Name,
1760 : rProp.Attributes,
1761 0 : rValue.Value );
1762 : }
1763 0 : catch ( beans::PropertyExistException const & )
1764 : {
1765 : }
1766 0 : catch ( beans::IllegalTypeException const & )
1767 : {
1768 : }
1769 0 : catch ( lang::IllegalArgumentException const & )
1770 : {
1771 : }
1772 : }
1773 : }
1774 :
1775 : // Set target values.
1776 0 : xTarget->setPropertyValues( aValues, xEnv );
1777 : }
1778 :
1779 :
1780 : // 3) Commit (insert) child.
1781 :
1782 :
1783 0 : xTarget->insert( rInfo.NameClash, xEnv );
1784 :
1785 :
1786 : // 4) Transfer (copy) children of source.
1787 :
1788 :
1789 0 : if ( xSource->isFolder() )
1790 : {
1791 : HierarchyEntry aFolder(
1792 0 : m_xContext, m_pProvider, xId->getContentIdentifier() );
1793 0 : HierarchyEntry::iterator it;
1794 :
1795 0 : while ( aFolder.next( it ) )
1796 : {
1797 0 : const HierarchyEntryData& rResult = *it;
1798 :
1799 0 : OUString aChildId = xId->getContentIdentifier();
1800 0 : if ( ( aChildId.lastIndexOf( '/' ) + 1 ) != aChildId.getLength() )
1801 0 : aChildId += "/";
1802 :
1803 0 : aChildId += rResult.getName();
1804 :
1805 0 : ucb::TransferInfo aInfo;
1806 0 : aInfo.MoveData = sal_False;
1807 0 : aInfo.NewTitle = "";
1808 0 : aInfo.SourceURL = aChildId;
1809 0 : aInfo.NameClash = rInfo.NameClash;
1810 :
1811 : // Transfer child to target.
1812 0 : xTarget->transfer( aInfo, xEnv );
1813 0 : }
1814 : }
1815 :
1816 :
1817 : // 5) Destroy source ( when moving only ) .
1818 :
1819 :
1820 0 : if ( rInfo.MoveData )
1821 : {
1822 0 : xSource->destroy( true, xEnv );
1823 :
1824 : // Remove all persistent data of source and its children.
1825 0 : if ( !xSource->removeData() )
1826 : {
1827 : uno::Any aProps
1828 : = uno::makeAny(
1829 : beans::PropertyValue(
1830 : OUString( "Uri"),
1831 : -1,
1832 : uno::makeAny(
1833 0 : xSource->m_xIdentifier->
1834 0 : getContentIdentifier()),
1835 0 : beans::PropertyState_DIRECT_VALUE));
1836 : ucbhelper::cancelCommandExecution(
1837 : ucb::IOErrorCode_CANT_WRITE,
1838 : uno::Sequence< uno::Any >(&aProps, 1),
1839 : xEnv,
1840 : OUString( "Cannot remove persistent data of source object!" ),
1841 0 : this );
1842 : // Unreachable
1843 : }
1844 :
1845 : // Remove own and all children's Additional Core Properties.
1846 0 : xSource->removeAdditionalPropertySet( true );
1847 0 : }
1848 0 : }
1849 :
1850 :
1851 :
1852 :
1853 : // HierarchyContentProperties Implementation.
1854 :
1855 :
1856 :
1857 :
1858 : uno::Sequence< ucb::ContentInfo >
1859 0 : HierarchyContentProperties::getCreatableContentsInfo() const
1860 : {
1861 0 : if ( getIsFolder() )
1862 : {
1863 0 : uno::Sequence< ucb::ContentInfo > aSeq( 2 );
1864 :
1865 : // Folder.
1866 0 : aSeq.getArray()[ 0 ].Type = HIERARCHY_FOLDER_CONTENT_TYPE;
1867 0 : aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
1868 :
1869 0 : uno::Sequence< beans::Property > aFolderProps( 1 );
1870 0 : aFolderProps.getArray()[ 0 ] = beans::Property(
1871 : OUString("Title"),
1872 : -1,
1873 0 : cppu::UnoType<OUString>::get(),
1874 0 : beans::PropertyAttribute::BOUND );
1875 0 : aSeq.getArray()[ 0 ].Properties = aFolderProps;
1876 :
1877 : // Link.
1878 0 : aSeq.getArray()[ 1 ].Type = HIERARCHY_LINK_CONTENT_TYPE;
1879 0 : aSeq.getArray()[ 1 ].Attributes = ucb::ContentInfoAttribute::KIND_LINK;
1880 :
1881 0 : uno::Sequence< beans::Property > aLinkProps( 2 );
1882 0 : aLinkProps.getArray()[ 0 ] = beans::Property(
1883 : OUString("Title"),
1884 : -1,
1885 0 : cppu::UnoType<OUString>::get(),
1886 0 : beans::PropertyAttribute::BOUND );
1887 0 : aLinkProps.getArray()[ 1 ] = beans::Property(
1888 : OUString("TargetURL"),
1889 : -1,
1890 0 : cppu::UnoType<OUString>::get(),
1891 0 : beans::PropertyAttribute::BOUND );
1892 0 : aSeq.getArray()[ 1 ].Properties = aLinkProps;
1893 :
1894 0 : return aSeq;
1895 : }
1896 : else
1897 : {
1898 0 : return uno::Sequence< ucb::ContentInfo >( 0 );
1899 : }
1900 : }
1901 :
1902 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|