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 <tools/diagnose_ex.h>
29 #include <com/sun/star/embed/InvalidStorageException.hpp>
30 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
31 #include <com/sun/star/io/IOException.hpp>
32 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
33 #include <cppuhelper/queryinterface.hxx>
34 #include <ucbhelper/contentidentifier.hxx>
35 #include <ucbhelper/macros.hxx>
37 #include "tdoc_provider.hxx"
38 #include "tdoc_content.hxx"
39 #include "tdoc_uri.hxx"
40 #include "tdoc_docmgr.hxx"
41 #include "tdoc_storage.hxx"
43 using namespace com::sun::star
;
44 using namespace tdoc_ucp
;
47 // ContentProvider Implementation.
50 ContentProvider::ContentProvider(
51 const uno::Reference
< uno::XComponentContext
>& rxContext
)
52 : ::ucbhelper::ContentProviderImplHelper( rxContext
),
53 m_xDocsMgr( new OfficeDocumentsManager( rxContext
, this ) ),
54 m_xStgElemFac( new StorageElementFactory( rxContext
, m_xDocsMgr
) )
60 ContentProvider::~ContentProvider()
62 if ( m_xDocsMgr
.is() )
63 m_xDocsMgr
->destroy();
67 // XInterface methods.
68 void SAL_CALL
ContentProvider::acquire()
71 OWeakObject::acquire();
74 void SAL_CALL
ContentProvider::release()
77 OWeakObject::release();
80 css::uno::Any SAL_CALL
ContentProvider::queryInterface( const css::uno::Type
& rType
)
82 css::uno::Any aRet
= cppu::queryInterface( rType
,
83 static_cast< lang::XTypeProvider
* >(this),
84 static_cast< lang::XServiceInfo
* >(this),
85 static_cast< ucb::XContentProvider
* >(this),
86 static_cast< frame::XTransientDocumentsDocumentContentIdentifierFactory
* >(this),
87 static_cast< frame::XTransientDocumentsDocumentContentFactory
* >(this)
89 return aRet
.hasValue() ? aRet
: OWeakObject::queryInterface( rType
);
92 // XTypeProvider methods.
95 XTYPEPROVIDER_IMPL_5( ContentProvider
,
98 ucb::XContentProvider
,
99 frame::XTransientDocumentsDocumentContentIdentifierFactory
,
100 frame::XTransientDocumentsDocumentContentFactory
);
103 // XServiceInfo methods.
104 OUString SAL_CALL
ContentProvider::getImplementationName()
106 return "com.sun.star.comp.ucb.TransientDocumentsContentProvider";
109 sal_Bool SAL_CALL
ContentProvider::supportsService( const OUString
& ServiceName
)
111 return cppu::supportsService( this, ServiceName
);
114 css::uno::Sequence
< OUString
> SAL_CALL
ContentProvider::getSupportedServiceNames()
116 return { "com.sun.star.ucb.TransientDocumentsContentProvider" };
120 // Service factory implementation.
123 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
124 ucb_tdoc_ContentProvider_get_implementation(
125 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
127 return cppu::acquire(new ContentProvider(context
));
130 // XContentProvider methods.
134 uno::Reference
< ucb::XContent
> SAL_CALL
135 ContentProvider::queryContent(
136 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
)
138 Uri
aUri( Identifier
->getContentIdentifier() );
139 if ( !aUri
.isValid() )
140 throw ucb::IllegalIdentifierException(
145 uno::Reference
< ucb::XContentIdentifier
> xCanonicId
146 = new ::ucbhelper::ContentIdentifier( aUri
.getUri() );
148 osl::MutexGuard
aGuard( m_aMutex
);
150 // Check, if a content with given id already exists...
151 uno::Reference
< ucb::XContent
> xContent
152 = queryExistingContent( xCanonicId
);
154 if ( !xContent
.is() )
156 // Create a new content.
157 xContent
= Content::create( m_xContext
, this, xCanonicId
);
158 registerNewContent( xContent
);
165 // XTransientDocumentsDocumentContentIdentifierFactory methods.
167 uno::Reference
<ucb::XContentIdentifier
> SAL_CALL
168 ContentProvider::createDocumentContentIdentifier(
169 uno::Reference
<frame::XModel
> const& xModel
)
171 // model -> id -> content identifier -> queryContent
172 if ( !m_xDocsMgr
.is() )
174 throw lang::IllegalArgumentException(
175 "No Document Manager!",
176 static_cast< cppu::OWeakObject
* >( this ),
180 OUString aDocId
= tdoc_ucp::OfficeDocumentsManager::queryDocumentId(xModel
);
181 if ( aDocId
.isEmpty() )
183 throw lang::IllegalArgumentException(
184 "Unable to obtain document id from model!",
185 static_cast< cppu::OWeakObject
* >( this ),
189 OUString aBuffer
= TDOC_URL_SCHEME
":/" + aDocId
;
191 uno::Reference
< ucb::XContentIdentifier
> xId
192 = new ::ucbhelper::ContentIdentifier( aBuffer
);
196 // XTransientDocumentsDocumentContentFactory methods.
198 uno::Reference
< ucb::XContent
> SAL_CALL
199 ContentProvider::createDocumentContent(
200 uno::Reference
<frame::XModel
> const& xModel
)
202 uno::Reference
<ucb::XContentIdentifier
> const xId(
203 createDocumentContentIdentifier(xModel
));
205 osl::MutexGuard
aGuard( m_aMutex
);
207 // Check, if a content with given id already exists...
208 uno::Reference
< ucb::XContent
> xContent
209 = queryExistingContent( xId
);
211 if ( !xContent
.is() )
213 // Create a new content.
214 xContent
= Content::create( m_xContext
, this, xId
);
221 throw lang::IllegalArgumentException(
222 "Illegal Content Identifier!",
223 static_cast< cppu::OWeakObject
* >( this ),
228 // interface OfficeDocumentsEventListener
232 void ContentProvider::notifyDocumentClosed( const OUString
& rDocId
)
234 osl::MutexGuard
aGuard( getContentListMutex() );
236 ::ucbhelper::ContentRefList aAllContents
;
237 queryExistingContents( aAllContents
);
239 // Notify all content objects related to the closed doc.
241 bool bFoundDocumentContent
= false;
242 rtl::Reference
< Content
> xRoot
;
244 for ( const auto& rContent
: aAllContents
)
246 Uri
aUri( rContent
->getIdentifier()->getContentIdentifier() );
247 OSL_ENSURE( aUri
.isValid(),
248 "ContentProvider::notifyDocumentClosed - Invalid URI!" );
250 if ( !bFoundDocumentContent
)
254 xRoot
= static_cast< Content
* >( rContent
.get() );
256 else if ( aUri
.isDocument() )
258 if ( aUri
.getDocumentId() == rDocId
)
260 bFoundDocumentContent
= true;
262 // document content will notify removal of child itself;
263 // no need for the root to propagate this.
269 if ( aUri
.getDocumentId() == rDocId
)
272 rtl::Reference
< Content
> xContent
273 = static_cast< Content
* >( rContent
.get() );
275 xContent
->notifyDocumentClosed();
281 // No document content found for rDocId but root content
282 // instantiated. Root content must announce document removal
283 // to content event listeners.
284 xRoot
->notifyChildRemoved( rDocId
);
290 void ContentProvider::notifyDocumentOpened( const OUString
& rDocId
)
292 osl::MutexGuard
aGuard( getContentListMutex() );
294 ::ucbhelper::ContentRefList aAllContents
;
295 queryExistingContents( aAllContents
);
297 // Find root content. If instantiated let it propagate document insertion.
299 for ( const auto& rContent
: aAllContents
)
301 Uri
aUri( rContent
->getIdentifier()->getContentIdentifier() );
302 OSL_ENSURE( aUri
.isValid(),
303 "ContentProvider::notifyDocumentOpened - Invalid URI!" );
307 rtl::Reference
< Content
> xRoot
308 = static_cast< Content
* >( rContent
.get() );
309 xRoot
->notifyChildInserted( rDocId
);
321 uno::Reference
< embed::XStorage
>
322 ContentProvider::queryStorage( const OUString
& rUri
,
323 StorageAccessMode eMode
) const
325 if ( m_xStgElemFac
.is() )
329 return m_xStgElemFac
->createStorage( rUri
, eMode
);
331 catch ( embed::InvalidStorageException
const & )
333 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
335 catch ( lang::IllegalArgumentException
const & )
337 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
339 catch ( io::IOException
const & )
341 // Okay to happen, for instance when the storage does not exist.
342 //OSL_ENSURE( false, "Caught IOException!" );
344 catch ( embed::StorageWrappedTargetException
const & )
346 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
349 return uno::Reference
< embed::XStorage
>();
353 uno::Reference
< embed::XStorage
>
354 ContentProvider::queryStorageClone( const OUString
& rUri
) const
356 if ( m_xStgElemFac
.is() )
361 uno::Reference
< embed::XStorage
> xParentStorage
362 = m_xStgElemFac
->createStorage( aUri
.getParentUri(), READ
);
363 uno::Reference
< embed::XStorage
> xStorage
364 = m_xStgElemFac
->createTemporaryStorage();
366 xParentStorage
->copyStorageElementLastCommitTo(
367 aUri
.getDecodedName(), xStorage
);
370 catch ( embed::InvalidStorageException
const & )
372 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
374 catch ( lang::IllegalArgumentException
const & )
376 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
378 catch ( io::IOException
const & )
380 // Okay to happen, for instance when the storage does not exist.
381 //OSL_ENSURE( false, "Caught IOException!" );
383 catch ( embed::StorageWrappedTargetException
const & )
385 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
389 return uno::Reference
< embed::XStorage
>();
393 uno::Reference
< io::XInputStream
>
394 ContentProvider::queryInputStream( const OUString
& rUri
,
395 const OUString
& rPassword
) const
397 if ( m_xStgElemFac
.is() )
401 return m_xStgElemFac
->createInputStream( rUri
, rPassword
);
403 catch ( embed::InvalidStorageException
const & )
405 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
407 catch ( lang::IllegalArgumentException
const & )
409 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
411 catch ( io::IOException
const & )
413 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
415 catch ( embed::StorageWrappedTargetException
const & )
417 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
419 // catch ( packages::WrongPasswordException const & )
421 // // the key provided is wrong; rethrow; to be handled by caller.
425 return uno::Reference
< io::XInputStream
>();
429 uno::Reference
< io::XOutputStream
>
430 ContentProvider::queryOutputStream( const OUString
& rUri
,
431 const OUString
& rPassword
,
432 bool bTruncate
) const
434 if ( m_xStgElemFac
.is() )
439 m_xStgElemFac
->createOutputStream( rUri
, rPassword
, bTruncate
);
441 catch ( embed::InvalidStorageException
const & )
443 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
445 catch ( lang::IllegalArgumentException
const & )
447 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
449 catch ( io::IOException
const & )
451 // Okay to happen, for instance when the storage does not exist.
452 //OSL_ENSURE( false, "Caught IOException!" );
454 catch ( embed::StorageWrappedTargetException
const & )
456 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
458 // catch ( packages::WrongPasswordException const & )
460 // // the key provided is wrong; rethrow; to be handled by caller.
464 return uno::Reference
< io::XOutputStream
>();
468 uno::Reference
< io::XStream
>
469 ContentProvider::queryStream( const OUString
& rUri
,
470 const OUString
& rPassword
,
471 bool bTruncate
) const
473 if ( m_xStgElemFac
.is() )
477 return m_xStgElemFac
->createStream( rUri
, rPassword
, bTruncate
);
479 catch ( embed::InvalidStorageException
const & )
481 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
483 catch ( lang::IllegalArgumentException
const & )
485 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
487 catch ( io::IOException
const & )
489 // Okay to happen, for instance when the storage does not exist.
490 //OSL_ENSURE( false, "Caught IOException!" );
492 catch ( embed::StorageWrappedTargetException
const & )
494 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
496 // catch ( packages::WrongPasswordException const & )
498 // // the key provided is wrong; rethrow; to be handled by caller.
502 return uno::Reference
< io::XStream
>();
506 bool ContentProvider::queryNamesOfChildren(
507 const OUString
& rUri
, uno::Sequence
< OUString
> & rNames
) const
512 // special handling for root, which has no storage, but children.
513 if ( m_xDocsMgr
.is() )
515 rNames
= m_xDocsMgr
->queryDocuments();
521 if ( m_xStgElemFac
.is() )
525 uno::Reference
< embed::XStorage
> xStorage
526 = m_xStgElemFac
->createStorage( rUri
, READ
);
528 OSL_ENSURE( xStorage
.is(), "Got no Storage!" );
532 rNames
= xStorage
->getElementNames();
536 catch ( embed::InvalidStorageException
const & )
538 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
540 catch ( lang::IllegalArgumentException
const & )
542 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
544 catch ( io::IOException
const & )
546 // Okay to happen, for instance if the storage does not exist.
547 //OSL_ENSURE( false, "Caught IOException!" );
549 catch ( embed::StorageWrappedTargetException
const & )
551 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
560 ContentProvider::queryStorageTitle( const OUString
& rUri
) const
570 else if ( aUri
.isDocument() )
572 // for documents, title shall not be derived from URL. It shall
573 // be something more 'speaking' than just the document UID.
574 if ( m_xDocsMgr
.is() )
575 aTitle
= m_xDocsMgr
->queryStorageTitle( aUri
.getDocumentId() );
579 // derive title from URL
580 aTitle
= aUri
.getDecodedName();
583 OSL_ENSURE( !aTitle
.isEmpty() || aUri
.isRoot(),
584 "ContentProvider::queryStorageTitle - empty title!" );
589 uno::Reference
< frame::XModel
>
590 ContentProvider::queryDocumentModel( const OUString
& rUri
) const
592 uno::Reference
< frame::XModel
> xModel
;
594 if ( m_xDocsMgr
.is() )
597 xModel
= m_xDocsMgr
->queryDocumentModel( aUri
.getDocumentId() );
600 OSL_ENSURE( xModel
.is(),
601 "ContentProvider::queryDocumentModel - no model!" );
605 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */