1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
30 
31 #include <imagemanagerimpl.hxx>
32 #include <threadhelp/resetableguard.hxx>
33 #include <xml/imagesconfiguration.hxx>
34 #include <uiconfiguration/graphicnameaccess.hxx>
35 #include <services.h>
36 
37 #include "properties.h"
38 
39 //_________________________________________________________________________________________________________________
40 //	interface includes
41 //_________________________________________________________________________________________________________________
42 #include <com/sun/star/ui/UIElementType.hpp>
43 #include <com/sun/star/ui/ConfigurationEvent.hpp>
44 #include <com/sun/star/lang/DisposedException.hpp>
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <com/sun/star/beans/PropertyValue.hpp>
47 #include <com/sun/star/embed/ElementModes.hpp>
48 #include <com/sun/star/io/XStream.hpp>
49 #include <com/sun/star/ui/ImageType.hpp>
50 
51 //_________________________________________________________________________________________________________________
52 //	other includes
53 //_________________________________________________________________________________________________________________
54 
55 #include <vcl/svapp.hxx>
56 #include <rtl/ustrbuf.hxx>
57 #include <osl/mutex.hxx>
58 #include <comphelper/sequence.hxx>
59 #include <tools/urlobj.hxx>
60 #include <unotools/ucbstreamhelper.hxx>
61 #include <vcl/pngread.hxx>
62 #include <vcl/pngwrite.hxx>
63 #include <rtl/logfile.hxx>
64 #include "svtools/miscopt.hxx"
65 
66 //_________________________________________________________________________________________________________________
67 //	namespaces
68 //_________________________________________________________________________________________________________________
69 
70 using ::rtl::OUString;
71 using ::com::sun::star::uno::Sequence;
72 using ::com::sun::star::uno::XInterface;
73 using ::com::sun::star::uno::Exception;
74 using ::com::sun::star::uno::RuntimeException;
75 using ::com::sun::star::uno::UNO_QUERY;
76 using ::com::sun::star::uno::Any;
77 using ::com::sun::star::uno::makeAny;
78 using ::com::sun::star::graphic::XGraphic;
79 using namespace ::com::sun::star;
80 using namespace ::com::sun::star::io;
81 using namespace ::com::sun::star::embed;
82 using namespace ::com::sun::star::lang;
83 using namespace ::com::sun::star::container;
84 using namespace ::com::sun::star::beans;
85 using namespace ::com::sun::star::ui;
86 using namespace ::cppu;
87 
88 // Image sizes for our toolbars/menus
89 const sal_Int32 IMAGE_SIZE_NORMAL         = 16;
90 const sal_Int32 IMAGE_SIZE_LARGE          = 26;
91 const sal_Int16 MAX_IMAGETYPE_VALUE       = ::com::sun::star::ui::ImageType::COLOR_HIGHCONTRAST|
92                                             ::com::sun::star::ui::ImageType::SIZE_LARGE;
93 
94 static const char   IMAGE_FOLDER[]        = "images";
95 static const char   BITMAPS_FOLDER[]      = "Bitmaps";
96 static const char   IMAGE_EXTENSION[]     = ".png";
97 
98 static const char*  IMAGELIST_XML_FILE[]  =
99 {
100     "sc_imagelist.xml",
101     "lc_imagelist.xml",
102     "sch_imagelist.xml",
103     "lch_imagelist.xml"
104 };
105 
106 static const char*  BITMAP_FILE_NAMES[]   =
107 {
108     "sc_userimages.png",
109     "lc_userimages.png",
110     "sch_userimages.png",
111     "lch_userimages.png"
112 };
113 
114 namespace framework
115 {
116     static char ModuleImageList[] = "private:resource/images/moduleimages";
117     static osl::Mutex*          pImageListWrapperMutex = 0;
118     static GlobalImageList*     pGlobalImageList = 0;
119     static const char* ImageType_Prefixes[ImageType_COUNT] =
120     {
121         "res/commandimagelist/sc_",
122         "res/commandimagelist/lc_",
123         "res/commandimagelist/sch_",
124         "res/commandimagelist/lch_"
125     };
126 
127 typedef GraphicNameAccess CmdToXGraphicNameAccess;
128 
129 static osl::Mutex& getGlobalImageListMutex()
130 {
131     if ( pImageListWrapperMutex == 0 )
132     {
133         osl::MutexGuard aGuard( osl::Mutex::getGlobalMutex() ) ;
134         if ( pImageListWrapperMutex == 0 )
135             pImageListWrapperMutex = new osl::Mutex;
136     }
137 
138     return *pImageListWrapperMutex;
139 }
140 
141 static GlobalImageList* getGlobalImageList( const uno::Reference< XMultiServiceFactory >& rServiceManager )
142 {
143     osl::MutexGuard guard( getGlobalImageListMutex() );
144 
145     if ( pGlobalImageList == 0 )
146         pGlobalImageList = new GlobalImageList( rServiceManager );
147 
148     return pGlobalImageList;
149 }
150 
151 static rtl::OUString getCanonicalName( const rtl::OUString& rFileName )
152 {
153     bool               bRemoveSlash( true );
154     sal_Int32          nLength = rFileName.getLength();
155     const sal_Unicode* pString = rFileName.getStr();
156 
157     rtl::OUStringBuffer aBuf( nLength );
158     for ( sal_Int32 i = 0; i < nLength; i++ )
159     {
160         const sal_Unicode c = pString[i];
161         switch ( c )
162         {
163             // map forbidden characters to escape
164             case '/' : if ( !bRemoveSlash )
165                          aBuf.appendAscii( "%2f" );
166                        break;
167             case '\\': aBuf.appendAscii( "%5c" ); bRemoveSlash = false; break;
168             case ':' : aBuf.appendAscii( "%3a" ); bRemoveSlash = false; break;
169             case '*' : aBuf.appendAscii( "%2a" ); bRemoveSlash = false; break;
170             case '?' : aBuf.appendAscii( "%3f" ); bRemoveSlash = false; break;
171             case '<' : aBuf.appendAscii( "%3c" ); bRemoveSlash = false; break;
172             case '>' : aBuf.appendAscii( "%3e" ); bRemoveSlash = false; break;
173             case '|' : aBuf.appendAscii( "%7c" ); bRemoveSlash = false; break;
174             default: aBuf.append( c ); bRemoveSlash = false;
175         }
176     }
177     return aBuf.makeStringAndClear();
178 }
179 
180 //_________________________________________________________________________________________________________________
181 
182 CmdImageList::CmdImageList( const uno::Reference< XMultiServiceFactory >& rServiceManager, const rtl::OUString& aModuleIdentifier ) :
183     m_bVectorInit( sal_False ),
184     m_aModuleIdentifier( aModuleIdentifier ),
185     m_xServiceManager( rServiceManager ),
186     m_nSymbolsStyle( SvtMiscOptions().GetCurrentSymbolsStyle() )
187 {
188     for ( sal_Int32 n=0; n < ImageType_COUNT; n++ )
189         m_pImageList[n] = 0;
190 }
191 
192 CmdImageList::~CmdImageList()
193 {
194     for ( sal_Int32 n=0; n < ImageType_COUNT; n++ )
195         delete m_pImageList[n];
196 }
197 
198 void CmdImageList::impl_fillCommandToImageNameMap()
199 {
200     RTL_LOGFILE_CONTEXT( aLog, "framework: CmdImageList::impl_fillCommandToImageNameMap" );
201 
202     if ( !m_bVectorInit )
203     {
204         const rtl::OUString aCommandImageList( RTL_CONSTASCII_USTRINGPARAM( UICOMMANDDESCRIPTION_NAMEACCESS_COMMANDIMAGELIST ));
205         Sequence< OUString > aCmdImageSeq;
206         uno::Reference< XNameAccess > xCmdDesc( m_xServiceManager->createInstance(
207                                                 SERVICENAME_UICOMMANDDESCRIPTION ),
208                                             UNO_QUERY );
209 
210         if ( m_aModuleIdentifier.getLength() > 0 )
211         {
212             // If we have a module identifier - use to retrieve the command image name list from it.
213             // Otherwise we will use the global command image list
214             try
215             {
216                 xCmdDesc->getByName( m_aModuleIdentifier ) >>= xCmdDesc;
217                 if ( xCmdDesc.is() )
218                     xCmdDesc->getByName( aCommandImageList ) >>= aCmdImageSeq;
219             }
220             catch ( NoSuchElementException& )
221             {
222                 // Module unknown we will work with an empty command image list!
223                 return;
224             }
225         }
226 
227         if ( xCmdDesc.is() )
228         {
229             try
230             {
231                 xCmdDesc->getByName( aCommandImageList ) >>= aCmdImageSeq;
232             }
233             catch ( NoSuchElementException& )
234             {
235             }
236             catch ( WrappedTargetException& )
237             {
238             }
239         }
240 
241         // We have to map commands which uses special characters like '/',':','?','\','<'.'>','|'
242         String aExt = String::CreateFromAscii( IMAGE_EXTENSION );
243         m_aImageCommandNameVector.resize(aCmdImageSeq.getLength() );
244         m_aImageNameVector.resize( aCmdImageSeq.getLength() );
245 
246         ::std::copy( aCmdImageSeq.getConstArray(),
247                      aCmdImageSeq.getConstArray()+aCmdImageSeq.getLength(),
248                      m_aImageCommandNameVector.begin() );
249 
250         // Create a image name vector that must be provided to the vcl imagelist. We also need
251         // a command to image name map to speed up access time for image retrieval.
252         OUString aUNOString( RTL_CONSTASCII_USTRINGPARAM( ".uno:" ));
253         String   aEmptyString;
254         const sal_uInt32 nCount = m_aImageCommandNameVector.size();
255 		for ( sal_uInt32 i = 0; i < nCount; i++ )
256         {
257             OUString aCommandName( m_aImageCommandNameVector[i] );
258             String   aImageName;
259 
260             if ( aCommandName.indexOf( aUNOString ) != 0 )
261             {
262                 INetURLObject aUrlObject( aCommandName, INetURLObject::ENCODE_ALL );
263                 aImageName = aUrlObject.GetURLPath();
264                 aImageName = getCanonicalName( aImageName ); // convert to valid filename
265             }
266             else
267             {
268                 // just remove the schema
269                 if ( aCommandName.getLength() > 5 )
270                     aImageName = aCommandName.copy( 5 );
271                 else
272                     aImageName = aEmptyString;
273 
274                 // Search for query part.
275                 sal_Int32 nIndex = aImageName.Search( '?' );
276                 if ( nIndex != STRING_NOTFOUND )
277                     aImageName = getCanonicalName( aImageName ); // convert to valid filename
278             }
279             // Image names are not case-dependent. Always use lower case characters to
280             // reflect this.
281             aImageName += aExt;
282             aImageName.ToLowerAscii();
283 
284             m_aImageNameVector[i] = aImageName;
285             m_aCommandToImageNameMap.insert( CommandToImageNameMap::value_type( aCommandName, aImageName ));
286         }
287 
288         m_bVectorInit = sal_True;
289     }
290 }
291 
292 ImageList* CmdImageList::impl_getImageList( sal_Int16 nImageType )
293 {
294     SvtMiscOptions aMiscOptions;
295 
296     sal_Int16 nSymbolsStyle = aMiscOptions.GetCurrentSymbolsStyle();
297     if ( nSymbolsStyle != m_nSymbolsStyle )
298     {
299         m_nSymbolsStyle = nSymbolsStyle;
300         for ( sal_Int32 n=0; n < ImageType_COUNT; n++ )
301             delete m_pImageList[n], m_pImageList[n] = NULL;
302     }
303 
304     if ( !m_pImageList[nImageType] )
305     {
306         m_pImageList[nImageType] = new ImageList( m_aImageNameVector,
307                                                   OUString::createFromAscii( ImageType_Prefixes[nImageType] ) );
308     }
309 
310     return m_pImageList[nImageType];
311 }
312 
313 std::vector< ::rtl::OUString >& CmdImageList::impl_getImageNameVector()
314 {
315     return m_aImageNameVector;
316 }
317 
318 std::vector< rtl::OUString >& CmdImageList::impl_getImageCommandNameVector()
319 {
320     return m_aImageCommandNameVector;
321 }
322 
323 Image CmdImageList::getImageFromCommandURL( sal_Int16 nImageType, const rtl::OUString& rCommandURL )
324 {
325     impl_fillCommandToImageNameMap();
326     CommandToImageNameMap::const_iterator pIter = m_aCommandToImageNameMap.find( rCommandURL );
327     if ( pIter != m_aCommandToImageNameMap.end() )
328     {
329         ImageList* pImageList = impl_getImageList( nImageType );
330         return pImageList->GetImage( pIter->second );
331     }
332 
333     return Image();
334 }
335 
336 bool CmdImageList::hasImage( sal_Int16 /*nImageType*/, const rtl::OUString& rCommandURL )
337 {
338     impl_fillCommandToImageNameMap();
339     CommandToImageNameMap::const_iterator pIter = m_aCommandToImageNameMap.find( rCommandURL );
340     if ( pIter != m_aCommandToImageNameMap.end() )
341         return true;
342     else
343         return false;
344 }
345 
346 ::std::vector< rtl::OUString >& CmdImageList::getImageNames()
347 {
348     return impl_getImageNameVector();
349 }
350 
351 ::std::vector< rtl::OUString >& CmdImageList::getImageCommandNames()
352 {
353     return impl_getImageCommandNameVector();
354 }
355 
356 //_________________________________________________________________________________________________________________
357 
358 GlobalImageList::GlobalImageList( const uno::Reference< XMultiServiceFactory >& rServiceManager ) :
359     CmdImageList( rServiceManager, rtl::OUString() ),
360     m_nRefCount( 0 )
361 {
362 }
363 
364 GlobalImageList::~GlobalImageList()
365 {
366 }
367 
368 Image GlobalImageList::getImageFromCommandURL( sal_Int16 nImageType, const rtl::OUString& rCommandURL )
369 {
370     osl::MutexGuard guard( getGlobalImageListMutex() );
371     return CmdImageList::getImageFromCommandURL( nImageType, rCommandURL );
372 }
373 
374 bool GlobalImageList::hasImage( sal_Int16 nImageType, const rtl::OUString& rCommandURL )
375 {
376     osl::MutexGuard guard( getGlobalImageListMutex() );
377     return CmdImageList::hasImage( nImageType, rCommandURL );
378 }
379 
380 ::std::vector< rtl::OUString >& GlobalImageList::getImageNames()
381 {
382     osl::MutexGuard guard( getGlobalImageListMutex() );
383     return impl_getImageNameVector();
384 }
385 
386 ::std::vector< rtl::OUString >& GlobalImageList::getImageCommandNames()
387 {
388     osl::MutexGuard guard( getGlobalImageListMutex() );
389     return impl_getImageCommandNameVector();
390 }
391 
392 oslInterlockedCount GlobalImageList::acquire()
393 {
394     osl_incrementInterlockedCount( &m_nRefCount );
395     return m_nRefCount;
396 }
397 
398 oslInterlockedCount GlobalImageList::release()
399 {
400     osl::MutexGuard guard( getGlobalImageListMutex() );
401 
402     if ( !osl_decrementInterlockedCount( &m_nRefCount ))
403     {
404         oslInterlockedCount nCount( m_nRefCount );
405         // remove global pointer as we destroy the object now
406         pGlobalImageList = 0;
407 		delete this;
408         return nCount;
409     }
410 
411     return m_nRefCount;
412 }
413 
414 static sal_Bool implts_checkAndScaleGraphic( uno::Reference< XGraphic >& rOutGraphic, const uno::Reference< XGraphic >& rInGraphic, sal_Int16 nImageType )
415 {
416     static Size   aNormSize( IMAGE_SIZE_NORMAL, IMAGE_SIZE_NORMAL );
417     static Size   aLargeSize( IMAGE_SIZE_LARGE, IMAGE_SIZE_LARGE );
418 
419     if ( !rInGraphic.is() )
420     {
421         rOutGraphic = Image().GetXGraphic();
422         return sal_False;
423     }
424 
425     // Check size and scale it
426     Image  aImage( rInGraphic );
427     Size   aSize = aImage.GetSizePixel();
428     bool   bMustScale( false );
429 
430     if (( nImageType == ImageType_Color_Large ) ||
431         ( nImageType == ImageType_HC_Large ))
432         bMustScale = ( aSize != aLargeSize );
433     else
434         bMustScale = ( aSize != aNormSize );
435 
436     if ( bMustScale )
437     {
438         BitmapEx aBitmap = aImage.GetBitmapEx();
439         aBitmap.Scale( aNormSize );
440         aImage = Image( aBitmap );
441         rOutGraphic = aImage.GetXGraphic();
442     }
443     else
444         rOutGraphic = rInGraphic;
445     return sal_True;
446 }
447 
448 static sal_Int16 implts_convertImageTypeToIndex( sal_Int16 nImageType )
449 {
450     sal_Int16 nIndex( 0 );
451     if ( nImageType & ::com::sun::star::ui::ImageType::SIZE_LARGE )
452         nIndex += 1;
453     if ( nImageType & ::com::sun::star::ui::ImageType::COLOR_HIGHCONTRAST )
454         nIndex += 2;
455     return nIndex;
456 }
457 
458 ImageList* ImageManagerImpl::implts_getUserImageList( ImageType nImageType )
459 {
460     ResetableGuard aGuard( m_aLock );
461     if ( !m_pUserImageList[nImageType] )
462         implts_loadUserImages( nImageType, m_xUserImageStorage, m_xUserBitmapsStorage );
463 
464     return m_pUserImageList[nImageType];
465 }
466 
467 void ImageManagerImpl::implts_initialize()
468 {
469     // Initialize the top-level structures with the storage data
470     if ( m_xUserConfigStorage.is() )
471     {
472         long nModes = m_bReadOnly ? ElementModes::READ : ElementModes::READWRITE;
473 
474         try
475         {
476             m_xUserImageStorage = m_xUserConfigStorage->openStorageElement( OUString::createFromAscii( IMAGE_FOLDER ),
477                                                                             nModes );
478             if ( m_xUserImageStorage.is() )
479             {
480                 m_xUserBitmapsStorage = m_xUserImageStorage->openStorageElement( OUString::createFromAscii( BITMAPS_FOLDER ),
481                                                                                  nModes );
482             }
483         }
484         catch ( com::sun::star::container::NoSuchElementException& )
485         {
486         }
487         catch ( ::com::sun::star::embed::InvalidStorageException& )
488         {
489         }
490         catch ( ::com::sun::star::lang::IllegalArgumentException& )
491         {
492         }
493         catch ( ::com::sun::star::io::IOException& )
494         {
495         }
496         catch ( ::com::sun::star::embed::StorageWrappedTargetException& )
497         {
498         }
499     }
500 }
501 
502 sal_Bool ImageManagerImpl::implts_loadUserImages(
503     ImageType nImageType,
504     const uno::Reference< XStorage >& xUserImageStorage,
505     const uno::Reference< XStorage >& xUserBitmapsStorage )
506 {
507     ResetableGuard aGuard( m_aLock );
508 
509     if ( xUserImageStorage.is() && xUserBitmapsStorage.is() )
510     {
511         try
512         {
513             uno::Reference< XStream > xStream = xUserImageStorage->openStreamElement( rtl::OUString::createFromAscii( IMAGELIST_XML_FILE[nImageType] ),
514                                                                                       ElementModes::READ );
515             uno::Reference< XInputStream > xInputStream = xStream->getInputStream();
516 
517             ImageListsDescriptor aUserImageListInfo;
518             ImagesConfiguration::LoadImages( m_xServiceManager,
519                                              xInputStream,
520                                              aUserImageListInfo );
521             if (( aUserImageListInfo.pImageList != 0 ) &&
522                 ( aUserImageListInfo.pImageList->Count() > 0 ))
523             {
524                 ImageListItemDescriptor* pList = aUserImageListInfo.pImageList->GetObject(0);
525                 sal_Int32 nCount = pList->pImageItemList->Count();
526                 std::vector< OUString > aUserImagesVector;
527                 aUserImagesVector.reserve(nCount);
528                 for ( sal_uInt16 i=0; i < nCount; i++ )
529                 {
530                     const ImageItemDescriptor* pItem = pList->pImageItemList->GetObject(i);
531                     aUserImagesVector.push_back( pItem->aCommandURL );
532                 }
533 
534                 uno::Reference< XStream > xBitmapStream = xUserBitmapsStorage->openStreamElement(
535                                                         rtl::OUString::createFromAscii( BITMAP_FILE_NAMES[nImageType] ),
536                                                         ElementModes::READ );
537 
538                 if ( xBitmapStream.is() )
539                 {
540                     SvStream* pSvStream( 0 );
541 		            BitmapEx aUserBitmap;
542 		            {
543 		                pSvStream = utl::UcbStreamHelper::CreateStream( xBitmapStream );
544 		                vcl::PNGReader aPngReader( *pSvStream );
545 		                aUserBitmap = aPngReader.Read();
546 		            }
547                     delete pSvStream;
548 
549                     // Delete old image list and create a new one from the read bitmap
550                     delete m_pUserImageList[nImageType];
551                     m_pUserImageList[nImageType] = new ImageList();
552 					m_pUserImageList[nImageType]->InsertFromHorizontalStrip
553 						( aUserBitmap, aUserImagesVector );
554                     return sal_True;
555                 }
556             }
557         }
558         catch ( com::sun::star::container::NoSuchElementException& )
559         {
560         }
561         catch ( ::com::sun::star::embed::InvalidStorageException& )
562         {
563         }
564         catch ( ::com::sun::star::lang::IllegalArgumentException& )
565         {
566         }
567         catch ( ::com::sun::star::io::IOException& )
568         {
569         }
570         catch ( ::com::sun::star::embed::StorageWrappedTargetException& )
571         {
572         }
573     }
574 
575     // Destroy old image list - create a new empty one
576     delete m_pUserImageList[nImageType];
577     m_pUserImageList[nImageType] = new ImageList;
578 
579     return sal_True;
580 }
581 
582 sal_Bool ImageManagerImpl::implts_storeUserImages(
583     ImageType nImageType,
584     const uno::Reference< XStorage >& xUserImageStorage,
585     const uno::Reference< XStorage >& xUserBitmapsStorage )
586 {
587     ResetableGuard aGuard( m_aLock );
588 
589     if ( m_bModified )
590     {
591         ImageList* pImageList = implts_getUserImageList( nImageType );
592         if ( pImageList->GetImageCount() > 0 )
593         {
594             ImageListsDescriptor aUserImageListInfo;
595             aUserImageListInfo.pImageList = new ImageListDescriptor;
596 
597             ImageListItemDescriptor* pList = new ImageListItemDescriptor;
598             aUserImageListInfo.pImageList->Insert( pList, 0 );
599 
600             pList->pImageItemList = new ImageItemListDescriptor;
601             for ( sal_uInt16 i=0; i < pImageList->GetImageCount(); i++ )
602             {
603                 ImageItemDescriptor* pItem = new ::framework::ImageItemDescriptor;
604 
605                 pItem->nIndex = i;
606                 pItem->aCommandURL = pImageList->GetImageName( i );
607                 pList->pImageItemList->Insert( pItem, pList->pImageItemList->Count() );
608             }
609 
610             pList->aURL = String::CreateFromAscii("Bitmaps/");
611             pList->aURL += String::CreateFromAscii( BITMAP_FILE_NAMES[nImageType] );
612 
613             uno::Reference< XTransactedObject > xTransaction;
614             uno::Reference< XOutputStream >     xOutputStream;
615             uno::Reference< XStream > xStream = xUserImageStorage->openStreamElement( rtl::OUString::createFromAscii( IMAGELIST_XML_FILE[nImageType] ),
616                                                                                       ElementModes::WRITE|ElementModes::TRUNCATE );
617             if ( xStream.is() )
618             {
619                 uno::Reference< XStream > xBitmapStream =
620                     xUserBitmapsStorage->openStreamElement( rtl::OUString::createFromAscii( BITMAP_FILE_NAMES[nImageType] ),
621                                                             ElementModes::WRITE|ElementModes::TRUNCATE );
622                 if ( xBitmapStream.is() )
623                 {
624                     SvStream* pSvStream = utl::UcbStreamHelper::CreateStream( xBitmapStream );
625                     {
626                         vcl::PNGWriter aPngWriter( pImageList->GetAsHorizontalStrip() );
627                         aPngWriter.Write( *pSvStream );
628                     }
629                     delete pSvStream;
630 
631                     // Commit user bitmaps storage
632                     xTransaction = uno::Reference< XTransactedObject >( xUserBitmapsStorage, UNO_QUERY );
633 					if ( xTransaction.is() )
634                     	xTransaction->commit();
635                 }
636 
637                 xOutputStream = xStream->getOutputStream();
638                 if ( xOutputStream.is() )
639                     ImagesConfiguration::StoreImages( m_xServiceManager, xOutputStream, aUserImageListInfo );
640 
641                 // Commit user image storage
642                 xTransaction = uno::Reference< XTransactedObject >( xUserImageStorage, UNO_QUERY );
643 				if ( xTransaction.is() )
644                 	xTransaction->commit();
645             }
646 
647             return sal_True;
648         }
649         else
650         {
651             // Remove the streams from the storage, if we have no data. We have to catch
652             // the NoSuchElementException as it can be possible that there is no stream at all!
653             try
654             {
655                 xUserImageStorage->removeElement( rtl::OUString::createFromAscii( IMAGELIST_XML_FILE[nImageType] ));
656             }
657             catch ( ::com::sun::star::container::NoSuchElementException& )
658             {
659             }
660 
661             try
662             {
663                 xUserBitmapsStorage->removeElement( rtl::OUString::createFromAscii( BITMAP_FILE_NAMES[nImageType] ));
664             }
665             catch ( ::com::sun::star::container::NoSuchElementException& )
666             {
667             }
668 
669             uno::Reference< XTransactedObject > xTransaction;
670 
671             // Commit user image storage
672             xTransaction = uno::Reference< XTransactedObject >( xUserImageStorage, UNO_QUERY );
673 			if ( xTransaction.is() )
674                 xTransaction->commit();
675 
676             // Commit user bitmaps storage
677             xTransaction = uno::Reference< XTransactedObject >( xUserBitmapsStorage, UNO_QUERY );
678 			if ( xTransaction.is() )
679                 xTransaction->commit();
680 
681             return sal_True;
682         }
683     }
684 
685     return sal_False;
686 }
687 const rtl::Reference< GlobalImageList >& ImageManagerImpl::implts_getGlobalImageList()
688 {
689     ResetableGuard aGuard( m_aLock );
690 
691     if ( !m_pGlobalImageList.is() )
692         m_pGlobalImageList = getGlobalImageList( m_xServiceManager );
693     return m_pGlobalImageList;
694 }
695 
696 CmdImageList* ImageManagerImpl::implts_getDefaultImageList()
697 {
698     ResetableGuard aGuard( m_aLock );
699 
700     if ( !m_pDefaultImageList )
701         m_pDefaultImageList = new CmdImageList( m_xServiceManager, m_aModuleIdentifier );
702 
703     return m_pDefaultImageList;
704 }
705 
706 ImageManagerImpl::ImageManagerImpl( const uno::Reference< XMultiServiceFactory >& xServiceManager,const uno::Reference< XInterface >& _xOwner,bool _bUseGlobal ) :
707     ThreadHelpBase( &Application::GetSolarMutex() )
708     , m_xServiceManager( xServiceManager )
709     , m_xOwner(_xOwner)
710     , m_pDefaultImageList( 0 )
711     , m_aXMLPostfix( RTL_CONSTASCII_USTRINGPARAM( ".xml" ))
712     , m_aResourceString( RTL_CONSTASCII_USTRINGPARAM( ModuleImageList ))
713     , m_aListenerContainer( m_aLock.getShareableOslMutex() )
714     , m_bUseGlobal(_bUseGlobal)
715     , m_bReadOnly( true )
716     , m_bInitialized( false )
717     , m_bModified( false )
718     , m_bConfigRead( false )
719     , m_bDisposed( false )
720 {
721     for ( sal_Int32 n=0; n < ImageType_COUNT; n++ )
722     {
723         m_pUserImageList[n] = 0;
724         m_bUserImageListModified[n] = false;
725     }
726 }
727 
728 ImageManagerImpl::~ImageManagerImpl()
729 {
730     clear();
731 }
732 
733 void ImageManagerImpl::dispose()
734 {
735     css::lang::EventObject aEvent( m_xOwner );
736     m_aListenerContainer.disposeAndClear( aEvent );
737 
738 	{
739 	    ResetableGuard aGuard( m_aLock );
740         m_xUserConfigStorage.clear();
741         m_xUserImageStorage.clear();
742         m_xUserRootCommit.clear();
743         m_bConfigRead = false;
744         m_bModified = false;
745         m_bDisposed = true;
746 
747         // delete user and default image list on dispose
748         for ( sal_Int32 n=0; n < ImageType_COUNT; n++ )
749         {
750             delete m_pUserImageList[n];
751             m_pUserImageList[n] = 0;
752         }
753         delete m_pDefaultImageList;
754         m_pDefaultImageList = 0;
755     }
756 
757 }
758 void ImageManagerImpl::addEventListener( const uno::Reference< XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
759 {
760     {
761         ResetableGuard aGuard( m_aLock );
762 
763 	    /* SAFE AREA ----------------------------------------------------------------------------------------------- */
764         if ( m_bDisposed )
765             throw DisposedException();
766     }
767 
768     m_aListenerContainer.addInterface( ::getCppuType( ( const uno::Reference< XEventListener >* ) NULL ), xListener );
769 }
770 
771 void ImageManagerImpl::removeEventListener( const uno::Reference< XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException)
772 {
773     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
774     m_aListenerContainer.removeInterface( ::getCppuType( ( const uno::Reference< XEventListener >* ) NULL ), xListener );
775 }
776 
777 // XInitialization
778 void ImageManagerImpl::initialize( const Sequence< Any >& aArguments )
779 {
780     ResetableGuard aLock( m_aLock );
781 
782     if ( !m_bInitialized )
783     {
784         for ( sal_Int32 n = 0; n < aArguments.getLength(); n++ )
785         {
786             PropertyValue aPropValue;
787             if ( aArguments[n] >>= aPropValue )
788             {
789                 if ( aPropValue.Name.equalsAscii( "UserConfigStorage" ))
790                 {
791                     aPropValue.Value >>= m_xUserConfigStorage;
792                 }
793                 else if ( aPropValue.Name.equalsAscii( "ModuleIdentifier" ))
794                 {
795                     aPropValue.Value >>= m_aModuleIdentifier;
796                 }
797                 else if ( aPropValue.Name.equalsAscii( "UserRootCommit" ))
798                 {
799                     aPropValue.Value >>= m_xUserRootCommit;
800                 }
801             }
802         }
803 
804         if ( m_xUserConfigStorage.is() )
805         {
806             uno::Reference< XPropertySet > xPropSet( m_xUserConfigStorage, UNO_QUERY );
807             if ( xPropSet.is() )
808             {
809                 long nOpenMode = 0;
810                 if ( xPropSet->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OpenMode" ))) >>= nOpenMode )
811                     m_bReadOnly = !( nOpenMode & ElementModes::WRITE );
812             }
813         }
814 
815         implts_initialize();
816 
817         m_bInitialized = true;
818     }
819 }
820 
821 // XImageManagerImpl
822 void ImageManagerImpl::reset()
823 throw (::com::sun::star::uno::RuntimeException)
824 {
825     ResetableGuard aLock( m_aLock );
826 
827     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
828     if ( m_bDisposed )
829         throw DisposedException();
830 
831     std::vector< OUString > aUserImageNames;
832 
833     for ( sal_Int32 i = 0; i < ImageType_COUNT; i++ )
834     {
835         aUserImageNames.clear();
836         ImageList* pImageList = implts_getUserImageList( ImageType(i));
837         pImageList->GetImageNames( aUserImageNames );
838 
839         Sequence< rtl::OUString > aRemoveList( aUserImageNames.size() );
840         const sal_uInt32 nCount = aUserImageNames.size();
841 		for ( sal_uInt32 j = 0; j < nCount; j++ )
842             aRemoveList[j] = aUserImageNames[j];
843 
844         // Remove images
845         removeImages( sal_Int16( i ), aRemoveList );
846         m_bUserImageListModified[i] = true;
847     }
848 
849     m_bModified = sal_True;
850 }
851 
852 Sequence< ::rtl::OUString > ImageManagerImpl::getAllImageNames( ::sal_Int16 nImageType )
853 throw (::com::sun::star::uno::RuntimeException)
854 {
855     ResetableGuard aLock( m_aLock );
856 
857     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
858     if ( m_bDisposed )
859         throw DisposedException();
860 
861     ImageNameMap aImageCmdNameMap;
862 
863     sal_Int16 nIndex = implts_convertImageTypeToIndex( nImageType );
864 
865     sal_uInt32 i( 0 );
866     if ( m_bUseGlobal )
867     {
868         rtl::Reference< GlobalImageList > rGlobalImageList = implts_getGlobalImageList();
869 
870         const std::vector< OUString >& rGlobalImageNameVector = rGlobalImageList->getImageCommandNames();
871         const sal_uInt32 nGlobalCount = rGlobalImageNameVector.size();
872         for ( i = 0; i < nGlobalCount; i++ )
873             aImageCmdNameMap.insert( ImageNameMap::value_type( rGlobalImageNameVector[i], sal_True ));
874 
875         const std::vector< OUString >& rModuleImageNameVector = implts_getDefaultImageList()->getImageCommandNames();
876         const sal_uInt32 nModuleCount = rModuleImageNameVector.size();
877         for ( i = 0; i < nModuleCount; i++ )
878             aImageCmdNameMap.insert( ImageNameMap::value_type( rModuleImageNameVector[i], sal_True ));
879     }
880 
881     ImageList* pImageList = implts_getUserImageList( ImageType( nIndex ));
882     std::vector< OUString > rUserImageNames;
883     pImageList->GetImageNames( rUserImageNames );
884     const sal_uInt32 nUserCount = rUserImageNames.size();
885     for ( i = 0; i < nUserCount; i++ )
886         aImageCmdNameMap.insert( ImageNameMap::value_type( rUserImageNames[i], sal_True ));
887 
888     Sequence< OUString > aImageNameSeq( aImageCmdNameMap.size() );
889     ImageNameMap::const_iterator pIter;
890     i = 0;
891     for ( pIter = aImageCmdNameMap.begin(); pIter != aImageCmdNameMap.end(); pIter++ )
892         aImageNameSeq[i++] = pIter->first;
893 
894     return aImageNameSeq;
895 }
896 
897 ::sal_Bool ImageManagerImpl::hasImage( ::sal_Int16 nImageType, const ::rtl::OUString& aCommandURL )
898 throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
899 {
900     ResetableGuard aLock( m_aLock );
901 
902     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
903     if ( m_bDisposed )
904         throw DisposedException();
905 
906     if (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE ))
907         throw IllegalArgumentException();
908 
909     sal_Int16 nIndex = implts_convertImageTypeToIndex( nImageType );
910     if ( m_bUseGlobal && implts_getGlobalImageList()->hasImage( nIndex, aCommandURL ))
911         return sal_True;
912     else
913     {
914         if ( m_bUseGlobal && implts_getDefaultImageList()->hasImage( nIndex, aCommandURL ))
915             return sal_True;
916         else
917         {
918             // User layer
919             ImageList* pImageList = implts_getUserImageList( ImageType( nIndex ));
920             if ( pImageList )
921                 return ( pImageList->GetImagePos( aCommandURL ) != IMAGELIST_IMAGE_NOTFOUND );
922         }
923     }
924 
925     return sal_False;
926 }
927 
928 Sequence< uno::Reference< XGraphic > > ImageManagerImpl::getImages(
929     ::sal_Int16 nImageType,
930     const Sequence< ::rtl::OUString >& aCommandURLSequence )
931 throw ( ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException )
932 {
933     ResetableGuard aLock( m_aLock );
934 
935     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
936     if ( m_bDisposed )
937         throw DisposedException();
938 
939     if (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE ))
940         throw IllegalArgumentException();
941 
942     Sequence< uno::Reference< XGraphic > > aGraphSeq( aCommandURLSequence.getLength() );
943 
944     const rtl::OUString* aStrArray = aCommandURLSequence.getConstArray();
945 
946     sal_Int16                         nIndex            = implts_convertImageTypeToIndex( nImageType );
947     rtl::Reference< GlobalImageList > rGlobalImageList;
948     CmdImageList*                     pDefaultImageList = NULL;
949     if ( m_bUseGlobal )
950     {
951         rGlobalImageList  = implts_getGlobalImageList();
952         pDefaultImageList = implts_getDefaultImageList();
953     }
954     ImageList*                        pUserImageList    = implts_getUserImageList( ImageType( nIndex ));
955 
956     // We have to search our image list in the following order:
957     // 1. user image list (read/write)
958     // 2. module image list (read)
959     // 3. global image list (read)
960     for ( sal_Int32 n = 0; n < aCommandURLSequence.getLength(); n++ )
961     {
962         Image aImage = pUserImageList->GetImage( aStrArray[n] );
963         if ( !aImage && m_bUseGlobal )
964         {
965             aImage = pDefaultImageList->getImageFromCommandURL( nIndex, aStrArray[n] );
966             if ( !aImage )
967                 aImage = rGlobalImageList->getImageFromCommandURL( nIndex, aStrArray[n] );
968         }
969 
970         aGraphSeq[n] = aImage.GetXGraphic();
971     }
972 
973     return aGraphSeq;
974 }
975 
976 void ImageManagerImpl::replaceImages(
977     ::sal_Int16 nImageType,
978     const Sequence< ::rtl::OUString >& aCommandURLSequence,
979     const Sequence< uno::Reference< XGraphic > >& aGraphicsSequence )
980 throw ( ::com::sun::star::lang::IllegalArgumentException,
981         ::com::sun::star::lang::IllegalAccessException,
982         ::com::sun::star::uno::RuntimeException)
983 {
984     CmdToXGraphicNameAccess* pInsertedImages( 0 );
985     CmdToXGraphicNameAccess* pReplacedImages( 0 );
986 
987     {
988         ResetableGuard aLock( m_aLock );
989 
990         /* SAFE AREA ----------------------------------------------------------------------------------------------- */
991         if ( m_bDisposed )
992             throw DisposedException();
993 
994         if (( aCommandURLSequence.getLength() != aGraphicsSequence.getLength() ) ||
995             (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE )))
996             throw IllegalArgumentException();
997 
998         if ( m_bReadOnly )
999             throw IllegalAccessException();
1000 
1001         sal_Int16 nIndex = implts_convertImageTypeToIndex( nImageType );
1002         ImageList* pImageList = implts_getUserImageList( ImageType( nIndex ));
1003 
1004         uno::Reference< XGraphic > xGraphic;
1005         for ( sal_Int32 i = 0; i < aCommandURLSequence.getLength(); i++ )
1006         {
1007             // Check size and scale. If we don't have any graphics ignore it
1008             if ( !implts_checkAndScaleGraphic( xGraphic, aGraphicsSequence[i], nIndex ))
1009                 continue;
1010 
1011             sal_uInt16 nPos = pImageList->GetImagePos( aCommandURLSequence[i] );
1012             if ( nPos == IMAGELIST_IMAGE_NOTFOUND )
1013             {
1014                 pImageList->AddImage( aCommandURLSequence[i], xGraphic );
1015                 if ( !pInsertedImages )
1016                     pInsertedImages = new CmdToXGraphicNameAccess();
1017                 pInsertedImages->addElement( aCommandURLSequence[i], xGraphic );
1018             }
1019             else
1020             {
1021                 pImageList->ReplaceImage( aCommandURLSequence[i], xGraphic );
1022                 if ( !pReplacedImages )
1023                     pReplacedImages = new CmdToXGraphicNameAccess();
1024                 pReplacedImages->addElement( aCommandURLSequence[i], xGraphic );
1025             }
1026         }
1027 
1028         if (( pInsertedImages != 0 ) || (  pReplacedImages != 0 ))
1029         {
1030             m_bModified = sal_True;
1031             m_bUserImageListModified[nIndex] = true;
1032         }
1033     }
1034 
1035     // Notify listeners
1036     if ( pInsertedImages != 0 )
1037     {
1038         ConfigurationEvent aInsertEvent;
1039         aInsertEvent.aInfo           <<= nImageType;
1040         aInsertEvent.Accessor        <<= m_xOwner;
1041         aInsertEvent.Source          = m_xOwner;
1042         aInsertEvent.ResourceURL     = m_aResourceString;
1043         aInsertEvent.Element         = uno::makeAny( uno::Reference< XNameAccess >(
1044                                         static_cast< OWeakObject *>( pInsertedImages ), UNO_QUERY ));
1045         implts_notifyContainerListener( aInsertEvent, NotifyOp_Insert );
1046     }
1047     if ( pReplacedImages != 0 )
1048     {
1049         ConfigurationEvent aReplaceEvent;
1050         aReplaceEvent.aInfo           <<= nImageType;
1051         aReplaceEvent.Accessor        <<= m_xOwner;
1052         aReplaceEvent.Source          = m_xOwner;
1053         aReplaceEvent.ResourceURL     = m_aResourceString;
1054         aReplaceEvent.ReplacedElement = Any();
1055         aReplaceEvent.Element         = uno::makeAny( uno::Reference< XNameAccess >(
1056                                             static_cast< OWeakObject *>( pReplacedImages ), UNO_QUERY ));
1057         implts_notifyContainerListener( aReplaceEvent, NotifyOp_Replace );
1058     }
1059 }
1060 
1061 void ImageManagerImpl::removeImages( ::sal_Int16 nImageType, const Sequence< ::rtl::OUString >& aCommandURLSequence )
1062 throw ( ::com::sun::star::lang::IllegalArgumentException,
1063         ::com::sun::star::lang::IllegalAccessException,
1064         ::com::sun::star::uno::RuntimeException)
1065 {
1066     CmdToXGraphicNameAccess* pRemovedImages( 0 );
1067     CmdToXGraphicNameAccess* pReplacedImages( 0 );
1068 
1069     {
1070         ResetableGuard aLock( m_aLock );
1071 
1072         /* SAFE AREA ----------------------------------------------------------------------------------------------- */
1073         if ( m_bDisposed )
1074             throw DisposedException();
1075 
1076         if (( nImageType < 0 ) || ( nImageType > MAX_IMAGETYPE_VALUE ))
1077             throw IllegalArgumentException();
1078 
1079         if ( m_bReadOnly )
1080             throw IllegalAccessException();
1081 
1082         sal_Int16 nIndex = implts_convertImageTypeToIndex( nImageType );
1083         rtl::Reference< GlobalImageList > rGlobalImageList;
1084         CmdImageList*                     pDefaultImageList = NULL;
1085         if ( m_bUseGlobal )
1086         {
1087             rGlobalImageList  = implts_getGlobalImageList();
1088             pDefaultImageList = implts_getDefaultImageList();
1089         }
1090         ImageList*                        pImageList        = implts_getUserImageList( ImageType( nIndex ));
1091         uno::Reference< XGraphic >        xEmptyGraphic( Image().GetXGraphic() );
1092 
1093         for ( sal_Int32 i = 0; i < aCommandURLSequence.getLength(); i++ )
1094         {
1095             sal_uInt16 nPos = pImageList->GetImagePos( aCommandURLSequence[i] );
1096             if ( nPos != IMAGELIST_IMAGE_NOTFOUND )
1097             {
1098                 Image aImage = pImageList->GetImage( nPos );
1099                 sal_uInt16 nId   = pImageList->GetImageId( nPos );
1100                 pImageList->RemoveImage( nId );
1101 
1102                 if ( m_bUseGlobal )
1103                 {
1104                     // Check, if we have a image in our module/global image list. If we find one =>
1105                     // this is a replace instead of a remove operation!
1106                     Image aNewImage = pDefaultImageList->getImageFromCommandURL( nIndex, aCommandURLSequence[i] );
1107                     if ( !aNewImage )
1108                         aNewImage = rGlobalImageList->getImageFromCommandURL( nIndex, aCommandURLSequence[i] );
1109                     if ( !aNewImage )
1110                     {
1111                         if ( !pRemovedImages )
1112                             pRemovedImages = new CmdToXGraphicNameAccess();
1113                         pRemovedImages->addElement( aCommandURLSequence[i], xEmptyGraphic );
1114                     }
1115                     else
1116                     {
1117                         if ( !pReplacedImages )
1118                             pReplacedImages = new CmdToXGraphicNameAccess();
1119                         pReplacedImages->addElement( aCommandURLSequence[i], aNewImage.GetXGraphic() );
1120                     }
1121                 } // if ( m_bUseGlobal )
1122                 else
1123                 {
1124                     if ( !pRemovedImages )
1125                         pRemovedImages = new CmdToXGraphicNameAccess();
1126                     pRemovedImages->addElement( aCommandURLSequence[i], xEmptyGraphic );
1127                 }
1128             }
1129         }
1130 
1131         if (( pReplacedImages != 0 ) || ( pRemovedImages != 0 ))
1132         {
1133             m_bModified = sal_True;
1134             m_bUserImageListModified[nIndex] = true;
1135         }
1136     }
1137 
1138     // Notify listeners
1139     if ( pRemovedImages != 0 )
1140     {
1141         ConfigurationEvent aRemoveEvent;
1142         aRemoveEvent.aInfo           = uno::makeAny( nImageType );
1143         aRemoveEvent.Accessor        = uno::makeAny( m_xOwner );
1144         aRemoveEvent.Source          = m_xOwner;
1145         aRemoveEvent.ResourceURL     = m_aResourceString;
1146         aRemoveEvent.Element         = uno::makeAny( uno::Reference< XNameAccess >(
1147                                             static_cast< OWeakObject *>( pRemovedImages ), UNO_QUERY ));
1148         implts_notifyContainerListener( aRemoveEvent, NotifyOp_Remove );
1149     }
1150     if ( pReplacedImages != 0 )
1151     {
1152         ConfigurationEvent aReplaceEvent;
1153         aReplaceEvent.aInfo           = uno::makeAny( nImageType );
1154         aReplaceEvent.Accessor        = uno::makeAny( m_xOwner );
1155         aReplaceEvent.Source          = m_xOwner;
1156         aReplaceEvent.ResourceURL     = m_aResourceString;
1157         aReplaceEvent.ReplacedElement = Any();
1158         aReplaceEvent.Element         = uno::makeAny( uno::Reference< XNameAccess >(
1159                                             static_cast< OWeakObject *>( pReplacedImages ), UNO_QUERY ));
1160         implts_notifyContainerListener( aReplaceEvent, NotifyOp_Replace );
1161     }
1162 }
1163 
1164 void ImageManagerImpl::insertImages( ::sal_Int16 nImageType, const Sequence< ::rtl::OUString >& aCommandURLSequence, const Sequence< uno::Reference< XGraphic > >& aGraphicSequence )
1165 throw ( ::com::sun::star::container::ElementExistException,
1166         ::com::sun::star::lang::IllegalArgumentException,
1167         ::com::sun::star::lang::IllegalAccessException,
1168         ::com::sun::star::uno::RuntimeException)
1169 {
1170     replaceImages(nImageType,aCommandURLSequence,aGraphicSequence);
1171 }
1172 
1173 
1174 // XUIConfigurationPersistence
1175 void ImageManagerImpl::reload()
1176 throw ( ::com::sun::star::uno::Exception,
1177         ::com::sun::star::uno::RuntimeException )
1178 {
1179     ResetableGuard aGuard( m_aLock );
1180 
1181     if ( m_bDisposed )
1182         throw DisposedException();
1183 
1184     CommandMap                   aOldUserCmdImageSet;
1185     std::vector< rtl::OUString > aNewUserCmdImageSet;
1186 
1187     if ( m_bModified )
1188     {
1189         for ( sal_Int16 i = 0; i < sal_Int16( ImageType_COUNT ); i++ )
1190         {
1191             if ( !m_bDisposed && m_bUserImageListModified[i] )
1192             {
1193                 std::vector< rtl::OUString > aOldUserCmdImageVector;
1194                 ImageList* pImageList = implts_getUserImageList( (ImageType)i );
1195                 pImageList->GetImageNames( aOldUserCmdImageVector );
1196 
1197                 // Fill hash map to speed up search afterwards
1198                 sal_uInt32 j( 0 );
1199                 const sal_uInt32 nOldCount = aOldUserCmdImageVector.size();
1200 				for ( j = 0; j < nOldCount; j++ )
1201                     aOldUserCmdImageSet.insert( CommandMap::value_type( aOldUserCmdImageVector[j], false ));
1202 
1203                 // Attention: This can make the old image list pointer invalid!
1204                 implts_loadUserImages( (ImageType)i, m_xUserImageStorage, m_xUserBitmapsStorage );
1205                 pImageList = implts_getUserImageList( (ImageType)i );
1206                 pImageList->GetImageNames( aNewUserCmdImageSet );
1207 
1208                 CmdToXGraphicNameAccess* pInsertedImages( 0 );
1209                 CmdToXGraphicNameAccess* pReplacedImages( 0 );
1210                 CmdToXGraphicNameAccess* pRemovedImages( 0 );
1211 
1212                 const sal_uInt32 nNewCount = aNewUserCmdImageSet.size();
1213 				for ( j = 0; j < nNewCount; j++ )
1214                 {
1215                     CommandMap::iterator pIter = aOldUserCmdImageSet.find( aNewUserCmdImageSet[j] );
1216                     if ( pIter != aOldUserCmdImageSet.end() )
1217                     {
1218                         pIter->second = true; // mark entry as replaced
1219                         if ( !pReplacedImages )
1220                             pReplacedImages = new CmdToXGraphicNameAccess();
1221                         pReplacedImages->addElement( aNewUserCmdImageSet[j],
1222                                                      pImageList->GetImage( aNewUserCmdImageSet[j] ).GetXGraphic() );
1223                     }
1224                     else
1225                     {
1226                         if ( !pInsertedImages )
1227                             pInsertedImages = new CmdToXGraphicNameAccess();
1228                         pInsertedImages->addElement( aNewUserCmdImageSet[j],
1229                                                      pImageList->GetImage( aNewUserCmdImageSet[j] ).GetXGraphic() );
1230                     }
1231                 }
1232 
1233                 // Search map for unmarked entries => they have been removed from the user list
1234                 // through this reload operation.
1235                 // We have to search the module and global image list!
1236                 rtl::Reference< GlobalImageList > rGlobalImageList;
1237                 CmdImageList*                     pDefaultImageList = NULL;
1238                 if ( m_bUseGlobal )
1239                 {
1240                     rGlobalImageList  = implts_getGlobalImageList();
1241                     pDefaultImageList = implts_getDefaultImageList();
1242                 }
1243                 uno::Reference< XGraphic >        xEmptyGraphic( Image().GetXGraphic() );
1244                 CommandMap::const_iterator        pIter = aOldUserCmdImageSet.begin();
1245                 while ( pIter != aOldUserCmdImageSet.end() )
1246                 {
1247                     if ( !pIter->second )
1248                     {
1249                         if ( m_bUseGlobal )
1250                         {
1251                             Image aImage = pDefaultImageList->getImageFromCommandURL( i, pIter->first );
1252                             if ( !aImage )
1253                                 aImage = rGlobalImageList->getImageFromCommandURL( i, pIter->first );
1254 
1255                             if ( !aImage )
1256                             {
1257                                 // No image in the module/global image list => remove user image
1258                                 if ( !pRemovedImages )
1259                                     pRemovedImages = new CmdToXGraphicNameAccess();
1260                                 pRemovedImages->addElement( pIter->first, xEmptyGraphic );
1261                             }
1262                             else
1263                             {
1264                                 // Image has been found in the module/global image list => replace user image
1265                                 if ( !pReplacedImages )
1266                                     pReplacedImages = new CmdToXGraphicNameAccess();
1267                                 pReplacedImages->addElement( pIter->first, aImage.GetXGraphic() );
1268                             }
1269                         } // if ( m_bUseGlobal )
1270                         else
1271                         {
1272                             // No image in the user image list => remove user image
1273                             if ( !pRemovedImages )
1274                                 pRemovedImages = new CmdToXGraphicNameAccess();
1275                             pRemovedImages->addElement( pIter->first, xEmptyGraphic );
1276                         }
1277                     }
1278                     ++pIter;
1279                 }
1280 
1281                 aGuard.unlock();
1282 
1283                 // Now notify our listeners. Unlock mutex to prevent deadlocks
1284                 if ( pInsertedImages != 0 )
1285                 {
1286                     ConfigurationEvent aInsertEvent;
1287                     aInsertEvent.aInfo           = uno::makeAny( i );
1288                     aInsertEvent.Accessor        = uno::makeAny( m_xOwner );
1289                     aInsertEvent.Source          = m_xOwner;
1290                     aInsertEvent.ResourceURL     = m_aResourceString;
1291                     aInsertEvent.Element         = uno::makeAny( uno::Reference< XNameAccess >(
1292                                                     static_cast< OWeakObject *>( pInsertedImages ), UNO_QUERY ));
1293                     implts_notifyContainerListener( aInsertEvent, NotifyOp_Insert );
1294                 }
1295                 if ( pReplacedImages != 0 )
1296                 {
1297                     ConfigurationEvent aReplaceEvent;
1298                     aReplaceEvent.aInfo           = uno::makeAny( i );
1299                     aReplaceEvent.Accessor        = uno::makeAny( m_xOwner );
1300                     aReplaceEvent.Source          = m_xOwner;
1301                     aReplaceEvent.ResourceURL     = m_aResourceString;
1302                     aReplaceEvent.ReplacedElement = Any();
1303                     aReplaceEvent.Element         = uno::makeAny( uno::Reference< XNameAccess >(
1304                                                     static_cast< OWeakObject *>( pReplacedImages ), UNO_QUERY ));
1305                     implts_notifyContainerListener( aReplaceEvent, NotifyOp_Replace );
1306                 }
1307                 if ( pRemovedImages != 0 )
1308                 {
1309                     ConfigurationEvent aRemoveEvent;
1310                     aRemoveEvent.aInfo           = uno::makeAny( i );
1311                     aRemoveEvent.Accessor        = uno::makeAny( m_xOwner );
1312                     aRemoveEvent.Source          = m_xOwner;
1313                     aRemoveEvent.ResourceURL     = m_aResourceString;
1314                     aRemoveEvent.Element         = uno::makeAny( uno::Reference< XNameAccess >(
1315                                                         static_cast< OWeakObject *>( pRemovedImages ), UNO_QUERY ));
1316                     implts_notifyContainerListener( aRemoveEvent, NotifyOp_Remove );
1317                 }
1318 
1319                 aGuard.lock();
1320             }
1321         }
1322     }
1323 }
1324 
1325 void ImageManagerImpl::store()
1326 throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
1327 {
1328     ResetableGuard aGuard( m_aLock );
1329 
1330     if ( m_bDisposed )
1331         throw DisposedException();
1332 
1333     if ( m_bModified )
1334     {
1335         sal_Bool bWritten( sal_False );
1336         for ( sal_Int32 i = 0; i < ImageType_COUNT; i++ )
1337         {
1338             sal_Bool bSuccess = implts_storeUserImages( ImageType(i), m_xUserImageStorage, m_xUserBitmapsStorage );
1339             if ( bSuccess )
1340                 bWritten = sal_True;
1341             m_bUserImageListModified[i] = false;
1342         }
1343 
1344         if ( bWritten &&
1345              m_xUserConfigStorage.is() )
1346         {
1347             uno::Reference< XTransactedObject > xUserConfigStorageCommit( m_xUserConfigStorage, UNO_QUERY );
1348 			if ( xUserConfigStorageCommit.is() )
1349             	xUserConfigStorageCommit->commit();
1350             if ( m_xUserRootCommit.is() )
1351                 m_xUserRootCommit->commit();
1352         }
1353 
1354         m_bModified = sal_False;
1355     }
1356 }
1357 
1358 void ImageManagerImpl::storeToStorage( const uno::Reference< XStorage >& Storage )
1359 throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
1360 {
1361     ResetableGuard aGuard( m_aLock );
1362 
1363     if ( m_bDisposed )
1364         throw DisposedException();
1365 
1366     if ( m_bModified && Storage.is() )
1367     {
1368         long nModes = ElementModes::READWRITE;
1369 
1370         uno::Reference< XStorage > xUserImageStorage = Storage->openStorageElement( OUString::createFromAscii( IMAGE_FOLDER ),
1371                                                                                     nModes );
1372         if ( xUserImageStorage.is() )
1373         {
1374             uno::Reference< XStorage > xUserBitmapsStorage = xUserImageStorage->openStorageElement( OUString::createFromAscii( BITMAPS_FOLDER ),
1375                                                                                                     nModes );
1376             for ( sal_Int32 i = 0; i < ImageType_COUNT; i++ )
1377             {
1378                 implts_getUserImageList( (ImageType)i );
1379                 implts_storeUserImages( (ImageType)i, xUserImageStorage, xUserBitmapsStorage );
1380             }
1381 
1382             uno::Reference< XTransactedObject > xTransaction( Storage, UNO_QUERY );
1383 			if ( xTransaction.is() )
1384             	xTransaction->commit();
1385         }
1386     }
1387 }
1388 
1389 sal_Bool ImageManagerImpl::isModified()
1390 throw (::com::sun::star::uno::RuntimeException)
1391 {
1392     ResetableGuard aGuard( m_aLock );
1393     return m_bModified;
1394 }
1395 
1396 sal_Bool ImageManagerImpl::isReadOnly() throw (::com::sun::star::uno::RuntimeException)
1397 {
1398     ResetableGuard aGuard( m_aLock );
1399     return m_bReadOnly;
1400 }
1401 // XUIConfiguration
1402 void ImageManagerImpl::addConfigurationListener( const uno::Reference< ::com::sun::star::ui::XUIConfigurationListener >& xListener )
1403 throw (::com::sun::star::uno::RuntimeException)
1404 {
1405     {
1406         ResetableGuard aGuard( m_aLock );
1407 
1408         /* SAFE AREA ----------------------------------------------------------------------------------------------- */
1409         if ( m_bDisposed )
1410             throw DisposedException();
1411     }
1412 
1413     m_aListenerContainer.addInterface( ::getCppuType( ( const uno::Reference< XUIConfigurationListener >* ) NULL ), xListener );
1414 }
1415 
1416 void ImageManagerImpl::removeConfigurationListener( const uno::Reference< ::com::sun::star::ui::XUIConfigurationListener >& xListener )
1417 throw (::com::sun::star::uno::RuntimeException)
1418 {
1419     /* SAFE AREA ----------------------------------------------------------------------------------------------- */
1420     m_aListenerContainer.removeInterface( ::getCppuType( ( const uno::Reference< XUIConfigurationListener >* ) NULL ), xListener );
1421 }
1422 
1423 
1424 void ImageManagerImpl::implts_notifyContainerListener( const ConfigurationEvent& aEvent, NotifyOp eOp )
1425 {
1426     ::cppu::OInterfaceContainerHelper* pContainer = m_aListenerContainer.getContainer(
1427                                         ::getCppuType( ( const css::uno::Reference< ::com::sun::star::ui::XUIConfigurationListener >*) NULL ) );
1428     if ( pContainer != NULL )
1429 	{
1430         ::cppu::OInterfaceIteratorHelper pIterator( *pContainer );
1431         while ( pIterator.hasMoreElements() )
1432         {
1433             try
1434             {
1435                 switch ( eOp )
1436                 {
1437                     case NotifyOp_Replace:
1438                         ((::com::sun::star::ui::XUIConfigurationListener*)pIterator.next())->elementReplaced( aEvent );
1439                         break;
1440                     case NotifyOp_Insert:
1441                         ((::com::sun::star::ui::XUIConfigurationListener*)pIterator.next())->elementInserted( aEvent );
1442                         break;
1443                     case NotifyOp_Remove:
1444                         ((::com::sun::star::ui::XUIConfigurationListener*)pIterator.next())->elementRemoved( aEvent );
1445                         break;
1446                 }
1447             }
1448             catch( css::uno::RuntimeException& )
1449             {
1450                 pIterator.remove();
1451             }
1452         }
1453 	}
1454 }
1455 void ImageManagerImpl::clear()
1456 {
1457     ResetableGuard aGuard( m_aLock );
1458     for ( sal_Int32 n = 0; n < ImageType_COUNT; n++ )
1459     {
1460         delete m_pUserImageList[n];
1461         m_pUserImageList[n] = 0;
1462     }
1463 }
1464 } // namespace framework
1465