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 .
20 #include "imagemanagerimpl.hxx"
22 #include <xml/imagesconfiguration.hxx>
23 #include <uiconfiguration/imagetype.hxx>
24 #include <uiconfiguration/graphicnameaccess.hxx>
26 #include <properties.h>
28 #include <com/sun/star/frame/theUICommandDescription.hpp>
29 #include <com/sun/star/ui/ConfigurationEvent.hpp>
30 #include <com/sun/star/lang/DisposedException.hpp>
31 #include <com/sun/star/lang/IllegalAccessException.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 #include <com/sun/star/embed/ElementModes.hpp>
35 #include <com/sun/star/embed/InvalidStorageException.hpp>
36 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
37 #include <com/sun/star/io/IOException.hpp>
38 #include <com/sun/star/io/XStream.hpp>
39 #include <com/sun/star/ui/ImageType.hpp>
40 #include <vcl/graph.hxx>
41 #include <vcl/svapp.hxx>
42 #include <o3tl/enumrange.hxx>
43 #include <comphelper/sequence.hxx>
44 #include <unotools/ucbstreamhelper.hxx>
45 #include <vcl/filter/PngImageReader.hxx>
46 #include <vcl/filter/PngImageWriter.hxx>
48 #include <unordered_set>
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
;
65 const sal_Int16 MAX_IMAGETYPE_VALUE
= css::ui::ImageType::SIZE_32
;
67 constexpr OUString IMAGE_FOLDER
= u
"images"_ustr
;
68 constexpr OUString BITMAPS_FOLDER
= u
"Bitmaps"_ustr
;
70 constexpr o3tl::enumarray
<vcl::ImageType
, OUString
> IMAGELIST_XML_FILE
72 u
"sc_imagelist.xml"_ustr
,
73 u
"lc_imagelist.xml"_ustr
,
74 u
"xc_imagelist.xml"_ustr
77 constexpr o3tl::enumarray
<vcl::ImageType
, OUString
> BITMAP_FILE_NAMES
79 u
"sc_userimages.png"_ustr
,
80 u
"lc_userimages.png"_ustr
,
81 u
"xc_userimages.png"_ustr
87 static GlobalImageList
* pGlobalImageList
= nullptr;
89 static std::mutex
& getGlobalImageListMutex()
91 static std::mutex mutex
;
95 static GlobalImageList
* getGlobalImageList( const uno::Reference
< uno::XComponentContext
>& rxContext
)
97 std::unique_lock
guard( getGlobalImageListMutex() );
99 if ( pGlobalImageList
== nullptr )
100 pGlobalImageList
= new GlobalImageList( rxContext
);
102 return pGlobalImageList
;
105 CmdImageList::CmdImageList( uno::Reference
< uno::XComponentContext
> rxContext
, OUString aModuleIdentifier
) :
106 m_bInitialized(false),
107 m_aModuleIdentifier(std::move( aModuleIdentifier
)),
108 m_xContext(std::move( rxContext
))
112 CmdImageList::~CmdImageList()
116 void CmdImageList::initialize()
121 const OUString
aCommandImageList(UICOMMANDDESCRIPTION_NAMEACCESS_COMMANDIMAGELIST
);
123 Sequence
<OUString
> aCommandImageSeq
;
124 uno::Reference
<XNameAccess
> xCommandDesc
= frame::theUICommandDescription::get(m_xContext
);
126 if (!m_aModuleIdentifier
.isEmpty())
128 // If we have a module identifier - use to retrieve the command image name list from it.
129 // Otherwise we will use the global command image list
132 xCommandDesc
->getByName(m_aModuleIdentifier
) >>= xCommandDesc
;
133 if (xCommandDesc
.is())
134 xCommandDesc
->getByName(aCommandImageList
) >>= aCommandImageSeq
;
136 catch (const NoSuchElementException
&)
138 // Module unknown we will work with an empty command image list!
143 if (xCommandDesc
.is())
147 xCommandDesc
->getByName(aCommandImageList
) >>= aCommandImageSeq
;
149 catch (const NoSuchElementException
&)
152 catch (const WrappedTargetException
&)
157 m_aResolver
.registerCommands(aCommandImageSeq
);
159 m_bInitialized
= true;
163 Image
CmdImageList::getImageFromCommandURL(vcl::ImageType nImageType
, const OUString
& rCommandURL
)
166 return m_aResolver
.getImageFromCommandURL(nImageType
, rCommandURL
);
169 bool CmdImageList::hasImage(vcl::ImageType
/*nImageType*/, const OUString
& rCommandURL
)
172 return m_aResolver
.hasImage(rCommandURL
);
175 std::vector
<OUString
>& CmdImageList::getImageCommandNames()
177 return m_aResolver
.getCommandNames();
180 GlobalImageList::GlobalImageList( const uno::Reference
< uno::XComponentContext
>& rxContext
) :
181 CmdImageList( rxContext
, OUString() )
185 GlobalImageList::~GlobalImageList()
187 std::unique_lock
guard( getGlobalImageListMutex() );
188 // remove global pointer as we destroy the object now
189 pGlobalImageList
= nullptr;
192 Image
GlobalImageList::getImageFromCommandURL( vcl::ImageType nImageType
, const OUString
& rCommandURL
)
194 std::unique_lock
guard( getGlobalImageListMutex() );
195 return CmdImageList::getImageFromCommandURL( nImageType
, rCommandURL
);
198 bool GlobalImageList::hasImage( vcl::ImageType nImageType
, const OUString
& rCommandURL
)
200 std::unique_lock
guard( getGlobalImageListMutex() );
201 return CmdImageList::hasImage( nImageType
, rCommandURL
);
204 ::std::vector
< OUString
>& GlobalImageList::getImageCommandNames()
206 std::unique_lock
guard( getGlobalImageListMutex() );
207 return CmdImageList::getImageCommandNames();
210 static bool implts_checkAndScaleGraphic( uno::Reference
< XGraphic
>& rOutGraphic
, const uno::Reference
< XGraphic
>& rInGraphic
, vcl::ImageType nImageType
)
212 if ( !rInGraphic
.is() )
214 rOutGraphic
= uno::Reference
<graphic::XGraphic
>();
218 static const o3tl::enumarray
<vcl::ImageType
, Size
> BITMAP_SIZE
=
220 Size(16, 16), Size(24, 24), Size(32, 32)
223 // Check size and scale it
224 Graphic
aImage(rInGraphic
);
225 if (BITMAP_SIZE
[nImageType
] != aImage
.GetSizePixel())
227 BitmapEx aBitmap
= aImage
.GetBitmapEx();
228 aBitmap
.Scale(BITMAP_SIZE
[nImageType
]);
229 aImage
= Graphic(aBitmap
);
230 rOutGraphic
= aImage
.GetXGraphic();
233 rOutGraphic
= rInGraphic
;
238 static vcl::ImageType
implts_convertImageTypeToIndex( sal_Int16 nImageType
)
240 if (nImageType
& css::ui::ImageType::SIZE_LARGE
)
241 return vcl::ImageType::Size26
;
242 else if (nImageType
& css::ui::ImageType::SIZE_32
)
243 return vcl::ImageType::Size32
;
245 return vcl::ImageType::Size16
;
248 ImageList
* ImageManagerImpl::implts_getUserImageList( vcl::ImageType nImageType
)
251 if ( !m_pUserImageList
[nImageType
] )
252 implts_loadUserImages( nImageType
, m_xUserImageStorage
, m_xUserBitmapsStorage
);
254 return m_pUserImageList
[nImageType
].get();
257 void ImageManagerImpl::implts_initialize()
259 // Initialize the top-level structures with the storage data
260 if ( !m_xUserConfigStorage
.is() )
263 tools::Long nModes
= m_bReadOnly
? ElementModes::READ
: ElementModes::READWRITE
;
267 m_xUserImageStorage
= m_xUserConfigStorage
->openStorageElement( IMAGE_FOLDER
,
269 if ( m_xUserImageStorage
.is() )
271 m_xUserBitmapsStorage
= m_xUserImageStorage
->openStorageElement( BITMAPS_FOLDER
,
275 catch ( const css::container::NoSuchElementException
& )
278 catch ( const css::embed::InvalidStorageException
& )
281 catch ( const css::lang::IllegalArgumentException
& )
284 catch ( const css::io::IOException
& )
287 catch ( const css::embed::StorageWrappedTargetException
& )
292 void ImageManagerImpl::implts_loadUserImages(
293 vcl::ImageType nImageType
,
294 const uno::Reference
< XStorage
>& xUserImageStorage
,
295 const uno::Reference
< XStorage
>& xUserBitmapsStorage
)
299 if ( xUserImageStorage
.is() && xUserBitmapsStorage
.is() )
303 uno::Reference
< XStream
> xStream
= xUserImageStorage
->openStreamElement( IMAGELIST_XML_FILE
[nImageType
],
304 ElementModes::READ
);
305 uno::Reference
< XInputStream
> xInputStream
= xStream
->getInputStream();
307 ImageItemDescriptorList aUserImageListInfo
;
308 ImagesConfiguration::LoadImages( m_xContext
,
310 aUserImageListInfo
);
311 if (!aUserImageListInfo
.aImageItemDescriptors
.empty())
313 sal_Int32 nCount
= aUserImageListInfo
.aImageItemDescriptors
.size();
314 std::vector
< OUString
> aUserImagesVector
;
315 aUserImagesVector
.reserve(nCount
);
316 for ( sal_Int32 i
=0; i
< nCount
; i
++ )
318 const ImageItemDescriptor
& rItem
= aUserImageListInfo
.aImageItemDescriptors
[i
];
319 aUserImagesVector
.push_back( rItem
.aCommandURL
);
322 uno::Reference
< XStream
> xBitmapStream
= xUserBitmapsStorage
->openStreamElement(
323 BITMAP_FILE_NAMES
[nImageType
],
324 ElementModes::READ
);
326 if ( xBitmapStream
.is() )
328 BitmapEx aUserBitmap
;
330 std::unique_ptr
<SvStream
> pSvStream(utl::UcbStreamHelper::CreateStream( xBitmapStream
));
331 vcl::PngImageReader
aPngReader( *pSvStream
);
332 aUserBitmap
= aPngReader
.read();
335 // Delete old image list and create a new one from the read bitmap
336 m_pUserImageList
[nImageType
].reset(new ImageList());
337 m_pUserImageList
[nImageType
]->InsertFromHorizontalStrip
338 ( aUserBitmap
, aUserImagesVector
);
343 catch ( const css::container::NoSuchElementException
& )
346 catch ( const css::embed::InvalidStorageException
& )
349 catch ( const css::lang::IllegalArgumentException
& )
352 catch ( const css::io::IOException
& )
355 catch ( const css::embed::StorageWrappedTargetException
& )
360 // Destroy old image list - create a new empty one
361 m_pUserImageList
[nImageType
].reset(new ImageList
);
364 bool ImageManagerImpl::implts_storeUserImages(
365 vcl::ImageType nImageType
,
366 const uno::Reference
< XStorage
>& xUserImageStorage
,
367 const uno::Reference
< XStorage
>& xUserBitmapsStorage
)
374 ImageList
* pImageList
= implts_getUserImageList( nImageType
);
375 if ( pImageList
->GetImageCount() > 0 )
377 ImageItemDescriptorList aUserImageListInfo
;
379 for ( sal_uInt16 i
=0; i
< pImageList
->GetImageCount(); i
++ )
381 ImageItemDescriptor aItem
;
383 aItem
.aCommandURL
= pImageList
->GetImageName(i
);
384 aUserImageListInfo
.aImageItemDescriptors
.push_back( aItem
);
386 aUserImageListInfo
.aURL
= "Bitmaps/" + BITMAP_FILE_NAMES
[nImageType
];
388 uno::Reference
< XTransactedObject
> xTransaction
;
389 uno::Reference
< XOutputStream
> xOutputStream
;
390 uno::Reference
< XStream
> xStream
= xUserImageStorage
->openStreamElement( IMAGELIST_XML_FILE
[nImageType
],
391 ElementModes::WRITE
|ElementModes::TRUNCATE
);
394 uno::Reference
< XStream
> xBitmapStream
=
395 xUserBitmapsStorage
->openStreamElement( BITMAP_FILE_NAMES
[nImageType
],
396 ElementModes::WRITE
|ElementModes::TRUNCATE
);
397 if ( xBitmapStream
.is() )
400 std::unique_ptr
<SvStream
> pSvStream(utl::UcbStreamHelper::CreateStream( xBitmapStream
));
401 vcl::PngImageWriter
aPngWriter( *pSvStream
);
402 auto rBitmap
= pImageList
->GetAsHorizontalStrip();
403 aPngWriter
.write( rBitmap
);
406 // Commit user bitmaps storage
407 xTransaction
.set( xUserBitmapsStorage
, UNO_QUERY
);
408 if ( xTransaction
.is() )
409 xTransaction
->commit();
412 xOutputStream
= xStream
->getOutputStream();
413 if ( xOutputStream
.is() )
414 ImagesConfiguration::StoreImages( m_xContext
, xOutputStream
, aUserImageListInfo
);
416 // Commit user image storage
417 xTransaction
.set( xUserImageStorage
, UNO_QUERY
);
418 if ( xTransaction
.is() )
419 xTransaction
->commit();
426 // Remove the streams from the storage, if we have no data. We have to catch
427 // the NoSuchElementException as it can be possible that there is no stream at all!
430 xUserImageStorage
->removeElement( IMAGELIST_XML_FILE
[nImageType
] );
432 catch ( const css::container::NoSuchElementException
& )
438 xUserBitmapsStorage
->removeElement( BITMAP_FILE_NAMES
[nImageType
] );
440 catch ( const css::container::NoSuchElementException
& )
444 uno::Reference
< XTransactedObject
> xTransaction
;
446 // Commit user image storage
447 xTransaction
.set( xUserImageStorage
, UNO_QUERY
);
448 if ( xTransaction
.is() )
449 xTransaction
->commit();
451 // Commit user bitmaps storage
452 xTransaction
.set( xUserBitmapsStorage
, UNO_QUERY
);
453 if ( xTransaction
.is() )
454 xTransaction
->commit();
462 const rtl::Reference
< GlobalImageList
>& ImageManagerImpl::implts_getGlobalImageList()
466 if ( !m_pGlobalImageList
.is() )
467 m_pGlobalImageList
= getGlobalImageList( m_xContext
);
468 return m_pGlobalImageList
;
471 CmdImageList
* ImageManagerImpl::implts_getDefaultImageList()
475 if ( !m_pDefaultImageList
)
476 m_pDefaultImageList
.reset(new CmdImageList( m_xContext
, m_aModuleIdentifier
));
478 return m_pDefaultImageList
.get();
481 ImageManagerImpl::ImageManagerImpl( uno::Reference
< uno::XComponentContext
> xContext
, ::cppu::OWeakObject
* pOwner
, bool _bUseGlobal
) :
482 m_xContext(std::move( xContext
))
484 , m_aResourceString( u
"private:resource/images/moduleimages"_ustr
)
485 , m_bUseGlobal(_bUseGlobal
)
486 , m_bReadOnly( true )
487 , m_bInitialized( false )
488 , m_bModified( false )
489 , m_bDisposed( false )
491 for ( vcl::ImageType n
: o3tl::enumrange
<vcl::ImageType
>() )
493 m_pUserImageList
[n
] = nullptr;
494 m_bUserImageListModified
[n
] = false;
498 ImageManagerImpl::~ImageManagerImpl()
503 void ImageManagerImpl::dispose()
505 uno::Reference
< uno::XInterface
> xOwner(m_pOwner
);
506 css::lang::EventObject
aEvent( xOwner
);
508 std::unique_lock
aGuard(m_mutex
);
509 m_aEventListeners
.disposeAndClear( aGuard
, aEvent
);
512 std::unique_lock
aGuard(m_mutex
);
513 m_aConfigListeners
.disposeAndClear( aGuard
, aEvent
);
518 m_xUserConfigStorage
.clear();
519 m_xUserImageStorage
.clear();
520 m_xUserRootCommit
.clear();
524 // delete user and default image list on dispose
525 for (auto& n
: m_pUserImageList
)
529 m_pDefaultImageList
.reset();
533 void ImageManagerImpl::addEventListener( const uno::Reference
< XEventListener
>& xListener
)
538 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
540 throw DisposedException();
543 std::unique_lock
aGuard(m_mutex
);
544 m_aEventListeners
.addInterface( aGuard
, xListener
);
547 void ImageManagerImpl::removeEventListener( const uno::Reference
< XEventListener
>& xListener
)
549 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
550 std::unique_lock
aGuard(m_mutex
);
551 m_aEventListeners
.removeInterface( aGuard
, xListener
);
555 void ImageManagerImpl::initialize( const Sequence
< Any
>& aArguments
)
559 if ( m_bInitialized
)
562 for ( const Any
& rArg
: aArguments
)
564 PropertyValue aPropValue
;
565 if ( rArg
>>= aPropValue
)
567 if ( aPropValue
.Name
== "UserConfigStorage" )
569 aPropValue
.Value
>>= m_xUserConfigStorage
;
571 else if ( aPropValue
.Name
== "ModuleIdentifier" )
573 aPropValue
.Value
>>= m_aModuleIdentifier
;
575 else if ( aPropValue
.Name
== "UserRootCommit" )
577 aPropValue
.Value
>>= m_xUserRootCommit
;
582 if ( m_xUserConfigStorage
.is() )
584 uno::Reference
< XPropertySet
> xPropSet( m_xUserConfigStorage
, UNO_QUERY
);
587 tools::Long nOpenMode
= 0;
588 if ( xPropSet
->getPropertyValue(u
"OpenMode"_ustr
) >>= nOpenMode
)
589 m_bReadOnly
= !( nOpenMode
& ElementModes::WRITE
);
595 m_bInitialized
= true;
599 void ImageManagerImpl::reset()
603 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
605 throw DisposedException();
607 std::vector
< OUString
> aUserImageNames
;
609 for ( vcl::ImageType i
: o3tl::enumrange
<vcl::ImageType
>() )
611 aUserImageNames
.clear();
612 ImageList
* pImageList
= implts_getUserImageList(i
);
613 pImageList
->GetImageNames( aUserImageNames
);
615 Sequence
< OUString
> aRemoveList( comphelper::containerToSequence(aUserImageNames
) );
618 removeImages( sal_Int16( i
), aRemoveList
);
619 m_bUserImageListModified
[i
] = true;
625 Sequence
< OUString
> ImageManagerImpl::getAllImageNames( ::sal_Int16 nImageType
)
629 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
631 throw DisposedException();
633 std::unordered_set
< OUString
> aImageCmdNames
;
635 vcl::ImageType nIndex
= implts_convertImageTypeToIndex( nImageType
);
640 rtl::Reference
< GlobalImageList
> rGlobalImageList
= implts_getGlobalImageList();
642 const std::vector
< OUString
>& rGlobalImageNameVector
= rGlobalImageList
->getImageCommandNames();
643 const sal_uInt32 nGlobalCount
= rGlobalImageNameVector
.size();
644 for ( i
= 0; i
< nGlobalCount
; i
++ )
645 aImageCmdNames
.insert( rGlobalImageNameVector
[i
] );
647 const std::vector
< OUString
>& rModuleImageNameVector
= implts_getDefaultImageList()->getImageCommandNames();
648 const sal_uInt32 nModuleCount
= rModuleImageNameVector
.size();
649 for ( i
= 0; i
< nModuleCount
; i
++ )
650 aImageCmdNames
.insert( rModuleImageNameVector
[i
] );
653 ImageList
* pImageList
= implts_getUserImageList(nIndex
);
654 std::vector
< OUString
> rUserImageNames
;
655 pImageList
->GetImageNames( rUserImageNames
);
656 const sal_uInt32 nUserCount
= rUserImageNames
.size();
657 for ( i
= 0; i
< nUserCount
; i
++ )
658 aImageCmdNames
.insert( rUserImageNames
[i
] );
660 return comphelper::containerToSequence( aImageCmdNames
);
663 bool ImageManagerImpl::hasImage( ::sal_Int16 nImageType
, const OUString
& aCommandURL
)
667 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
669 throw DisposedException();
671 if (( nImageType
< 0 ) || ( nImageType
> MAX_IMAGETYPE_VALUE
))
672 throw IllegalArgumentException();
674 vcl::ImageType nIndex
= implts_convertImageTypeToIndex( nImageType
);
675 if ( m_bUseGlobal
&& implts_getGlobalImageList()->hasImage( nIndex
, aCommandURL
))
679 if ( m_bUseGlobal
&& implts_getDefaultImageList()->hasImage( nIndex
, aCommandURL
))
684 ImageList
* pImageList
= implts_getUserImageList(nIndex
);
686 return ( pImageList
->GetImagePos( aCommandURL
) != IMAGELIST_IMAGE_NOTFOUND
);
695 css::uno::Reference
< css::graphic::XGraphic
> GetXGraphic(const Image
&rImage
)
697 return Graphic(rImage
).GetXGraphic();
701 Sequence
< uno::Reference
< XGraphic
> > ImageManagerImpl::getImages(
702 ::sal_Int16 nImageType
,
703 const Sequence
< OUString
>& aCommandURLSequence
)
707 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
709 throw DisposedException();
711 if (( nImageType
< 0 ) || ( nImageType
> MAX_IMAGETYPE_VALUE
))
712 throw IllegalArgumentException();
714 Sequence
< uno::Reference
< XGraphic
> > aGraphSeq( aCommandURLSequence
.getLength() );
716 vcl::ImageType nIndex
= implts_convertImageTypeToIndex( nImageType
);
717 rtl::Reference
< GlobalImageList
> rGlobalImageList
;
718 CmdImageList
* pDefaultImageList
= nullptr;
721 rGlobalImageList
= implts_getGlobalImageList();
722 pDefaultImageList
= implts_getDefaultImageList();
724 ImageList
* pUserImageList
= implts_getUserImageList(nIndex
);
726 // We have to search our image list in the following order:
727 // 1. user image list (read/write)
728 // 2. module image list (read)
729 // 3. global image list (read)
730 auto aGraphSeqRange
= asNonConstRange(aGraphSeq
);
732 for ( const OUString
& rURL
: aCommandURLSequence
)
734 Image aImage
= pUserImageList
->GetImage( rURL
);
735 if ( !aImage
&& m_bUseGlobal
)
737 aImage
= pDefaultImageList
->getImageFromCommandURL( nIndex
, rURL
);
739 aImage
= rGlobalImageList
->getImageFromCommandURL( nIndex
, rURL
);
742 aGraphSeqRange
[n
++] = GetXGraphic(aImage
);
748 void ImageManagerImpl::replaceImages(
749 ::sal_Int16 nImageType
,
750 const Sequence
< OUString
>& aCommandURLSequence
,
751 const Sequence
< uno::Reference
< XGraphic
> >& aGraphicsSequence
)
753 rtl::Reference
<GraphicNameAccess
> pInsertedImages
;
754 rtl::Reference
<GraphicNameAccess
> pReplacedImages
;
759 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
761 throw DisposedException();
763 if (( aCommandURLSequence
.getLength() != aGraphicsSequence
.getLength() ) ||
764 (( nImageType
< 0 ) || ( nImageType
> MAX_IMAGETYPE_VALUE
)))
765 throw IllegalArgumentException();
768 throw IllegalAccessException();
770 vcl::ImageType nIndex
= implts_convertImageTypeToIndex( nImageType
);
771 ImageList
* pImageList
= implts_getUserImageList(nIndex
);
773 uno::Reference
< XGraphic
> xGraphic
;
774 for ( sal_Int32 i
= 0; i
< aCommandURLSequence
.getLength(); i
++ )
776 // Check size and scale. If we don't have any graphics ignore it
777 if ( !implts_checkAndScaleGraphic( xGraphic
, aGraphicsSequence
[i
], nIndex
))
780 sal_uInt16 nPos
= pImageList
->GetImagePos( aCommandURLSequence
[i
] );
781 if ( nPos
== IMAGELIST_IMAGE_NOTFOUND
)
783 pImageList
->AddImage(aCommandURLSequence
[i
], Image(xGraphic
));
784 if ( !pInsertedImages
)
785 pInsertedImages
= new GraphicNameAccess();
786 pInsertedImages
->addElement( aCommandURLSequence
[i
], xGraphic
);
790 pImageList
->ReplaceImage(aCommandURLSequence
[i
], Image(xGraphic
));
791 if ( !pReplacedImages
)
792 pReplacedImages
= new GraphicNameAccess();
793 pReplacedImages
->addElement( aCommandURLSequence
[i
], xGraphic
);
797 if (( pInsertedImages
!= nullptr ) || ( pReplacedImages
!= nullptr ))
800 m_bUserImageListModified
[nIndex
] = true;
804 uno::Reference
< uno::XInterface
> xOwner(m_pOwner
);
806 if ( pInsertedImages
!= nullptr )
808 ConfigurationEvent aInsertEvent
;
809 aInsertEvent
.aInfo
<<= nImageType
;
810 aInsertEvent
.Accessor
<<= xOwner
;
811 aInsertEvent
.Source
= xOwner
;
812 aInsertEvent
.ResourceURL
= m_aResourceString
;
813 aInsertEvent
.Element
<<= uno::Reference
< XNameAccess
>(pInsertedImages
);
814 implts_notifyContainerListener( aInsertEvent
, NotifyOp_Insert
);
816 if ( pReplacedImages
!= nullptr )
818 ConfigurationEvent aReplaceEvent
;
819 aReplaceEvent
.aInfo
<<= nImageType
;
820 aReplaceEvent
.Accessor
<<= xOwner
;
821 aReplaceEvent
.Source
= std::move(xOwner
);
822 aReplaceEvent
.ResourceURL
= m_aResourceString
;
823 aReplaceEvent
.ReplacedElement
= Any();
824 aReplaceEvent
.Element
<<= uno::Reference
< XNameAccess
>(pReplacedImages
);
825 implts_notifyContainerListener( aReplaceEvent
, NotifyOp_Replace
);
829 void ImageManagerImpl::removeImages( ::sal_Int16 nImageType
, const Sequence
< OUString
>& aCommandURLSequence
)
831 rtl::Reference
<GraphicNameAccess
> pRemovedImages
;
832 rtl::Reference
<GraphicNameAccess
> pReplacedImages
;
837 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
839 throw DisposedException();
841 if (( nImageType
< 0 ) || ( nImageType
> MAX_IMAGETYPE_VALUE
))
842 throw IllegalArgumentException();
845 throw IllegalAccessException();
847 vcl::ImageType nIndex
= implts_convertImageTypeToIndex( nImageType
);
848 rtl::Reference
< GlobalImageList
> rGlobalImageList
;
849 CmdImageList
* pDefaultImageList
= nullptr;
852 rGlobalImageList
= implts_getGlobalImageList();
853 pDefaultImageList
= implts_getDefaultImageList();
855 ImageList
* pImageList
= implts_getUserImageList(nIndex
);
856 uno::Reference
<XGraphic
> xEmptyGraphic
;
858 for ( const OUString
& rURL
: aCommandURLSequence
)
860 sal_uInt16 nPos
= pImageList
->GetImagePos( rURL
);
861 if ( nPos
!= IMAGELIST_IMAGE_NOTFOUND
)
863 sal_uInt16 nId
= pImageList
->GetImageId( nPos
);
864 pImageList
->RemoveImage( nId
);
868 // Check, if we have an image in our module/global image list. If we find one =>
869 // this is a replace instead of a remove operation!
870 Image aNewImage
= pDefaultImageList
->getImageFromCommandURL( nIndex
, rURL
);
872 aNewImage
= rGlobalImageList
->getImageFromCommandURL( nIndex
, rURL
);
875 if ( !pRemovedImages
)
876 pRemovedImages
= new GraphicNameAccess();
877 pRemovedImages
->addElement( rURL
, xEmptyGraphic
);
881 if ( !pReplacedImages
)
882 pReplacedImages
= new GraphicNameAccess();
883 pReplacedImages
->addElement(rURL
, GetXGraphic(aNewImage
));
885 } // if ( m_bUseGlobal )
888 if ( !pRemovedImages
)
889 pRemovedImages
= new GraphicNameAccess();
890 pRemovedImages
->addElement( rURL
, xEmptyGraphic
);
895 if (( pReplacedImages
!= nullptr ) || ( pRemovedImages
!= nullptr ))
898 m_bUserImageListModified
[nIndex
] = true;
903 uno::Reference
< uno::XInterface
> xOwner(m_pOwner
);
904 if ( pRemovedImages
!= nullptr )
906 ConfigurationEvent aRemoveEvent
;
907 aRemoveEvent
.aInfo
<<= nImageType
;
908 aRemoveEvent
.Accessor
<<= xOwner
;
909 aRemoveEvent
.Source
= xOwner
;
910 aRemoveEvent
.ResourceURL
= m_aResourceString
;
911 aRemoveEvent
.Element
<<= uno::Reference
< XNameAccess
>(pRemovedImages
);
912 implts_notifyContainerListener( aRemoveEvent
, NotifyOp_Remove
);
914 if ( pReplacedImages
!= nullptr )
916 ConfigurationEvent aReplaceEvent
;
917 aReplaceEvent
.aInfo
<<= nImageType
;
918 aReplaceEvent
.Accessor
<<= xOwner
;
919 aReplaceEvent
.Source
= std::move(xOwner
);
920 aReplaceEvent
.ResourceURL
= m_aResourceString
;
921 aReplaceEvent
.ReplacedElement
= Any();
922 aReplaceEvent
.Element
<<= uno::Reference
< XNameAccess
>(pReplacedImages
);
923 implts_notifyContainerListener( aReplaceEvent
, NotifyOp_Replace
);
927 void ImageManagerImpl::insertImages( ::sal_Int16 nImageType
, const Sequence
< OUString
>& aCommandURLSequence
, const Sequence
< uno::Reference
< XGraphic
> >& aGraphicSequence
)
929 replaceImages(nImageType
,aCommandURLSequence
,aGraphicSequence
);
932 // XUIConfigurationPersistence
933 void ImageManagerImpl::reload()
935 SolarMutexResettableGuard aGuard
;
938 throw DisposedException();
940 CommandMap aOldUserCmdImageSet
;
941 std::vector
< OUString
> aNewUserCmdImageSet
;
946 for ( vcl::ImageType i
: o3tl::enumrange
<vcl::ImageType
>() )
948 if ( !m_bDisposed
&& m_bUserImageListModified
[i
] )
950 std::vector
< OUString
> aOldUserCmdImageVector
;
951 ImageList
* pImageList
= implts_getUserImageList(i
);
952 pImageList
->GetImageNames( aOldUserCmdImageVector
);
954 // Fill hash map to speed up search afterwards
956 const sal_uInt32 nOldCount
= aOldUserCmdImageVector
.size();
957 for ( j
= 0; j
< nOldCount
; j
++ )
958 aOldUserCmdImageSet
.emplace( aOldUserCmdImageVector
[j
], false );
960 // Attention: This can make the old image list pointer invalid!
961 implts_loadUserImages( i
, m_xUserImageStorage
, m_xUserBitmapsStorage
);
962 pImageList
= implts_getUserImageList(i
);
963 pImageList
->GetImageNames( aNewUserCmdImageSet
);
965 rtl::Reference
<GraphicNameAccess
> pInsertedImages
;
966 rtl::Reference
<GraphicNameAccess
> pReplacedImages
;
967 rtl::Reference
<GraphicNameAccess
> pRemovedImages
;
969 for (auto const& newUserCmdImage
: aNewUserCmdImageSet
)
971 CommandMap::iterator pIter
= aOldUserCmdImageSet
.find(newUserCmdImage
);
972 if ( pIter
!= aOldUserCmdImageSet
.end() )
974 pIter
->second
= true; // mark entry as replaced
975 if ( !pReplacedImages
)
976 pReplacedImages
= new GraphicNameAccess();
977 pReplacedImages
->addElement( newUserCmdImage
,
978 GetXGraphic(pImageList
->GetImage(newUserCmdImage
)) );
982 if ( !pInsertedImages
)
983 pInsertedImages
= new GraphicNameAccess();
984 pInsertedImages
->addElement( newUserCmdImage
,
985 GetXGraphic(pImageList
->GetImage(newUserCmdImage
)) );
989 // Search map for unmarked entries => they have been removed from the user list
990 // through this reload operation.
991 // We have to search the module and global image list!
992 rtl::Reference
< GlobalImageList
> rGlobalImageList
;
993 CmdImageList
* pDefaultImageList
= nullptr;
996 rGlobalImageList
= implts_getGlobalImageList();
997 pDefaultImageList
= implts_getDefaultImageList();
999 uno::Reference
<XGraphic
> xEmptyGraphic
;
1000 for (auto const& oldUserCmdImage
: aOldUserCmdImageSet
)
1002 if ( !oldUserCmdImage
.second
)
1006 Image aImage
= pDefaultImageList
->getImageFromCommandURL( i
, oldUserCmdImage
.first
);
1008 aImage
= rGlobalImageList
->getImageFromCommandURL( i
, oldUserCmdImage
.first
);
1012 // No image in the module/global image list => remove user image
1013 if ( !pRemovedImages
)
1014 pRemovedImages
= new GraphicNameAccess();
1015 pRemovedImages
->addElement( oldUserCmdImage
.first
, xEmptyGraphic
);
1019 // Image has been found in the module/global image list => replace user image
1020 if ( !pReplacedImages
)
1021 pReplacedImages
= new GraphicNameAccess();
1022 pReplacedImages
->addElement(oldUserCmdImage
.first
, GetXGraphic(aImage
));
1024 } // if ( m_bUseGlobal )
1027 // No image in the user image list => remove user image
1028 if ( !pRemovedImages
)
1029 pRemovedImages
= new GraphicNameAccess();
1030 pRemovedImages
->addElement( oldUserCmdImage
.first
, xEmptyGraphic
);
1037 // Now notify our listeners. Unlock mutex to prevent deadlocks
1038 uno::Reference
< uno::XInterface
> xOwner(m_pOwner
);
1039 if ( pInsertedImages
!= nullptr )
1041 ConfigurationEvent aInsertEvent
;
1042 aInsertEvent
.aInfo
<<=static_cast<sal_uInt16
>(i
);
1043 aInsertEvent
.Accessor
<<= xOwner
;
1044 aInsertEvent
.Source
= xOwner
;
1045 aInsertEvent
.ResourceURL
= m_aResourceString
;
1046 aInsertEvent
.Element
<<= uno::Reference
< XNameAccess
>( pInsertedImages
);
1047 implts_notifyContainerListener( aInsertEvent
, NotifyOp_Insert
);
1049 if ( pReplacedImages
!= nullptr )
1051 ConfigurationEvent aReplaceEvent
;
1052 aReplaceEvent
.aInfo
<<= static_cast<sal_uInt16
>(i
);
1053 aReplaceEvent
.Accessor
<<= xOwner
;
1054 aReplaceEvent
.Source
= xOwner
;
1055 aReplaceEvent
.ResourceURL
= m_aResourceString
;
1056 aReplaceEvent
.ReplacedElement
= Any();
1057 aReplaceEvent
.Element
<<= uno::Reference
< XNameAccess
>( pReplacedImages
);
1058 implts_notifyContainerListener( aReplaceEvent
, NotifyOp_Replace
);
1060 if ( pRemovedImages
!= nullptr )
1062 ConfigurationEvent aRemoveEvent
;
1063 aRemoveEvent
.aInfo
<<= static_cast<sal_uInt16
>(i
);
1064 aRemoveEvent
.Accessor
<<= xOwner
;
1065 aRemoveEvent
.Source
= std::move(xOwner
);
1066 aRemoveEvent
.ResourceURL
= m_aResourceString
;
1067 aRemoveEvent
.Element
<<= uno::Reference
< XNameAccess
>( pRemovedImages
);
1068 implts_notifyContainerListener( aRemoveEvent
, NotifyOp_Remove
);
1076 void ImageManagerImpl::store()
1081 throw DisposedException();
1086 bool bWritten( false );
1087 for ( vcl::ImageType i
: o3tl::enumrange
<vcl::ImageType
>() )
1089 bool bSuccess
= implts_storeUserImages(i
, m_xUserImageStorage
, m_xUserBitmapsStorage
);
1092 m_bUserImageListModified
[i
] = false;
1096 m_xUserConfigStorage
.is() )
1098 uno::Reference
< XTransactedObject
> xUserConfigStorageCommit( m_xUserConfigStorage
, UNO_QUERY
);
1099 if ( xUserConfigStorageCommit
.is() )
1100 xUserConfigStorageCommit
->commit();
1101 if ( m_xUserRootCommit
.is() )
1102 m_xUserRootCommit
->commit();
1105 m_bModified
= false;
1108 void ImageManagerImpl::storeToStorage( const uno::Reference
< XStorage
>& Storage
)
1113 throw DisposedException();
1115 if ( !(m_bModified
&& Storage
.is()) )
1118 tools::Long nModes
= ElementModes::READWRITE
;
1120 uno::Reference
< XStorage
> xUserImageStorage
= Storage
->openStorageElement( IMAGE_FOLDER
,
1122 if ( !xUserImageStorage
.is() )
1125 uno::Reference
< XStorage
> xUserBitmapsStorage
= xUserImageStorage
->openStorageElement( BITMAPS_FOLDER
,
1127 for ( vcl::ImageType i
: o3tl::enumrange
<vcl::ImageType
>() )
1129 implts_getUserImageList(i
);
1130 implts_storeUserImages( i
, xUserImageStorage
, xUserBitmapsStorage
);
1133 uno::Reference
< XTransactedObject
> xTransaction( Storage
, UNO_QUERY
);
1134 if ( xTransaction
.is() )
1135 xTransaction
->commit();
1138 bool ImageManagerImpl::isModified() const
1144 bool ImageManagerImpl::isReadOnly() const
1150 void ImageManagerImpl::addConfigurationListener( const uno::Reference
< css::ui::XUIConfigurationListener
>& xListener
)
1155 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
1157 throw DisposedException();
1160 std::unique_lock
aGuard(m_mutex
);
1161 m_aConfigListeners
.addInterface( aGuard
, xListener
);
1164 void ImageManagerImpl::removeConfigurationListener( const uno::Reference
< css::ui::XUIConfigurationListener
>& xListener
)
1166 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
1167 std::unique_lock
aGuard(m_mutex
);
1168 m_aConfigListeners
.removeInterface( aGuard
, xListener
);
1171 void ImageManagerImpl::implts_notifyContainerListener( const ConfigurationEvent
& aEvent
, NotifyOp eOp
)
1173 std::unique_lock
aGuard(m_mutex
);
1174 comphelper::OInterfaceIteratorHelper4
pIterator( aGuard
, m_aConfigListeners
);
1176 while ( pIterator
.hasMoreElements() )
1182 case NotifyOp_Replace
:
1183 pIterator
.next()->elementReplaced( aEvent
);
1185 case NotifyOp_Insert
:
1186 pIterator
.next()->elementInserted( aEvent
);
1188 case NotifyOp_Remove
:
1189 pIterator
.next()->elementRemoved( aEvent
);
1193 catch( const css::uno::RuntimeException
& )
1196 pIterator
.remove(aGuard
);
1201 void ImageManagerImpl::clear()
1205 for (auto & n
: m_pUserImageList
)
1210 } // namespace framework
1212 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */