lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / ucbhelper / source / provider / providerhelper.cxx
blob766c6ebd3dd5f07050fc1f2021549b223d90ee32
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <sal/config.h>
22 #include <com/sun/star/beans/IllegalTypeException.hpp>
23 #include <com/sun/star/beans/PropertyExistException.hpp>
24 #include <com/sun/star/beans/XPropertyAccess.hpp>
25 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <com/sun/star/container/XNamed.hpp>
27 #include <com/sun/star/ucb/Store.hpp>
28 #include <com/sun/star/ucb/XPropertySetRegistry.hpp>
29 #include <com/sun/star/ucb/XPropertySetRegistryFactory.hpp>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <cppuhelper/queryinterface.hxx>
32 #include <ucbhelper/contenthelper.hxx>
33 #include <ucbhelper/contentidentifier.hxx>
34 #include <ucbhelper/providerhelper.hxx>
35 #include <ucbhelper/macros.hxx>
37 #include <osl/diagnose.h>
38 #include <osl/mutex.hxx>
39 #include <cppuhelper/weakref.hxx>
41 #include <unordered_map>
43 using namespace com::sun::star;
45 namespace ucbhelper_impl
48 typedef std::unordered_map
50 OUString,
51 uno::WeakReference< ucb::XContent >
53 Contents;
55 struct ContentProviderImplHelper_Impl
57 uno::Reference< css::ucb::XPropertySetRegistry > m_xPropertySetRegistry;
58 Contents m_aContents;
61 } // namespace ucbhelper_impl
63 namespace ucbhelper {
65 ContentProviderImplHelper::ContentProviderImplHelper(
66 const uno::Reference< uno::XComponentContext >& rxContext )
67 : m_pImpl( new ucbhelper_impl::ContentProviderImplHelper_Impl ),
68 m_xContext( rxContext )
72 // virtual
73 ContentProviderImplHelper::~ContentProviderImplHelper()
77 // XInterface
78 void SAL_CALL ContentProviderImplHelper::acquire()
79 throw()
81 OWeakObject::acquire();
84 void SAL_CALL ContentProviderImplHelper::release()
85 throw()
87 OWeakObject::release();
90 css::uno::Any SAL_CALL ContentProviderImplHelper::queryInterface( const css::uno::Type & rType )
92 css::uno::Any aRet = cppu::queryInterface( rType,
93 static_cast< lang::XTypeProvider* >(this),
94 static_cast< lang::XServiceInfo* >(this),
95 static_cast< css::ucb::XContentProvider* >(this)
97 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
100 XTYPEPROVIDER_IMPL_3( ContentProviderImplHelper,
101 lang::XTypeProvider,
102 lang::XServiceInfo,
103 css::ucb::XContentProvider );
105 // virtual
106 sal_Bool SAL_CALL ContentProviderImplHelper::supportsService(
107 const OUString& ServiceName )
109 return cppu::supportsService(this, ServiceName);
112 // virtual
113 sal_Int32 SAL_CALL ContentProviderImplHelper::compareContentIds(
114 const uno::Reference< css::ucb::XContentIdentifier >& Id1,
115 const uno::Reference< css::ucb::XContentIdentifier >& Id2 )
117 // Simply do a string compare.
119 OUString aURL1( Id1->getContentIdentifier() );
120 OUString aURL2( Id2->getContentIdentifier() );
122 return aURL1.compareTo( aURL2 );
125 void ContentProviderImplHelper::cleanupRegisteredContents()
127 osl::MutexGuard aGuard( m_aMutex );
129 ucbhelper_impl::Contents::iterator it
130 = m_pImpl->m_aContents.begin();
131 while( it != m_pImpl->m_aContents.end() )
133 uno::Reference< ucb::XContent > xContent( (*it).second );
134 if ( !xContent.is() )
136 ucbhelper_impl::Contents::iterator tmp = it;
137 ++it;
138 m_pImpl->m_aContents.erase( tmp );
140 else
142 ++it;
147 void ContentProviderImplHelper::removeContent( ContentImplHelper* pContent )
149 osl::MutexGuard aGuard( m_aMutex );
151 cleanupRegisteredContents();
153 const OUString aURL(
154 pContent->getIdentifier()->getContentIdentifier() );
156 ucbhelper_impl::Contents::iterator it = m_pImpl->m_aContents.find( aURL );
158 if ( it != m_pImpl->m_aContents.end() )
159 m_pImpl->m_aContents.erase( it );
162 rtl::Reference< ContentImplHelper >
163 ContentProviderImplHelper::queryExistingContent(
164 const uno::Reference< css::ucb::XContentIdentifier >& Identifier )
166 return queryExistingContent( Identifier->getContentIdentifier() );
169 rtl::Reference< ContentImplHelper >
170 ContentProviderImplHelper::queryExistingContent( const OUString& rURL )
172 osl::MutexGuard aGuard( m_aMutex );
174 cleanupRegisteredContents();
176 // Check, if a content with given id already exists...
178 ucbhelper_impl::Contents::const_iterator it
179 = m_pImpl->m_aContents.find( rURL );
180 if ( it != m_pImpl->m_aContents.end() )
182 uno::Reference< ucb::XContent > xContent( (*it).second );
183 if ( xContent.is() )
185 return rtl::Reference< ContentImplHelper >(
186 static_cast< ContentImplHelper * >( xContent.get() ) );
189 return rtl::Reference< ContentImplHelper >();
192 void ContentProviderImplHelper::queryExistingContents(
193 ContentRefList& rContents )
195 osl::MutexGuard aGuard( m_aMutex );
197 cleanupRegisteredContents();
199 for ( const auto& rContent : m_pImpl->m_aContents )
201 uno::Reference< ucb::XContent > xContent( rContent.second );
202 if ( xContent.is() )
204 rContents.emplace_back(
205 static_cast< ContentImplHelper * >( xContent.get() ) );
210 void ContentProviderImplHelper::registerNewContent(
211 const uno::Reference< ucb::XContent > & xContent )
213 if ( xContent.is() )
215 osl::MutexGuard aGuard( m_aMutex );
217 cleanupRegisteredContents();
219 const OUString aURL(
220 xContent->getIdentifier()->getContentIdentifier() );
221 ucbhelper_impl::Contents::const_iterator it
222 = m_pImpl->m_aContents.find( aURL );
223 if ( it == m_pImpl->m_aContents.end() )
224 m_pImpl->m_aContents[ aURL ] = xContent;
228 uno::Reference< css::ucb::XPropertySetRegistry >
229 ContentProviderImplHelper::getAdditionalPropertySetRegistry()
231 // Get propertyset registry.
233 osl::MutexGuard aGuard( m_aMutex );
235 if ( !m_pImpl->m_xPropertySetRegistry.is() )
237 uno::Reference< css::ucb::XPropertySetRegistryFactory >
238 xRegFac = css::ucb::Store::create( m_xContext );
240 // Open/create a registry.
241 m_pImpl->m_xPropertySetRegistry
242 = xRegFac->createPropertySetRegistry( OUString() );
244 OSL_ENSURE( m_pImpl->m_xPropertySetRegistry.is(),
245 "ContentProviderImplHelper::getAdditionalPropertySet - "
246 "Error opening registry!" );
249 return m_pImpl->m_xPropertySetRegistry;
252 uno::Reference< css::ucb::XPersistentPropertySet >
253 ContentProviderImplHelper::getAdditionalPropertySet(
254 const OUString& rKey, bool bCreate )
256 // Get propertyset registry.
257 getAdditionalPropertySetRegistry();
259 if ( m_pImpl->m_xPropertySetRegistry.is() )
261 // Open/create persistent property set.
262 return m_pImpl->m_xPropertySetRegistry->openPropertySet(
263 rKey, bCreate );
266 return uno::Reference< css::ucb::XPersistentPropertySet >();
269 bool ContentProviderImplHelper::renameAdditionalPropertySet(
270 const OUString& rOldKey,
271 const OUString& rNewKey,
272 bool bRecursive )
274 if ( rOldKey == rNewKey )
275 return true;
277 osl::MutexGuard aGuard( m_aMutex );
279 if ( bRecursive )
281 // Get propertyset registry.
282 getAdditionalPropertySetRegistry();
284 if ( m_pImpl->m_xPropertySetRegistry.is() )
286 uno::Reference< container::XNameAccess > xNameAccess(
287 m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
288 if ( xNameAccess.is() )
290 uno::Sequence< OUString > aKeys
291 = xNameAccess->getElementNames();
292 sal_Int32 nCount = aKeys.getLength();
293 if ( nCount > 0 )
295 OUString aOldKeyWithSlash = rOldKey;
296 OUString aOldKeyWithoutSlash;
297 if ( !aOldKeyWithSlash.endsWith("/") )
299 aOldKeyWithSlash += "/";
300 aOldKeyWithoutSlash = rOldKey;
302 else if ( !rOldKey.isEmpty() )
303 aOldKeyWithoutSlash
304 = rOldKey.copy( 0, rOldKey.getLength() - 1 );
306 const OUString* pKeys = aKeys.getConstArray();
307 for ( sal_Int32 n = 0; n < nCount; ++n )
309 const OUString& rKey = pKeys[ n ];
310 if ( rKey.startsWith( aOldKeyWithSlash )
311 || rKey == aOldKeyWithoutSlash )
313 OUString aNewKey
314 = rKey.replaceAt(
315 0, rOldKey.getLength(), rNewKey );
316 if ( !renameAdditionalPropertySet(
317 rKey, aNewKey, false ) )
318 return false;
323 else
324 return false;
326 else
327 return false;
329 else
331 // Get old property set, if exists.
332 uno::Reference< css::ucb::XPersistentPropertySet > xOldSet
333 = getAdditionalPropertySet( rOldKey, false );
334 if ( xOldSet.is() )
336 // Rename property set.
337 uno::Reference< container::XNamed > xNamed(
338 xOldSet, uno::UNO_QUERY );
339 if ( xNamed.is() )
341 // ??? throws no exceptions and has no return value ???
342 xNamed->setName( rNewKey );
344 else
345 return false;
348 return true;
351 bool ContentProviderImplHelper::copyAdditionalPropertySet(
352 const OUString& rSourceKey,
353 const OUString& rTargetKey,
354 bool bRecursive )
356 if ( rSourceKey == rTargetKey )
357 return true;
359 osl::MutexGuard aGuard( m_aMutex );
361 if ( bRecursive )
363 // Get propertyset registry.
364 getAdditionalPropertySetRegistry();
366 if ( m_pImpl->m_xPropertySetRegistry.is() )
368 uno::Reference< container::XNameAccess > xNameAccess(
369 m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
370 if ( xNameAccess.is() )
372 uno::Sequence< OUString > aKeys
373 = xNameAccess->getElementNames();
374 sal_Int32 nCount = aKeys.getLength();
375 if ( nCount > 0 )
377 OUString aSrcKeyWithSlash = rSourceKey;
378 OUString aSrcKeyWithoutSlash;
379 if ( !aSrcKeyWithSlash.endsWith("/") )
381 aSrcKeyWithSlash += "/";
382 aSrcKeyWithoutSlash = rSourceKey;
384 else if ( !rSourceKey.isEmpty() )
385 aSrcKeyWithoutSlash = rSourceKey.copy(
386 0, rSourceKey.getLength() - 1 );
388 const OUString* pKeys = aKeys.getConstArray();
389 for ( sal_Int32 n = 0; n < nCount; ++n )
391 const OUString& rKey = pKeys[ n ];
392 if ( rKey.startsWith(aSrcKeyWithSlash )
393 || rKey == aSrcKeyWithoutSlash )
395 OUString aNewKey
396 = rKey.replaceAt(
397 0, rSourceKey.getLength(), rTargetKey );
398 if ( !copyAdditionalPropertySet(
399 rKey, aNewKey, false ) )
400 return false;
405 else
406 return false;
408 else
409 return false;
411 else
413 // Get old property set, if exists.
414 uno::Reference< css::ucb::XPersistentPropertySet >
415 xOldPropSet = getAdditionalPropertySet( rSourceKey, false );
416 if ( !xOldPropSet.is() )
417 return false;
419 uno::Reference< beans::XPropertySetInfo > xPropSetInfo
420 = xOldPropSet->getPropertySetInfo();
421 if ( !xPropSetInfo.is() )
422 return false;
424 uno::Reference< beans::XPropertyAccess > xOldPropAccess(
425 xOldPropSet, uno::UNO_QUERY );
426 if ( !xOldPropAccess.is() )
427 return false;
429 // Obtain all values from old set.
430 uno::Sequence< beans::PropertyValue > aValues
431 = xOldPropAccess->getPropertyValues();
432 sal_Int32 nCount = aValues.getLength();
434 uno::Sequence< beans::Property > aProps
435 = xPropSetInfo->getProperties();
437 if ( nCount )
439 // Fail, if property set with new key already exists.
440 uno::Reference< css::ucb::XPersistentPropertySet >
441 xNewPropSet
442 = getAdditionalPropertySet( rTargetKey, false );
443 if ( xNewPropSet.is() )
444 return false;
446 // Create new, empty set.
447 xNewPropSet = getAdditionalPropertySet( rTargetKey, true );
448 if ( !xNewPropSet.is() )
449 return false;
451 uno::Reference< beans::XPropertyContainer > xNewPropContainer(
452 xNewPropSet, uno::UNO_QUERY );
453 if ( !xNewPropContainer.is() )
454 return false;
456 for ( sal_Int32 n = 0; n < nCount; ++n )
458 const beans::PropertyValue& rValue = aValues[ n ];
460 sal_Int16 nAttribs = 0;
461 for ( sal_Int32 m = 0; m < aProps.getLength(); ++m )
463 if ( aProps[ m ].Name == rValue.Name )
465 nAttribs = aProps[ m ].Attributes;
466 break;
472 xNewPropContainer->addProperty(
473 rValue.Name, nAttribs, rValue.Value );
475 catch ( beans::PropertyExistException & )
478 catch ( beans::IllegalTypeException & )
481 catch ( lang::IllegalArgumentException & )
487 return true;
490 bool ContentProviderImplHelper::removeAdditionalPropertySet(
491 const OUString& rKey, bool bRecursive )
493 osl::MutexGuard aGuard( m_aMutex );
495 if ( bRecursive )
497 // Get propertyset registry.
498 getAdditionalPropertySetRegistry();
500 if ( m_pImpl->m_xPropertySetRegistry.is() )
502 uno::Reference< container::XNameAccess > xNameAccess(
503 m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
504 if ( xNameAccess.is() )
506 uno::Sequence< OUString > aKeys
507 = xNameAccess->getElementNames();
508 sal_Int32 nCount = aKeys.getLength();
509 if ( nCount > 0 )
511 OUString aKeyWithSlash = rKey;
512 OUString aKeyWithoutSlash;
513 if ( !aKeyWithSlash.endsWith("/") )
515 aKeyWithSlash += "/";
516 aKeyWithoutSlash = rKey;
518 else if ( !rKey.isEmpty() )
519 aKeyWithoutSlash
520 = rKey.copy( 0, rKey.getLength() - 1 );
522 const OUString* pKeys = aKeys.getConstArray();
523 for ( sal_Int32 n = 0; n < nCount; ++n )
525 const OUString& rCurrKey = pKeys[ n ];
526 if ( rCurrKey.startsWith(aKeyWithSlash )
527 || rCurrKey == aKeyWithoutSlash )
529 if ( !removeAdditionalPropertySet(
530 rCurrKey, false ) )
531 return false;
536 else
537 return false;
539 else
540 return false;
542 else
544 // Get propertyset registry.
545 getAdditionalPropertySetRegistry();
547 if ( m_pImpl->m_xPropertySetRegistry.is() )
548 m_pImpl->m_xPropertySetRegistry->removePropertySet( rKey );
549 else
550 return false;
552 return true;
555 } // namespace ucbhelper
557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */