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 0 : 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 0 : HierarchyContentProperties aProps;
92 0 : if ( !loadData( rxContext, pProvider, Identifier, aProps ) )
93 0 : return 0;
94 :
95 0 : 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 0 : 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 0 : m_bIsReadOnly( true )
127 : {
128 0 : setKind( Identifier );
129 0 : }
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 0 : HierarchyContent::~HierarchyContent()
150 : {
151 0 : }
152 :
153 :
154 :
155 : // XInterface methods.
156 :
157 :
158 :
159 : // virtual
160 0 : void SAL_CALL HierarchyContent::acquire()
161 : throw( )
162 : {
163 0 : ContentImplHelper::acquire();
164 0 : }
165 :
166 :
167 : // virtual
168 0 : void SAL_CALL HierarchyContent::release()
169 : throw( )
170 : {
171 0 : ContentImplHelper::release();
172 0 : }
173 :
174 :
175 : // virtual
176 0 : uno::Any SAL_CALL HierarchyContent::queryInterface( const uno::Type & rType )
177 : throw ( uno::RuntimeException, std::exception )
178 : {
179 0 : uno::Any aRet = ContentImplHelper::queryInterface( rType );
180 :
181 0 : 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 0 : 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 0 : HierarchyContent::getIdentifier()
329 : throw( uno::RuntimeException, std::exception )
330 : {
331 : // Transient?
332 0 : if ( m_eState == TRANSIENT )
333 : {
334 : // Transient contents have no identifier.
335 0 : return uno::Reference< ucb::XContentIdentifier >();
336 : }
337 :
338 0 : 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 : sal_Bool bDeletePhysical = sal_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 : sal_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 : sal_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 sal_True;
655 : }
656 :
657 0 : return HierarchyEntry( rxContext, pProvider, aURL ).hasData();
658 : }
659 :
660 :
661 : //static
662 0 : sal_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 0 : OUString aURL = Identifier->getContentIdentifier();
669 :
670 : // Am I a root folder?
671 0 : HierarchyUri aUri( aURL );
672 0 : if ( aUri.isRootFolder() )
673 : {
674 0 : 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 sal_False;
682 :
683 0 : rProps = HierarchyContentProperties( aData );
684 : }
685 0 : return sal_True;
686 : }
687 :
688 :
689 0 : sal_Bool HierarchyContent::storeData()
690 : {
691 : HierarchyEntry aEntry(
692 0 : m_xContext, m_pProvider, m_xIdentifier->getContentIdentifier() );
693 0 : return aEntry.setData( m_aProps.getHierarchyEntryData(), sal_True );
694 : }
695 :
696 :
697 0 : sal_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 : sal_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 0 : void HierarchyContent::setKind(
717 : const uno::Reference< ucb::XContentIdentifier >& Identifier )
718 : {
719 0 : if ( m_aProps.getIsFolder() )
720 : {
721 : // Am I a root folder?
722 0 : HierarchyUri aUri( Identifier->getContentIdentifier() );
723 0 : if ( aUri.isRootFolder() )
724 0 : m_eKind = ROOT;
725 : else
726 0 : m_eKind = FOLDER;
727 : }
728 : else
729 0 : m_eKind = LINK;
730 0 : }
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 instanciated 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.compareTo( aURL, nLen ) == 0 ) )
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 : sal_Bool HierarchyContent::exchangeIdentity(
837 : const uno::Reference< ucb::XContentIdentifier >& xNewId )
838 : {
839 0 : if ( !xNewId.is() )
840 0 : return sal_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 sal_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 sal_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 instanciated 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 sal_False;
900 :
901 0 : ++it;
902 0 : }
903 : }
904 0 : return sal_True;
905 0 : }
906 : }
907 :
908 : OSL_FAIL( "HierarchyContent::exchangeIdentity - "
909 : "Panic! Cannot exchange identity!" );
910 0 : return sal_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 : sal_Bool bTriedToGetAdditionalPropSet = sal_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 = sal_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 : getCppuType( static_cast< const OUString * >( 0 ) ),
1009 : beans::PropertyAttribute::BOUND
1010 : | beans::PropertyAttribute::READONLY ),
1011 0 : rData.getContentType() );
1012 : xRow->appendString (
1013 : beans::Property( OUString("Title"),
1014 : -1,
1015 0 : getCppuType( static_cast< const OUString * >( 0 ) ),
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 : getCppuType(
1039 0 : static_cast< const OUString * >( 0 ) ),
1040 : // @@@ Might actually be read-only!
1041 : beans::PropertyAttribute::BOUND ),
1042 0 : rData.getTargetURL() );
1043 : xRow->appendObject(
1044 : beans::Property(
1045 : OUString("CreatableContentsInfo"),
1046 : -1,
1047 : getCppuType( static_cast<
1048 0 : const uno::Sequence< ucb::ContentInfo > * >( 0 ) ),
1049 : beans::PropertyAttribute::BOUND
1050 : | beans::PropertyAttribute::READONLY ),
1051 0 : uno::makeAny( rData.getCreatableContentsInfo() ) );
1052 :
1053 : // Append all Additional Core Properties.
1054 :
1055 : uno::Reference< beans::XPropertySet > xSet(
1056 : pProvider->getAdditionalPropertySet( rContentId, false ),
1057 0 : uno::UNO_QUERY );
1058 0 : xRow->appendPropertySet( xSet );
1059 : }
1060 :
1061 0 : return uno::Reference< sdbc::XRow >( xRow.get() );
1062 : }
1063 :
1064 :
1065 0 : uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues(
1066 : const uno::Sequence< beans::Property >& rProperties )
1067 : {
1068 0 : osl::Guard< osl::Mutex > aGuard( m_aMutex );
1069 : return getPropertyValues( m_xContext,
1070 : rProperties,
1071 : m_aProps,
1072 : m_pProvider,
1073 0 : m_xIdentifier->getContentIdentifier() );
1074 : }
1075 :
1076 :
1077 0 : uno::Sequence< uno::Any > HierarchyContent::setPropertyValues(
1078 : const uno::Sequence< beans::PropertyValue >& rValues,
1079 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1080 : throw( uno::Exception )
1081 : {
1082 0 : osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1083 :
1084 0 : uno::Sequence< uno::Any > aRet( rValues.getLength() );
1085 0 : uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1086 0 : sal_Int32 nChanged = 0;
1087 :
1088 0 : beans::PropertyChangeEvent aEvent;
1089 0 : aEvent.Source = static_cast< cppu::OWeakObject * >( this );
1090 0 : aEvent.Further = sal_False;
1091 : // aEvent.PropertyName =
1092 0 : aEvent.PropertyHandle = -1;
1093 : // aEvent.OldValue =
1094 : // aEvent.NewValue =
1095 :
1096 0 : const beans::PropertyValue* pValues = rValues.getConstArray();
1097 0 : sal_Int32 nCount = rValues.getLength();
1098 :
1099 0 : uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1100 0 : sal_Bool bTriedToGetAdditionalPropSet = sal_False;
1101 :
1102 0 : sal_Bool bExchange = sal_False;
1103 0 : OUString aOldTitle;
1104 0 : OUString aOldName;
1105 0 : sal_Int32 nTitlePos = -1;
1106 :
1107 0 : for ( sal_Int32 n = 0; n < nCount; ++n )
1108 : {
1109 0 : const beans::PropertyValue& rValue = pValues[ n ];
1110 :
1111 0 : if ( rValue.Name == "ContentType" )
1112 : {
1113 : // Read-only property!
1114 0 : aRet[ n ] <<= lang::IllegalAccessException(
1115 : OUString( "Property is read-only!" ),
1116 0 : static_cast< cppu::OWeakObject * >( this ) );
1117 : }
1118 0 : else if ( rValue.Name == "IsDocument" )
1119 : {
1120 : // Read-only property!
1121 0 : aRet[ n ] <<= lang::IllegalAccessException(
1122 : OUString( "Property is read-only!" ),
1123 0 : static_cast< cppu::OWeakObject * >( this ) );
1124 : }
1125 0 : else if ( rValue.Name == "IsFolder" )
1126 : {
1127 : // Read-only property!
1128 0 : aRet[ n ] <<= lang::IllegalAccessException(
1129 : OUString( "Property is read-only!" ),
1130 0 : static_cast< cppu::OWeakObject * >( this ) );
1131 : }
1132 0 : else if ( rValue.Name == "CreatableContentsInfo" )
1133 : {
1134 : // Read-only property!
1135 0 : aRet[ n ] <<= lang::IllegalAccessException(
1136 : OUString( "Property is read-only!" ),
1137 0 : static_cast< cppu::OWeakObject * >( this ) );
1138 : }
1139 0 : else if ( rValue.Name == "Title" )
1140 : {
1141 0 : if ( isReadOnly() )
1142 : {
1143 0 : aRet[ n ] <<= lang::IllegalAccessException(
1144 : OUString( "Property is read-only!" ),
1145 0 : static_cast< cppu::OWeakObject * >( this ) );
1146 : }
1147 : else
1148 : {
1149 0 : OUString aNewValue;
1150 0 : if ( rValue.Value >>= aNewValue )
1151 : {
1152 : // No empty titles!
1153 0 : if ( !aNewValue.isEmpty() )
1154 : {
1155 0 : if ( aNewValue != m_aProps.getTitle() )
1156 : {
1157 : // modified title -> modified URL -> exchange !
1158 0 : if ( m_eState == PERSISTENT )
1159 0 : bExchange = sal_True;
1160 :
1161 0 : aOldTitle = m_aProps.getTitle();
1162 0 : aOldName = m_aProps.getName();
1163 :
1164 0 : m_aProps.setTitle( aNewValue );
1165 : m_aProps.setName(
1166 : ::ucb_impl::urihelper::encodeSegment(
1167 0 : aNewValue ) );
1168 :
1169 : // property change event will be set later...
1170 :
1171 : // remember position within sequence of values
1172 : // (for error handling).
1173 0 : nTitlePos = n;
1174 : }
1175 : }
1176 : else
1177 : {
1178 0 : aRet[ n ] <<= lang::IllegalArgumentException(
1179 : OUString( "Empty title not allowed!" ),
1180 : static_cast< cppu::OWeakObject * >( this ),
1181 0 : -1 );
1182 : }
1183 : }
1184 : else
1185 : {
1186 0 : aRet[ n ] <<= beans::IllegalTypeException(
1187 : OUString( "Property value has wrong type!" ),
1188 0 : static_cast< cppu::OWeakObject * >( this ) );
1189 0 : }
1190 : }
1191 : }
1192 0 : else if ( rValue.Name == "TargetURL" )
1193 : {
1194 0 : if ( isReadOnly() )
1195 : {
1196 0 : aRet[ n ] <<= lang::IllegalAccessException(
1197 : OUString( "Property is read-only!" ),
1198 0 : static_cast< cppu::OWeakObject * >( this ) );
1199 : }
1200 : else
1201 : {
1202 : // TargetURL is only supported by links.
1203 :
1204 0 : if ( m_eKind == LINK )
1205 : {
1206 0 : OUString aNewValue;
1207 0 : if ( rValue.Value >>= aNewValue )
1208 : {
1209 : // No empty target URL's!
1210 0 : if ( !aNewValue.isEmpty() )
1211 : {
1212 0 : if ( aNewValue != m_aProps.getTargetURL() )
1213 : {
1214 0 : aEvent.PropertyName = rValue.Name;
1215 : aEvent.OldValue
1216 0 : = uno::makeAny( m_aProps.getTargetURL() );
1217 : aEvent.NewValue
1218 0 : = uno::makeAny( aNewValue );
1219 :
1220 0 : aChanges.getArray()[ nChanged ] = aEvent;
1221 :
1222 0 : m_aProps.setTargetURL( aNewValue );
1223 0 : nChanged++;
1224 : }
1225 : }
1226 : else
1227 : {
1228 0 : aRet[ n ] <<= lang::IllegalArgumentException(
1229 : OUString( "Empty target URL not allowed!" ),
1230 : static_cast< cppu::OWeakObject * >( this ),
1231 0 : -1 );
1232 : }
1233 : }
1234 : else
1235 : {
1236 0 : aRet[ n ] <<= beans::IllegalTypeException(
1237 : OUString( "Property value has wrong type!" ),
1238 0 : static_cast< cppu::OWeakObject * >( this ) );
1239 0 : }
1240 : }
1241 : else
1242 : {
1243 0 : aRet[ n ] <<= beans::UnknownPropertyException(
1244 : OUString( "TargetURL only supported by links!" ),
1245 0 : static_cast< cppu::OWeakObject * >( this ) );
1246 : }
1247 : }
1248 : }
1249 : else
1250 : {
1251 : // Not a Core Property! Maybe it's an Additional Core Property?!
1252 :
1253 0 : if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1254 : {
1255 0 : xAdditionalPropSet = getAdditionalPropertySet( false );
1256 0 : bTriedToGetAdditionalPropSet = sal_True;
1257 : }
1258 :
1259 0 : if ( xAdditionalPropSet.is() )
1260 : {
1261 : try
1262 : {
1263 0 : uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1264 0 : rValue.Name );
1265 0 : if ( aOldValue != rValue.Value )
1266 : {
1267 0 : xAdditionalPropSet->setPropertyValue(
1268 0 : rValue.Name, rValue.Value );
1269 :
1270 0 : aEvent.PropertyName = rValue.Name;
1271 0 : aEvent.OldValue = aOldValue;
1272 0 : aEvent.NewValue = rValue.Value;
1273 :
1274 0 : aChanges.getArray()[ nChanged ] = aEvent;
1275 0 : nChanged++;
1276 0 : }
1277 : }
1278 0 : catch ( beans::UnknownPropertyException const & e )
1279 : {
1280 0 : aRet[ n ] <<= e;
1281 : }
1282 0 : catch ( lang::WrappedTargetException const & e )
1283 : {
1284 0 : aRet[ n ] <<= e;
1285 : }
1286 0 : catch ( beans::PropertyVetoException const & e )
1287 : {
1288 0 : aRet[ n ] <<= e;
1289 : }
1290 0 : catch ( lang::IllegalArgumentException const & e )
1291 : {
1292 0 : aRet[ n ] <<= e;
1293 : }
1294 : }
1295 : else
1296 : {
1297 0 : aRet[ n ] <<= uno::Exception(
1298 : OUString( "No property set for storing the value!" ),
1299 0 : static_cast< cppu::OWeakObject * >( this ) );
1300 : }
1301 : }
1302 : }
1303 :
1304 0 : if ( bExchange )
1305 : {
1306 : uno::Reference< ucb::XContentIdentifier > xOldId
1307 0 : = m_xIdentifier;
1308 : uno::Reference< ucb::XContentIdentifier > xNewId
1309 0 : = makeNewIdentifier( m_aProps.getTitle() );
1310 :
1311 0 : aGuard.clear();
1312 0 : if ( exchangeIdentity( xNewId ) )
1313 : {
1314 : // Adapt persistent data.
1315 0 : renameData( xOldId, xNewId );
1316 :
1317 : // Adapt Additional Core Properties.
1318 0 : renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1319 0 : xNewId->getContentIdentifier(),
1320 0 : true );
1321 : }
1322 : else
1323 : {
1324 : // Roll-back.
1325 0 : m_aProps.setTitle( aOldTitle );
1326 0 : m_aProps.setName ( aOldName );
1327 :
1328 0 : aOldTitle = aOldName = "";
1329 :
1330 : // Set error .
1331 0 : aRet[ nTitlePos ] <<= uno::Exception(
1332 : OUString("Exchange failed!"),
1333 0 : static_cast< cppu::OWeakObject * >( this ) );
1334 0 : }
1335 : }
1336 :
1337 0 : if ( !aOldTitle.isEmpty() )
1338 : {
1339 0 : aEvent.PropertyName = "Title";
1340 0 : aEvent.OldValue = uno::makeAny( aOldTitle );
1341 0 : aEvent.NewValue = uno::makeAny( m_aProps.getTitle() );
1342 :
1343 0 : aChanges.getArray()[ nChanged ] = aEvent;
1344 0 : nChanged++;
1345 : }
1346 :
1347 0 : if ( nChanged > 0 )
1348 : {
1349 : // Save changes, if content was already made persistent.
1350 0 : if ( !bExchange && ( m_eState == PERSISTENT ) )
1351 : {
1352 0 : if ( !storeData() )
1353 : {
1354 : uno::Any aProps
1355 : = uno::makeAny(
1356 : beans::PropertyValue(
1357 : OUString( "Uri"),
1358 : -1,
1359 0 : uno::makeAny(m_xIdentifier->
1360 0 : getContentIdentifier()),
1361 0 : beans::PropertyState_DIRECT_VALUE));
1362 : ucbhelper::cancelCommandExecution(
1363 : ucb::IOErrorCode_CANT_WRITE,
1364 : uno::Sequence< uno::Any >(&aProps, 1),
1365 : xEnv,
1366 : OUString( "Cannot store persistent data!" ),
1367 0 : this );
1368 : // Unreachable
1369 : }
1370 : }
1371 :
1372 0 : aChanges.realloc( nChanged );
1373 :
1374 0 : aGuard.clear();
1375 0 : notifyPropertiesChange( aChanges );
1376 : }
1377 :
1378 0 : return aRet;
1379 : }
1380 :
1381 :
1382 0 : void HierarchyContent::insert( sal_Int32 nNameClashResolve,
1383 : const uno::Reference<
1384 : ucb::XCommandEnvironment > & xEnv )
1385 : throw( uno::Exception )
1386 : {
1387 0 : osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1388 :
1389 : // Am I the root folder?
1390 0 : if ( m_eKind == ROOT )
1391 : {
1392 : ucbhelper::cancelCommandExecution(
1393 : uno::makeAny( ucb::UnsupportedCommandException(
1394 : OUString( "Not supported by root folder!" ),
1395 : static_cast< cppu::OWeakObject * >( this ) ) ),
1396 0 : xEnv );
1397 : // Unreachable
1398 : }
1399 :
1400 : // Check, if all required properties were set.
1401 0 : if ( m_aProps.getTitle().isEmpty() )
1402 : {
1403 0 : uno::Sequence< OUString > aProps( 1 );
1404 0 : aProps[ 0 ] = "Title";
1405 : ucbhelper::cancelCommandExecution(
1406 : uno::makeAny( ucb::MissingPropertiesException(
1407 : OUString(),
1408 : static_cast< cppu::OWeakObject * >( this ),
1409 : aProps ) ),
1410 0 : xEnv );
1411 : // Unreachable
1412 : }
1413 :
1414 : // Assemble new content identifier...
1415 :
1416 : uno::Reference< ucb::XContentIdentifier > xId
1417 0 : = makeNewIdentifier( m_aProps.getTitle() );
1418 :
1419 : // Handle possible name clash...
1420 :
1421 0 : switch ( nNameClashResolve )
1422 : {
1423 : // fail.
1424 : case ucb::NameClash::ERROR:
1425 0 : if ( hasData( xId ) )
1426 : {
1427 : ucbhelper::cancelCommandExecution(
1428 : uno::makeAny(
1429 : ucb::NameClashException(
1430 : OUString(),
1431 : static_cast< cppu::OWeakObject * >( this ),
1432 : task::InteractionClassification_ERROR,
1433 0 : m_aProps.getTitle() ) ),
1434 0 : xEnv );
1435 : // Unreachable
1436 : }
1437 0 : break;
1438 :
1439 : // replace existing object.
1440 : case ucb::NameClash::OVERWRITE:
1441 0 : break;
1442 :
1443 : // "invent" a new valid title.
1444 : case ucb::NameClash::RENAME:
1445 0 : if ( hasData( xId ) )
1446 : {
1447 0 : sal_Int32 nTry = 0;
1448 :
1449 0 : do
1450 : {
1451 0 : OUString aNewId = xId->getContentIdentifier();
1452 0 : aNewId += "_";
1453 0 : aNewId += OUString::number( ++nTry );
1454 0 : xId = new ::ucbhelper::ContentIdentifier( aNewId );
1455 : }
1456 0 : while ( hasData( xId ) && ( nTry < 1000 ) );
1457 :
1458 0 : if ( nTry == 1000 )
1459 : {
1460 : ucbhelper::cancelCommandExecution(
1461 : uno::makeAny(
1462 : ucb::UnsupportedNameClashException(
1463 : OUString( "Unable to resolve name clash!" ),
1464 : static_cast< cppu::OWeakObject * >( this ),
1465 : nNameClashResolve ) ),
1466 0 : xEnv );
1467 : // Unreachable
1468 : }
1469 : else
1470 : {
1471 0 : OUString aNewTitle( m_aProps.getTitle() );
1472 0 : aNewTitle += "_";
1473 0 : aNewTitle += OUString::number( nTry );
1474 0 : m_aProps.setTitle( aNewTitle );
1475 : }
1476 : }
1477 0 : break;
1478 :
1479 : case ucb::NameClash::KEEP: // deprecated
1480 : case ucb::NameClash::ASK:
1481 : default:
1482 0 : if ( hasData( xId ) )
1483 : {
1484 : ucbhelper::cancelCommandExecution(
1485 : uno::makeAny(
1486 : ucb::UnsupportedNameClashException(
1487 : OUString(),
1488 : static_cast< cppu::OWeakObject * >( this ),
1489 : nNameClashResolve ) ),
1490 0 : xEnv );
1491 : // Unreachable
1492 : }
1493 0 : break;
1494 : }
1495 :
1496 : // Identifier changed?
1497 0 : sal_Bool bNewId = ( xId->getContentIdentifier()
1498 0 : != m_xIdentifier->getContentIdentifier() );
1499 0 : m_xIdentifier = xId;
1500 :
1501 0 : if ( !storeData() )
1502 : {
1503 : uno::Any aProps
1504 : = uno::makeAny(beans::PropertyValue(
1505 : OUString( "Uri"),
1506 : -1,
1507 0 : uno::makeAny(m_xIdentifier->
1508 0 : getContentIdentifier()),
1509 0 : beans::PropertyState_DIRECT_VALUE));
1510 : ucbhelper::cancelCommandExecution(
1511 : ucb::IOErrorCode_CANT_WRITE,
1512 : uno::Sequence< uno::Any >(&aProps, 1),
1513 : xEnv,
1514 : OUString("Cannot store persistent data!"),
1515 0 : this );
1516 : // Unreachable
1517 : }
1518 :
1519 0 : m_eState = PERSISTENT;
1520 :
1521 0 : if ( bNewId )
1522 : {
1523 0 : aGuard.clear();
1524 0 : inserted();
1525 0 : }
1526 0 : }
1527 :
1528 :
1529 0 : void HierarchyContent::destroy( sal_Bool bDeletePhysical,
1530 : const uno::Reference<
1531 : ucb::XCommandEnvironment > & xEnv )
1532 : throw( uno::Exception )
1533 : {
1534 : // @@@ take care about bDeletePhysical -> trashcan support
1535 :
1536 0 : osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1537 :
1538 0 : uno::Reference< ucb::XContent > xThis = this;
1539 :
1540 : // Persistent?
1541 0 : if ( m_eState != PERSISTENT )
1542 : {
1543 : ucbhelper::cancelCommandExecution(
1544 : uno::makeAny( ucb::UnsupportedCommandException(
1545 : OUString( "Not persistent!" ),
1546 : static_cast< cppu::OWeakObject * >( this ) ) ),
1547 0 : xEnv );
1548 : // Unreachable
1549 : }
1550 :
1551 : // Am I the root folder?
1552 0 : if ( m_eKind == ROOT )
1553 : {
1554 : ucbhelper::cancelCommandExecution(
1555 : uno::makeAny( ucb::UnsupportedCommandException(
1556 : OUString( "Not supported by root folder!" ),
1557 : static_cast< cppu::OWeakObject * >( this ) ) ),
1558 0 : xEnv );
1559 : // Unreachable
1560 : }
1561 :
1562 0 : m_eState = DEAD;
1563 :
1564 0 : aGuard.clear();
1565 0 : deleted();
1566 :
1567 0 : if ( m_eKind == FOLDER )
1568 : {
1569 : // Process instanciated children...
1570 :
1571 0 : HierarchyContentRefList aChildren;
1572 0 : queryChildren( aChildren );
1573 :
1574 0 : HierarchyContentRefList::const_iterator it = aChildren.begin();
1575 0 : HierarchyContentRefList::const_iterator end = aChildren.end();
1576 :
1577 0 : while ( it != end )
1578 : {
1579 0 : (*it)->destroy( bDeletePhysical, xEnv );
1580 0 : ++it;
1581 0 : }
1582 0 : }
1583 0 : }
1584 :
1585 :
1586 0 : void HierarchyContent::transfer(
1587 : const ucb::TransferInfo& rInfo,
1588 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1589 : throw( uno::Exception )
1590 : {
1591 0 : osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1592 :
1593 : // Persistent?
1594 0 : if ( m_eState != PERSISTENT )
1595 : {
1596 : ucbhelper::cancelCommandExecution(
1597 : uno::makeAny( ucb::UnsupportedCommandException(
1598 : OUString( "Not persistent!" ),
1599 : static_cast< cppu::OWeakObject * >( this ) ) ),
1600 0 : xEnv );
1601 : // Unreachable
1602 : }
1603 :
1604 : // Is source a hierarchy content?
1605 0 : if ( !rInfo.SourceURL.startsWith( HIERARCHY_URL_SCHEME ":/" ) )
1606 : {
1607 : ucbhelper::cancelCommandExecution(
1608 : uno::makeAny( ucb::InteractiveBadTransferURLException(
1609 : OUString(),
1610 : static_cast< cppu::OWeakObject * >( this ) ) ),
1611 0 : xEnv );
1612 : // Unreachable
1613 : }
1614 :
1615 : // Is source not a parent of me / not me?
1616 0 : OUString aId = m_xIdentifier->getContentIdentifier();
1617 0 : sal_Int32 nPos = aId.lastIndexOf( '/' );
1618 0 : if ( nPos != ( aId.getLength() - 1 ) )
1619 : {
1620 : // No trailing slash found. Append.
1621 0 : aId += "/";
1622 : }
1623 :
1624 0 : if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1625 : {
1626 0 : if ( aId.compareTo(
1627 0 : rInfo.SourceURL, rInfo.SourceURL.getLength() ) == 0 )
1628 : {
1629 : uno::Any aProps
1630 : = uno::makeAny(beans::PropertyValue(
1631 : OUString( "Uri"),
1632 : -1,
1633 : uno::makeAny(rInfo.SourceURL),
1634 0 : beans::PropertyState_DIRECT_VALUE));
1635 : ucbhelper::cancelCommandExecution(
1636 : ucb::IOErrorCode_RECURSIVE,
1637 : uno::Sequence< uno::Any >(&aProps, 1),
1638 : xEnv,
1639 : OUString( "Target is equal to or is a child of source!" ),
1640 0 : this );
1641 : // Unreachable
1642 : }
1643 : }
1644 :
1645 :
1646 : // 0) Obtain content object for source.
1647 :
1648 :
1649 : uno::Reference< ucb::XContentIdentifier > xId
1650 0 : = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
1651 :
1652 : // Note: The static cast is okay here, because its sure that
1653 : // m_xProvider is always the HierarchyContentProvider.
1654 0 : rtl::Reference< HierarchyContent > xSource;
1655 :
1656 : try
1657 : {
1658 0 : xSource = static_cast< HierarchyContent * >(
1659 0 : m_xProvider->queryContent( xId ).get() );
1660 : }
1661 0 : catch ( ucb::IllegalIdentifierException const & )
1662 : {
1663 : // queryContent
1664 : }
1665 :
1666 0 : if ( !xSource.is() )
1667 : {
1668 : uno::Any aProps
1669 : = uno::makeAny(beans::PropertyValue(
1670 : OUString( "Uri"),
1671 : -1,
1672 0 : uno::makeAny(xId->getContentIdentifier()),
1673 0 : beans::PropertyState_DIRECT_VALUE));
1674 : ucbhelper::cancelCommandExecution(
1675 : ucb::IOErrorCode_CANT_READ,
1676 : uno::Sequence< uno::Any >(&aProps, 1),
1677 : xEnv,
1678 : OUString( "Cannot instanciate source object!" ),
1679 0 : this );
1680 : // Unreachable
1681 : }
1682 :
1683 :
1684 : // 1) Create new child content.
1685 :
1686 :
1687 0 : OUString aType = xSource->isFolder()
1688 : ? OUString( HIERARCHY_FOLDER_CONTENT_TYPE )
1689 0 : : OUString( HIERARCHY_LINK_CONTENT_TYPE );
1690 0 : ucb::ContentInfo aContentInfo;
1691 0 : aContentInfo.Type = aType;
1692 0 : aContentInfo.Attributes = 0;
1693 :
1694 : // Note: The static cast is okay here, because its sure that
1695 : // createNewContent always creates a HierarchyContent.
1696 : rtl::Reference< HierarchyContent > xTarget
1697 : = static_cast< HierarchyContent * >(
1698 0 : createNewContent( aContentInfo ).get() );
1699 0 : if ( !xTarget.is() )
1700 : {
1701 : uno::Any aProps
1702 : = uno::makeAny(beans::PropertyValue(
1703 : OUString( "Folder"),
1704 : -1,
1705 : uno::makeAny(aId),
1706 0 : beans::PropertyState_DIRECT_VALUE));
1707 : ucbhelper::cancelCommandExecution(
1708 : ucb::IOErrorCode_CANT_CREATE,
1709 : uno::Sequence< uno::Any >(&aProps, 1),
1710 : xEnv,
1711 : OUString( "XContentCreator::createNewContent failed!" ),
1712 0 : this );
1713 : // Unreachable
1714 : }
1715 :
1716 :
1717 : // 2) Copy data from source content to child content.
1718 :
1719 :
1720 : uno::Sequence< beans::Property > aSourceProps
1721 0 : = xSource->getPropertySetInfo( xEnv )->getProperties();
1722 0 : sal_Int32 nCount = aSourceProps.getLength();
1723 :
1724 0 : if ( nCount )
1725 : {
1726 0 : sal_Bool bHadTitle = rInfo.NewTitle.isEmpty();
1727 :
1728 : // Get all source values.
1729 : uno::Reference< sdbc::XRow > xRow
1730 0 : = xSource->getPropertyValues( aSourceProps );
1731 :
1732 0 : uno::Sequence< beans::PropertyValue > aValues( nCount );
1733 0 : beans::PropertyValue* pValues = aValues.getArray();
1734 :
1735 0 : const beans::Property* pProps = aSourceProps.getConstArray();
1736 0 : for ( sal_Int32 n = 0; n < nCount; ++n )
1737 : {
1738 0 : const beans::Property& rProp = pProps[ n ];
1739 0 : beans::PropertyValue& rValue = pValues[ n ];
1740 :
1741 0 : rValue.Name = rProp.Name;
1742 0 : rValue.Handle = rProp.Handle;
1743 :
1744 0 : if ( !bHadTitle && rProp.Name == "Title" )
1745 : {
1746 : // Set new title instead of original.
1747 0 : bHadTitle = sal_True;
1748 0 : rValue.Value <<= rInfo.NewTitle;
1749 : }
1750 : else
1751 0 : rValue.Value = xRow->getObject(
1752 : n + 1,
1753 0 : uno::Reference< container::XNameAccess >() );
1754 :
1755 0 : rValue.State = beans::PropertyState_DIRECT_VALUE;
1756 :
1757 0 : if ( rProp.Attributes & beans::PropertyAttribute::REMOVABLE )
1758 : {
1759 : // Add Additional Core Property.
1760 : try
1761 : {
1762 0 : xTarget->addProperty( rProp.Name,
1763 : rProp.Attributes,
1764 0 : rValue.Value );
1765 : }
1766 0 : catch ( beans::PropertyExistException const & )
1767 : {
1768 : }
1769 0 : catch ( beans::IllegalTypeException const & )
1770 : {
1771 : }
1772 0 : catch ( lang::IllegalArgumentException const & )
1773 : {
1774 : }
1775 : }
1776 : }
1777 :
1778 : // Set target values.
1779 0 : xTarget->setPropertyValues( aValues, xEnv );
1780 : }
1781 :
1782 :
1783 : // 3) Commit (insert) child.
1784 :
1785 :
1786 0 : xTarget->insert( rInfo.NameClash, xEnv );
1787 :
1788 :
1789 : // 4) Transfer (copy) children of source.
1790 :
1791 :
1792 0 : if ( xSource->isFolder() )
1793 : {
1794 : HierarchyEntry aFolder(
1795 0 : m_xContext, m_pProvider, xId->getContentIdentifier() );
1796 0 : HierarchyEntry::iterator it;
1797 :
1798 0 : while ( aFolder.next( it ) )
1799 : {
1800 0 : const HierarchyEntryData& rResult = *it;
1801 :
1802 0 : OUString aChildId = xId->getContentIdentifier();
1803 0 : if ( ( aChildId.lastIndexOf( '/' ) + 1 ) != aChildId.getLength() )
1804 0 : aChildId += "/";
1805 :
1806 0 : aChildId += rResult.getName();
1807 :
1808 0 : ucb::TransferInfo aInfo;
1809 0 : aInfo.MoveData = sal_False;
1810 0 : aInfo.NewTitle = "";
1811 0 : aInfo.SourceURL = aChildId;
1812 0 : aInfo.NameClash = rInfo.NameClash;
1813 :
1814 : // Transfer child to target.
1815 0 : xTarget->transfer( aInfo, xEnv );
1816 0 : }
1817 : }
1818 :
1819 :
1820 : // 5) Destroy source ( when moving only ) .
1821 :
1822 :
1823 0 : if ( rInfo.MoveData )
1824 : {
1825 0 : xSource->destroy( sal_True, xEnv );
1826 :
1827 : // Remove all persistent data of source and its children.
1828 0 : if ( !xSource->removeData() )
1829 : {
1830 : uno::Any aProps
1831 : = uno::makeAny(
1832 : beans::PropertyValue(
1833 : OUString( "Uri"),
1834 : -1,
1835 : uno::makeAny(
1836 0 : xSource->m_xIdentifier->
1837 0 : getContentIdentifier()),
1838 0 : beans::PropertyState_DIRECT_VALUE));
1839 : ucbhelper::cancelCommandExecution(
1840 : ucb::IOErrorCode_CANT_WRITE,
1841 : uno::Sequence< uno::Any >(&aProps, 1),
1842 : xEnv,
1843 : OUString( "Cannot remove persistent data of source object!" ),
1844 0 : this );
1845 : // Unreachable
1846 : }
1847 :
1848 : // Remove own and all children's Additional Core Properties.
1849 0 : xSource->removeAdditionalPropertySet( true );
1850 0 : }
1851 0 : }
1852 :
1853 :
1854 :
1855 :
1856 : // HierarchyContentProperties Implementation.
1857 :
1858 :
1859 :
1860 :
1861 : uno::Sequence< ucb::ContentInfo >
1862 0 : HierarchyContentProperties::getCreatableContentsInfo() const
1863 : {
1864 0 : if ( getIsFolder() )
1865 : {
1866 0 : uno::Sequence< ucb::ContentInfo > aSeq( 2 );
1867 :
1868 : // Folder.
1869 0 : aSeq.getArray()[ 0 ].Type = HIERARCHY_FOLDER_CONTENT_TYPE;
1870 0 : aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
1871 :
1872 0 : uno::Sequence< beans::Property > aFolderProps( 1 );
1873 0 : aFolderProps.getArray()[ 0 ] = beans::Property(
1874 : OUString("Title"),
1875 : -1,
1876 0 : getCppuType( static_cast< const OUString * >( 0 ) ),
1877 0 : beans::PropertyAttribute::BOUND );
1878 0 : aSeq.getArray()[ 0 ].Properties = aFolderProps;
1879 :
1880 : // Link.
1881 0 : aSeq.getArray()[ 1 ].Type = HIERARCHY_LINK_CONTENT_TYPE;
1882 0 : aSeq.getArray()[ 1 ].Attributes = ucb::ContentInfoAttribute::KIND_LINK;
1883 :
1884 0 : uno::Sequence< beans::Property > aLinkProps( 2 );
1885 0 : aLinkProps.getArray()[ 0 ] = beans::Property(
1886 : OUString("Title"),
1887 : -1,
1888 0 : getCppuType( static_cast< const OUString * >( 0 ) ),
1889 0 : beans::PropertyAttribute::BOUND );
1890 0 : aLinkProps.getArray()[ 1 ] = beans::Property(
1891 : OUString("TargetURL"),
1892 : -1,
1893 0 : getCppuType( static_cast< const OUString * >( 0 ) ),
1894 0 : beans::PropertyAttribute::BOUND );
1895 0 : aSeq.getArray()[ 1 ].Properties = aLinkProps;
1896 :
1897 0 : return aSeq;
1898 : }
1899 : else
1900 : {
1901 0 : return uno::Sequence< ucb::ContentInfo >( 0 );
1902 : }
1903 : }
1904 :
1905 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|