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