1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 /**************************************************************************
23 **************************************************************************
25 *************************************************************************/
27 #include "rtl/ustrbuf.hxx"
28 #include <osl/diagnose.h>
30 #include "com/sun/star/container/XNameAccess.hpp"
31 #include "com/sun/star/embed/XStorage.hpp"
33 #include "comphelper/processfactory.hxx"
34 #include "ucbhelper/contentidentifier.hxx"
36 #include "tdoc_provider.hxx"
37 #include "tdoc_content.hxx"
38 #include "tdoc_uri.hxx"
39 #include "tdoc_docmgr.hxx"
40 #include "tdoc_storage.hxx"
42 using namespace com::sun::star
;
43 using namespace tdoc_ucp
;
48 // ContentProvider Implementation.
53 ContentProvider::ContentProvider(
54 const uno::Reference
< uno::XComponentContext
>& rxContext
)
55 : ::ucbhelper::ContentProviderImplHelper( rxContext
),
56 m_xDocsMgr( new OfficeDocumentsManager( rxContext
, this ) ),
57 m_xStgElemFac( new StorageElementFactory( rxContext
, m_xDocsMgr
) )
63 ContentProvider::~ContentProvider()
65 if ( m_xDocsMgr
.is() )
66 m_xDocsMgr
->destroy();
71 // XInterface methods.
72 void SAL_CALL
ContentProvider::acquire()
75 OWeakObject::acquire();
78 void SAL_CALL
ContentProvider::release()
81 OWeakObject::release();
84 css::uno::Any SAL_CALL
ContentProvider::queryInterface( const css::uno::Type
& rType
)
85 throw( css::uno::RuntimeException
, std::exception
)
87 css::uno::Any aRet
= cppu::queryInterface( rType
,
88 (static_cast< lang::XTypeProvider
* >(this)),
89 (static_cast< lang::XServiceInfo
* >(this)),
90 (static_cast< ucb::XContentProvider
* >(this)),
91 (static_cast< frame::XTransientDocumentsDocumentContentFactory
* >(this))
93 return aRet
.hasValue() ? aRet
: OWeakObject::queryInterface( rType
);
96 // XTypeProvider methods.
100 XTYPEPROVIDER_IMPL_4( ContentProvider
,
103 ucb::XContentProvider
,
104 frame::XTransientDocumentsDocumentContentFactory
);
108 // XServiceInfo methods.
112 XSERVICEINFO_IMPL_1_CTX(
114 OUString( "com.sun.star.comp.ucb.TransientDocumentsContentProvider" ),
115 TDOC_CONTENT_PROVIDER_SERVICE_NAME
);
119 // Service factory implementation.
123 ONE_INSTANCE_SERVICE_FACTORY_IMPL( ContentProvider
);
127 // XContentProvider methods.
132 uno::Reference
< ucb::XContent
> SAL_CALL
133 ContentProvider::queryContent(
134 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
)
135 throw( ucb::IllegalIdentifierException
, uno::RuntimeException
, std::exception
)
137 Uri
aUri( Identifier
->getContentIdentifier() );
138 if ( !aUri
.isValid() )
139 throw ucb::IllegalIdentifierException(
140 OUString( "Invalid URL!" ),
144 uno::Reference
< ucb::XContentIdentifier
> xCanonicId
145 = new ::ucbhelper::ContentIdentifier( aUri
.getUri() );
147 osl::MutexGuard
aGuard( m_aMutex
);
149 // Check, if a content with given id already exists...
150 uno::Reference
< ucb::XContent
> xContent
151 = queryExistingContent( xCanonicId
).get();
153 if ( !xContent
.is() )
155 // Create a new content.
156 xContent
= Content::create( m_xContext
, this, xCanonicId
);
157 registerNewContent( xContent
);
165 // XTransientDocumentsDocumentContentFactory methods.
170 uno::Reference
< ucb::XContent
> SAL_CALL
171 ContentProvider::createDocumentContent(
172 const uno::Reference
< frame::XModel
>& Model
)
173 throw ( lang::IllegalArgumentException
, uno::RuntimeException
, std::exception
)
175 // model -> id -> content identifier -> queryContent
176 if ( m_xDocsMgr
.is() )
178 OUString aDocId
= tdoc_ucp::OfficeDocumentsManager::queryDocumentId( Model
);
179 if ( !aDocId
.isEmpty() )
181 OUStringBuffer aBuffer
;
182 aBuffer
.appendAscii( TDOC_URL_SCHEME
":/" );
183 aBuffer
.append( aDocId
);
185 uno::Reference
< ucb::XContentIdentifier
> xId
186 = new ::ucbhelper::ContentIdentifier( aBuffer
.makeStringAndClear() );
188 osl::MutexGuard
aGuard( m_aMutex
);
190 // Check, if a content with given id already exists...
191 uno::Reference
< ucb::XContent
> xContent
192 = queryExistingContent( xId
).get();
194 if ( !xContent
.is() )
196 // Create a new content.
197 xContent
= Content::create( m_xContext
, this, xId
);
204 throw lang::IllegalArgumentException(
206 "Illegal Content Identifier!" ),
207 static_cast< cppu::OWeakObject
* >( this ),
212 throw lang::IllegalArgumentException(
214 "Unable to obtain document id from model!" ),
215 static_cast< cppu::OWeakObject
* >( this ),
221 throw lang::IllegalArgumentException(
223 "No Document Manager!" ),
224 static_cast< cppu::OWeakObject
* >( this ),
231 // interface OfficeDocumentsEventListener
236 void ContentProvider::notifyDocumentClosed( const OUString
& rDocId
)
238 osl::MutexGuard
aGuard( getContentListMutex() );
240 ::ucbhelper::ContentRefList aAllContents
;
241 queryExistingContents( aAllContents
);
243 ::ucbhelper::ContentRefList::const_iterator it
= aAllContents
.begin();
244 ::ucbhelper::ContentRefList::const_iterator end
= aAllContents
.end();
246 // Notify all content objects related to the closed doc.
248 bool bFoundDocumentContent
= false;
249 rtl::Reference
< Content
> xRoot
;
253 Uri
aUri( (*it
)->getIdentifier()->getContentIdentifier() );
254 OSL_ENSURE( aUri
.isValid(),
255 "ContentProvider::notifyDocumentClosed - Invalid URI!" );
257 if ( !bFoundDocumentContent
)
261 xRoot
= static_cast< Content
* >( (*it
).get() );
263 else if ( aUri
.isDocument() )
265 if ( aUri
.getDocumentId() == rDocId
)
267 bFoundDocumentContent
= true;
269 // document content will notify removal of child itself;
270 // no need for the root to propagate this.
276 if ( aUri
.getDocumentId() == rDocId
)
279 rtl::Reference
< Content
> xContent
280 = static_cast< Content
* >( (*it
).get() );
282 xContent
->notifyDocumentClosed();
290 // No document content found for rDocId but root content
291 // instantiated. Root content must announce document removal
292 // to content event listeners.
293 xRoot
->notifyChildRemoved( rDocId
);
299 void ContentProvider::notifyDocumentOpened( const OUString
& rDocId
)
301 osl::MutexGuard
aGuard( getContentListMutex() );
303 ::ucbhelper::ContentRefList aAllContents
;
304 queryExistingContents( aAllContents
);
306 ::ucbhelper::ContentRefList::const_iterator it
= aAllContents
.begin();
307 ::ucbhelper::ContentRefList::const_iterator end
= aAllContents
.end();
309 // Find root content. If instantiated let it propagate document insertion.
313 Uri
aUri( (*it
)->getIdentifier()->getContentIdentifier() );
314 OSL_ENSURE( aUri
.isValid(),
315 "ContentProvider::notifyDocumentOpened - Invalid URI!" );
319 rtl::Reference
< Content
> xRoot
320 = static_cast< Content
* >( (*it
).get() );
321 xRoot
->notifyChildInserted( rDocId
);
337 uno::Reference
< embed::XStorage
>
338 ContentProvider::queryStorage( const OUString
& rUri
,
339 StorageAccessMode eMode
) const
341 if ( m_xStgElemFac
.is() )
345 return m_xStgElemFac
->createStorage( rUri
, eMode
);
347 catch ( embed::InvalidStorageException
const & )
349 OSL_FAIL( "Caught InvalidStorageException!" );
351 catch ( lang::IllegalArgumentException
const & )
353 OSL_FAIL( "Caught IllegalArgumentException!" );
355 catch ( io::IOException
const & )
357 // Okay to happen, for instance when the storage does not exist.
358 //OSL_ENSURE( false, "Caught IOException!" );
360 catch ( embed::StorageWrappedTargetException
const & )
362 OSL_FAIL( "Caught embed::StorageWrappedTargetException!" );
365 return uno::Reference
< embed::XStorage
>();
369 uno::Reference
< embed::XStorage
>
370 ContentProvider::queryStorageClone( const OUString
& rUri
) const
372 if ( m_xStgElemFac
.is() )
377 uno::Reference
< embed::XStorage
> xParentStorage
378 = m_xStgElemFac
->createStorage( aUri
.getParentUri(), READ
);
379 uno::Reference
< embed::XStorage
> xStorage
380 = m_xStgElemFac
->createTemporaryStorage();
382 xParentStorage
->copyStorageElementLastCommitTo(
383 aUri
.getDecodedName(), xStorage
);
386 catch ( embed::InvalidStorageException
const & )
388 OSL_FAIL( "Caught InvalidStorageException!" );
390 catch ( lang::IllegalArgumentException
const & )
392 OSL_FAIL( "Caught IllegalArgumentException!" );
394 catch ( io::IOException
const & )
396 // Okay to happen, for instance when the storage does not exist.
397 //OSL_ENSURE( false, "Caught IOException!" );
399 catch ( embed::StorageWrappedTargetException
const & )
401 OSL_FAIL( "Caught embed::StorageWrappedTargetException!" );
405 return uno::Reference
< embed::XStorage
>();
409 uno::Reference
< io::XInputStream
>
410 ContentProvider::queryInputStream( const OUString
& rUri
,
411 const OUString
& rPassword
) const
412 throw ( packages::WrongPasswordException
, css::uno::RuntimeException
)
414 if ( m_xStgElemFac
.is() )
418 return m_xStgElemFac
->createInputStream( rUri
, rPassword
);
420 catch ( embed::InvalidStorageException
const & )
422 OSL_FAIL( "Caught InvalidStorageException!" );
424 catch ( lang::IllegalArgumentException
const & )
426 OSL_FAIL( "Caught IllegalArgumentException!" );
428 catch ( io::IOException
const & )
430 OSL_FAIL( "Caught IOException!" );
432 catch ( embed::StorageWrappedTargetException
const & )
434 OSL_FAIL( "Caught embed::StorageWrappedTargetException!" );
436 // catch ( packages::WrongPasswordException const & )
438 // // the key provided is wrong; rethrow; to be handled by caller.
442 return uno::Reference
< io::XInputStream
>();
446 uno::Reference
< io::XOutputStream
>
447 ContentProvider::queryOutputStream( const OUString
& rUri
,
448 const OUString
& rPassword
,
449 bool bTruncate
) const
450 throw ( packages::WrongPasswordException
,
451 uno::RuntimeException
)
453 if ( m_xStgElemFac
.is() )
458 m_xStgElemFac
->createOutputStream( rUri
, rPassword
, bTruncate
);
460 catch ( embed::InvalidStorageException
const & )
462 OSL_FAIL( "Caught InvalidStorageException!" );
464 catch ( lang::IllegalArgumentException
const & )
466 OSL_FAIL( "Caught IllegalArgumentException!" );
468 catch ( io::IOException
const & )
470 // Okay to happen, for instance when the storage does not exist.
471 //OSL_ENSURE( false, "Caught IOException!" );
473 catch ( embed::StorageWrappedTargetException
const & )
475 OSL_FAIL( "Caught embed::StorageWrappedTargetException!" );
477 // catch ( packages::WrongPasswordException const & )
479 // // the key provided is wrong; rethrow; to be handled by caller.
483 return uno::Reference
< io::XOutputStream
>();
487 uno::Reference
< io::XStream
>
488 ContentProvider::queryStream( const OUString
& rUri
,
489 const OUString
& rPassword
,
490 bool bTruncate
) const
491 throw ( packages::WrongPasswordException
, uno::RuntimeException
)
493 if ( m_xStgElemFac
.is() )
497 return m_xStgElemFac
->createStream( rUri
, rPassword
, bTruncate
);
499 catch ( embed::InvalidStorageException
const & )
501 OSL_FAIL( "Caught InvalidStorageException!" );
503 catch ( lang::IllegalArgumentException
const & )
505 OSL_FAIL( "Caught IllegalArgumentException!" );
507 catch ( io::IOException
const & )
509 // Okay to happen, for instance when the storage does not exist.
510 //OSL_ENSURE( false, "Caught IOException!" );
512 catch ( embed::StorageWrappedTargetException
const & )
514 OSL_FAIL( "Caught embed::StorageWrappedTargetException!" );
516 // catch ( packages::WrongPasswordException const & )
518 // // the key provided is wrong; rethrow; to be handled by caller.
522 return uno::Reference
< io::XStream
>();
526 bool ContentProvider::queryNamesOfChildren(
527 const OUString
& rUri
, uno::Sequence
< OUString
> & rNames
) const
532 // special handling for root, which has no storage, but children.
533 if ( m_xDocsMgr
.is() )
535 rNames
= m_xDocsMgr
->queryDocuments();
541 if ( m_xStgElemFac
.is() )
545 uno::Reference
< embed::XStorage
> xStorage
546 = m_xStgElemFac
->createStorage( rUri
, READ
);
548 OSL_ENSURE( xStorage
.is(), "Got no Storage!" );
552 uno::Reference
< container::XNameAccess
> xNA(
553 xStorage
, uno::UNO_QUERY
);
555 OSL_ENSURE( xNA
.is(), "Got no css.container.XNameAccess!" );
558 rNames
= xNA
->getElementNames();
563 catch ( embed::InvalidStorageException
const & )
565 OSL_FAIL( "Caught InvalidStorageException!" );
567 catch ( lang::IllegalArgumentException
const & )
569 OSL_FAIL( "Caught IllegalArgumentException!" );
571 catch ( io::IOException
const & )
573 // Okay to happen, for instance if the storage does not exist.
574 //OSL_ENSURE( false, "Caught IOException!" );
576 catch ( embed::StorageWrappedTargetException
const & )
578 OSL_FAIL( "Caught embed::StorageWrappedTargetException!" );
587 ContentProvider::queryStorageTitle( const OUString
& rUri
) const
597 else if ( aUri
.isDocument() )
599 // for documents, title shall not be derived from URL. It shall
600 // be somethimg more 'speaking' than just the document UID.
601 if ( m_xDocsMgr
.is() )
602 aTitle
= m_xDocsMgr
->queryStorageTitle( aUri
.getDocumentId() );
606 // derive title from URL
607 aTitle
= aUri
.getDecodedName();
610 OSL_ENSURE( !aTitle
.isEmpty() || aUri
.isRoot(),
611 "ContentProvider::queryStorageTitle - empty title!" );
616 uno::Reference
< frame::XModel
>
617 ContentProvider::queryDocumentModel( const OUString
& rUri
) const
619 uno::Reference
< frame::XModel
> xModel
;
621 if ( m_xDocsMgr
.is() )
624 xModel
= m_xDocsMgr
->queryDocumentModel( aUri
.getDocumentId() );
627 OSL_ENSURE( xModel
.is(),
628 "ContentProvider::queryDocumentModel - no model!" );
632 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */