Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / framework / source / uiconfiguration / imagemanagerimpl.cxx
bloba24e3a05c33c08c664f8db02d770862e3325e403
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 "imagemanagerimpl.hxx"
21 #include <xml/imagesconfiguration.hxx>
22 #include <uiconfiguration/imagetype.hxx>
23 #include <uiconfiguration/graphicnameaccess.hxx>
24 #include <services.h>
26 #include <properties.h>
28 #include <com/sun/star/frame/theUICommandDescription.hpp>
29 #include <com/sun/star/ui/UIElementType.hpp>
30 #include <com/sun/star/ui/ConfigurationEvent.hpp>
31 #include <com/sun/star/lang/DisposedException.hpp>
32 #include <com/sun/star/lang/IllegalAccessException.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/beans/PropertyValue.hpp>
35 #include <com/sun/star/embed/ElementModes.hpp>
36 #include <com/sun/star/embed/InvalidStorageException.hpp>
37 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
38 #include <com/sun/star/io/IOException.hpp>
39 #include <com/sun/star/io/XStream.hpp>
40 #include <com/sun/star/ui/ImageType.hpp>
41 #include <vcl/graph.hxx>
42 #include <vcl/svapp.hxx>
43 #include <rtl/ustrbuf.hxx>
44 #include <o3tl/enumrange.hxx>
45 #include <osl/mutex.hxx>
46 #include <comphelper/sequence.hxx>
47 #include <tools/urlobj.hxx>
48 #include <unotools/ucbstreamhelper.hxx>
49 #include <vcl/pngread.hxx>
50 #include <vcl/pngwrite.hxx>
51 #include <rtl/instance.hxx>
52 #include <svtools/miscopt.hxx>
53 #include <memory>
55 using ::com::sun::star::uno::Sequence;
56 using ::com::sun::star::uno::XInterface;
57 using ::com::sun::star::uno::RuntimeException;
58 using ::com::sun::star::uno::UNO_QUERY;
59 using ::com::sun::star::uno::Any;
60 using ::com::sun::star::graphic::XGraphic;
61 using namespace ::com::sun::star;
62 using namespace ::com::sun::star::io;
63 using namespace ::com::sun::star::embed;
64 using namespace ::com::sun::star::lang;
65 using namespace ::com::sun::star::container;
66 using namespace ::com::sun::star::beans;
67 using namespace ::com::sun::star::ui;
68 using namespace ::cppu;
70 const sal_Int16 MAX_IMAGETYPE_VALUE = css::ui::ImageType::SIZE_32;
72 static const char IMAGE_FOLDER[] = "images";
73 static const char BITMAPS_FOLDER[] = "Bitmaps";
75 static const o3tl::enumarray<vcl::ImageType, const char*> IMAGELIST_XML_FILE =
77 "sc_imagelist.xml",
78 "lc_imagelist.xml",
79 "xc_imagelist.xml"
82 static const o3tl::enumarray<vcl::ImageType, const char*> BITMAP_FILE_NAMES =
84 "sc_userimages.png",
85 "lc_userimages.png",
86 "xc_userimages.png"
89 namespace framework
92 static GlobalImageList* pGlobalImageList = nullptr;
94 namespace
96 class theGlobalImageListMutex
97 : public rtl::Static<osl::Mutex, theGlobalImageListMutex> {};
100 static osl::Mutex& getGlobalImageListMutex()
102 return theGlobalImageListMutex::get();
105 static GlobalImageList* getGlobalImageList( const uno::Reference< uno::XComponentContext >& rxContext )
107 osl::MutexGuard guard( getGlobalImageListMutex() );
109 if ( pGlobalImageList == nullptr )
110 pGlobalImageList = new GlobalImageList( rxContext );
112 return pGlobalImageList;
115 CmdImageList::CmdImageList( const uno::Reference< uno::XComponentContext >& rxContext, const OUString& aModuleIdentifier ) :
116 m_bInitialized(false),
117 m_aModuleIdentifier( aModuleIdentifier ),
118 m_xContext( rxContext )
122 CmdImageList::~CmdImageList()
126 void CmdImageList::initialize()
128 if (!m_bInitialized)
130 const OUString aCommandImageList(UICOMMANDDESCRIPTION_NAMEACCESS_COMMANDIMAGELIST);
132 Sequence<OUString> aCommandImageSeq;
133 uno::Reference<XNameAccess> xCommandDesc = frame::theUICommandDescription::get(m_xContext);
135 if (!m_aModuleIdentifier.isEmpty())
137 // If we have a module identifier - use to retrieve the command image name list from it.
138 // Otherwise we will use the global command image list
141 xCommandDesc->getByName(m_aModuleIdentifier) >>= xCommandDesc;
142 if (xCommandDesc.is())
143 xCommandDesc->getByName(aCommandImageList) >>= aCommandImageSeq;
145 catch (const NoSuchElementException&)
147 // Module unknown we will work with an empty command image list!
148 return;
152 if (xCommandDesc.is())
156 xCommandDesc->getByName(aCommandImageList) >>= aCommandImageSeq;
158 catch (const NoSuchElementException&)
161 catch (const WrappedTargetException&)
166 m_aResolver.registerCommands(aCommandImageSeq);
168 m_bInitialized = true;
173 Image CmdImageList::getImageFromCommandURL(vcl::ImageType nImageType, const OUString& rCommandURL)
175 initialize();
176 return m_aResolver.getImageFromCommandURL(nImageType, rCommandURL);
179 bool CmdImageList::hasImage(vcl::ImageType /*nImageType*/, const OUString& rCommandURL)
181 initialize();
182 return m_aResolver.hasImage(rCommandURL);
185 std::vector<OUString>& CmdImageList::getImageCommandNames()
187 return m_aResolver.getCommandNames();
190 GlobalImageList::GlobalImageList( const uno::Reference< uno::XComponentContext >& rxContext ) :
191 CmdImageList( rxContext, OUString() )
195 GlobalImageList::~GlobalImageList()
197 osl::MutexGuard guard( getGlobalImageListMutex() );
198 // remove global pointer as we destroy the object now
199 pGlobalImageList = nullptr;
202 Image GlobalImageList::getImageFromCommandURL( vcl::ImageType nImageType, const OUString& rCommandURL )
204 osl::MutexGuard guard( getGlobalImageListMutex() );
205 return CmdImageList::getImageFromCommandURL( nImageType, rCommandURL );
208 bool GlobalImageList::hasImage( vcl::ImageType nImageType, const OUString& rCommandURL )
210 osl::MutexGuard guard( getGlobalImageListMutex() );
211 return CmdImageList::hasImage( nImageType, rCommandURL );
214 ::std::vector< OUString >& GlobalImageList::getImageCommandNames()
216 osl::MutexGuard guard( getGlobalImageListMutex() );
217 return CmdImageList::getImageCommandNames();
220 static bool implts_checkAndScaleGraphic( uno::Reference< XGraphic >& rOutGraphic, const uno::Reference< XGraphic >& rInGraphic, vcl::ImageType nImageType )
222 static Size aNormSize(16, 16);
223 static Size aLargeSize(26, 26);
224 static Size aSize32(32, 32);
226 if ( !rInGraphic.is() )
228 rOutGraphic = uno::Reference<graphic::XGraphic>();
229 return false;
232 // Check size and scale it
233 Graphic aImage(rInGraphic);
234 Size aSize = aImage.GetSizePixel();
235 bool bMustScale( false );
237 if (nImageType == vcl::ImageType::Size26)
238 bMustScale = (aSize != aLargeSize);
239 else if (nImageType == vcl::ImageType::Size32)
240 bMustScale = (aSize != aSize32);
241 else
242 bMustScale = (aSize != aNormSize);
244 if (bMustScale)
246 BitmapEx aBitmap = aImage.GetBitmapEx();
247 aBitmap.Scale( aNormSize );
248 aImage = Graphic(aBitmap);
249 rOutGraphic = aImage.GetXGraphic();
251 else
252 rOutGraphic = rInGraphic;
254 return true;
257 static vcl::ImageType implts_convertImageTypeToIndex( sal_Int16 nImageType )
259 if (nImageType & css::ui::ImageType::SIZE_LARGE)
260 return vcl::ImageType::Size26;
261 else if (nImageType & css::ui::ImageType::SIZE_32)
262 return vcl::ImageType::Size32;
263 else
264 return vcl::ImageType::Size16;
267 ImageList* ImageManagerImpl::implts_getUserImageList( vcl::ImageType nImageType )
269 SolarMutexGuard g;
270 if ( !m_pUserImageList[nImageType] )
271 implts_loadUserImages( nImageType, m_xUserImageStorage, m_xUserBitmapsStorage );
273 return m_pUserImageList[nImageType].get();
276 void ImageManagerImpl::implts_initialize()
278 // Initialize the top-level structures with the storage data
279 if ( m_xUserConfigStorage.is() )
281 long nModes = m_bReadOnly ? ElementModes::READ : ElementModes::READWRITE;
285 m_xUserImageStorage = m_xUserConfigStorage->openStorageElement( IMAGE_FOLDER,
286 nModes );
287 if ( m_xUserImageStorage.is() )
289 m_xUserBitmapsStorage = m_xUserImageStorage->openStorageElement( BITMAPS_FOLDER,
290 nModes );
293 catch ( const css::container::NoSuchElementException& )
296 catch ( const css::embed::InvalidStorageException& )
299 catch ( const css::lang::IllegalArgumentException& )
302 catch ( const css::io::IOException& )
305 catch ( const css::embed::StorageWrappedTargetException& )
311 void ImageManagerImpl::implts_loadUserImages(
312 vcl::ImageType nImageType,
313 const uno::Reference< XStorage >& xUserImageStorage,
314 const uno::Reference< XStorage >& xUserBitmapsStorage )
316 SolarMutexGuard g;
318 if ( xUserImageStorage.is() && xUserBitmapsStorage.is() )
322 uno::Reference< XStream > xStream = xUserImageStorage->openStreamElement( OUString::createFromAscii( IMAGELIST_XML_FILE[nImageType] ),
323 ElementModes::READ );
324 uno::Reference< XInputStream > xInputStream = xStream->getInputStream();
326 ImageItemDescriptorList aUserImageListInfo;
327 ImagesConfiguration::LoadImages( m_xContext,
328 xInputStream,
329 aUserImageListInfo );
330 if ( !aUserImageListInfo.empty() )
332 sal_Int32 nCount = aUserImageListInfo.size();
333 std::vector< OUString > aUserImagesVector;
334 aUserImagesVector.reserve(nCount);
335 for ( sal_Int32 i=0; i < nCount; i++ )
337 const ImageItemDescriptor& rItem = aUserImageListInfo[i];
338 aUserImagesVector.push_back( rItem.aCommandURL );
341 uno::Reference< XStream > xBitmapStream = xUserBitmapsStorage->openStreamElement(
342 OUString::createFromAscii( BITMAP_FILE_NAMES[nImageType] ),
343 ElementModes::READ );
345 if ( xBitmapStream.is() )
347 BitmapEx aUserBitmap;
349 std::unique_ptr<SvStream> pSvStream(utl::UcbStreamHelper::CreateStream( xBitmapStream ));
350 vcl::PNGReader aPngReader( *pSvStream );
351 aUserBitmap = aPngReader.Read();
354 // Delete old image list and create a new one from the read bitmap
355 m_pUserImageList[nImageType].reset(new ImageList());
356 m_pUserImageList[nImageType]->InsertFromHorizontalStrip
357 ( aUserBitmap, aUserImagesVector );
358 return;
362 catch ( const css::container::NoSuchElementException& )
365 catch ( const css::embed::InvalidStorageException& )
368 catch ( const css::lang::IllegalArgumentException& )
371 catch ( const css::io::IOException& )
374 catch ( const css::embed::StorageWrappedTargetException& )
379 // Destroy old image list - create a new empty one
380 m_pUserImageList[nImageType].reset(new ImageList);
383 bool ImageManagerImpl::implts_storeUserImages(
384 vcl::ImageType nImageType,
385 const uno::Reference< XStorage >& xUserImageStorage,
386 const uno::Reference< XStorage >& xUserBitmapsStorage )
388 SolarMutexGuard g;
390 if ( m_bModified )
392 ImageList* pImageList = implts_getUserImageList( nImageType );
393 if ( pImageList->GetImageCount() > 0 )
395 ImageItemDescriptorList aUserImageListInfo;
397 for ( sal_uInt16 i=0; i < pImageList->GetImageCount(); i++ )
399 ImageItemDescriptor aItem;
400 aItem.aCommandURL = pImageList->GetImageName( i );
401 aUserImageListInfo.push_back( aItem );
404 uno::Reference< XTransactedObject > xTransaction;
405 uno::Reference< XOutputStream > xOutputStream;
406 uno::Reference< XStream > xStream = xUserImageStorage->openStreamElement( OUString::createFromAscii( IMAGELIST_XML_FILE[nImageType] ),
407 ElementModes::WRITE|ElementModes::TRUNCATE );
408 if ( xStream.is() )
410 uno::Reference< XStream > xBitmapStream =
411 xUserBitmapsStorage->openStreamElement( OUString::createFromAscii( BITMAP_FILE_NAMES[nImageType] ),
412 ElementModes::WRITE|ElementModes::TRUNCATE );
413 if ( xBitmapStream.is() )
416 std::unique_ptr<SvStream> pSvStream(utl::UcbStreamHelper::CreateStream( xBitmapStream ));
417 vcl::PNGWriter aPngWriter( pImageList->GetAsHorizontalStrip() );
418 aPngWriter.Write( *pSvStream );
421 // Commit user bitmaps storage
422 xTransaction.set( xUserBitmapsStorage, UNO_QUERY );
423 if ( xTransaction.is() )
424 xTransaction->commit();
427 xOutputStream = xStream->getOutputStream();
428 if ( xOutputStream.is() )
429 ImagesConfiguration::StoreImages( m_xContext, xOutputStream, aUserImageListInfo );
431 // Commit user image storage
432 xTransaction.set( xUserImageStorage, UNO_QUERY );
433 if ( xTransaction.is() )
434 xTransaction->commit();
437 return true;
439 else
441 // Remove the streams from the storage, if we have no data. We have to catch
442 // the NoSuchElementException as it can be possible that there is no stream at all!
445 xUserImageStorage->removeElement( OUString::createFromAscii( IMAGELIST_XML_FILE[nImageType] ));
447 catch ( const css::container::NoSuchElementException& )
453 xUserBitmapsStorage->removeElement( OUString::createFromAscii( BITMAP_FILE_NAMES[nImageType] ));
455 catch ( const css::container::NoSuchElementException& )
459 uno::Reference< XTransactedObject > xTransaction;
461 // Commit user image storage
462 xTransaction.set( xUserImageStorage, UNO_QUERY );
463 if ( xTransaction.is() )
464 xTransaction->commit();
466 // Commit user bitmaps storage
467 xTransaction.set( xUserBitmapsStorage, UNO_QUERY );
468 if ( xTransaction.is() )
469 xTransaction->commit();
471 return true;
475 return false;
478 const rtl::Reference< GlobalImageList >& ImageManagerImpl::implts_getGlobalImageList()
480 SolarMutexGuard g;
482 if ( !m_pGlobalImageList.is() )
483 m_pGlobalImageList = getGlobalImageList( m_xContext );
484 return m_pGlobalImageList;
487 CmdImageList* ImageManagerImpl::implts_getDefaultImageList()
489 SolarMutexGuard g;
491 if ( !m_pDefaultImageList )
492 m_pDefaultImageList.reset(new CmdImageList( m_xContext, m_aModuleIdentifier ));
494 return m_pDefaultImageList.get();
497 ImageManagerImpl::ImageManagerImpl( const uno::Reference< uno::XComponentContext >& rxContext,::cppu::OWeakObject* pOwner,bool _bUseGlobal ) :
498 m_xContext( rxContext )
499 , m_pOwner(pOwner)
500 , m_aResourceString( "private:resource/images/moduleimages" )
501 , m_aListenerContainer( m_mutex )
502 , m_bUseGlobal(_bUseGlobal)
503 , m_bReadOnly( true )
504 , m_bInitialized( false )
505 , m_bModified( false )
506 , m_bDisposed( false )
508 for ( vcl::ImageType n : o3tl::enumrange<vcl::ImageType>() )
510 m_pUserImageList[n] = nullptr;
511 m_bUserImageListModified[n] = false;
515 ImageManagerImpl::~ImageManagerImpl()
517 clear();
520 void ImageManagerImpl::dispose()
522 uno::Reference< uno::XInterface > xOwner(m_pOwner);
523 css::lang::EventObject aEvent( xOwner );
524 m_aListenerContainer.disposeAndClear( aEvent );
527 SolarMutexGuard g;
528 m_xUserConfigStorage.clear();
529 m_xUserImageStorage.clear();
530 m_xUserRootCommit.clear();
531 m_bModified = false;
532 m_bDisposed = true;
534 // delete user and default image list on dispose
535 for (auto& n : m_pUserImageList)
537 n.reset();
539 m_pDefaultImageList.reset();
543 void ImageManagerImpl::addEventListener( const uno::Reference< XEventListener >& xListener )
546 SolarMutexGuard g;
548 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
549 if ( m_bDisposed )
550 throw DisposedException();
553 m_aListenerContainer.addInterface( cppu::UnoType<XEventListener>::get(), xListener );
556 void ImageManagerImpl::removeEventListener( const uno::Reference< XEventListener >& xListener )
558 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
559 m_aListenerContainer.removeInterface( cppu::UnoType<XEventListener>::get(), xListener );
562 // XInitialization
563 void ImageManagerImpl::initialize( const Sequence< Any >& aArguments )
565 SolarMutexGuard g;
567 if ( !m_bInitialized )
569 for ( sal_Int32 n = 0; n < aArguments.getLength(); n++ )
571 PropertyValue aPropValue;
572 if ( aArguments[n] >>= aPropValue )
574 if ( aPropValue.Name == "UserConfigStorage" )
576 aPropValue.Value >>= m_xUserConfigStorage;
578 else if ( aPropValue.Name == "ModuleIdentifier" )
580 aPropValue.Value >>= m_aModuleIdentifier;
582 else if ( aPropValue.Name == "UserRootCommit" )
584 aPropValue.Value >>= m_xUserRootCommit;
589 if ( m_xUserConfigStorage.is() )
591 uno::Reference< XPropertySet > xPropSet( m_xUserConfigStorage, UNO_QUERY );
592 if ( xPropSet.is() )
594 long nOpenMode = 0;
595 if ( xPropSet->getPropertyValue("OpenMode") >>= nOpenMode )
596 m_bReadOnly = !( nOpenMode & ElementModes::WRITE );
600 implts_initialize();
602 m_bInitialized = true;
606 // XImageManagerImpl
607 void ImageManagerImpl::reset()
609 SolarMutexGuard g;
611 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
612 if ( m_bDisposed )
613 throw DisposedException();
615 std::vector< OUString > aUserImageNames;
617 for ( vcl::ImageType i : o3tl::enumrange<vcl::ImageType>() )
619 aUserImageNames.clear();
620 ImageList* pImageList = implts_getUserImageList(i);
621 pImageList->GetImageNames( aUserImageNames );
623 Sequence< OUString > aRemoveList( comphelper::containerToSequence(aUserImageNames) );
625 // Remove images
626 removeImages( sal_Int16( i ), aRemoveList );
627 m_bUserImageListModified[i] = true;
630 m_bModified = true;
633 Sequence< OUString > ImageManagerImpl::getAllImageNames( ::sal_Int16 nImageType )
635 SolarMutexGuard g;
637 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
638 if ( m_bDisposed )
639 throw DisposedException();
641 ImageNameMap aImageCmdNameMap;
643 vcl::ImageType nIndex = implts_convertImageTypeToIndex( nImageType );
645 sal_uInt32 i( 0 );
646 if ( m_bUseGlobal )
648 rtl::Reference< GlobalImageList > rGlobalImageList = implts_getGlobalImageList();
650 const std::vector< OUString >& rGlobalImageNameVector = rGlobalImageList->getImageCommandNames();
651 const sal_uInt32 nGlobalCount = rGlobalImageNameVector.size();
652 for ( i = 0; i < nGlobalCount; i++ )
653 aImageCmdNameMap.emplace( rGlobalImageNameVector[i], true );
655 const std::vector< OUString >& rModuleImageNameVector = implts_getDefaultImageList()->getImageCommandNames();
656 const sal_uInt32 nModuleCount = rModuleImageNameVector.size();
657 for ( i = 0; i < nModuleCount; i++ )
658 aImageCmdNameMap.emplace( rModuleImageNameVector[i], true );
661 ImageList* pImageList = implts_getUserImageList(nIndex);
662 std::vector< OUString > rUserImageNames;
663 pImageList->GetImageNames( rUserImageNames );
664 const sal_uInt32 nUserCount = rUserImageNames.size();
665 for ( i = 0; i < nUserCount; i++ )
666 aImageCmdNameMap.emplace( rUserImageNames[i], true );
668 return comphelper::mapKeysToSequence( aImageCmdNameMap );
671 bool ImageManagerImpl::hasImage( ::sal_Int16 nImageType, const OUString& aCommandURL )
673 SolarMutexGuard g;
675 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
676 if ( m_bDisposed )
677 throw DisposedException();
679 if (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE ))
680 throw IllegalArgumentException();
682 vcl::ImageType nIndex = implts_convertImageTypeToIndex( nImageType );
683 if ( m_bUseGlobal && implts_getGlobalImageList()->hasImage( nIndex, aCommandURL ))
684 return true;
685 else
687 if ( m_bUseGlobal && implts_getDefaultImageList()->hasImage( nIndex, aCommandURL ))
688 return true;
689 else
691 // User layer
692 ImageList* pImageList = implts_getUserImageList(nIndex);
693 if ( pImageList )
694 return ( pImageList->GetImagePos( aCommandURL ) != IMAGELIST_IMAGE_NOTFOUND );
698 return false;
701 namespace
703 css::uno::Reference< css::graphic::XGraphic > GetXGraphic(const Image &rImage)
705 return Graphic(rImage).GetXGraphic();
709 Sequence< uno::Reference< XGraphic > > ImageManagerImpl::getImages(
710 ::sal_Int16 nImageType,
711 const Sequence< OUString >& aCommandURLSequence )
713 SolarMutexGuard g;
715 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
716 if ( m_bDisposed )
717 throw DisposedException();
719 if (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE ))
720 throw IllegalArgumentException();
722 Sequence< uno::Reference< XGraphic > > aGraphSeq( aCommandURLSequence.getLength() );
724 const OUString* aStrArray = aCommandURLSequence.getConstArray();
726 vcl::ImageType nIndex = implts_convertImageTypeToIndex( nImageType );
727 rtl::Reference< GlobalImageList > rGlobalImageList;
728 CmdImageList* pDefaultImageList = nullptr;
729 if ( m_bUseGlobal )
731 rGlobalImageList = implts_getGlobalImageList();
732 pDefaultImageList = implts_getDefaultImageList();
734 ImageList* pUserImageList = implts_getUserImageList(nIndex);
736 // We have to search our image list in the following order:
737 // 1. user image list (read/write)
738 // 2. module image list (read)
739 // 3. global image list (read)
740 for ( sal_Int32 n = 0; n < aCommandURLSequence.getLength(); n++ )
742 Image aImage = pUserImageList->GetImage( aStrArray[n] );
743 if ( !aImage && m_bUseGlobal )
745 aImage = pDefaultImageList->getImageFromCommandURL( nIndex, aStrArray[n] );
746 if ( !aImage )
747 aImage = rGlobalImageList->getImageFromCommandURL( nIndex, aStrArray[n] );
750 aGraphSeq[n] = GetXGraphic(aImage);
753 return aGraphSeq;
756 void ImageManagerImpl::replaceImages(
757 ::sal_Int16 nImageType,
758 const Sequence< OUString >& aCommandURLSequence,
759 const Sequence< uno::Reference< XGraphic > >& aGraphicsSequence )
761 GraphicNameAccess* pInsertedImages( nullptr );
762 GraphicNameAccess* pReplacedImages( nullptr );
765 SolarMutexGuard g;
767 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
768 if ( m_bDisposed )
769 throw DisposedException();
771 if (( aCommandURLSequence.getLength() != aGraphicsSequence.getLength() ) ||
772 (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE )))
773 throw IllegalArgumentException();
775 if ( m_bReadOnly )
776 throw IllegalAccessException();
778 vcl::ImageType nIndex = implts_convertImageTypeToIndex( nImageType );
779 ImageList* pImageList = implts_getUserImageList(nIndex);
781 uno::Reference< XGraphic > xGraphic;
782 for ( sal_Int32 i = 0; i < aCommandURLSequence.getLength(); i++ )
784 // Check size and scale. If we don't have any graphics ignore it
785 if ( !implts_checkAndScaleGraphic( xGraphic, aGraphicsSequence[i], nIndex ))
786 continue;
788 sal_uInt16 nPos = pImageList->GetImagePos( aCommandURLSequence[i] );
789 if ( nPos == IMAGELIST_IMAGE_NOTFOUND )
791 pImageList->AddImage(aCommandURLSequence[i], Image(xGraphic));
792 if ( !pInsertedImages )
793 pInsertedImages = new GraphicNameAccess();
794 pInsertedImages->addElement( aCommandURLSequence[i], xGraphic );
796 else
798 pImageList->ReplaceImage(aCommandURLSequence[i], Image(xGraphic));
799 if ( !pReplacedImages )
800 pReplacedImages = new GraphicNameAccess();
801 pReplacedImages->addElement( aCommandURLSequence[i], xGraphic );
805 if (( pInsertedImages != nullptr ) || ( pReplacedImages != nullptr ))
807 m_bModified = true;
808 m_bUserImageListModified[nIndex] = true;
812 uno::Reference< uno::XInterface > xOwner(m_pOwner);
813 // Notify listeners
814 if ( pInsertedImages != nullptr )
816 ConfigurationEvent aInsertEvent;
817 aInsertEvent.aInfo <<= nImageType;
818 aInsertEvent.Accessor <<= xOwner;
819 aInsertEvent.Source = xOwner;
820 aInsertEvent.ResourceURL = m_aResourceString;
821 aInsertEvent.Element <<= uno::Reference< XNameAccess >(
822 static_cast< OWeakObject *>( pInsertedImages ), UNO_QUERY );
823 implts_notifyContainerListener( aInsertEvent, NotifyOp_Insert );
825 if ( pReplacedImages != nullptr )
827 ConfigurationEvent aReplaceEvent;
828 aReplaceEvent.aInfo <<= nImageType;
829 aReplaceEvent.Accessor <<= xOwner;
830 aReplaceEvent.Source = xOwner;
831 aReplaceEvent.ResourceURL = m_aResourceString;
832 aReplaceEvent.ReplacedElement = Any();
833 aReplaceEvent.Element <<= uno::Reference< XNameAccess >(
834 static_cast< OWeakObject *>( pReplacedImages ), UNO_QUERY );
835 implts_notifyContainerListener( aReplaceEvent, NotifyOp_Replace );
839 void ImageManagerImpl::removeImages( ::sal_Int16 nImageType, const Sequence< OUString >& aCommandURLSequence )
841 GraphicNameAccess* pRemovedImages( nullptr );
842 GraphicNameAccess* pReplacedImages( nullptr );
845 SolarMutexGuard g;
847 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
848 if ( m_bDisposed )
849 throw DisposedException();
851 if (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE ))
852 throw IllegalArgumentException();
854 if ( m_bReadOnly )
855 throw IllegalAccessException();
857 vcl::ImageType nIndex = implts_convertImageTypeToIndex( nImageType );
858 rtl::Reference< GlobalImageList > rGlobalImageList;
859 CmdImageList* pDefaultImageList = nullptr;
860 if ( m_bUseGlobal )
862 rGlobalImageList = implts_getGlobalImageList();
863 pDefaultImageList = implts_getDefaultImageList();
865 ImageList* pImageList = implts_getUserImageList(nIndex);
866 uno::Reference<XGraphic> xEmptyGraphic;
868 for ( sal_Int32 i = 0; i < aCommandURLSequence.getLength(); i++ )
870 sal_uInt16 nPos = pImageList->GetImagePos( aCommandURLSequence[i] );
871 if ( nPos != IMAGELIST_IMAGE_NOTFOUND )
873 sal_uInt16 nId = pImageList->GetImageId( nPos );
874 pImageList->RemoveImage( nId );
876 if ( m_bUseGlobal )
878 // Check, if we have an image in our module/global image list. If we find one =>
879 // this is a replace instead of a remove operation!
880 Image aNewImage = pDefaultImageList->getImageFromCommandURL( nIndex, aCommandURLSequence[i] );
881 if ( !aNewImage )
882 aNewImage = rGlobalImageList->getImageFromCommandURL( nIndex, aCommandURLSequence[i] );
883 if ( !aNewImage )
885 if ( !pRemovedImages )
886 pRemovedImages = new GraphicNameAccess();
887 pRemovedImages->addElement( aCommandURLSequence[i], xEmptyGraphic );
889 else
891 if ( !pReplacedImages )
892 pReplacedImages = new GraphicNameAccess();
893 pReplacedImages->addElement(aCommandURLSequence[i], GetXGraphic(aNewImage));
895 } // if ( m_bUseGlobal )
896 else
898 if ( !pRemovedImages )
899 pRemovedImages = new GraphicNameAccess();
900 pRemovedImages->addElement( aCommandURLSequence[i], xEmptyGraphic );
905 if (( pReplacedImages != nullptr ) || ( pRemovedImages != nullptr ))
907 m_bModified = true;
908 m_bUserImageListModified[nIndex] = true;
912 // Notify listeners
913 uno::Reference< uno::XInterface > xOwner(m_pOwner);
914 if ( pRemovedImages != nullptr )
916 ConfigurationEvent aRemoveEvent;
917 aRemoveEvent.aInfo <<= nImageType;
918 aRemoveEvent.Accessor <<= xOwner;
919 aRemoveEvent.Source = xOwner;
920 aRemoveEvent.ResourceURL = m_aResourceString;
921 aRemoveEvent.Element <<= uno::Reference< XNameAccess >(
922 static_cast< OWeakObject *>( pRemovedImages ), UNO_QUERY );
923 implts_notifyContainerListener( aRemoveEvent, NotifyOp_Remove );
925 if ( pReplacedImages != nullptr )
927 ConfigurationEvent aReplaceEvent;
928 aReplaceEvent.aInfo <<= nImageType;
929 aReplaceEvent.Accessor <<= xOwner;
930 aReplaceEvent.Source = xOwner;
931 aReplaceEvent.ResourceURL = m_aResourceString;
932 aReplaceEvent.ReplacedElement = Any();
933 aReplaceEvent.Element <<= uno::Reference< XNameAccess >(
934 static_cast< OWeakObject *>( pReplacedImages ), UNO_QUERY );
935 implts_notifyContainerListener( aReplaceEvent, NotifyOp_Replace );
939 void ImageManagerImpl::insertImages( ::sal_Int16 nImageType, const Sequence< OUString >& aCommandURLSequence, const Sequence< uno::Reference< XGraphic > >& aGraphicSequence )
941 replaceImages(nImageType,aCommandURLSequence,aGraphicSequence);
944 // XUIConfigurationPersistence
945 void ImageManagerImpl::reload()
947 SolarMutexClearableGuard aGuard;
949 if ( m_bDisposed )
950 throw DisposedException();
952 CommandMap aOldUserCmdImageSet;
953 std::vector< OUString > aNewUserCmdImageSet;
955 if ( m_bModified )
957 for ( vcl::ImageType i : o3tl::enumrange<vcl::ImageType>() )
959 if ( !m_bDisposed && m_bUserImageListModified[i] )
961 std::vector< OUString > aOldUserCmdImageVector;
962 ImageList* pImageList = implts_getUserImageList(i);
963 pImageList->GetImageNames( aOldUserCmdImageVector );
965 // Fill hash map to speed up search afterwards
966 sal_uInt32 j( 0 );
967 const sal_uInt32 nOldCount = aOldUserCmdImageVector.size();
968 for ( j = 0; j < nOldCount; j++ )
969 aOldUserCmdImageSet.emplace( aOldUserCmdImageVector[j], false );
971 // Attention: This can make the old image list pointer invalid!
972 implts_loadUserImages( i, m_xUserImageStorage, m_xUserBitmapsStorage );
973 pImageList = implts_getUserImageList(i);
974 pImageList->GetImageNames( aNewUserCmdImageSet );
976 GraphicNameAccess* pInsertedImages( nullptr );
977 GraphicNameAccess* pReplacedImages( nullptr );
978 GraphicNameAccess* pRemovedImages( nullptr );
980 for (auto const& newUserCmdImage : aNewUserCmdImageSet)
982 CommandMap::iterator pIter = aOldUserCmdImageSet.find(newUserCmdImage);
983 if ( pIter != aOldUserCmdImageSet.end() )
985 pIter->second = true; // mark entry as replaced
986 if ( !pReplacedImages )
987 pReplacedImages = new GraphicNameAccess();
988 pReplacedImages->addElement( newUserCmdImage,
989 GetXGraphic(pImageList->GetImage(newUserCmdImage)) );
991 else
993 if ( !pInsertedImages )
994 pInsertedImages = new GraphicNameAccess();
995 pInsertedImages->addElement( newUserCmdImage,
996 GetXGraphic(pImageList->GetImage(newUserCmdImage)) );
1000 // Search map for unmarked entries => they have been removed from the user list
1001 // through this reload operation.
1002 // We have to search the module and global image list!
1003 rtl::Reference< GlobalImageList > rGlobalImageList;
1004 CmdImageList* pDefaultImageList = nullptr;
1005 if ( m_bUseGlobal )
1007 rGlobalImageList = implts_getGlobalImageList();
1008 pDefaultImageList = implts_getDefaultImageList();
1010 uno::Reference<XGraphic> xEmptyGraphic;
1011 for (auto const& oldUserCmdImage : aOldUserCmdImageSet)
1013 if ( !oldUserCmdImage.second )
1015 if ( m_bUseGlobal )
1017 Image aImage = pDefaultImageList->getImageFromCommandURL( i, oldUserCmdImage.first );
1018 if ( !aImage )
1019 aImage = rGlobalImageList->getImageFromCommandURL( i, oldUserCmdImage.first );
1021 if ( !aImage )
1023 // No image in the module/global image list => remove user image
1024 if ( !pRemovedImages )
1025 pRemovedImages = new GraphicNameAccess();
1026 pRemovedImages->addElement( oldUserCmdImage.first, xEmptyGraphic );
1028 else
1030 // Image has been found in the module/global image list => replace user image
1031 if ( !pReplacedImages )
1032 pReplacedImages = new GraphicNameAccess();
1033 pReplacedImages->addElement(oldUserCmdImage.first, GetXGraphic(aImage));
1035 } // if ( m_bUseGlobal )
1036 else
1038 // No image in the user image list => remove user image
1039 if ( !pRemovedImages )
1040 pRemovedImages = new GraphicNameAccess();
1041 pRemovedImages->addElement( oldUserCmdImage.first, xEmptyGraphic );
1046 aGuard.clear();
1048 // Now notify our listeners. Unlock mutex to prevent deadlocks
1049 uno::Reference< uno::XInterface > xOwner(m_pOwner);
1050 if ( pInsertedImages != nullptr )
1052 ConfigurationEvent aInsertEvent;
1053 aInsertEvent.aInfo <<=static_cast<sal_uInt16>(i);
1054 aInsertEvent.Accessor <<= xOwner;
1055 aInsertEvent.Source = xOwner;
1056 aInsertEvent.ResourceURL = m_aResourceString;
1057 aInsertEvent.Element <<= uno::Reference< XNameAccess >(
1058 static_cast< OWeakObject *>( pInsertedImages ), UNO_QUERY );
1059 implts_notifyContainerListener( aInsertEvent, NotifyOp_Insert );
1061 if ( pReplacedImages != nullptr )
1063 ConfigurationEvent aReplaceEvent;
1064 aReplaceEvent.aInfo <<= static_cast<sal_uInt16>(i);
1065 aReplaceEvent.Accessor <<= xOwner;
1066 aReplaceEvent.Source = xOwner;
1067 aReplaceEvent.ResourceURL = m_aResourceString;
1068 aReplaceEvent.ReplacedElement = Any();
1069 aReplaceEvent.Element <<= uno::Reference< XNameAccess >(
1070 static_cast< OWeakObject *>( pReplacedImages ), UNO_QUERY );
1071 implts_notifyContainerListener( aReplaceEvent, NotifyOp_Replace );
1073 if ( pRemovedImages != nullptr )
1075 ConfigurationEvent aRemoveEvent;
1076 aRemoveEvent.aInfo <<= static_cast<sal_uInt16>(i);
1077 aRemoveEvent.Accessor <<= xOwner;
1078 aRemoveEvent.Source = xOwner;
1079 aRemoveEvent.ResourceURL = m_aResourceString;
1080 aRemoveEvent.Element <<= uno::Reference< XNameAccess >(
1081 static_cast< OWeakObject *>( pRemovedImages ), UNO_QUERY );
1082 implts_notifyContainerListener( aRemoveEvent, NotifyOp_Remove );
1085 aGuard.clear();
1091 void ImageManagerImpl::store()
1093 SolarMutexGuard g;
1095 if ( m_bDisposed )
1096 throw DisposedException();
1098 if ( m_bModified )
1100 bool bWritten( false );
1101 for ( vcl::ImageType i : o3tl::enumrange<vcl::ImageType>() )
1103 bool bSuccess = implts_storeUserImages(i, m_xUserImageStorage, m_xUserBitmapsStorage );
1104 if ( bSuccess )
1105 bWritten = true;
1106 m_bUserImageListModified[i] = false;
1109 if ( bWritten &&
1110 m_xUserConfigStorage.is() )
1112 uno::Reference< XTransactedObject > xUserConfigStorageCommit( m_xUserConfigStorage, UNO_QUERY );
1113 if ( xUserConfigStorageCommit.is() )
1114 xUserConfigStorageCommit->commit();
1115 if ( m_xUserRootCommit.is() )
1116 m_xUserRootCommit->commit();
1119 m_bModified = false;
1123 void ImageManagerImpl::storeToStorage( const uno::Reference< XStorage >& Storage )
1125 SolarMutexGuard g;
1127 if ( m_bDisposed )
1128 throw DisposedException();
1130 if ( m_bModified && Storage.is() )
1132 long nModes = ElementModes::READWRITE;
1134 uno::Reference< XStorage > xUserImageStorage = Storage->openStorageElement( IMAGE_FOLDER,
1135 nModes );
1136 if ( xUserImageStorage.is() )
1138 uno::Reference< XStorage > xUserBitmapsStorage = xUserImageStorage->openStorageElement( BITMAPS_FOLDER,
1139 nModes );
1140 for ( vcl::ImageType i : o3tl::enumrange<vcl::ImageType>() )
1142 implts_getUserImageList(i);
1143 implts_storeUserImages( i, xUserImageStorage, xUserBitmapsStorage );
1146 uno::Reference< XTransactedObject > xTransaction( Storage, UNO_QUERY );
1147 if ( xTransaction.is() )
1148 xTransaction->commit();
1153 bool ImageManagerImpl::isModified() const
1155 SolarMutexGuard g;
1156 return m_bModified;
1159 bool ImageManagerImpl::isReadOnly() const
1161 SolarMutexGuard g;
1162 return m_bReadOnly;
1164 // XUIConfiguration
1165 void ImageManagerImpl::addConfigurationListener( const uno::Reference< css::ui::XUIConfigurationListener >& xListener )
1168 SolarMutexGuard g;
1170 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
1171 if ( m_bDisposed )
1172 throw DisposedException();
1175 m_aListenerContainer.addInterface( cppu::UnoType<XUIConfigurationListener>::get(), xListener );
1178 void ImageManagerImpl::removeConfigurationListener( const uno::Reference< css::ui::XUIConfigurationListener >& xListener )
1180 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
1181 m_aListenerContainer.removeInterface( cppu::UnoType<XUIConfigurationListener>::get(), xListener );
1184 void ImageManagerImpl::implts_notifyContainerListener( const ConfigurationEvent& aEvent, NotifyOp eOp )
1186 ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer(
1187 cppu::UnoType<css::ui::XUIConfigurationListener>::get());
1188 if ( pContainer != nullptr )
1190 ::cppu::OInterfaceIteratorHelper pIterator( *pContainer );
1191 while ( pIterator.hasMoreElements() )
1195 switch ( eOp )
1197 case NotifyOp_Replace:
1198 static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementReplaced( aEvent );
1199 break;
1200 case NotifyOp_Insert:
1201 static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementInserted( aEvent );
1202 break;
1203 case NotifyOp_Remove:
1204 static_cast< css::ui::XUIConfigurationListener*>(pIterator.next())->elementRemoved( aEvent );
1205 break;
1208 catch( const css::uno::RuntimeException& )
1210 pIterator.remove();
1215 void ImageManagerImpl::clear()
1217 SolarMutexGuard g;
1219 for (auto & n : m_pUserImageList)
1221 n.reset();
1224 } // namespace framework
1226 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */