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 #include "imagemanagerimpl.hxx"
21 #include <xml/imagesconfiguration.hxx>
22 #include <uiconfiguration/imagetype.hxx>
23 #include <uiconfiguration/graphicnameaccess.hxx>
24 
25 #include <properties.h>
26 
27 #include <com/sun/star/frame/theUICommandDescription.hpp>
28 #include <com/sun/star/ui/ConfigurationEvent.hpp>
29 #include <com/sun/star/lang/DisposedException.hpp>
30 #include <com/sun/star/lang/IllegalAccessException.hpp>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 #include <com/sun/star/embed/ElementModes.hpp>
34 #include <com/sun/star/embed/InvalidStorageException.hpp>
35 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
36 #include <com/sun/star/io/IOException.hpp>
37 #include <com/sun/star/io/XStream.hpp>
38 #include <com/sun/star/ui/ImageType.hpp>
39 #include <vcl/graph.hxx>
40 #include <vcl/svapp.hxx>
41 #include <o3tl/enumrange.hxx>
42 #include <osl/mutex.hxx>
43 #include <comphelper/sequence.hxx>
44 #include <unotools/ucbstreamhelper.hxx>
45 #include <vcl/filter/PngImageReader.hxx>
46 #include <vcl/pngwrite.hxx>
47 #include <rtl/instance.hxx>
48 #include <memory>
49 
50 using ::com::sun::star::uno::Sequence;
51 using ::com::sun::star::uno::XInterface;
52 using ::com::sun::star::uno::RuntimeException;
53 using ::com::sun::star::uno::UNO_QUERY;
54 using ::com::sun::star::uno::Any;
55 using ::com::sun::star::graphic::XGraphic;
56 using namespace ::com::sun::star;
57 using namespace ::com::sun::star::io;
58 using namespace ::com::sun::star::embed;
59 using namespace ::com::sun::star::lang;
60 using namespace ::com::sun::star::container;
61 using namespace ::com::sun::star::beans;
62 using namespace ::com::sun::star::ui;
63 using namespace ::cppu;
64 
65 const sal_Int16 MAX_IMAGETYPE_VALUE       = css::ui::ImageType::SIZE_32;
66 
67 constexpr OUStringLiteral IMAGE_FOLDER = u"images";
68 constexpr OUStringLiteral BITMAPS_FOLDER = u"Bitmaps";
69 
70 const o3tl::enumarray<vcl::ImageType, const char*> IMAGELIST_XML_FILE =
71 {
72     "sc_imagelist.xml",
73     "lc_imagelist.xml",
74     "xc_imagelist.xml"
75 };
76 
77 const o3tl::enumarray<vcl::ImageType, const char*> BITMAP_FILE_NAMES =
78 {
79     "sc_userimages.png",
80     "lc_userimages.png",
81     "xc_userimages.png"
82 };
83 
84 namespace framework
85 {
86 
87 static GlobalImageList*     pGlobalImageList = nullptr;
88 
89 namespace
90 {
91     class theGlobalImageListMutex
92         : public rtl::Static<osl::Mutex, theGlobalImageListMutex> {};
93 }
94 
getGlobalImageListMutex()95 static osl::Mutex& getGlobalImageListMutex()
96 {
97     return theGlobalImageListMutex::get();
98 }
99 
getGlobalImageList(const uno::Reference<uno::XComponentContext> & rxContext)100 static GlobalImageList* getGlobalImageList( const uno::Reference< uno::XComponentContext >& rxContext )
101 {
102     osl::MutexGuard guard( getGlobalImageListMutex() );
103 
104     if ( pGlobalImageList == nullptr )
105         pGlobalImageList = new GlobalImageList( rxContext );
106 
107     return pGlobalImageList;
108 }
109 
CmdImageList(const uno::Reference<uno::XComponentContext> & rxContext,const OUString & aModuleIdentifier)110 CmdImageList::CmdImageList( const uno::Reference< uno::XComponentContext >& rxContext, const OUString& aModuleIdentifier ) :
111     m_bInitialized(false),
112     m_aModuleIdentifier( aModuleIdentifier ),
113     m_xContext( rxContext )
114 {
115 }
116 
~CmdImageList()117 CmdImageList::~CmdImageList()
118 {
119 }
120 
initialize()121 void CmdImageList::initialize()
122 {
123     if (m_bInitialized)
124         return;
125 
126     const OUString aCommandImageList(UICOMMANDDESCRIPTION_NAMEACCESS_COMMANDIMAGELIST);
127 
128     Sequence<OUString> aCommandImageSeq;
129     uno::Reference<XNameAccess> xCommandDesc = frame::theUICommandDescription::get(m_xContext);
130 
131     if (!m_aModuleIdentifier.isEmpty())
132     {
133         // If we have a module identifier - use to retrieve the command image name list from it.
134         // Otherwise we will use the global command image list
135         try
136         {
137             xCommandDesc->getByName(m_aModuleIdentifier) >>= xCommandDesc;
138             if (xCommandDesc.is())
139                 xCommandDesc->getByName(aCommandImageList) >>= aCommandImageSeq;
140         }
141         catch (const NoSuchElementException&)
142         {
143             // Module unknown we will work with an empty command image list!
144             return;
145         }
146     }
147 
148     if (xCommandDesc.is())
149     {
150         try
151         {
152             xCommandDesc->getByName(aCommandImageList) >>= aCommandImageSeq;
153         }
154         catch (const NoSuchElementException&)
155         {
156         }
157         catch (const WrappedTargetException&)
158         {
159         }
160     }
161 
162     m_aResolver.registerCommands(aCommandImageSeq);
163 
164     m_bInitialized = true;
165 }
166 
167 
getImageFromCommandURL(vcl::ImageType nImageType,const OUString & rCommandURL)168 Image CmdImageList::getImageFromCommandURL(vcl::ImageType nImageType, const OUString& rCommandURL)
169 {
170     initialize();
171     return m_aResolver.getImageFromCommandURL(nImageType, rCommandURL);
172 }
173 
hasImage(vcl::ImageType,const OUString & rCommandURL)174 bool CmdImageList::hasImage(vcl::ImageType /*nImageType*/, const OUString& rCommandURL)
175 {
176     initialize();
177     return m_aResolver.hasImage(rCommandURL);
178 }
179 
getImageCommandNames()180 std::vector<OUString>& CmdImageList::getImageCommandNames()
181 {
182     return m_aResolver.getCommandNames();
183 }
184 
GlobalImageList(const uno::Reference<uno::XComponentContext> & rxContext)185 GlobalImageList::GlobalImageList( const uno::Reference< uno::XComponentContext >& rxContext ) :
186     CmdImageList( rxContext, OUString() )
187 {
188 }
189 
~GlobalImageList()190 GlobalImageList::~GlobalImageList()
191 {
192     osl::MutexGuard guard( getGlobalImageListMutex() );
193     // remove global pointer as we destroy the object now
194     pGlobalImageList = nullptr;
195 }
196 
getImageFromCommandURL(vcl::ImageType nImageType,const OUString & rCommandURL)197 Image GlobalImageList::getImageFromCommandURL( vcl::ImageType nImageType, const OUString& rCommandURL )
198 {
199     osl::MutexGuard guard( getGlobalImageListMutex() );
200     return CmdImageList::getImageFromCommandURL( nImageType, rCommandURL );
201 }
202 
hasImage(vcl::ImageType nImageType,const OUString & rCommandURL)203 bool GlobalImageList::hasImage( vcl::ImageType nImageType, const OUString& rCommandURL )
204 {
205     osl::MutexGuard guard( getGlobalImageListMutex() );
206     return CmdImageList::hasImage( nImageType, rCommandURL );
207 }
208 
getImageCommandNames()209 ::std::vector< OUString >& GlobalImageList::getImageCommandNames()
210 {
211     osl::MutexGuard guard( getGlobalImageListMutex() );
212     return CmdImageList::getImageCommandNames();
213 }
214 
implts_checkAndScaleGraphic(uno::Reference<XGraphic> & rOutGraphic,const uno::Reference<XGraphic> & rInGraphic,vcl::ImageType nImageType)215 static bool implts_checkAndScaleGraphic( uno::Reference< XGraphic >& rOutGraphic, const uno::Reference< XGraphic >& rInGraphic, vcl::ImageType nImageType )
216 {
217     if ( !rInGraphic.is() )
218     {
219         rOutGraphic = uno::Reference<graphic::XGraphic>();
220         return false;
221     }
222 
223     static const o3tl::enumarray<vcl::ImageType, Size> BITMAP_SIZE =
224     {
225         Size(16, 16), Size(24, 24), Size(32, 32)
226     };
227 
228     // Check size and scale it
229     Graphic aImage(rInGraphic);
230     if (BITMAP_SIZE[nImageType] != aImage.GetSizePixel())
231     {
232         BitmapEx aBitmap = aImage.GetBitmapEx();
233         aBitmap.Scale(BITMAP_SIZE[nImageType]);
234         aImage = Graphic(aBitmap);
235         rOutGraphic = aImage.GetXGraphic();
236     }
237     else
238         rOutGraphic = rInGraphic;
239 
240     return true;
241 }
242 
implts_convertImageTypeToIndex(sal_Int16 nImageType)243 static vcl::ImageType implts_convertImageTypeToIndex( sal_Int16 nImageType )
244 {
245     if (nImageType & css::ui::ImageType::SIZE_LARGE)
246         return vcl::ImageType::Size26;
247     else if (nImageType & css::ui::ImageType::SIZE_32)
248         return vcl::ImageType::Size32;
249     else
250         return vcl::ImageType::Size16;
251 }
252 
implts_getUserImageList(vcl::ImageType nImageType)253 ImageList* ImageManagerImpl::implts_getUserImageList( vcl::ImageType nImageType )
254 {
255     SolarMutexGuard g;
256     if ( !m_pUserImageList[nImageType] )
257         implts_loadUserImages( nImageType, m_xUserImageStorage, m_xUserBitmapsStorage );
258 
259     return m_pUserImageList[nImageType].get();
260 }
261 
implts_initialize()262 void ImageManagerImpl::implts_initialize()
263 {
264     // Initialize the top-level structures with the storage data
265     if ( !m_xUserConfigStorage.is() )
266         return;
267 
268     tools::Long nModes = m_bReadOnly ? ElementModes::READ : ElementModes::READWRITE;
269 
270     try
271     {
272         m_xUserImageStorage = m_xUserConfigStorage->openStorageElement( IMAGE_FOLDER,
273                                                                         nModes );
274         if ( m_xUserImageStorage.is() )
275         {
276             m_xUserBitmapsStorage = m_xUserImageStorage->openStorageElement( BITMAPS_FOLDER,
277                                                                              nModes );
278         }
279     }
280     catch ( const css::container::NoSuchElementException& )
281     {
282     }
283     catch ( const css::embed::InvalidStorageException& )
284     {
285     }
286     catch ( const css::lang::IllegalArgumentException& )
287     {
288     }
289     catch ( const css::io::IOException& )
290     {
291     }
292     catch ( const css::embed::StorageWrappedTargetException& )
293     {
294     }
295 }
296 
implts_loadUserImages(vcl::ImageType nImageType,const uno::Reference<XStorage> & xUserImageStorage,const uno::Reference<XStorage> & xUserBitmapsStorage)297 void ImageManagerImpl::implts_loadUserImages(
298     vcl::ImageType nImageType,
299     const uno::Reference< XStorage >& xUserImageStorage,
300     const uno::Reference< XStorage >& xUserBitmapsStorage )
301 {
302     SolarMutexGuard g;
303 
304     if ( xUserImageStorage.is() && xUserBitmapsStorage.is() )
305     {
306         try
307         {
308             uno::Reference< XStream > xStream = xUserImageStorage->openStreamElement( OUString::createFromAscii( IMAGELIST_XML_FILE[nImageType] ),
309                                                                                       ElementModes::READ );
310             uno::Reference< XInputStream > xInputStream = xStream->getInputStream();
311 
312             ImageItemDescriptorList aUserImageListInfo;
313             ImagesConfiguration::LoadImages( m_xContext,
314                                              xInputStream,
315                                              aUserImageListInfo );
316             if ( !aUserImageListInfo.empty() )
317             {
318                 sal_Int32 nCount = aUserImageListInfo.size();
319                 std::vector< OUString > aUserImagesVector;
320                 aUserImagesVector.reserve(nCount);
321                 for ( sal_Int32 i=0; i < nCount; i++ )
322                 {
323                     const ImageItemDescriptor& rItem = aUserImageListInfo[i];
324                     aUserImagesVector.push_back( rItem.aCommandURL );
325                 }
326 
327                 uno::Reference< XStream > xBitmapStream = xUserBitmapsStorage->openStreamElement(
328                                                         OUString::createFromAscii( BITMAP_FILE_NAMES[nImageType] ),
329                                                         ElementModes::READ );
330 
331                 if ( xBitmapStream.is() )
332                 {
333                     BitmapEx aUserBitmap;
334                     {
335                         std::unique_ptr<SvStream> pSvStream(utl::UcbStreamHelper::CreateStream( xBitmapStream ));
336                         vcl::PngImageReader aPngReader( *pSvStream );
337                         aUserBitmap = aPngReader.read();
338                     }
339 
340                     // Delete old image list and create a new one from the read bitmap
341                     m_pUserImageList[nImageType].reset(new ImageList());
342                     m_pUserImageList[nImageType]->InsertFromHorizontalStrip
343                         ( aUserBitmap, aUserImagesVector );
344                     return;
345                 }
346             }
347         }
348         catch ( const css::container::NoSuchElementException& )
349         {
350         }
351         catch ( const css::embed::InvalidStorageException& )
352         {
353         }
354         catch ( const css::lang::IllegalArgumentException& )
355         {
356         }
357         catch ( const css::io::IOException& )
358         {
359         }
360         catch ( const css::embed::StorageWrappedTargetException& )
361         {
362         }
363     }
364 
365     // Destroy old image list - create a new empty one
366     m_pUserImageList[nImageType].reset(new ImageList);
367 }
368 
implts_storeUserImages(vcl::ImageType nImageType,const uno::Reference<XStorage> & xUserImageStorage,const uno::Reference<XStorage> & xUserBitmapsStorage)369 bool ImageManagerImpl::implts_storeUserImages(
370     vcl::ImageType nImageType,
371     const uno::Reference< XStorage >& xUserImageStorage,
372     const uno::Reference< XStorage >& xUserBitmapsStorage )
373 {
374     SolarMutexGuard g;
375 
376     if ( m_bModified )
377     {
378         ImageList* pImageList = implts_getUserImageList( nImageType );
379         if ( pImageList->GetImageCount() > 0 )
380         {
381             ImageItemDescriptorList aUserImageListInfo;
382 
383             for ( sal_uInt16 i=0; i < pImageList->GetImageCount(); i++ )
384             {
385                 ImageItemDescriptor aItem;
386                 aItem.aCommandURL = pImageList->GetImageName( i );
387                 aUserImageListInfo.push_back( aItem );
388             }
389 
390             uno::Reference< XTransactedObject > xTransaction;
391             uno::Reference< XOutputStream >     xOutputStream;
392             uno::Reference< XStream > xStream = xUserImageStorage->openStreamElement( OUString::createFromAscii( IMAGELIST_XML_FILE[nImageType] ),
393                                                                                       ElementModes::WRITE|ElementModes::TRUNCATE );
394             if ( xStream.is() )
395             {
396                 uno::Reference< XStream > xBitmapStream =
397                     xUserBitmapsStorage->openStreamElement( OUString::createFromAscii( BITMAP_FILE_NAMES[nImageType] ),
398                                                             ElementModes::WRITE|ElementModes::TRUNCATE );
399                 if ( xBitmapStream.is() )
400                 {
401                     {
402                         std::unique_ptr<SvStream> pSvStream(utl::UcbStreamHelper::CreateStream( xBitmapStream ));
403                         vcl::PNGWriter aPngWriter( pImageList->GetAsHorizontalStrip() );
404                         aPngWriter.Write( *pSvStream );
405                     }
406 
407                     // Commit user bitmaps storage
408                     xTransaction.set( xUserBitmapsStorage, UNO_QUERY );
409                     if ( xTransaction.is() )
410                         xTransaction->commit();
411                 }
412 
413                 xOutputStream = xStream->getOutputStream();
414                 if ( xOutputStream.is() )
415                     ImagesConfiguration::StoreImages( m_xContext, xOutputStream, aUserImageListInfo );
416 
417                 // Commit user image storage
418                 xTransaction.set( xUserImageStorage, UNO_QUERY );
419                 if ( xTransaction.is() )
420                     xTransaction->commit();
421             }
422 
423             return true;
424         }
425         else
426         {
427             // Remove the streams from the storage, if we have no data. We have to catch
428             // the NoSuchElementException as it can be possible that there is no stream at all!
429             try
430             {
431                 xUserImageStorage->removeElement( OUString::createFromAscii( IMAGELIST_XML_FILE[nImageType] ));
432             }
433             catch ( const css::container::NoSuchElementException& )
434             {
435             }
436 
437             try
438             {
439                 xUserBitmapsStorage->removeElement( OUString::createFromAscii( BITMAP_FILE_NAMES[nImageType] ));
440             }
441             catch ( const css::container::NoSuchElementException& )
442             {
443             }
444 
445             uno::Reference< XTransactedObject > xTransaction;
446 
447             // Commit user image storage
448             xTransaction.set( xUserImageStorage, UNO_QUERY );
449             if ( xTransaction.is() )
450                 xTransaction->commit();
451 
452             // Commit user bitmaps storage
453             xTransaction.set( xUserBitmapsStorage, UNO_QUERY );
454             if ( xTransaction.is() )
455                 xTransaction->commit();
456 
457             return true;
458         }
459     }
460 
461     return false;
462 }
463 
implts_getGlobalImageList()464 const rtl::Reference< GlobalImageList >& ImageManagerImpl::implts_getGlobalImageList()
465 {
466     SolarMutexGuard g;
467 
468     if ( !m_pGlobalImageList.is() )
469         m_pGlobalImageList = getGlobalImageList( m_xContext );
470     return m_pGlobalImageList;
471 }
472 
implts_getDefaultImageList()473 CmdImageList* ImageManagerImpl::implts_getDefaultImageList()
474 {
475     SolarMutexGuard g;
476 
477     if ( !m_pDefaultImageList )
478         m_pDefaultImageList.reset(new CmdImageList( m_xContext, m_aModuleIdentifier ));
479 
480     return m_pDefaultImageList.get();
481 }
482 
ImageManagerImpl(const uno::Reference<uno::XComponentContext> & rxContext,::cppu::OWeakObject * pOwner,bool _bUseGlobal)483 ImageManagerImpl::ImageManagerImpl( const uno::Reference< uno::XComponentContext >& rxContext,::cppu::OWeakObject* pOwner,bool _bUseGlobal ) :
484     m_xContext( rxContext )
485     , m_pOwner(pOwner)
486     , m_aResourceString( "private:resource/images/moduleimages" )
487     , m_aListenerContainer( m_mutex )
488     , m_bUseGlobal(_bUseGlobal)
489     , m_bReadOnly( true )
490     , m_bInitialized( false )
491     , m_bModified( false )
492     , m_bDisposed( false )
493 {
494     for ( vcl::ImageType n : o3tl::enumrange<vcl::ImageType>() )
495     {
496         m_pUserImageList[n] = nullptr;
497         m_bUserImageListModified[n] = false;
498     }
499 }
500 
~ImageManagerImpl()501 ImageManagerImpl::~ImageManagerImpl()
502 {
503     clear();
504 }
505 
dispose()506 void ImageManagerImpl::dispose()
507 {
508     uno::Reference< uno::XInterface > xOwner(m_pOwner);
509     css::lang::EventObject aEvent( xOwner );
510     m_aListenerContainer.disposeAndClear( aEvent );
511 
512     {
513         SolarMutexGuard g;
514         m_xUserConfigStorage.clear();
515         m_xUserImageStorage.clear();
516         m_xUserRootCommit.clear();
517         m_bModified = false;
518         m_bDisposed = true;
519 
520         // delete user and default image list on dispose
521         for (auto& n : m_pUserImageList)
522         {
523             n.reset();
524         }
525         m_pDefaultImageList.reset();
526     }
527 
528 }
addEventListener(const uno::Reference<XEventListener> & xListener)529 void ImageManagerImpl::addEventListener( const uno::Reference< XEventListener >& xListener )
530 {
531     {
532         SolarMutexGuard g;
533 
534         /* SAFE AREA ----------------------------------------------------------------------------------------------- */
535         if ( m_bDisposed )
536             throw DisposedException();
537     }
538 
539     m_aListenerContainer.addInterface( cppu::UnoType<XEventListener>::get(), xListener );
540 }
541 
removeEventListener(const uno::Reference<XEventListener> & xListener)542 void ImageManagerImpl::removeEventListener( const uno::Reference< XEventListener >& xListener )
543 {
544     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
545     m_aListenerContainer.removeInterface( cppu::UnoType<XEventListener>::get(), xListener );
546 }
547 
548 // XInitialization
initialize(const Sequence<Any> & aArguments)549 void ImageManagerImpl::initialize( const Sequence< Any >& aArguments )
550 {
551     SolarMutexGuard g;
552 
553     if ( m_bInitialized )
554         return;
555 
556     for ( const Any& rArg : aArguments )
557     {
558         PropertyValue aPropValue;
559         if ( rArg >>= aPropValue )
560         {
561             if ( aPropValue.Name == "UserConfigStorage" )
562             {
563                 aPropValue.Value >>= m_xUserConfigStorage;
564             }
565             else if ( aPropValue.Name == "ModuleIdentifier" )
566             {
567                 aPropValue.Value >>= m_aModuleIdentifier;
568             }
569             else if ( aPropValue.Name == "UserRootCommit" )
570             {
571                 aPropValue.Value >>= m_xUserRootCommit;
572             }
573         }
574     }
575 
576     if ( m_xUserConfigStorage.is() )
577     {
578         uno::Reference< XPropertySet > xPropSet( m_xUserConfigStorage, UNO_QUERY );
579         if ( xPropSet.is() )
580         {
581             tools::Long nOpenMode = 0;
582             if ( xPropSet->getPropertyValue("OpenMode") >>= nOpenMode )
583                 m_bReadOnly = !( nOpenMode & ElementModes::WRITE );
584         }
585     }
586 
587     implts_initialize();
588 
589     m_bInitialized = true;
590 }
591 
592 // XImageManagerImpl
reset()593 void ImageManagerImpl::reset()
594 {
595     SolarMutexGuard g;
596 
597     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
598     if ( m_bDisposed )
599         throw DisposedException();
600 
601     std::vector< OUString > aUserImageNames;
602 
603     for ( vcl::ImageType i : o3tl::enumrange<vcl::ImageType>() )
604     {
605         aUserImageNames.clear();
606         ImageList* pImageList = implts_getUserImageList(i);
607         pImageList->GetImageNames( aUserImageNames );
608 
609         Sequence< OUString > aRemoveList( comphelper::containerToSequence(aUserImageNames) );
610 
611         // Remove images
612         removeImages( sal_Int16( i ), aRemoveList );
613         m_bUserImageListModified[i] = true;
614     }
615 
616     m_bModified = true;
617 }
618 
getAllImageNames(::sal_Int16 nImageType)619 Sequence< OUString > ImageManagerImpl::getAllImageNames( ::sal_Int16 nImageType )
620 {
621     SolarMutexGuard g;
622 
623     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
624     if ( m_bDisposed )
625         throw DisposedException();
626 
627     ImageNameMap aImageCmdNameMap;
628 
629     vcl::ImageType nIndex = implts_convertImageTypeToIndex( nImageType );
630 
631     sal_uInt32 i( 0 );
632     if ( m_bUseGlobal )
633     {
634         rtl::Reference< GlobalImageList > rGlobalImageList = implts_getGlobalImageList();
635 
636         const std::vector< OUString >& rGlobalImageNameVector = rGlobalImageList->getImageCommandNames();
637         const sal_uInt32 nGlobalCount = rGlobalImageNameVector.size();
638         for ( i = 0; i < nGlobalCount; i++ )
639             aImageCmdNameMap.emplace( rGlobalImageNameVector[i], true );
640 
641         const std::vector< OUString >& rModuleImageNameVector = implts_getDefaultImageList()->getImageCommandNames();
642         const sal_uInt32 nModuleCount = rModuleImageNameVector.size();
643         for ( i = 0; i < nModuleCount; i++ )
644             aImageCmdNameMap.emplace( rModuleImageNameVector[i], true );
645     }
646 
647     ImageList* pImageList = implts_getUserImageList(nIndex);
648     std::vector< OUString > rUserImageNames;
649     pImageList->GetImageNames( rUserImageNames );
650     const sal_uInt32 nUserCount = rUserImageNames.size();
651     for ( i = 0; i < nUserCount; i++ )
652         aImageCmdNameMap.emplace( rUserImageNames[i], true );
653 
654     return comphelper::mapKeysToSequence( aImageCmdNameMap );
655 }
656 
hasImage(::sal_Int16 nImageType,const OUString & aCommandURL)657 bool ImageManagerImpl::hasImage( ::sal_Int16 nImageType, const OUString& aCommandURL )
658 {
659     SolarMutexGuard g;
660 
661     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
662     if ( m_bDisposed )
663         throw DisposedException();
664 
665     if (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE ))
666         throw IllegalArgumentException();
667 
668     vcl::ImageType nIndex = implts_convertImageTypeToIndex( nImageType );
669     if ( m_bUseGlobal && implts_getGlobalImageList()->hasImage( nIndex, aCommandURL ))
670         return true;
671     else
672     {
673         if ( m_bUseGlobal && implts_getDefaultImageList()->hasImage( nIndex, aCommandURL ))
674             return true;
675         else
676         {
677             // User layer
678             ImageList* pImageList = implts_getUserImageList(nIndex);
679             if ( pImageList )
680                 return ( pImageList->GetImagePos( aCommandURL ) != IMAGELIST_IMAGE_NOTFOUND );
681         }
682     }
683 
684     return false;
685 }
686 
687 namespace
688 {
GetXGraphic(const Image & rImage)689     css::uno::Reference< css::graphic::XGraphic > GetXGraphic(const Image &rImage)
690     {
691         return Graphic(rImage).GetXGraphic();
692     }
693 }
694 
getImages(::sal_Int16 nImageType,const Sequence<OUString> & aCommandURLSequence)695 Sequence< uno::Reference< XGraphic > > ImageManagerImpl::getImages(
696     ::sal_Int16 nImageType,
697     const Sequence< OUString >& aCommandURLSequence )
698 {
699     SolarMutexGuard g;
700 
701     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
702     if ( m_bDisposed )
703         throw DisposedException();
704 
705     if (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE ))
706         throw IllegalArgumentException();
707 
708     Sequence< uno::Reference< XGraphic > > aGraphSeq( aCommandURLSequence.getLength() );
709 
710     vcl::ImageType                    nIndex            = implts_convertImageTypeToIndex( nImageType );
711     rtl::Reference< GlobalImageList > rGlobalImageList;
712     CmdImageList*                     pDefaultImageList = nullptr;
713     if ( m_bUseGlobal )
714     {
715         rGlobalImageList  = implts_getGlobalImageList();
716         pDefaultImageList = implts_getDefaultImageList();
717     }
718     ImageList*                        pUserImageList    = implts_getUserImageList(nIndex);
719 
720     // We have to search our image list in the following order:
721     // 1. user image list (read/write)
722     // 2. module image list (read)
723     // 3. global image list (read)
724     sal_Int32 n = 0;
725     for ( const OUString& rURL : aCommandURLSequence )
726     {
727         Image aImage = pUserImageList->GetImage( rURL );
728         if ( !aImage && m_bUseGlobal )
729         {
730             aImage = pDefaultImageList->getImageFromCommandURL( nIndex, rURL );
731             if ( !aImage )
732                 aImage = rGlobalImageList->getImageFromCommandURL( nIndex, rURL );
733         }
734 
735         aGraphSeq[n++] = GetXGraphic(aImage);
736     }
737 
738     return aGraphSeq;
739 }
740 
replaceImages(::sal_Int16 nImageType,const Sequence<OUString> & aCommandURLSequence,const Sequence<uno::Reference<XGraphic>> & aGraphicsSequence)741 void ImageManagerImpl::replaceImages(
742     ::sal_Int16 nImageType,
743     const Sequence< OUString >& aCommandURLSequence,
744     const Sequence< uno::Reference< XGraphic > >& aGraphicsSequence )
745 {
746     rtl::Reference<GraphicNameAccess> pInsertedImages;
747     rtl::Reference<GraphicNameAccess> pReplacedImages;
748 
749     {
750         SolarMutexGuard g;
751 
752         /* SAFE AREA ----------------------------------------------------------------------------------------------- */
753         if ( m_bDisposed )
754             throw DisposedException();
755 
756         if (( aCommandURLSequence.getLength() != aGraphicsSequence.getLength() ) ||
757             (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE )))
758             throw IllegalArgumentException();
759 
760         if ( m_bReadOnly )
761             throw IllegalAccessException();
762 
763         vcl::ImageType nIndex = implts_convertImageTypeToIndex( nImageType );
764         ImageList* pImageList = implts_getUserImageList(nIndex);
765 
766         uno::Reference< XGraphic > xGraphic;
767         for ( sal_Int32 i = 0; i < aCommandURLSequence.getLength(); i++ )
768         {
769             // Check size and scale. If we don't have any graphics ignore it
770             if ( !implts_checkAndScaleGraphic( xGraphic, aGraphicsSequence[i], nIndex ))
771                 continue;
772 
773             sal_uInt16 nPos = pImageList->GetImagePos( aCommandURLSequence[i] );
774             if ( nPos == IMAGELIST_IMAGE_NOTFOUND )
775             {
776                 pImageList->AddImage(aCommandURLSequence[i], Image(xGraphic));
777                 if ( !pInsertedImages )
778                     pInsertedImages = new GraphicNameAccess();
779                 pInsertedImages->addElement( aCommandURLSequence[i], xGraphic );
780             }
781             else
782             {
783                 pImageList->ReplaceImage(aCommandURLSequence[i], Image(xGraphic));
784                 if ( !pReplacedImages )
785                     pReplacedImages = new GraphicNameAccess();
786                 pReplacedImages->addElement( aCommandURLSequence[i], xGraphic );
787             }
788         }
789 
790         if (( pInsertedImages != nullptr ) || (  pReplacedImages != nullptr ))
791         {
792             m_bModified = true;
793             m_bUserImageListModified[nIndex] = true;
794         }
795     }
796 
797     uno::Reference< uno::XInterface > xOwner(m_pOwner);
798     // Notify listeners
799     if ( pInsertedImages != nullptr )
800     {
801         ConfigurationEvent aInsertEvent;
802         aInsertEvent.aInfo           <<= nImageType;
803         aInsertEvent.Accessor        <<= xOwner;
804         aInsertEvent.Source          = xOwner;
805         aInsertEvent.ResourceURL     = m_aResourceString;
806         aInsertEvent.Element         <<= uno::Reference< XNameAccess >(pInsertedImages);
807         implts_notifyContainerListener( aInsertEvent, NotifyOp_Insert );
808     }
809     if ( pReplacedImages != nullptr )
810     {
811         ConfigurationEvent aReplaceEvent;
812         aReplaceEvent.aInfo           <<= nImageType;
813         aReplaceEvent.Accessor        <<= xOwner;
814         aReplaceEvent.Source          = xOwner;
815         aReplaceEvent.ResourceURL     = m_aResourceString;
816         aReplaceEvent.ReplacedElement = Any();
817         aReplaceEvent.Element         <<= uno::Reference< XNameAccess >(pReplacedImages);
818         implts_notifyContainerListener( aReplaceEvent, NotifyOp_Replace );
819     }
820 }
821 
removeImages(::sal_Int16 nImageType,const Sequence<OUString> & aCommandURLSequence)822 void ImageManagerImpl::removeImages( ::sal_Int16 nImageType, const Sequence< OUString >& aCommandURLSequence )
823 {
824     rtl::Reference<GraphicNameAccess> pRemovedImages;
825     rtl::Reference<GraphicNameAccess> pReplacedImages;
826 
827     {
828         SolarMutexGuard g;
829 
830         /* SAFE AREA ----------------------------------------------------------------------------------------------- */
831         if ( m_bDisposed )
832             throw DisposedException();
833 
834         if (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE ))
835             throw IllegalArgumentException();
836 
837         if ( m_bReadOnly )
838             throw IllegalAccessException();
839 
840         vcl::ImageType nIndex = implts_convertImageTypeToIndex( nImageType );
841         rtl::Reference< GlobalImageList > rGlobalImageList;
842         CmdImageList*                     pDefaultImageList = nullptr;
843         if ( m_bUseGlobal )
844         {
845             rGlobalImageList  = implts_getGlobalImageList();
846             pDefaultImageList = implts_getDefaultImageList();
847         }
848         ImageList*                        pImageList        = implts_getUserImageList(nIndex);
849         uno::Reference<XGraphic> xEmptyGraphic;
850 
851         for ( const OUString& rURL : aCommandURLSequence )
852         {
853             sal_uInt16 nPos = pImageList->GetImagePos( rURL );
854             if ( nPos != IMAGELIST_IMAGE_NOTFOUND )
855             {
856                 sal_uInt16 nId   = pImageList->GetImageId( nPos );
857                 pImageList->RemoveImage( nId );
858 
859                 if ( m_bUseGlobal )
860                 {
861                     // Check, if we have an image in our module/global image list. If we find one =>
862                     // this is a replace instead of a remove operation!
863                     Image aNewImage = pDefaultImageList->getImageFromCommandURL( nIndex, rURL );
864                     if ( !aNewImage )
865                         aNewImage = rGlobalImageList->getImageFromCommandURL( nIndex, rURL );
866                     if ( !aNewImage )
867                     {
868                         if ( !pRemovedImages )
869                             pRemovedImages = new GraphicNameAccess();
870                         pRemovedImages->addElement( rURL, xEmptyGraphic );
871                     }
872                     else
873                     {
874                         if ( !pReplacedImages )
875                             pReplacedImages = new GraphicNameAccess();
876                         pReplacedImages->addElement(rURL, GetXGraphic(aNewImage));
877                     }
878                 } // if ( m_bUseGlobal )
879                 else
880                 {
881                     if ( !pRemovedImages )
882                         pRemovedImages = new GraphicNameAccess();
883                     pRemovedImages->addElement( rURL, xEmptyGraphic );
884                 }
885             }
886         }
887 
888         if (( pReplacedImages != nullptr ) || ( pRemovedImages != nullptr ))
889         {
890             m_bModified = true;
891             m_bUserImageListModified[nIndex] = true;
892         }
893     }
894 
895     // Notify listeners
896     uno::Reference< uno::XInterface > xOwner(m_pOwner);
897     if ( pRemovedImages != nullptr )
898     {
899         ConfigurationEvent aRemoveEvent;
900         aRemoveEvent.aInfo           <<= nImageType;
901         aRemoveEvent.Accessor        <<= xOwner;
902         aRemoveEvent.Source          = xOwner;
903         aRemoveEvent.ResourceURL     = m_aResourceString;
904         aRemoveEvent.Element         <<= uno::Reference< XNameAccess >(pRemovedImages);
905         implts_notifyContainerListener( aRemoveEvent, NotifyOp_Remove );
906     }
907     if ( pReplacedImages != nullptr )
908     {
909         ConfigurationEvent aReplaceEvent;
910         aReplaceEvent.aInfo           <<= nImageType;
911         aReplaceEvent.Accessor        <<= xOwner;
912         aReplaceEvent.Source          = xOwner;
913         aReplaceEvent.ResourceURL     = m_aResourceString;
914         aReplaceEvent.ReplacedElement = Any();
915         aReplaceEvent.Element         <<= uno::Reference< XNameAccess >(pReplacedImages);
916         implts_notifyContainerListener( aReplaceEvent, NotifyOp_Replace );
917     }
918 }
919 
insertImages(::sal_Int16 nImageType,const Sequence<OUString> & aCommandURLSequence,const Sequence<uno::Reference<XGraphic>> & aGraphicSequence)920 void ImageManagerImpl::insertImages( ::sal_Int16 nImageType, const Sequence< OUString >& aCommandURLSequence, const Sequence< uno::Reference< XGraphic > >& aGraphicSequence )
921 {
922     replaceImages(nImageType,aCommandURLSequence,aGraphicSequence);
923 }
924 
925 // XUIConfigurationPersistence
reload()926 void ImageManagerImpl::reload()
927 {
928     SolarMutexResettableGuard aGuard;
929 
930     if ( m_bDisposed )
931         throw DisposedException();
932 
933     CommandMap                   aOldUserCmdImageSet;
934     std::vector< OUString > aNewUserCmdImageSet;
935 
936     if ( !m_bModified )
937         return;
938 
939     for ( vcl::ImageType i : o3tl::enumrange<vcl::ImageType>() )
940     {
941         if ( !m_bDisposed && m_bUserImageListModified[i] )
942         {
943             std::vector< OUString > aOldUserCmdImageVector;
944             ImageList* pImageList = implts_getUserImageList(i);
945             pImageList->GetImageNames( aOldUserCmdImageVector );
946 
947             // Fill hash map to speed up search afterwards
948             sal_uInt32 j( 0 );
949             const sal_uInt32 nOldCount = aOldUserCmdImageVector.size();
950             for ( j = 0; j < nOldCount; j++ )
951                 aOldUserCmdImageSet.emplace( aOldUserCmdImageVector[j], false );
952 
953             // Attention: This can make the old image list pointer invalid!
954             implts_loadUserImages( i, m_xUserImageStorage, m_xUserBitmapsStorage );
955             pImageList = implts_getUserImageList(i);
956             pImageList->GetImageNames( aNewUserCmdImageSet );
957 
958             rtl::Reference<GraphicNameAccess> pInsertedImages;
959             rtl::Reference<GraphicNameAccess> pReplacedImages;
960             rtl::Reference<GraphicNameAccess> pRemovedImages;
961 
962             for (auto const& newUserCmdImage : aNewUserCmdImageSet)
963             {
964                 CommandMap::iterator pIter = aOldUserCmdImageSet.find(newUserCmdImage);
965                 if ( pIter != aOldUserCmdImageSet.end() )
966                 {
967                     pIter->second = true; // mark entry as replaced
968                     if ( !pReplacedImages )
969                         pReplacedImages = new GraphicNameAccess();
970                     pReplacedImages->addElement( newUserCmdImage,
971                                                  GetXGraphic(pImageList->GetImage(newUserCmdImage)) );
972                 }
973                 else
974                 {
975                     if ( !pInsertedImages )
976                         pInsertedImages = new GraphicNameAccess();
977                     pInsertedImages->addElement( newUserCmdImage,
978                                                  GetXGraphic(pImageList->GetImage(newUserCmdImage)) );
979                 }
980             }
981 
982             // Search map for unmarked entries => they have been removed from the user list
983             // through this reload operation.
984             // We have to search the module and global image list!
985             rtl::Reference< GlobalImageList > rGlobalImageList;
986             CmdImageList*                     pDefaultImageList = nullptr;
987             if ( m_bUseGlobal )
988             {
989                 rGlobalImageList  = implts_getGlobalImageList();
990                 pDefaultImageList = implts_getDefaultImageList();
991             }
992             uno::Reference<XGraphic> xEmptyGraphic;
993             for (auto const& oldUserCmdImage : aOldUserCmdImageSet)
994             {
995                 if ( !oldUserCmdImage.second )
996                 {
997                     if ( m_bUseGlobal )
998                     {
999                         Image aImage = pDefaultImageList->getImageFromCommandURL( i, oldUserCmdImage.first );
1000                         if ( !aImage )
1001                             aImage = rGlobalImageList->getImageFromCommandURL( i, oldUserCmdImage.first );
1002 
1003                         if ( !aImage )
1004                         {
1005                             // No image in the module/global image list => remove user image
1006                             if ( !pRemovedImages )
1007                                 pRemovedImages = new GraphicNameAccess();
1008                             pRemovedImages->addElement( oldUserCmdImage.first, xEmptyGraphic );
1009                         }
1010                         else
1011                         {
1012                             // Image has been found in the module/global image list => replace user image
1013                             if ( !pReplacedImages )
1014                                 pReplacedImages = new GraphicNameAccess();
1015                             pReplacedImages->addElement(oldUserCmdImage.first, GetXGraphic(aImage));
1016                         }
1017                     } // if ( m_bUseGlobal )
1018                     else
1019                     {
1020                         // No image in the user image list => remove user image
1021                         if ( !pRemovedImages )
1022                             pRemovedImages = new GraphicNameAccess();
1023                         pRemovedImages->addElement( oldUserCmdImage.first, xEmptyGraphic );
1024                     }
1025                 }
1026             }
1027 
1028             aGuard.clear();
1029 
1030             // Now notify our listeners. Unlock mutex to prevent deadlocks
1031             uno::Reference< uno::XInterface > xOwner(m_pOwner);
1032             if ( pInsertedImages != nullptr )
1033             {
1034                 ConfigurationEvent aInsertEvent;
1035                 aInsertEvent.aInfo           <<=static_cast<sal_uInt16>(i);
1036                 aInsertEvent.Accessor        <<= xOwner;
1037                 aInsertEvent.Source          = xOwner;
1038                 aInsertEvent.ResourceURL     = m_aResourceString;
1039                 aInsertEvent.Element         <<= uno::Reference< XNameAccess >( pInsertedImages );
1040                 implts_notifyContainerListener( aInsertEvent, NotifyOp_Insert );
1041             }
1042             if ( pReplacedImages != nullptr )
1043             {
1044                 ConfigurationEvent aReplaceEvent;
1045                 aReplaceEvent.aInfo           <<= static_cast<sal_uInt16>(i);
1046                 aReplaceEvent.Accessor        <<= xOwner;
1047                 aReplaceEvent.Source          = xOwner;
1048                 aReplaceEvent.ResourceURL     = m_aResourceString;
1049                 aReplaceEvent.ReplacedElement = Any();
1050                 aReplaceEvent.Element         <<= uno::Reference< XNameAccess >( pReplacedImages );
1051                 implts_notifyContainerListener( aReplaceEvent, NotifyOp_Replace );
1052             }
1053             if ( pRemovedImages != nullptr )
1054             {
1055                 ConfigurationEvent aRemoveEvent;
1056                 aRemoveEvent.aInfo           <<= static_cast<sal_uInt16>(i);
1057                 aRemoveEvent.Accessor        <<= xOwner;
1058                 aRemoveEvent.Source          = xOwner;
1059                 aRemoveEvent.ResourceURL     = m_aResourceString;
1060                 aRemoveEvent.Element         <<= uno::Reference< XNameAccess >( pRemovedImages );
1061                 implts_notifyContainerListener( aRemoveEvent, NotifyOp_Remove );
1062             }
1063 
1064             aGuard.reset();
1065         }
1066     }
1067 }
1068 
store()1069 void ImageManagerImpl::store()
1070 {
1071     SolarMutexGuard g;
1072 
1073     if ( m_bDisposed )
1074         throw DisposedException();
1075 
1076     if ( !m_bModified )
1077         return;
1078 
1079     bool bWritten( false );
1080     for ( vcl::ImageType i : o3tl::enumrange<vcl::ImageType>() )
1081     {
1082         bool bSuccess = implts_storeUserImages(i, m_xUserImageStorage, m_xUserBitmapsStorage );
1083         if ( bSuccess )
1084             bWritten = true;
1085         m_bUserImageListModified[i] = false;
1086     }
1087 
1088     if ( bWritten &&
1089          m_xUserConfigStorage.is() )
1090     {
1091         uno::Reference< XTransactedObject > xUserConfigStorageCommit( m_xUserConfigStorage, UNO_QUERY );
1092         if ( xUserConfigStorageCommit.is() )
1093             xUserConfigStorageCommit->commit();
1094         if ( m_xUserRootCommit.is() )
1095             m_xUserRootCommit->commit();
1096     }
1097 
1098     m_bModified = false;
1099 }
1100 
storeToStorage(const uno::Reference<XStorage> & Storage)1101 void ImageManagerImpl::storeToStorage( const uno::Reference< XStorage >& Storage )
1102 {
1103     SolarMutexGuard g;
1104 
1105     if ( m_bDisposed )
1106         throw DisposedException();
1107 
1108     if ( !(m_bModified && Storage.is()) )
1109         return;
1110 
1111     tools::Long nModes = ElementModes::READWRITE;
1112 
1113     uno::Reference< XStorage > xUserImageStorage = Storage->openStorageElement( IMAGE_FOLDER,
1114                                                                                 nModes );
1115     if ( !xUserImageStorage.is() )
1116         return;
1117 
1118     uno::Reference< XStorage > xUserBitmapsStorage = xUserImageStorage->openStorageElement( BITMAPS_FOLDER,
1119                                                                                             nModes );
1120     for ( vcl::ImageType i : o3tl::enumrange<vcl::ImageType>() )
1121     {
1122         implts_getUserImageList(i);
1123         implts_storeUserImages( i, xUserImageStorage, xUserBitmapsStorage );
1124     }
1125 
1126     uno::Reference< XTransactedObject > xTransaction( Storage, UNO_QUERY );
1127     if ( xTransaction.is() )
1128         xTransaction->commit();
1129 }
1130 
isModified() const1131 bool ImageManagerImpl::isModified() const
1132 {
1133     SolarMutexGuard g;
1134     return m_bModified;
1135 }
1136 
isReadOnly() const1137 bool ImageManagerImpl::isReadOnly() const
1138 {
1139     SolarMutexGuard g;
1140     return m_bReadOnly;
1141 }
1142 // XUIConfiguration
addConfigurationListener(const uno::Reference<css::ui::XUIConfigurationListener> & xListener)1143 void ImageManagerImpl::addConfigurationListener( const uno::Reference< css::ui::XUIConfigurationListener >& xListener )
1144 {
1145     {
1146         SolarMutexGuard g;
1147 
1148         /* SAFE AREA ----------------------------------------------------------------------------------------------- */
1149         if ( m_bDisposed )
1150             throw DisposedException();
1151     }
1152 
1153     m_aListenerContainer.addInterface( cppu::UnoType<XUIConfigurationListener>::get(), xListener );
1154 }
1155 
removeConfigurationListener(const uno::Reference<css::ui::XUIConfigurationListener> & xListener)1156 void ImageManagerImpl::removeConfigurationListener( const uno::Reference< css::ui::XUIConfigurationListener >& xListener )
1157 {
1158     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
1159     m_aListenerContainer.removeInterface( cppu::UnoType<XUIConfigurationListener>::get(), xListener );
1160 }
1161 
implts_notifyContainerListener(const ConfigurationEvent & aEvent,NotifyOp eOp)1162 void ImageManagerImpl::implts_notifyContainerListener( const ConfigurationEvent& aEvent, NotifyOp eOp )
1163 {
1164     ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer(
1165                                         cppu::UnoType<css::ui::XUIConfigurationListener>::get());
1166     if ( pContainer == nullptr )
1167         return;
1168 
1169     ::cppu::OInterfaceIteratorHelper pIterator( *pContainer );
1170     while ( pIterator.hasMoreElements() )
1171     {
1172         try
1173         {
1174             switch ( eOp )
1175             {
1176                 case NotifyOp_Replace:
1177                     static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementReplaced( aEvent );
1178                     break;
1179                 case NotifyOp_Insert:
1180                     static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementInserted( aEvent );
1181                     break;
1182                 case NotifyOp_Remove:
1183                     static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementRemoved( aEvent );
1184                     break;
1185             }
1186         }
1187         catch( const css::uno::RuntimeException& )
1188         {
1189             pIterator.remove();
1190         }
1191     }
1192 }
clear()1193 void ImageManagerImpl::clear()
1194 {
1195     SolarMutexGuard g;
1196 
1197     for (auto & n : m_pUserImageList)
1198     {
1199         n.reset();
1200     }
1201 }
1202 } // namespace framework
1203 
1204 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1205