1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <o3tl/string_view.hxx>
23 #include <unotools/dynamicmenuoptions.hxx>
24 #include <tools/debug.hxx>
25 #include <unotools/configmgr.hxx>
26 #include <unotools/configitem.hxx>
27 #include <com/sun/star/uno/Any.hxx>
28 #include <com/sun/star/uno/Sequence.hxx>
32 #include <string_view>
34 using namespace ::com::sun::star::uno
;
35 using namespace ::com::sun::star::beans
;
37 constexpr OUStringLiteral DYNAMICMENU_PROPERTYNAME_URL
= u
"URL";
38 constexpr OUStringLiteral DYNAMICMENU_PROPERTYNAME_TITLE
= u
"Title";
39 constexpr OUStringLiteral DYNAMICMENU_PROPERTYNAME_IMAGEIDENTIFIER
= u
"ImageIdentifier";
40 constexpr OUStringLiteral DYNAMICMENU_PROPERTYNAME_TARGETNAME
= u
"TargetName";
42 constexpr OUString PATHDELIMITER
= u
"/"_ustr
;
44 constexpr OUString SETNODE_NEWMENU
= u
"New"_ustr
;
45 constexpr OUString SETNODE_WIZARDMENU
= u
"Wizard"_ustr
;
47 #define PROPERTYNAME_URL DYNAMICMENU_PROPERTYNAME_URL
48 #define PROPERTYNAME_TITLE DYNAMICMENU_PROPERTYNAME_TITLE
49 #define PROPERTYNAME_IMAGEIDENTIFIER DYNAMICMENU_PROPERTYNAME_IMAGEIDENTIFIER
50 #define PROPERTYNAME_TARGETNAME DYNAMICMENU_PROPERTYNAME_TARGETNAME
52 #define PROPERTYCOUNT 4
54 constexpr std::u16string_view PATHPREFIX_SETUP
= u
"m";
58 /*-****************************************************************************************************************
59 @descr support simple menu structures and operations on it
60 ****************************************************************************************************************-*/
63 // append setup written menu entry
64 // Don't touch name of entry. It was defined by setup and must be the same every time!
65 // Look for double menu entries here too... may be some separator items are superfluous...
66 void AppendSetupEntry( const SvtDynMenuEntry
& rEntry
)
68 if( lSetupEntries
.empty() || lSetupEntries
.rbegin()->sURL
!= rEntry
.sURL
)
69 lSetupEntries
.push_back( rEntry
);
72 // convert internal list to external format
73 // for using it on right menus really
74 // Notice: We build a property list with 4 entries and set it on result list then.
75 // Separator entries will be packed in another way then normal entries! We define
76 // special string "sSeparator" to perform too ...
77 std::vector
< SvtDynMenuEntry
> GetList() const
79 sal_Int32 nSetupCount
= static_cast<sal_Int32
>(lSetupEntries
.size());
80 sal_Int32 nUserCount
= static_cast<sal_Int32
>(lUserEntries
.size());
82 std::vector
< SvtDynMenuEntry
> lResult ( nSetupCount
+nUserCount
);
83 OUString
sSeparator ( u
"private:separator"_ustr
);
85 for( const auto& pList
: {&lSetupEntries
, &lUserEntries
} )
87 for( const auto& rItem
: *pList
)
89 SvtDynMenuEntry entry
;
90 if( rItem
.sURL
== sSeparator
)
92 entry
.sURL
= sSeparator
;
98 lResult
[nStep
] = std::move(entry
);
106 std::vector
< SvtDynMenuEntry
> lSetupEntries
;
107 std::vector
< SvtDynMenuEntry
> lUserEntries
;
112 namespace SvtDynamicMenuOptions
115 static Sequence
< OUString
> lcl_GetPropertyNames(
116 css::uno::Reference
<css::container::XHierarchicalNameAccess
> const & xHierarchyAccess
,
117 sal_uInt32
& nNewCount
, sal_uInt32
& nWizardCount
);
119 std::vector
< SvtDynMenuEntry
> GetMenu( EDynamicMenuType eMenu
)
122 SvtDynMenu aWizardMenu
;
124 Reference
<css::container::XHierarchicalNameAccess
> xHierarchyAccess
= utl::ConfigManager::acquireTree(u
"Office.Common/Menus/");
126 // Get names and values of all accessible menu entries and fill internal structures.
127 // See impl_GetPropertyNames() for further information.
128 sal_uInt32 nNewCount
= 0;
129 sal_uInt32 nWizardCount
= 0;
130 Sequence
< OUString
> lNames
= lcl_GetPropertyNames ( xHierarchyAccess
, nNewCount
,
132 Sequence
< Any
> lValues
= utl::ConfigItem::GetProperties( xHierarchyAccess
, lNames
, /*bAllLocales*/false );
134 // Safe impossible cases.
135 // We need values from ALL configuration keys.
136 // Follow assignment use order of values in relation to our list of key names!
137 DBG_ASSERT( !(lNames
.getLength()!=lValues
.getLength()), "SvtDynamicMenuOptions_Impl::SvtDynamicMenuOptions_Impl()\nI miss some values of configuration keys!\n" );
139 // Copy values from list in right order to our internal member.
140 // Attention: List for names and values have an internal construction pattern!
142 // first "New" menu ...
144 // /New/1/URL "private:factory/swriter"
145 // /New/1/Title "New Writer Document"
146 // /New/1/ImageIdentifier "icon_writer"
147 // /New/1/TargetName "_blank"
149 // /New/2/URL "private:factory/scalc"
150 // /New/2/Title "New Calc Document"
151 // /New/2/ImageIdentifier "icon_calc"
152 // /New/2/TargetName "_blank"
154 // second "Wizard" menu ...
155 // /Wizard/1/URL "file://b"
156 // /Wizard/1/Title "PaintSomething"
157 // /Wizard/1/ImageIdentifier "icon_?"
158 // /Wizard/1/TargetName "_self"
162 sal_uInt32 nItem
= 0;
163 sal_uInt32 nPosition
= 0;
165 // Get names/values for new menu.
166 // 4 subkeys for every item!
167 for( nItem
=0; nItem
<nNewCount
; ++nItem
)
169 SvtDynMenuEntry aItem
;
170 lValues
[nPosition
] >>= aItem
.sURL
;
172 lValues
[nPosition
] >>= aItem
.sTitle
;
174 lValues
[nPosition
] >>= aItem
.sImageIdentifier
;
176 lValues
[nPosition
] >>= aItem
.sTargetName
;
178 aNewMenu
.AppendSetupEntry( aItem
);
181 // Attention: Don't reset nPosition here!
183 // Get names/values for wizard menu.
184 // 4 subkeys for every item!
185 for( nItem
=0; nItem
<nWizardCount
; ++nItem
)
187 SvtDynMenuEntry aItem
;
188 lValues
[nPosition
] >>= aItem
.sURL
;
190 lValues
[nPosition
] >>= aItem
.sTitle
;
192 lValues
[nPosition
] >>= aItem
.sImageIdentifier
;
194 lValues
[nPosition
] >>= aItem
.sTargetName
;
196 aWizardMenu
.AppendSetupEntry( aItem
);
199 std::vector
< SvtDynMenuEntry
> lReturn
;
202 case EDynamicMenuType::NewMenu
:
203 lReturn
= aNewMenu
.GetList();
206 case EDynamicMenuType::WizardMenu
:
207 lReturn
= aWizardMenu
.GetList();
213 static void lcl_SortAndExpandPropertyNames( const Sequence
< OUString
>& lSource
,
214 Sequence
< OUString
>& lDestination
, std::u16string_view sSetNode
);
216 /*-****************************************************************************************************
217 @short return list of key names of our configuration management which represent our module tree
218 @descr This method returns the current list of key names! We need it to get needed values from our
219 configuration management and support dynamical menu item lists!
220 @param "nNewCount" , returns count of menu entries for "new"
221 @param "nWizardCount" , returns count of menu entries for "wizard"
222 @return A list of configuration key names is returned.
223 *//*-*****************************************************************************************************/
224 static Sequence
< OUString
> lcl_GetPropertyNames(
225 css::uno::Reference
<css::container::XHierarchicalNameAccess
> const & xHierarchyAccess
,
226 sal_uInt32
& nNewCount
, sal_uInt32
& nWizardCount
)
228 // First get ALL names of current existing list items in configuration!
229 Sequence
< OUString
> lNewItems
= utl::ConfigItem::GetNodeNames( xHierarchyAccess
, SETNODE_NEWMENU
, utl::ConfigNameFormat::LocalPath
);
230 Sequence
< OUString
> lWizardItems
= utl::ConfigItem::GetNodeNames( xHierarchyAccess
, SETNODE_WIZARDMENU
, utl::ConfigNameFormat::LocalPath
);
232 // Get information about list counts ...
233 nNewCount
= lNewItems
.getLength();
234 nWizardCount
= lWizardItems
.getLength();
236 // Sort and expand all three list to result list ...
237 Sequence
< OUString
> lProperties
;
238 lcl_SortAndExpandPropertyNames( lNewItems
, lProperties
, SETNODE_NEWMENU
);
239 lcl_SortAndExpandPropertyNames( lWizardItems
, lProperties
, SETNODE_WIZARDMENU
);
245 /*-****************************************************************************************************
246 @short sort given source list and expand it for all well known properties to destination
247 @descr We must support sets of entries with count inside the name .. but some of them could be missing!
248 e.g. s1-s2-s3-s0-u1-s6-u5-u7
249 Then we must sort it by name and expand it to the follow one:
267 Rules: We start with all setup written entries names "sx" and x=[0..n].
268 Then we handle all "ux" items. Inside these blocks we sort it ascending by number.
270 @attention We add these expanded list to the end of given "lDestination" list!
271 So we must start on "lDestination.getLength()".
272 Reallocation of memory of destination list is done by us!
274 @seealso method impl_GetPropertyNames()
276 @param "lSource" , original list (e.g. [m1-m2-m3-m6-m0] )
277 @param "lDestination" , destination of operation
278 @param "sSetNode" , name of configuration set to build complete path
279 @return A list of configuration key names is returned.
280 *//*-*****************************************************************************************************/
282 static void lcl_SortAndExpandPropertyNames( const Sequence
< OUString
>& lSource
,
283 Sequence
< OUString
>& lDestination
,
284 std::u16string_view sSetNode
)
286 struct CountWithPrefixSort
288 bool operator() ( std::u16string_view s1
, std::u16string_view s2
) const
290 // Get order numbers from entry name without prefix.
293 sal_Int32 n1
= o3tl::toInt32(s1
.substr( 1 ));
294 sal_Int32 n2
= o3tl::toInt32(s2
.substr( 1 ));
295 // MUST be in [0,1] ... because it's a difference between
296 // insert-positions of given entries in sorted list!
300 struct SelectByPrefix
302 bool operator() ( std::u16string_view s
) const
304 // Prefer setup written entries by check first letter of given string. It must be a "s".
305 return o3tl::starts_with( s
, PATHPREFIX_SETUP
);
309 std::vector
< OUString
> lTemp
;
310 sal_Int32 nSourceCount
= lSource
.getLength();
311 sal_Int32 nDestinationStep
= lDestination
.getLength(); // start on end of current list ...!
313 lDestination
.realloc( (nSourceCount
*PROPERTYCOUNT
)+nDestinationStep
); // get enough memory for copy operations after nDestination ...
314 auto plDestination
= lDestination
.getArray();
316 // Copy all items to temp. vector to use fast sort operations :-)
317 lTemp
.insert( lTemp
.end(), lSource
.begin(), lSource
.end() );
319 // Sort all entries by number ...
320 std::stable_sort( lTemp
.begin(), lTemp
.end(), CountWithPrefixSort() );
321 // and split into setup & user written entries!
322 std::stable_partition( lTemp
.begin(), lTemp
.end(), SelectByPrefix() );
324 // Copy sorted entries to destination and expand every item with
325 // 4 supported sub properties.
326 for( const auto& rItem
: lTemp
)
328 OUString
sFixPath(OUString::Concat(sSetNode
) + PATHDELIMITER
+ rItem
+ PATHDELIMITER
);
329 plDestination
[nDestinationStep
++] = sFixPath
+ PROPERTYNAME_URL
;
330 plDestination
[nDestinationStep
++] = sFixPath
+ PROPERTYNAME_TITLE
;
331 plDestination
[nDestinationStep
++] = sFixPath
+ PROPERTYNAME_IMAGEIDENTIFIER
;
332 plDestination
[nDestinationStep
++] = sFixPath
+ PROPERTYNAME_TARGETNAME
;
337 } // namespace SvtDynamicMenuOptions
339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */