office-gobmx/unotools/source/config/dynamicmenuoptions.cxx
Caolán McNamara 8f008bf4b9 cid#1554812 COPY_INSTEAD_OF_MOVE
and

cid#1555227 COPY_INSTEAD_OF_MOVE
cid#1555329 COPY_INSTEAD_OF_MOVE
cid#1555384 COPY_INSTEAD_OF_MOVE
cid#1555387 COPY_INSTEAD_OF_MOVE
cid#1555399 COPY_INSTEAD_OF_MOVE
cid#1555400 COPY_INSTEAD_OF_MOVE
cid#1555406 COPY_INSTEAD_OF_MOVE

Change-Id: I85dc45e2686c6b3e8b97a23872cb26416edc27c8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171178
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
2024-07-29 14:50:38 +02:00

339 lines
14 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/config.h>
#include <o3tl/string_view.hxx>
#include <unotools/dynamicmenuoptions.hxx>
#include <tools/debug.hxx>
#include <unotools/configmgr.hxx>
#include <unotools/configitem.hxx>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Sequence.hxx>
#include <vector>
#include <algorithm>
#include <string_view>
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
constexpr OUStringLiteral DYNAMICMENU_PROPERTYNAME_URL = u"URL";
constexpr OUStringLiteral DYNAMICMENU_PROPERTYNAME_TITLE = u"Title";
constexpr OUStringLiteral DYNAMICMENU_PROPERTYNAME_IMAGEIDENTIFIER = u"ImageIdentifier";
constexpr OUStringLiteral DYNAMICMENU_PROPERTYNAME_TARGETNAME = u"TargetName";
constexpr OUString PATHDELIMITER = u"/"_ustr;
constexpr OUString SETNODE_NEWMENU = u"New"_ustr;
constexpr OUString SETNODE_WIZARDMENU = u"Wizard"_ustr;
#define PROPERTYNAME_URL DYNAMICMENU_PROPERTYNAME_URL
#define PROPERTYNAME_TITLE DYNAMICMENU_PROPERTYNAME_TITLE
#define PROPERTYNAME_IMAGEIDENTIFIER DYNAMICMENU_PROPERTYNAME_IMAGEIDENTIFIER
#define PROPERTYNAME_TARGETNAME DYNAMICMENU_PROPERTYNAME_TARGETNAME
#define PROPERTYCOUNT 4
constexpr std::u16string_view PATHPREFIX_SETUP = u"m";
namespace
{
/*-****************************************************************************************************************
@descr support simple menu structures and operations on it
****************************************************************************************************************-*/
struct SvtDynMenu
{
// append setup written menu entry
// Don't touch name of entry. It was defined by setup and must be the same every time!
// Look for double menu entries here too... may be some separator items are superfluous...
void AppendSetupEntry( const SvtDynMenuEntry& rEntry )
{
if( lSetupEntries.empty() || lSetupEntries.rbegin()->sURL != rEntry.sURL )
lSetupEntries.push_back( rEntry );
}
// convert internal list to external format
// for using it on right menus really
// Notice: We build a property list with 4 entries and set it on result list then.
// Separator entries will be packed in another way then normal entries! We define
// special string "sSeparator" to perform too ...
std::vector< SvtDynMenuEntry > GetList() const
{
sal_Int32 nSetupCount = static_cast<sal_Int32>(lSetupEntries.size());
sal_Int32 nUserCount = static_cast<sal_Int32>(lUserEntries.size());
sal_Int32 nStep = 0;
std::vector< SvtDynMenuEntry > lResult ( nSetupCount+nUserCount );
OUString sSeparator ( u"private:separator"_ustr );
for( const auto& pList : {&lSetupEntries, &lUserEntries} )
{
for( const auto& rItem : *pList )
{
SvtDynMenuEntry entry;
if( rItem.sURL == sSeparator )
{
entry.sURL = sSeparator;
}
else
{
entry = rItem;
}
lResult[nStep] = std::move(entry);
++nStep;
}
}
return lResult;
}
private:
std::vector< SvtDynMenuEntry > lSetupEntries;
std::vector< SvtDynMenuEntry > lUserEntries;
};
}
namespace SvtDynamicMenuOptions
{
static Sequence< OUString > lcl_GetPropertyNames(
css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess,
sal_uInt32& nNewCount, sal_uInt32& nWizardCount );
std::vector< SvtDynMenuEntry > GetMenu( EDynamicMenuType eMenu )
{
SvtDynMenu aNewMenu;
SvtDynMenu aWizardMenu;
Reference<css::container::XHierarchicalNameAccess> xHierarchyAccess = utl::ConfigManager::acquireTree(u"Office.Common/Menus/");
// Get names and values of all accessible menu entries and fill internal structures.
// See impl_GetPropertyNames() for further information.
sal_uInt32 nNewCount = 0;
sal_uInt32 nWizardCount = 0;
Sequence< OUString > lNames = lcl_GetPropertyNames ( xHierarchyAccess, nNewCount ,
nWizardCount );
Sequence< Any > lValues = utl::ConfigItem::GetProperties( xHierarchyAccess, lNames, /*bAllLocales*/false );
// Safe impossible cases.
// We need values from ALL configuration keys.
// Follow assignment use order of values in relation to our list of key names!
DBG_ASSERT( !(lNames.getLength()!=lValues.getLength()), "SvtDynamicMenuOptions_Impl::SvtDynamicMenuOptions_Impl()\nI miss some values of configuration keys!\n" );
// Copy values from list in right order to our internal member.
// Attention: List for names and values have an internal construction pattern!
// first "New" menu ...
// Name Value
// /New/1/URL "private:factory/swriter"
// /New/1/Title "New Writer Document"
// /New/1/ImageIdentifier "icon_writer"
// /New/1/TargetName "_blank"
// /New/2/URL "private:factory/scalc"
// /New/2/Title "New Calc Document"
// /New/2/ImageIdentifier "icon_calc"
// /New/2/TargetName "_blank"
// second "Wizard" menu ...
// /Wizard/1/URL "file://b"
// /Wizard/1/Title "PaintSomething"
// /Wizard/1/ImageIdentifier "icon_?"
// /Wizard/1/TargetName "_self"
// ... and so on ...
sal_uInt32 nItem = 0;
sal_uInt32 nPosition = 0;
// Get names/values for new menu.
// 4 subkeys for every item!
for( nItem=0; nItem<nNewCount; ++nItem )
{
SvtDynMenuEntry aItem;
lValues[nPosition] >>= aItem.sURL;
++nPosition;
lValues[nPosition] >>= aItem.sTitle;
++nPosition;
lValues[nPosition] >>= aItem.sImageIdentifier;
++nPosition;
lValues[nPosition] >>= aItem.sTargetName;
++nPosition;
aNewMenu.AppendSetupEntry( aItem );
}
// Attention: Don't reset nPosition here!
// Get names/values for wizard menu.
// 4 subkeys for every item!
for( nItem=0; nItem<nWizardCount; ++nItem )
{
SvtDynMenuEntry aItem;
lValues[nPosition] >>= aItem.sURL;
++nPosition;
lValues[nPosition] >>= aItem.sTitle;
++nPosition;
lValues[nPosition] >>= aItem.sImageIdentifier;
++nPosition;
lValues[nPosition] >>= aItem.sTargetName;
++nPosition;
aWizardMenu.AppendSetupEntry( aItem );
}
std::vector< SvtDynMenuEntry > lReturn;
switch( eMenu )
{
case EDynamicMenuType::NewMenu :
lReturn = aNewMenu.GetList();
break;
case EDynamicMenuType::WizardMenu :
lReturn = aWizardMenu.GetList();
break;
}
return lReturn;
}
static void lcl_SortAndExpandPropertyNames( const Sequence< OUString >& lSource,
Sequence< OUString >& lDestination, std::u16string_view sSetNode );
/*-****************************************************************************************************
@short return list of key names of our configuration management which represent our module tree
@descr This method returns the current list of key names! We need it to get needed values from our
configuration management and support dynamical menu item lists!
@param "nNewCount" , returns count of menu entries for "new"
@param "nWizardCount" , returns count of menu entries for "wizard"
@return A list of configuration key names is returned.
*//*-*****************************************************************************************************/
static Sequence< OUString > lcl_GetPropertyNames(
css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess,
sal_uInt32& nNewCount, sal_uInt32& nWizardCount )
{
// First get ALL names of current existing list items in configuration!
Sequence< OUString > lNewItems = utl::ConfigItem::GetNodeNames( xHierarchyAccess, SETNODE_NEWMENU, utl::ConfigNameFormat::LocalPath );
Sequence< OUString > lWizardItems = utl::ConfigItem::GetNodeNames( xHierarchyAccess, SETNODE_WIZARDMENU, utl::ConfigNameFormat::LocalPath );
// Get information about list counts ...
nNewCount = lNewItems.getLength();
nWizardCount = lWizardItems.getLength();
// Sort and expand all three list to result list ...
Sequence< OUString > lProperties;
lcl_SortAndExpandPropertyNames( lNewItems , lProperties, SETNODE_NEWMENU );
lcl_SortAndExpandPropertyNames( lWizardItems , lProperties, SETNODE_WIZARDMENU );
// Return result.
return lProperties;
}
/*-****************************************************************************************************
@short sort given source list and expand it for all well known properties to destination
@descr We must support sets of entries with count inside the name .. but some of them could be missing!
e.g. s1-s2-s3-s0-u1-s6-u5-u7
Then we must sort it by name and expand it to the follow one:
sSetNode/s0/URL
sSetNode/s0/Title
sSetNode/s0/...
sSetNode/s1/URL
sSetNode/s1/Title
sSetNode/s1/...
...
sSetNode/s6/URL
sSetNode/s6/Title
sSetNode/s6/...
sSetNode/u1/URL
sSetNode/u1/Title
sSetNode/u1/...
...
sSetNode/u7/URL
sSetNode/u7/Title
sSetNode/u7/...
Rules: We start with all setup written entries names "sx" and x=[0..n].
Then we handle all "ux" items. Inside these blocks we sort it ascending by number.
@attention We add these expanded list to the end of given "lDestination" list!
So we must start on "lDestination.getLength()".
Reallocation of memory of destination list is done by us!
@seealso method impl_GetPropertyNames()
@param "lSource" , original list (e.g. [m1-m2-m3-m6-m0] )
@param "lDestination" , destination of operation
@param "sSetNode" , name of configuration set to build complete path
@return A list of configuration key names is returned.
*//*-*****************************************************************************************************/
static void lcl_SortAndExpandPropertyNames( const Sequence< OUString >& lSource ,
Sequence< OUString >& lDestination ,
std::u16string_view sSetNode )
{
struct CountWithPrefixSort
{
bool operator() ( std::u16string_view s1, std::u16string_view s2 ) const
{
// Get order numbers from entry name without prefix.
// e.g. "m10" => 10
// "m5" => 5
sal_Int32 n1 = o3tl::toInt32(s1.substr( 1 ));
sal_Int32 n2 = o3tl::toInt32(s2.substr( 1 ));
// MUST be in [0,1] ... because it's a difference between
// insert-positions of given entries in sorted list!
return( n1<n2 );
}
};
struct SelectByPrefix
{
bool operator() ( std::u16string_view s ) const
{
// Prefer setup written entries by check first letter of given string. It must be a "s".
return o3tl::starts_with( s, PATHPREFIX_SETUP );
}
};
std::vector< OUString > lTemp;
sal_Int32 nSourceCount = lSource.getLength();
sal_Int32 nDestinationStep = lDestination.getLength(); // start on end of current list ...!
lDestination.realloc( (nSourceCount*PROPERTYCOUNT)+nDestinationStep ); // get enough memory for copy operations after nDestination ...
auto plDestination = lDestination.getArray();
// Copy all items to temp. vector to use fast sort operations :-)
lTemp.insert( lTemp.end(), lSource.begin(), lSource.end() );
// Sort all entries by number ...
std::stable_sort( lTemp.begin(), lTemp.end(), CountWithPrefixSort() );
// and split into setup & user written entries!
std::stable_partition( lTemp.begin(), lTemp.end(), SelectByPrefix() );
// Copy sorted entries to destination and expand every item with
// 4 supported sub properties.
for( const auto& rItem : lTemp )
{
OUString sFixPath(OUString::Concat(sSetNode) + PATHDELIMITER + rItem + PATHDELIMITER);
plDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_URL;
plDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_TITLE;
plDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_IMAGEIDENTIFIER;
plDestination[nDestinationStep++] = sFixPath + PROPERTYNAME_TARGETNAME;
}
}
} // namespace SvtDynamicMenuOptions
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */