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_unotools.hxx"
30 #ifndef GCC
31 #endif
32 
33 //_________________________________________________________________________________________________________________
34 //	includes
35 //_________________________________________________________________________________________________________________
36 
37 #include <unotools/dynamicmenuoptions.hxx>
38 #include <unotools/moduleoptions.hxx>
39 #include <unotools/configmgr.hxx>
40 #include <unotools/configitem.hxx>
41 #include <tools/debug.hxx>
42 #include <com/sun/star/uno/Any.hxx>
43 #include <com/sun/star/uno/Sequence.hxx>
44 
45 #ifndef __SGI_STL_VECTOR
46 #include <vector>
47 #endif
48 
49 #include <itemholder1.hxx>
50 
51 #include <algorithm>
52 
53 //_________________________________________________________________________________________________________________
54 //	namespaces
55 //_________________________________________________________________________________________________________________
56 
57 using namespace ::std					;
58 using namespace ::utl					;
59 using namespace ::rtl					;
60 using namespace ::osl					;
61 using namespace ::com::sun::star::uno	;
62 using namespace ::com::sun::star::beans	;
63 
64 //_________________________________________________________________________________________________________________
65 //	const
66 //_________________________________________________________________________________________________________________
67 
68 #define ROOTNODE_MENUS                                  OUString(RTL_CONSTASCII_USTRINGPARAM("Office.Common/Menus/"     ))
69 #define PATHDELIMITER                                   OUString(RTL_CONSTASCII_USTRINGPARAM("/"                        ))
70 
71 #define SETNODE_NEWMENU                                 OUString(RTL_CONSTASCII_USTRINGPARAM("New"                      ))
72 #define SETNODE_WIZARDMENU                              OUString(RTL_CONSTASCII_USTRINGPARAM("Wizard"                   ))
73 #define SETNODE_HELPBOOKMARKS                           OUString(RTL_CONSTASCII_USTRINGPARAM("HelpBookmarks"            ))
74 
75 #define PROPERTYNAME_URL                                DYNAMICMENU_PROPERTYNAME_URL
76 #define PROPERTYNAME_TITLE                              DYNAMICMENU_PROPERTYNAME_TITLE
77 #define PROPERTYNAME_IMAGEIDENTIFIER                    DYNAMICMENU_PROPERTYNAME_IMAGEIDENTIFIER
78 #define PROPERTYNAME_TARGETNAME                         DYNAMICMENU_PROPERTYNAME_TARGETNAME
79 
80 #define PROPERTYCOUNT                                   4
81 
82 #define OFFSET_URL                                      0
83 #define OFFSET_TITLE                                    1
84 #define OFFSET_IMAGEIDENTIFIER                          2
85 #define OFFSET_TARGETNAME                               3
86 
87 #define PATHPREFIX_SETUP                                OUString(RTL_CONSTASCII_USTRINGPARAM("m"                        ))
88 #define PATHPREFIX_USER                                 OUString(RTL_CONSTASCII_USTRINGPARAM("u"                        ))
89 
90 //_________________________________________________________________________________________________________________
91 //	private declarations!
92 //_________________________________________________________________________________________________________________
93 
94 /*-****************************************************************************************************************
95     @descr  struct to hold information about one menu entry.
96 ****************************************************************************************************************-*/
97 struct SvtDynMenuEntry
98 {
99     public:
100         SvtDynMenuEntry() {};
101 
102         SvtDynMenuEntry(  const OUString& sNewURL             ,
103                     const OUString& sNewTitle           ,
104                     const OUString& sNewImageIdentifier ,
105                     const OUString& sNewTargetName      )
106         {
107             sURL                = sNewURL               ;
108             sTitle              = sNewTitle             ;
109             sImageIdentifier    = sNewImageIdentifier   ;
110             sTargetName         = sNewTargetName        ;
111         }
112 
113     public:
114         OUString    sName               ;
115         OUString    sURL                ;
116         OUString    sTitle              ;
117         OUString    sImageIdentifier    ;
118         OUString    sTargetName         ;
119 };
120 
121 /*-****************************************************************************************************************
122     @descr  support simple menu structures and operations on it
123 ****************************************************************************************************************-*/
124 class SvtDynMenu
125 {
126     public:
127         //---------------------------------------------------------------------------------------------------------
128         // append setup written menu entry
129         // Don't touch name of entry. It was defined by setup and must be the same everytime!
130         // Look for double menu entries here too ... may be some seperator items are supeflous ...
131         void AppendSetupEntry( const SvtDynMenuEntry& rEntry )
132         {
133             if(
134                 ( lSetupEntries.size()         <  1           )  ||
135                 ( lSetupEntries.rbegin()->sURL != rEntry.sURL )
136               )
137             {
138                 lSetupEntries.push_back( rEntry );
139             }
140         }
141 
142         //---------------------------------------------------------------------------------------------------------
143         // append user specific menu entry
144         // We must find unique name for it by using special prefix
145         // and next count of user setted entries!
146         // Look for double menu entries here too ... may be some seperator items are supeflous ...
147         void AppendUserEntry( SvtDynMenuEntry& rEntry )
148         {
149             if(
150                 ( lUserEntries.size()         <  1           )  ||
151                 ( lUserEntries.rbegin()->sURL != rEntry.sURL )
152               )
153             {
154                 rEntry.sName  = PATHPREFIX_USER;
155                 rEntry.sName += OUString::valueOf( (sal_Int32)impl_getNextUserEntryNr() );
156                 lUserEntries.push_back( rEntry );
157             }
158         }
159 
160         //---------------------------------------------------------------------------------------------------------
161         // the only way to free memory!
162         void Clear()
163         {
164             lSetupEntries.clear();
165             lUserEntries.clear();
166         }
167 
168         //---------------------------------------------------------------------------------------------------------
169         // convert internal list to external format
170         // for using it on right menus realy
171         // Notice:   We build a property list with 4 entries and set it on result list then.
172         //           The while-loop starts with pointer on internal member list lSetupEntries, change to
173         //           lUserEntries then and stop after that with NULL!
174         //           Separator entries will be packed in another way then normal entries! We define
175         //           special strings "sEmpty" and "sSeperator" to perform too ...
176         Sequence< Sequence< PropertyValue > > GetList() const
177         {
178             sal_Int32                             nSetupCount = (sal_Int32)lSetupEntries.size();
179             sal_Int32                             nUserCount  = (sal_Int32)lUserEntries.size();
180             sal_Int32                             nStep       = 0;
181             Sequence< PropertyValue >             lProperties ( PROPERTYCOUNT );
182             Sequence< Sequence< PropertyValue > > lResult     ( nSetupCount+nUserCount );
183             OUString                              sSeperator  ( RTL_CONSTASCII_USTRINGPARAM("private:separator") );
184             OUString                              sEmpty      ;
185             const vector< SvtDynMenuEntry >*            pList       = &lSetupEntries;
186 
187             lProperties[OFFSET_URL            ].Name = PROPERTYNAME_URL             ;
188             lProperties[OFFSET_TITLE          ].Name = PROPERTYNAME_TITLE           ;
189             lProperties[OFFSET_IMAGEIDENTIFIER].Name = PROPERTYNAME_IMAGEIDENTIFIER ;
190             lProperties[OFFSET_TARGETNAME     ].Name = PROPERTYNAME_TARGETNAME      ;
191 
192             while( pList != NULL )
193             {
194                 for( vector< SvtDynMenuEntry >::const_iterator pItem =pList->begin();
195                                                          pItem!=pList->end()  ;
196                                                          ++pItem              )
197                 {
198                     if( pItem->sURL == sSeperator )
199                     {
200                         lProperties[OFFSET_URL              ].Value <<= sSeperator  ;
201                         lProperties[OFFSET_TITLE            ].Value <<= sEmpty      ;
202                         lProperties[OFFSET_IMAGEIDENTIFIER  ].Value <<= sEmpty      ;
203                         lProperties[OFFSET_TARGETNAME       ].Value <<= sEmpty      ;
204                     }
205                     else
206                     {
207                         lProperties[OFFSET_URL              ].Value <<= pItem->sURL            ;
208                         lProperties[OFFSET_TITLE            ].Value <<= pItem->sTitle          ;
209                         lProperties[OFFSET_IMAGEIDENTIFIER  ].Value <<= pItem->sImageIdentifier;
210                         lProperties[OFFSET_TARGETNAME       ].Value <<= pItem->sTargetName     ;
211                     }
212                     lResult[nStep] = lProperties;
213                     ++nStep;
214                 }
215                 if( pList == &lSetupEntries )
216                     pList = &lUserEntries;
217                 else
218                     pList = NULL;
219             }
220             return lResult;
221         }
222 
223     private:
224         //---------------------------------------------------------------------------------------------------------
225         // search for an entry named "ux" with x=[0..i] inside our menu
226         // which has set highest number x. So we can add another user entry.
227         sal_Int32 impl_getNextUserEntryNr() const
228         {
229             sal_Int32 nNr = 0;
230             for( vector< SvtDynMenuEntry >::const_iterator pItem =lUserEntries.begin();
231                                                      pItem!=lUserEntries.end()  ;
232                                                      ++pItem                    )
233             {
234                 if( pItem->sName.compareTo( PATHPREFIX_USER, 1 ) == 0 )
235                 {
236                     OUString  sNr      = pItem->sName.copy( 1, pItem->sName.getLength()-1 );
237                     sal_Int32 nCheckNr = sNr.toInt32();
238                     if( nCheckNr > nNr )
239                         nNr = nCheckNr;
240                 }
241             }
242             // Attention: Code isn't prepared for recyling of unused fragmented numbers!
243             // If we reach end of sal_Int32 range ... we must stop further working ...
244             // But I think nobody expand a menu to more then 1000 ... 100000 ... entries ... or?
245             DBG_ASSERT( !(nNr>0x7fffffff), "Menu::impl_getNextUserEntryNr()\nUser count can be out of range next time ...\n" );
246             return nNr;
247         }
248 
249     private:
250         vector< SvtDynMenuEntry > lSetupEntries;
251         vector< SvtDynMenuEntry > lUserEntries ;
252 };
253 
254 class SvtDynamicMenuOptions_Impl : public ConfigItem
255 {
256 	//-------------------------------------------------------------------------------------------------------------
257 	//	public methods
258 	//-------------------------------------------------------------------------------------------------------------
259 
260 	public:
261 
262 		//---------------------------------------------------------------------------------------------------------
263 		//	constructor / destructor
264 		//---------------------------------------------------------------------------------------------------------
265 
266          SvtDynamicMenuOptions_Impl();
267         ~SvtDynamicMenuOptions_Impl();
268 
269 		//---------------------------------------------------------------------------------------------------------
270 		//	overloaded methods of baseclass
271 		//---------------------------------------------------------------------------------------------------------
272 
273 		/*-****************************************************************************************************//**
274 			@short		called for notify of configmanager
275 			@descr		These method is called from the ConfigManager before application ends or from the
276 			 			PropertyChangeListener if the sub tree broadcasts changes. You must update your
277 						internal values.
278 
279 			@seealso	baseclass ConfigItem
280 
281             @param      "lPropertyNames" is the list of properties which should be updated.
282 			@return		-
283 
284 			@onerror	-
285 		*//*-*****************************************************************************************************/
286 
287         virtual void Notify( const Sequence< OUString >& lPropertyNames );
288 
289 		/*-****************************************************************************************************//**
290 			@short		write changes to configuration
291 			@descr		These method writes the changed values into the sub tree
292 						and should always called in our destructor to guarantee consistency of config data.
293 
294 			@seealso	baseclass ConfigItem
295 
296 			@param		-
297 			@return		-
298 
299 			@onerror	-
300 		*//*-*****************************************************************************************************/
301 
302     	virtual void Commit();
303 
304 		//---------------------------------------------------------------------------------------------------------
305 		//	public interface
306 		//---------------------------------------------------------------------------------------------------------
307 
308 		/*-****************************************************************************************************//**
309             @short      base implementation of public interface for "SvtDynamicMenuOptions"!
310             @descr      These class is used as static member of "SvtDynamicMenuOptions" ...
311 						=> The code exist only for one time and isn't duplicated for every instance!
312 
313 			@seealso	-
314 
315 			@param		-
316 			@return		-
317 
318 			@onerror	-
319 		*//*-*****************************************************************************************************/
320 
321         void                                    Clear       (           EDynamicMenuType    eMenu           );
322         Sequence< Sequence< PropertyValue > >   GetMenu     (           EDynamicMenuType    eMenu           ) const ;
323         void                                    AppendItem  (           EDynamicMenuType    eMenu           ,
324                                                                 const   OUString&           sURL            ,
325                                                                 const   OUString&           sTitle          ,
326                                                                 const   OUString&           sImageIdentifier,
327                                                                 const   OUString&           sTargetName     );
328 
329 	//-------------------------------------------------------------------------------------------------------------
330 	//	private methods
331 	//-------------------------------------------------------------------------------------------------------------
332 
333 	private:
334 
335 		/*-****************************************************************************************************//**
336             @short      return list of key names of our configuration management which represent oue module tree
337 			@descr		These methods return the current list of key names! We need it to get needed values from our
338                         configuration management and support dynamical menu item lists!
339 
340 			@seealso	-
341 
342             @param      "nNewCount"     ,   returns count of menu entries for "new"
343             @param      "nWizardCount"  ,   returns count of menu entries for "wizard"
344 			@return		A list of configuration key names is returned.
345 
346 			@onerror	-
347 		*//*-*****************************************************************************************************/
348 
349         Sequence< OUString > impl_GetPropertyNames( sal_uInt32& nNewCount, sal_uInt32& nWizardCount, sal_uInt32& nHelpBookmarksCount );
350 
351         /*-****************************************************************************************************//**
352             @short      sort given source list and expand it for all well known properties to destination
353             @descr      We must support sets of entries with count inside the name .. but some of them could be missing!
354                         e.g. s1-s2-s3-s0-u1-s6-u5-u7
355                         Then we must sort it by name and expand it to the follow one:
356                             sSetNode/s0/URL
357                             sSetNode/s0/Title
358                             sSetNode/s0/...
359                             sSetNode/s1/URL
360                             sSetNode/s1/Title
361                             sSetNode/s1/...
362                             ...
363                             sSetNode/s6/URL
364                             sSetNode/s6/Title
365                             sSetNode/s6/...
366                             sSetNode/u1/URL
367                             sSetNode/u1/Title
368                             sSetNode/u1/...
369                             ...
370                             sSetNode/u7/URL
371                             sSetNode/u7/Title
372                             sSetNode/u7/...
373                         Rules: We start with all setup written entries names "sx" and x=[0..n].
374                         Then we handle all "ux" items. Inside these blocks we sort it ascending by number.
375 
376             @attention  We add these expanded list to the end of given "lDestination" list!
377                         So we must start on "lDestination.getLength()".
378                         Reallocation of memory of destination list is done by us!
379 
380             @seealso    method impl_GetPropertyNames()
381 
382             @param      "lSource"      ,   original list (e.g. [m1-m2-m3-m6-m0] )
383             @param      "lDestination" ,   destination of operation
384             @param      "sSetNode"     ,   name of configuration set to build complete path
385 			@return		A list of configuration key names is returned.
386 
387 			@onerror	-
388 		*//*-*****************************************************************************************************/
389 
390         void impl_SortAndExpandPropertyNames( const Sequence< OUString >& lSource      ,
391                                                     Sequence< OUString >& lDestination ,
392                                               const OUString&             sSetNode     );
393 
394 	//-------------------------------------------------------------------------------------------------------------
395 	//	private member
396 	//-------------------------------------------------------------------------------------------------------------
397 
398 	private:
399 
400         SvtDynMenu  m_aNewMenu              ;
401         SvtDynMenu  m_aWizardMenu           ;
402         SvtDynMenu  m_aHelpBookmarksMenu    ;
403 };
404 
405 //_________________________________________________________________________________________________________________
406 //	definitions
407 //_________________________________________________________________________________________________________________
408 
409 //*****************************************************************************************************************
410 //	constructor
411 //*****************************************************************************************************************
412 SvtDynamicMenuOptions_Impl::SvtDynamicMenuOptions_Impl()
413 	// Init baseclasses first
414     :   ConfigItem( ROOTNODE_MENUS )
415 	// Init member then...
416 {
417     // Get names and values of all accessable menu entries and fill internal structures.
418 	// See impl_GetPropertyNames() for further informations.
419     sal_uInt32              nNewCount           = 0;
420     sal_uInt32              nWizardCount        = 0;
421     sal_uInt32              nHelpBookmarksCount = 0;
422     Sequence< OUString >    lNames              = impl_GetPropertyNames ( nNewCount           ,
423                                                                           nWizardCount        ,
424                                                                           nHelpBookmarksCount );
425     Sequence< Any >         lValues             = GetProperties         ( lNames              );
426 
427 	// Safe impossible cases.
428 	// We need values from ALL configuration keys.
429 	// Follow assignment use order of values in relation to our list of key names!
430     DBG_ASSERT( !(lNames.getLength()!=lValues.getLength()), "SvtDynamicMenuOptions_Impl::SvtDynamicMenuOptions_Impl()\nI miss some values of configuration keys!\n" );
431 
432 	// Copy values from list in right order to ouer internal member.
433 	// Attention: List for names and values have an internal construction pattern!
434     //
435     // first "New" menu ...
436     //      Name                            Value
437     //      /New/1/URL                      "private:factory/swriter"
438     //      /New/1/Title                    "Neues Writer Dokument"
439     //      /New/1/ImageIdentifier          "icon_writer"
440     //      /New/1/TargetName               "_blank"
441     //
442     //      /New/2/URL                      "private:factory/scalc"
443     //      /New/2/Title                    "Neues Calc Dokument"
444     //      /New/2/ImageIdentifier          "icon_calc"
445     //      /New/2/TargetName               "_blank"
446     //
447     // second "Wizard" menu ...
448     //      /Wizard/1/URL                   "file://b"
449     //      /Wizard/1/Title                 "MalWas"
450     //      /Wizard/1/ImageIdentifier       "icon_?"
451     //      /Wizard/1/TargetName            "_self"
452     //
453     //      ... and so on ...
454 
455     sal_uInt32  nItem     = 0 ;
456     sal_uInt32  nPosition = 0 ;
457     OUString    sName         ;
458 
459     // We must use these one instance object(!) to get information about installed modules.
460     // These information are used to filter menu entries wich need not installed modules ...
461     // Such entries shouldnt be available then!
462     // see impl_IsEntrySupported() too
463     SvtModuleOptions aModuleOptions;
464 
465     // Get names/values for new menu.
466 	// 4 subkeys for every item!
467     for( nItem=0; nItem<nNewCount; ++nItem )
468 	{
469         SvtDynMenuEntry   aItem                       ;
470         lValues[nPosition] >>= aItem.sURL             ;
471 		++nPosition;
472         lValues[nPosition] >>= aItem.sTitle           ;
473 		++nPosition;
474         lValues[nPosition] >>= aItem.sImageIdentifier ;
475 		++nPosition;
476         lValues[nPosition] >>= aItem.sTargetName      ;
477 		++nPosition;
478         m_aNewMenu.AppendSetupEntry( aItem );
479 	}
480 
481 	// Attention: Don't reset nPosition here!
482 
483     // Get names/values for wizard menu.
484 	// 4 subkeys for every item!
485     for( nItem=0; nItem<nWizardCount; ++nItem )
486 	{
487         SvtDynMenuEntry   aItem                       ;
488         lValues[nPosition] >>= aItem.sURL             ;
489 		++nPosition;
490         lValues[nPosition] >>= aItem.sTitle           ;
491 		++nPosition;
492         lValues[nPosition] >>= aItem.sImageIdentifier ;
493 		++nPosition;
494         lValues[nPosition] >>= aItem.sTargetName      ;
495 		++nPosition;
496         m_aWizardMenu.AppendSetupEntry( aItem );
497 	}
498 
499 	// Attention: Don't reset nPosition here!
500 
501 	// Get names/values for wizard menu.
502 	// 4 subkeys for every item!
503     for( nItem=0; nItem<nHelpBookmarksCount; ++nItem )
504 	{
505         SvtDynMenuEntry   aItem                       ;
506         lValues[nPosition] >>= aItem.sURL             ;
507 		++nPosition;
508         lValues[nPosition] >>= aItem.sTitle           ;
509 		++nPosition;
510         lValues[nPosition] >>= aItem.sImageIdentifier ;
511 		++nPosition;
512         lValues[nPosition] >>= aItem.sTargetName      ;
513 		++nPosition;
514         m_aHelpBookmarksMenu.AppendSetupEntry( aItem );
515 	}
516 
517 /*TODO: Not used in the moment! see Notify() ...
518 	// Enable notification mechanism of ouer baseclass.
519 	// We need it to get information about changes outside these class on ouer used configuration keys!
520     EnableNotification( lNames );
521 */
522 }
523 
524 //*****************************************************************************************************************
525 //	destructor
526 //*****************************************************************************************************************
527 SvtDynamicMenuOptions_Impl::~SvtDynamicMenuOptions_Impl()
528 {
529 	// We must save our current values .. if user forget it!
530 	if( IsModified() == sal_True )
531 	{
532 		Commit();
533 	}
534 }
535 
536 //*****************************************************************************************************************
537 //	public method
538 //*****************************************************************************************************************
539 void SvtDynamicMenuOptions_Impl::Notify( const Sequence< OUString >& )
540 {
541     DBG_ASSERT( sal_False, "SvtDynamicMenuOptions_Impl::Notify()\nNot implemented yet! I don't know how I can handle a dynamical list of unknown properties ...\n" );
542 }
543 
544 //*****************************************************************************************************************
545 //	public method
546 //*****************************************************************************************************************
547 void SvtDynamicMenuOptions_Impl::Commit()
548 {
549     DBG_ERROR( "SvtDynamicMenuOptions_Impl::Commit()\nNot implemented yet!\n" );
550     /*
551     // Write all properties!
552     // Delete complete sets first.
553     ClearNodeSet( SETNODE_NEWMENU    );
554     ClearNodeSet( SETNODE_WIZARDMENU );
555     ClearNodeSet( SETNODE_HELPBOOKMARKS );
556 
557     MenuEntry                    aItem                           ;
558     OUString                    sNode                           ;
559     Sequence< PropertyValue >   lPropertyValues( PROPERTYCOUNT );
560     sal_uInt32                  nItem          = 0              ;
561 
562     // Copy "new" menu entries to save-list!
563     sal_uInt32 nNewCount = m_aNewMenu.size();
564     for( nItem=0; nItem<nNewCount; ++nItem )
565 	{
566         aItem = m_aNewMenu[nItem];
567         // Format:  "New/1/URL"
568         //          "New/1/Title"
569         //          ...
570         sNode = SETNODE_NEWMENU + PATHDELIMITER + PATHPREFIX + OUString::valueOf( (sal_Int32)nItem ) + PATHDELIMITER;
571 
572         lPropertyValues[OFFSET_URL             ].Name  =   sNode + PROPERTYNAME_URL             ;
573         lPropertyValues[OFFSET_TITLE           ].Name  =   sNode + PROPERTYNAME_TITLE           ;
574         lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Name  =   sNode + PROPERTYNAME_IMAGEIDENTIFIER ;
575         lPropertyValues[OFFSET_TARGETNAME      ].Name  =   sNode + PROPERTYNAME_TARGETNAME      ;
576 
577         lPropertyValues[OFFSET_URL             ].Value <<= aItem.sURL                           ;
578         lPropertyValues[OFFSET_TITLE           ].Value <<= aItem.sTitle                         ;
579         lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Value <<= aItem.sImageIdentifier               ;
580         lPropertyValues[OFFSET_TARGETNAME      ].Value <<= aItem.sTargetName                    ;
581 
582         SetSetProperties( SETNODE_NEWMENU, lPropertyValues );
583 	}
584 
585     // Copy "wizard" menu entries to save-list!
586     sal_uInt32 nWizardCount = m_aWizardMenu.size();
587     for( nItem=0; nItem<nWizardCount; ++nItem )
588 	{
589         aItem = m_aWizardMenu[nItem];
590         // Format:  "Wizard/1/URL"
591         //          "Wizard/1/Title"
592         //          ...
593         sNode = SETNODE_WIZARDMENU + PATHDELIMITER + PATHPREFIX + OUString::valueOf( (sal_Int32)nItem ) + PATHDELIMITER;
594 
595         lPropertyValues[OFFSET_URL             ].Name  =   sNode + PROPERTYNAME_URL             ;
596         lPropertyValues[OFFSET_TITLE           ].Name  =   sNode + PROPERTYNAME_TITLE           ;
597         lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Name  =   sNode + PROPERTYNAME_IMAGEIDENTIFIER ;
598         lPropertyValues[OFFSET_TARGETNAME      ].Name  =   sNode + PROPERTYNAME_TARGETNAME      ;
599 
600         lPropertyValues[OFFSET_URL             ].Value <<= aItem.sURL                           ;
601         lPropertyValues[OFFSET_TITLE           ].Value <<= aItem.sTitle                         ;
602         lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Value <<= aItem.sImageIdentifier               ;
603         lPropertyValues[OFFSET_TARGETNAME      ].Value <<= aItem.sTargetName                    ;
604 
605         SetSetProperties( SETNODE_WIZARDMENU, lPropertyValues );
606 	}
607 
608 	// Copy help bookmarks entries to save-list!
609     sal_uInt32 nHelpBookmarksCount = m_aHelpBookmarksMenu.size();
610     for( nItem=0; nItem<nHelpBookmarksCount; ++nItem )
611 	{
612         aItem = m_aHelpBookmarksMenu[nItem];
613         // Format:  "HelpBookmarks/1/URL"
614         //          "HelpBookmarks/1/Title"
615         //          ...
616         sNode = SETNODE_HELPBOOKMARKS + PATHDELIMITER + PATHPREFIX + OUString::valueOf( (sal_Int32)nItem ) + PATHDELIMITER;
617 
618         lPropertyValues[OFFSET_URL             ].Name  =   sNode + PROPERTYNAME_URL             ;
619         lPropertyValues[OFFSET_TITLE           ].Name  =   sNode + PROPERTYNAME_TITLE           ;
620         lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Name  =   sNode + PROPERTYNAME_IMAGEIDENTIFIER ;
621         lPropertyValues[OFFSET_TARGETNAME      ].Name  =   sNode + PROPERTYNAME_TARGETNAME      ;
622 
623         lPropertyValues[OFFSET_URL             ].Value <<= aItem.sURL                           ;
624         lPropertyValues[OFFSET_TITLE           ].Value <<= aItem.sTitle                         ;
625         lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Value <<= aItem.sImageIdentifier               ;
626         lPropertyValues[OFFSET_TARGETNAME      ].Value <<= aItem.sTargetName                    ;
627 
628         SetSetProperties( SETNODE_HELPBOOKMARKS, lPropertyValues );
629 	}
630     */
631 }
632 
633 //*****************************************************************************************************************
634 //	public method
635 //*****************************************************************************************************************
636 void SvtDynamicMenuOptions_Impl::Clear( EDynamicMenuType eMenu )
637 {
638     switch( eMenu )
639 	{
640         case E_NEWMENU      :   {
641                                     m_aNewMenu.Clear();
642                                     SetModified();
643                                 }
644                                 break;
645 
646         case E_WIZARDMENU   :   {
647                                     m_aWizardMenu.Clear();
648                                     SetModified();
649                                 }
650                                 break;
651 
652         case E_HELPBOOKMARKS :  {
653                                     m_aHelpBookmarksMenu.Clear();
654                                     SetModified();
655                                 }
656                                 break;
657 	}
658 }
659 
660 //*****************************************************************************************************************
661 //	public method
662 //*****************************************************************************************************************
663 Sequence< Sequence< PropertyValue > > SvtDynamicMenuOptions_Impl::GetMenu( EDynamicMenuType eMenu ) const
664 {
665     Sequence< Sequence< PropertyValue > > lReturn;
666     switch( eMenu )
667 	{
668         case E_NEWMENU      :   {
669                                     lReturn = m_aNewMenu.GetList();
670                                 }
671                                 break;
672 
673         case E_WIZARDMENU   :   {
674                                     lReturn = m_aWizardMenu.GetList();
675                                 }
676                                 break;
677 
678         case E_HELPBOOKMARKS :  {
679                                     lReturn = m_aHelpBookmarksMenu.GetList();
680                                 }
681                                 break;
682 	}
683     return lReturn;
684 }
685 
686 //*****************************************************************************************************************
687 //	public method
688 //*****************************************************************************************************************
689 void SvtDynamicMenuOptions_Impl::AppendItem(            EDynamicMenuType    eMenu           ,
690                                                 const   OUString&           sURL            ,
691                                                 const   OUString&           sTitle          ,
692                                                 const   OUString&           sImageIdentifier,
693                                                 const   OUString&           sTargetName     )
694 {
695     SvtDynMenuEntry aItem( sURL, sTitle, sImageIdentifier, sTargetName );
696 
697     switch( eMenu )
698 	{
699         case E_NEWMENU  :   {
700                                 m_aNewMenu.AppendUserEntry( aItem );
701 								SetModified();
702 							}
703 							break;
704 
705         case E_WIZARDMENU   :   {
706                                 m_aWizardMenu.AppendUserEntry( aItem );
707 								SetModified();
708 							}
709 							break;
710 
711         case E_HELPBOOKMARKS :  {
712                                 m_aHelpBookmarksMenu.AppendUserEntry( aItem );
713 								SetModified();
714 							}
715 							break;
716 	}
717 }
718 
719 //*****************************************************************************************************************
720 //	private method
721 //*****************************************************************************************************************
722 Sequence< OUString > SvtDynamicMenuOptions_Impl::impl_GetPropertyNames( sal_uInt32& nNewCount, sal_uInt32& nWizardCount, sal_uInt32& nHelpBookmarksCount )
723 {
724 	// First get ALL names of current existing list items in configuration!
725     Sequence< OUString > lNewItems           = GetNodeNames( SETNODE_NEWMENU       );
726     Sequence< OUString > lWizardItems        = GetNodeNames( SETNODE_WIZARDMENU    );
727     Sequence< OUString > lHelpBookmarksItems = GetNodeNames( SETNODE_HELPBOOKMARKS );
728 
729 	// Get information about list counts ...
730     nNewCount           = lNewItems.getLength          ();
731     nWizardCount        = lWizardItems.getLength       ();
732     nHelpBookmarksCount = lHelpBookmarksItems.getLength();
733 
734     // Sort and expand all three list to result list ...
735     Sequence< OUString > lProperties;
736     impl_SortAndExpandPropertyNames( lNewItems          , lProperties, SETNODE_NEWMENU       );
737     impl_SortAndExpandPropertyNames( lWizardItems       , lProperties, SETNODE_WIZARDMENU    );
738     impl_SortAndExpandPropertyNames( lHelpBookmarksItems, lProperties, SETNODE_HELPBOOKMARKS );
739 
740 	// Return result.
741     return lProperties;
742 }
743 
744 //*****************************************************************************************************************
745 //  private helper
746 //*****************************************************************************************************************
747 class CountWithPrefixSort
748 {
749     public:
750         int operator() ( const OUString& s1 ,
751                          const OUString& s2 ) const
752         {
753             // Get order numbers from entry name without prefix.
754             // e.g. "m10" => 10
755             //      "m5"  => 5
756             sal_Int32 n1 = s1.copy( 1, s1.getLength()-1 ).toInt32();
757             sal_Int32 n2 = s2.copy( 1, s2.getLength()-1 ).toInt32();
758             // MUST be in [0,1] ... because it's a difference between
759             // insert-positions of given entries in sorted list!
760             return( n1<n2 );
761         }
762 };
763 
764 class SelectByPrefix
765 {
766     public:
767         bool operator() ( const OUString& s ) const
768         {
769             // Prefer setup written entries by check first letter of given string. It must be a "s".
770             return( s.indexOf( PATHPREFIX_SETUP ) == 0 );
771         }
772 };
773 
774 //*****************************************************************************************************************
775 //	private method
776 //*****************************************************************************************************************
777 void SvtDynamicMenuOptions_Impl::impl_SortAndExpandPropertyNames( const Sequence< OUString >& lSource      ,
778                                                                         Sequence< OUString >& lDestination ,
779                                                                   const OUString&             sSetNode     )
780 {
781     OUString            sFixPath                                    ;
782     vector< OUString >  lTemp                                       ;
783     sal_Int32           nSourceCount     = lSource.getLength()      ;
784     sal_Int32           nDestinationStep = lDestination.getLength() ; // start on end of current list ...!
785 
786     lDestination.realloc( (nSourceCount*PROPERTYCOUNT)+nDestinationStep ); // get enough memory for copy operations after nDestination ...
787 
788     // Copy all items to temp. vector to use fast sort operations :-)
789     for( sal_Int32 nSourceStep=0; nSourceStep<nSourceCount; ++nSourceStep )
790         lTemp.push_back( lSource[nSourceStep] );
791 
792     // Sort all entries by number ...
793     stable_sort( lTemp.begin(), lTemp.end(), CountWithPrefixSort() );
794     // and split into setup & user written entries!
795     stable_partition( lTemp.begin(), lTemp.end(), SelectByPrefix() );
796 
797     // Copy sorted entries to destination and expand every item with
798     // 4 supported sub properties.
799     for( vector< OUString >::const_iterator pItem =lTemp.begin() ;
800                                             pItem!=lTemp.end()   ;
801                                             ++pItem              )
802     {
803         sFixPath  = sSetNode       ;
804         sFixPath += PATHDELIMITER  ;
805         sFixPath += *pItem         ;
806         sFixPath += PATHDELIMITER  ;
807 
808         lDestination[nDestinationStep]  = sFixPath                      ;
809         lDestination[nDestinationStep] += PROPERTYNAME_URL              ;
810         ++nDestinationStep;
811         lDestination[nDestinationStep]  = sFixPath                      ;
812         lDestination[nDestinationStep] += PROPERTYNAME_TITLE            ;
813         ++nDestinationStep;
814         lDestination[nDestinationStep]  = sFixPath                      ;
815         lDestination[nDestinationStep] += PROPERTYNAME_IMAGEIDENTIFIER  ;
816         ++nDestinationStep;
817         lDestination[nDestinationStep]  = sFixPath                      ;
818         lDestination[nDestinationStep] += PROPERTYNAME_TARGETNAME       ;
819         ++nDestinationStep;
820     }
821 }
822 
823 //*****************************************************************************************************************
824 //	initialize static member
825 //	DON'T DO IT IN YOUR HEADER!
826 //	see definition for further informations
827 //*****************************************************************************************************************
828 SvtDynamicMenuOptions_Impl*     SvtDynamicMenuOptions::m_pDataContainer = NULL  ;
829 sal_Int32                       SvtDynamicMenuOptions::m_nRefCount      = 0     ;
830 
831 //*****************************************************************************************************************
832 //	constructor
833 //*****************************************************************************************************************
834 SvtDynamicMenuOptions::SvtDynamicMenuOptions()
835 {
836     // Global access, must be guarded (multithreading!).
837     MutexGuard aGuard( GetOwnStaticMutex() );
838 	// Increase ouer refcount ...
839 	++m_nRefCount;
840 	// ... and initialize ouer data container only if it not already exist!
841     if( m_pDataContainer == NULL )
842 	{
843         m_pDataContainer = new SvtDynamicMenuOptions_Impl;
844         ItemHolder1::holdConfigItem(E_DYNAMICMENUOPTIONS);
845 	}
846 }
847 
848 //*****************************************************************************************************************
849 //	destructor
850 //*****************************************************************************************************************
851 SvtDynamicMenuOptions::~SvtDynamicMenuOptions()
852 {
853     // Global access, must be guarded (multithreading!)
854     MutexGuard aGuard( GetOwnStaticMutex() );
855 	// Decrease ouer refcount.
856 	--m_nRefCount;
857 	// If last instance was deleted ...
858 	// we must destroy ouer static data container!
859     if( m_nRefCount <= 0 )
860 	{
861 		delete m_pDataContainer;
862 		m_pDataContainer = NULL;
863 	}
864 }
865 
866 //*****************************************************************************************************************
867 //	public method
868 //*****************************************************************************************************************
869 void SvtDynamicMenuOptions::Clear( EDynamicMenuType eMenu )
870 {
871     MutexGuard aGuard( GetOwnStaticMutex() );
872     m_pDataContainer->Clear( eMenu );
873 }
874 
875 //*****************************************************************************************************************
876 //	public method
877 //*****************************************************************************************************************
878 Sequence< Sequence< PropertyValue > > SvtDynamicMenuOptions::GetMenu( EDynamicMenuType eMenu ) const
879 {
880     MutexGuard aGuard( GetOwnStaticMutex() );
881     return m_pDataContainer->GetMenu( eMenu );
882 }
883 
884 //*****************************************************************************************************************
885 //	public method
886 //*****************************************************************************************************************
887 void SvtDynamicMenuOptions::AppendItem(         EDynamicMenuType    eMenu           ,
888                                         const   OUString&           sURL            ,
889                                         const   OUString&           sTitle          ,
890                                         const   OUString&           sImageIdentifier,
891                                         const   OUString&           sTargetName     )
892 {
893     MutexGuard aGuard( GetOwnStaticMutex() );
894     m_pDataContainer->AppendItem( eMenu, sURL, sTitle, sImageIdentifier, sTargetName );
895 }
896 
897 //*****************************************************************************************************************
898 //	private method
899 //*****************************************************************************************************************
900 Mutex& SvtDynamicMenuOptions::GetOwnStaticMutex()
901 {
902 	// Initialize static mutex only for one time!
903     static Mutex* pMutex = NULL;
904 	// If these method first called (Mutex not already exist!) ...
905     if( pMutex == NULL )
906     {
907 		// ... we must create a new one. Protect follow code with the global mutex -
908 		// It must be - we create a static variable!
909         MutexGuard aGuard( Mutex::getGlobalMutex() );
910 		// We must check our pointer again - because it can be that another instance of ouer class will be fastr then these!
911         if( pMutex == NULL )
912         {
913 			// Create the new mutex and set it for return on static variable.
914             static Mutex aMutex;
915             pMutex = &aMutex;
916         }
917     }
918 	// Return new created or already existing mutex object.
919     return *pMutex;
920 }
921