nss: upgrade to release 3.73
[LibreOffice.git] / unotools / source / config / dynamicmenuoptions.cxx
blob2421d228fdf0f3c6213e95ae2ac2dbedc3be0a15
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <sal/log.hxx>
23 #include <unotools/dynamicmenuoptions.hxx>
24 #include <unotools/configitem.hxx>
25 #include <tools/debug.hxx>
26 #include <com/sun/star/uno/Any.hxx>
27 #include <com/sun/star/uno/Sequence.hxx>
28 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <vector>
32 #include "itemholder1.hxx"
34 #include <algorithm>
36 using namespace ::std;
37 using namespace ::utl;
38 using namespace ::osl;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::beans;
42 #define ROOTNODE_MENUS "Office.Common/Menus/"
43 #define PATHDELIMITER "/"
45 #define SETNODE_NEWMENU "New"
46 #define SETNODE_WIZARDMENU "Wizard"
48 #define PROPERTYNAME_URL DYNAMICMENU_PROPERTYNAME_URL
49 #define PROPERTYNAME_TITLE DYNAMICMENU_PROPERTYNAME_TITLE
50 #define PROPERTYNAME_IMAGEIDENTIFIER DYNAMICMENU_PROPERTYNAME_IMAGEIDENTIFIER
51 #define PROPERTYNAME_TARGETNAME DYNAMICMENU_PROPERTYNAME_TARGETNAME
53 #define PROPERTYCOUNT 4
55 #define OFFSET_URL 0
56 #define OFFSET_TITLE 1
57 #define OFFSET_IMAGEIDENTIFIER 2
58 #define OFFSET_TARGETNAME 3
60 #define PATHPREFIX_SETUP "m"
62 namespace {
64 /*-****************************************************************************************************************
65 @descr struct to hold information about one menu entry.
66 ****************************************************************************************************************-*/
67 struct SvtDynMenuEntry
69 OUString sURL;
70 OUString sTitle;
71 OUString sImageIdentifier;
72 OUString sTargetName;
75 /*-****************************************************************************************************************
76 @descr support simple menu structures and operations on it
77 ****************************************************************************************************************-*/
78 class SvtDynMenu
80 public:
81 // append setup written menu entry
82 // Don't touch name of entry. It was defined by setup and must be the same every time!
83 // Look for double menu entries here too... may be some separator items are superfluous...
84 void AppendSetupEntry( const SvtDynMenuEntry& rEntry )
86 if(
87 ( lSetupEntries.empty() ) ||
88 ( lSetupEntries.rbegin()->sURL != rEntry.sURL )
91 lSetupEntries.push_back( rEntry );
95 // convert internal list to external format
96 // for using it on right menus really
97 // Notice: We build a property list with 4 entries and set it on result list then.
98 // Separator entries will be packed in another way then normal entries! We define
99 // special string "sSeparator" to perform too ...
100 Sequence< Sequence< PropertyValue > > GetList() const
102 sal_Int32 nSetupCount = static_cast<sal_Int32>(lSetupEntries.size());
103 sal_Int32 nUserCount = static_cast<sal_Int32>(lUserEntries.size());
104 sal_Int32 nStep = 0;
105 Sequence< PropertyValue > lProperties ( PROPERTYCOUNT );
106 Sequence< Sequence< PropertyValue > > lResult ( nSetupCount+nUserCount );
107 OUString sSeparator ( "private:separator" );
109 lProperties[OFFSET_URL ].Name = PROPERTYNAME_URL;
110 lProperties[OFFSET_TITLE ].Name = PROPERTYNAME_TITLE;
111 lProperties[OFFSET_IMAGEIDENTIFIER].Name = PROPERTYNAME_IMAGEIDENTIFIER;
112 lProperties[OFFSET_TARGETNAME ].Name = PROPERTYNAME_TARGETNAME;
114 for( const auto& pList : {&lSetupEntries, &lUserEntries} )
116 for( const auto& rItem : *pList )
118 if( rItem.sURL == sSeparator )
120 lProperties[OFFSET_URL ].Value <<= sSeparator;
121 lProperties[OFFSET_TITLE ].Value <<= OUString();
122 lProperties[OFFSET_IMAGEIDENTIFIER ].Value <<= OUString();
123 lProperties[OFFSET_TARGETNAME ].Value <<= OUString();
125 else
127 lProperties[OFFSET_URL ].Value <<= rItem.sURL;
128 lProperties[OFFSET_TITLE ].Value <<= rItem.sTitle;
129 lProperties[OFFSET_IMAGEIDENTIFIER ].Value <<= rItem.sImageIdentifier;
130 lProperties[OFFSET_TARGETNAME ].Value <<= rItem.sTargetName;
132 lResult[nStep] = lProperties;
133 ++nStep;
136 return lResult;
139 private:
140 vector< SvtDynMenuEntry > lSetupEntries;
141 vector< SvtDynMenuEntry > lUserEntries;
146 class SvtDynamicMenuOptions_Impl : public ConfigItem
148 public:
150 SvtDynamicMenuOptions_Impl();
151 virtual ~SvtDynamicMenuOptions_Impl() override;
153 /*-****************************************************************************************************
154 @short called for notify of configmanager
155 @descr This method is called from the ConfigManager before the application ends or from the
156 PropertyChangeListener if the sub tree broadcasts changes. You must update your
157 internal values.
159 @seealso baseclass ConfigItem
161 @param "lPropertyNames" is the list of properties which should be updated.
162 *//*-*****************************************************************************************************/
164 virtual void Notify( const Sequence< OUString >& lPropertyNames ) override;
166 /*-****************************************************************************************************
167 @short base implementation of public interface for "SvtDynamicMenuOptions"!
168 @descr These class is used as static member of "SvtDynamicMenuOptions" ...
169 => The code exist only for one time and isn't duplicated for every instance!
170 *//*-*****************************************************************************************************/
172 Sequence< Sequence< PropertyValue > > GetMenu ( EDynamicMenuType eMenu ) const;
174 private:
176 virtual void ImplCommit() override;
178 /*-****************************************************************************************************
179 @short return list of key names of our configuration management which represent our module tree
180 @descr This method returns the current list of key names! We need it to get needed values from our
181 configuration management and support dynamical menu item lists!
182 @param "nNewCount" , returns count of menu entries for "new"
183 @param "nWizardCount" , returns count of menu entries for "wizard"
184 @return A list of configuration key names is returned.
185 *//*-*****************************************************************************************************/
187 Sequence< OUString > impl_GetPropertyNames( sal_uInt32& nNewCount, sal_uInt32& nWizardCount );
189 /*-****************************************************************************************************
190 @short sort given source list and expand it for all well known properties to destination
191 @descr We must support sets of entries with count inside the name .. but some of them could be missing!
192 e.g. s1-s2-s3-s0-u1-s6-u5-u7
193 Then we must sort it by name and expand it to the follow one:
194 sSetNode/s0/URL
195 sSetNode/s0/Title
196 sSetNode/s0/...
197 sSetNode/s1/URL
198 sSetNode/s1/Title
199 sSetNode/s1/...
201 sSetNode/s6/URL
202 sSetNode/s6/Title
203 sSetNode/s6/...
204 sSetNode/u1/URL
205 sSetNode/u1/Title
206 sSetNode/u1/...
208 sSetNode/u7/URL
209 sSetNode/u7/Title
210 sSetNode/u7/...
211 Rules: We start with all setup written entries names "sx" and x=[0..n].
212 Then we handle all "ux" items. Inside these blocks we sort it ascending by number.
214 @attention We add these expanded list to the end of given "lDestination" list!
215 So we must start on "lDestination.getLength()".
216 Reallocation of memory of destination list is done by us!
218 @seealso method impl_GetPropertyNames()
220 @param "lSource" , original list (e.g. [m1-m2-m3-m6-m0] )
221 @param "lDestination" , destination of operation
222 @param "sSetNode" , name of configuration set to build complete path
223 @return A list of configuration key names is returned.
224 *//*-*****************************************************************************************************/
226 static void impl_SortAndExpandPropertyNames( const Sequence< OUString >& lSource ,
227 Sequence< OUString >& lDestination ,
228 const OUString& sSetNode );
230 // private member
232 private:
234 SvtDynMenu m_aNewMenu;
235 SvtDynMenu m_aWizardMenu;
238 // constructor
240 SvtDynamicMenuOptions_Impl::SvtDynamicMenuOptions_Impl()
241 // Init baseclasses first
242 : ConfigItem( ROOTNODE_MENUS )
243 // Init member then...
245 // Get names and values of all accessible menu entries and fill internal structures.
246 // See impl_GetPropertyNames() for further information.
247 sal_uInt32 nNewCount = 0;
248 sal_uInt32 nWizardCount = 0;
249 Sequence< OUString > lNames = impl_GetPropertyNames ( nNewCount ,
250 nWizardCount );
251 Sequence< Any > lValues = GetProperties ( lNames );
253 // Safe impossible cases.
254 // We need values from ALL configuration keys.
255 // Follow assignment use order of values in relation to our list of key names!
256 DBG_ASSERT( !(lNames.getLength()!=lValues.getLength()), "SvtDynamicMenuOptions_Impl::SvtDynamicMenuOptions_Impl()\nI miss some values of configuration keys!\n" );
258 // Copy values from list in right order to our internal member.
259 // Attention: List for names and values have an internal construction pattern!
261 // first "New" menu ...
262 // Name Value
263 // /New/1/URL "private:factory/swriter"
264 // /New/1/Title "New Writer Document"
265 // /New/1/ImageIdentifier "icon_writer"
266 // /New/1/TargetName "_blank"
268 // /New/2/URL "private:factory/scalc"
269 // /New/2/Title "New Calc Document"
270 // /New/2/ImageIdentifier "icon_calc"
271 // /New/2/TargetName "_blank"
273 // second "Wizard" menu ...
274 // /Wizard/1/URL "file://b"
275 // /Wizard/1/Title "PaintSomething"
276 // /Wizard/1/ImageIdentifier "icon_?"
277 // /Wizard/1/TargetName "_self"
279 // ... and so on ...
281 sal_uInt32 nItem = 0;
282 sal_uInt32 nPosition = 0;
284 // Get names/values for new menu.
285 // 4 subkeys for every item!
286 for( nItem=0; nItem<nNewCount; ++nItem )
288 SvtDynMenuEntry aItem;
289 lValues[nPosition] >>= aItem.sURL;
290 ++nPosition;
291 lValues[nPosition] >>= aItem.sTitle;
292 ++nPosition;
293 lValues[nPosition] >>= aItem.sImageIdentifier;
294 ++nPosition;
295 lValues[nPosition] >>= aItem.sTargetName;
296 ++nPosition;
297 m_aNewMenu.AppendSetupEntry( aItem );
300 // Attention: Don't reset nPosition here!
302 // Get names/values for wizard menu.
303 // 4 subkeys for every item!
304 for( nItem=0; nItem<nWizardCount; ++nItem )
306 SvtDynMenuEntry aItem;
307 lValues[nPosition] >>= aItem.sURL;
308 ++nPosition;
309 lValues[nPosition] >>= aItem.sTitle;
310 ++nPosition;
311 lValues[nPosition] >>= aItem.sImageIdentifier;
312 ++nPosition;
313 lValues[nPosition] >>= aItem.sTargetName;
314 ++nPosition;
315 m_aWizardMenu.AppendSetupEntry( aItem );
318 // Attention: Don't reset nPosition here!
320 /*TODO: Not used in the moment! see Notify() ...
321 // Enable notification mechanism of our baseclass.
322 // We need it to get information about changes outside these class on our used configuration keys!
323 EnableNotification( lNames );
327 // destructor
329 SvtDynamicMenuOptions_Impl::~SvtDynamicMenuOptions_Impl()
331 assert(!IsModified()); // should have been committed
334 // public method
336 void SvtDynamicMenuOptions_Impl::Notify( const Sequence< OUString >& )
338 SAL_WARN( "unotools.config", "SvtDynamicMenuOptions_Impl::Notify() Not implemented yet! I don't know how I can handle a dynamical list of unknown properties ..." );
341 // public method
343 void SvtDynamicMenuOptions_Impl::ImplCommit()
345 SAL_WARN("unotools.config", "SvtDynamicMenuOptions_Impl::ImplCommit(): Not implemented yet!");
347 // Write all properties!
348 // Delete complete sets first.
349 ClearNodeSet( SETNODE_NEWMENU );
350 ClearNodeSet( SETNODE_WIZARDMENU );
352 MenuEntry aItem;
353 OUString sNode;
354 Sequence< PropertyValue > lPropertyValues( PROPERTYCOUNT );
355 sal_uInt32 nItem = 0;
357 // Copy "new" menu entries to save-list!
358 sal_uInt32 nNewCount = m_aNewMenu.size();
359 for( nItem=0; nItem<nNewCount; ++nItem )
361 aItem = m_aNewMenu[nItem];
362 // Format: "New/1/URL"
363 // "New/1/Title"
364 // ...
365 sNode = SETNODE_NEWMENU + PATHDELIMITER + PATHPREFIX + OUString::valueOf( (sal_Int32)nItem ) + PATHDELIMITER;
367 lPropertyValues[OFFSET_URL ].Name = sNode + PROPERTYNAME_URL;
368 lPropertyValues[OFFSET_TITLE ].Name = sNode + PROPERTYNAME_TITLE;
369 lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Name = sNode + PROPERTYNAME_IMAGEIDENTIFIER;
370 lPropertyValues[OFFSET_TARGETNAME ].Name = sNode + PROPERTYNAME_TARGETNAME;
372 lPropertyValues[OFFSET_URL ].Value <<= aItem.sURL;
373 lPropertyValues[OFFSET_TITLE ].Value <<= aItem.sTitle;
374 lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Value <<= aItem.sImageIdentifier;
375 lPropertyValues[OFFSET_TARGETNAME ].Value <<= aItem.sTargetName;
377 SetSetProperties( SETNODE_NEWMENU, lPropertyValues );
380 // Copy "wizard" menu entries to save-list!
381 sal_uInt32 nWizardCount = m_aWizardMenu.size();
382 for( nItem=0; nItem<nWizardCount; ++nItem )
384 aItem = m_aWizardMenu[nItem];
385 // Format: "Wizard/1/URL"
386 // "Wizard/1/Title"
387 // ...
388 sNode = SETNODE_WIZARDMENU + PATHDELIMITER + PATHPREFIX + OUString::valueOf( (sal_Int32)nItem ) + PATHDELIMITER;
390 lPropertyValues[OFFSET_URL ].Name = sNode + PROPERTYNAME_URL;
391 lPropertyValues[OFFSET_TITLE ].Name = sNode + PROPERTYNAME_TITLE;
392 lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Name = sNode + PROPERTYNAME_IMAGEIDENTIFIER;
393 lPropertyValues[OFFSET_TARGETNAME ].Name = sNode + PROPERTYNAME_TARGETNAME;
395 lPropertyValues[OFFSET_URL ].Value <<= aItem.sURL;
396 lPropertyValues[OFFSET_TITLE ].Value <<= aItem.sTitle;
397 lPropertyValues[OFFSET_IMAGEIDENTIFIER ].Value <<= aItem.sImageIdentifier;
398 lPropertyValues[OFFSET_TARGETNAME ].Value <<= aItem.sTargetName;
400 SetSetProperties( SETNODE_WIZARDMENU, lPropertyValues );
406 // public method
408 Sequence< Sequence< PropertyValue > > SvtDynamicMenuOptions_Impl::GetMenu( EDynamicMenuType eMenu ) const
410 Sequence< Sequence< PropertyValue > > lReturn;
411 switch( eMenu )
413 case EDynamicMenuType::NewMenu :
414 lReturn = m_aNewMenu.GetList();
415 break;
417 case EDynamicMenuType::WizardMenu :
418 lReturn = m_aWizardMenu.GetList();
419 break;
421 return lReturn;
424 // private method
426 Sequence< OUString > SvtDynamicMenuOptions_Impl::impl_GetPropertyNames( sal_uInt32& nNewCount, sal_uInt32& nWizardCount )
428 // First get ALL names of current existing list items in configuration!
429 Sequence< OUString > lNewItems = GetNodeNames( SETNODE_NEWMENU );
430 Sequence< OUString > lWizardItems = GetNodeNames( SETNODE_WIZARDMENU );
432 // Get information about list counts ...
433 nNewCount = lNewItems.getLength ();
434 nWizardCount = lWizardItems.getLength ();
436 // Sort and expand all three list to result list ...
437 Sequence< OUString > lProperties;
438 impl_SortAndExpandPropertyNames( lNewItems , lProperties, SETNODE_NEWMENU );
439 impl_SortAndExpandPropertyNames( lWizardItems , lProperties, SETNODE_WIZARDMENU );
441 // Return result.
442 return lProperties;
445 // private helper
447 namespace {
449 class CountWithPrefixSort
451 public:
452 bool operator() ( const OUString& s1 ,
453 const OUString& s2 ) const
455 // Get order numbers from entry name without prefix.
456 // e.g. "m10" => 10
457 // "m5" => 5
458 sal_Int32 n1 = s1.copy( 1 ).toInt32();
459 sal_Int32 n2 = s2.copy( 1 ).toInt32();
460 // MUST be in [0,1] ... because it's a difference between
461 // insert-positions of given entries in sorted list!
462 return( n1<n2 );
466 class SelectByPrefix
468 public:
469 bool operator() ( const OUString& s ) const
471 // Prefer setup written entries by check first letter of given string. It must be a "s".
472 return s.startsWith( PATHPREFIX_SETUP );
478 // private method
480 void SvtDynamicMenuOptions_Impl::impl_SortAndExpandPropertyNames( const Sequence< OUString >& lSource ,
481 Sequence< OUString >& lDestination ,
482 const OUString& sSetNode )
484 vector< OUString > lTemp;
485 sal_Int32 nSourceCount = lSource.getLength();
486 sal_Int32 nDestinationStep = lDestination.getLength(); // start on end of current list ...!
488 lDestination.realloc( (nSourceCount*PROPERTYCOUNT)+nDestinationStep ); // get enough memory for copy operations after nDestination ...
490 // Copy all items to temp. vector to use fast sort operations :-)
491 lTemp.insert( lTemp.end(), lSource.begin(), lSource.end() );
493 // Sort all entries by number ...
494 stable_sort( lTemp.begin(), lTemp.end(), CountWithPrefixSort() );
495 // and split into setup & user written entries!
496 stable_partition( lTemp.begin(), lTemp.end(), SelectByPrefix() );
498 // Copy sorted entries to destination and expand every item with
499 // 4 supported sub properties.
500 for( const auto& rItem : lTemp )
502 OUString sFixPath(sSetNode + PATHDELIMITER + rItem + PATHDELIMITER);
503 lDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_URL;
504 lDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_TITLE;
505 lDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_IMAGEIDENTIFIER;
506 lDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_TARGETNAME;
510 namespace {
511 // global
512 std::weak_ptr<SvtDynamicMenuOptions_Impl> g_pDynamicMenuOptions;
515 SvtDynamicMenuOptions::SvtDynamicMenuOptions()
517 // Global access, must be guarded (multithreading!).
518 MutexGuard aGuard( GetOwnStaticMutex() );
520 m_pImpl = g_pDynamicMenuOptions.lock();
521 if( !m_pImpl )
523 m_pImpl = std::make_shared<SvtDynamicMenuOptions_Impl>();
524 g_pDynamicMenuOptions = m_pImpl;
525 ItemHolder1::holdConfigItem(EItem::DynamicMenuOptions);
529 SvtDynamicMenuOptions::~SvtDynamicMenuOptions()
531 // Global access, must be guarded (multithreading!)
532 MutexGuard aGuard( GetOwnStaticMutex() );
534 m_pImpl.reset();
537 // public method
539 Sequence< Sequence< PropertyValue > > SvtDynamicMenuOptions::GetMenu( EDynamicMenuType eMenu ) const
541 MutexGuard aGuard( GetOwnStaticMutex() );
542 return m_pImpl->GetMenu( eMenu );
545 namespace
547 class theDynamicMenuOptionsMutex : public rtl::Static<osl::Mutex, theDynamicMenuOptionsMutex>{};
550 // private method
552 Mutex& SvtDynamicMenuOptions::GetOwnStaticMutex()
554 return theDynamicMenuOptionsMutex::get();
557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */