cid#1636561 Dereference after null check
[LibreOffice.git] / unotools / source / config / dynamicmenuoptions.cxx
blob6d38e7f8ef660092704a0165b440c33f6a2bbacb
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 <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>
30 #include <vector>
31 #include <algorithm>
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";
56 namespace
58 /*-****************************************************************************************************************
59 @descr support simple menu structures and operations on it
60 ****************************************************************************************************************-*/
61 struct SvtDynMenu
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());
81 sal_Int32 nStep = 0;
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;
94 else
96 entry = rItem;
98 lResult[nStep] = std::move(entry);
99 ++nStep;
102 return lResult;
105 private:
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 )
121 SvtDynMenu aNewMenu;
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 ,
131 nWizardCount );
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 ...
143 // Name Value
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"
160 // ... and so on ...
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;
171 ++nPosition;
172 lValues[nPosition] >>= aItem.sTitle;
173 ++nPosition;
174 lValues[nPosition] >>= aItem.sImageIdentifier;
175 ++nPosition;
176 lValues[nPosition] >>= aItem.sTargetName;
177 ++nPosition;
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;
189 ++nPosition;
190 lValues[nPosition] >>= aItem.sTitle;
191 ++nPosition;
192 lValues[nPosition] >>= aItem.sImageIdentifier;
193 ++nPosition;
194 lValues[nPosition] >>= aItem.sTargetName;
195 ++nPosition;
196 aWizardMenu.AppendSetupEntry( aItem );
199 std::vector< SvtDynMenuEntry > lReturn;
200 switch( eMenu )
202 case EDynamicMenuType::NewMenu :
203 lReturn = aNewMenu.GetList();
204 break;
206 case EDynamicMenuType::WizardMenu :
207 lReturn = aWizardMenu.GetList();
208 break;
210 return lReturn;
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 );
241 // Return result.
242 return lProperties;
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:
250 sSetNode/s0/URL
251 sSetNode/s0/Title
252 sSetNode/s0/...
253 sSetNode/s1/URL
254 sSetNode/s1/Title
255 sSetNode/s1/...
257 sSetNode/s6/URL
258 sSetNode/s6/Title
259 sSetNode/s6/...
260 sSetNode/u1/URL
261 sSetNode/u1/Title
262 sSetNode/u1/...
264 sSetNode/u7/URL
265 sSetNode/u7/Title
266 sSetNode/u7/...
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.
291 // e.g. "m10" => 10
292 // "m5" => 5
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!
297 return( n1<n2 );
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: */