Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/unotools/source/config/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 41 kB image not shown  

Quelle  configitem.cxx   Sprache: 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 <sal/log.hxx>
#include <unotools/configitem.hxx>
#include <unotools/configmgr.hxx>
#include <unotools/configpaths.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/util/XChangesListener.hpp>
#include <com/sun/star/util/XChangesNotifier.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/configuration/XTemplateContainer.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/util/XChangesBatch.hpp>
#include <o3tl/deleter.hxx>
#include <osl/diagnose.h>
#include <comphelper/configuration.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/solarmutex.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <comphelper/propertyvalue.hxx>
#include <cppuhelper/implbase.hxx>
#include <utility>

using namespace utl;
using namespace com::sun::star::uno;
using namespace com::sun::star::util;
using namespace com::sun::star::lang;
using namespace com::sun::star::beans;
using namespace com::sun::star::container;
using namespace com::sun::star::configuration;

/*
    The ConfigChangeListener_Impl receives notifications from the configuration about changes that
    have happened. It forwards this notification to the ConfigItem it knows a pParent by calling its
    "CallNotify" method. As ConfigItems are most probably not thread safe, the SolarMutex is acquired
    before doing so.
*/


namespace utl{
    class ConfigChangeListener_Impl : public cppu::WeakImplHelper
    <
        css::util::XChangesListener
    >
    {
        public:
            ConfigItem*                 pParent;
            const Sequence< OUString >  aPropertyNames;
            ConfigChangeListener_Impl(ConfigItem& rItem, const Sequence< OUString >& rNames);

        //XChangesListener
        virtual void SAL_CALL changesOccurred( const ChangesEvent& Event ) override;

        //XEventListener
        virtual void SAL_CALL disposing( const EventObject& Source ) override;
    };
}

namespace {

class ValueCounter_Impl
{
    sal_Int16& rCnt;
public:
    explicit ValueCounter_Impl(sal_Int16& rCounter)
        : rCnt(rCounter)
    {
        rCnt++;
    }
    ~ValueCounter_Impl()
    {
        OSL_ENSURE(rCnt>0, "RefCount < 0 ??");
        rCnt--;
    }
};

}

ConfigChangeListener_Impl::ConfigChangeListener_Impl(
             ConfigItem& rItem, const Sequence< OUString >& rNames) :
    pParent(&rItem),
    aPropertyNames(rNames)
{
}

void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent& rEvent )
{
    Sequence<OUString>  aChangedNames(rEvent.Changes.getLength());
    OUString* pNames = aChangedNames.getArray();

    sal_Int32 nNotify = 0;
    for(const auto& rElementChange : rEvent.Changes)
    {
        OUString sTemp;
        rElementChange.Accessor >>= sTemp;
        //true if the path is completely correct or if it is longer
        //i.e ...Print/Content/Graphic and .../Print
        bool bFound = std::any_of(aPropertyNames.begin(), aPropertyNames.end(),
            [&sTemp](const OUString& rCheckPropertyName) { return isPrefixOfConfigurationPath(sTemp, rCheckPropertyName); });
        if(bFound)
            pNames[nNotify++] = sTemp;
    }
    if( nNotify )
    {
        ::comphelper::SolarMutex *pMutex = ::comphelper::SolarMutex::get();
        if ( pMutex )
        {
            osl::Guard<comphelper::SolarMutex> aMutexGuard( pMutex );
            aChangedNames.realloc(nNotify);
            pParent->CallNotify(aChangedNames);
        }
    }
}

void ConfigChangeListener_Impl::disposing( const EventObject& /*rSource*/ )
{
    pParent->RemoveChangesListener();
}

ConfigItem::ConfigItem(OUString aSubTree, ConfigItemMode nSetMode ) :
    sSubTree(std::move(aSubTree)),
    m_nMode(nSetMode),
    m_bIsModified(false),
    m_bEnableInternalNotification(false),
    m_nInValueChange(0)
{
    if (comphelper::IsFuzzing())
        return;

    if (nSetMode & ConfigItemMode::ReleaseTree)
        ConfigManager::getConfigManager().addConfigItem(*this);
    else
        m_xHierarchyAccess = ConfigManager::getConfigManager().addConfigItem(*this);
}

ConfigItem::ConfigItem(ConfigItem const &) = default;
ConfigItem::ConfigItem(ConfigItem &&) = default;

ConfigItem::~ConfigItem()
{
    suppress_fun_call_w_exception(RemoveChangesListener());
    ConfigManager::getConfigManager().removeConfigItem(*this);
}

void ConfigItem::CallNotify( const css::uno::Sequence<OUString>& rPropertyNames )
{
    // the call is forwarded to the virtual Notify() method
    // it is pure virtual, so all classes deriving from ConfigItem have to decide how they
    // want to notify listeners
    if(m_nInValueChange <= 0 || m_bEnableInternalNotification)
        Notify(rPropertyNames);
}

// In special mode ALL_LOCALES we must support reading/writing of localized cfg entries as Sequence< PropertyValue >.
// These methods are helper to convert given lists of names and Any-values.
// format:  PropertyValue.Name  = <locale as ISO string>
//          PropertyValue.Value = <value; type depends from cfg entry!>
// e.g.
//          LOCALIZED NODE
//          "UIName"
//                      LOCALE      VALUE
//                      "de"        "Mein Name"
//                      "en-US"     "my name"

static void impl_packLocalizedProperties(  const   Sequence< OUString >&   lInNames    ,
                                           const   Sequence< Any >&        lInValues   ,
                                                   Sequence< Any >&        lOutValues  )
{
    // This method should be called for special AllLocales ConfigItem-mode only!

    // Optimise follow algorithm ... A LITTLE BIT :-)
    // There exist two different possibilities:
    //  i ) There exist no localized entries ...                        =>  size of lOutValues will be the same like lInNames/lInValues!
    //  ii) There exist some (mostly one or two) localized entries ...  =>  size of lOutValues will be the same like lInNames/lInValues!
    //  ... Why? If a localized value exist - the any is filled with an XInterface object (is a SetNode-service).
    //      We read all his child nodes and pack it into Sequence< PropertyValue >.
    //      The result list we pack into the return any. We never change size of lists!
    lOutValues.realloc(lInNames.getLength());

    // Algorithm:
    // Copy all names and values from in to out lists.
    // Look for special localized entries ... You can detect it as "XInterface" packed into an Any.
    // Use this XInterface-object to read all localized values and pack it into Sequence< PropertyValue >.
    // Add this list to out lists then.

    std::transform(lInValues.begin(), lInValues.end(), lOutValues.getArray(), [](const Any& value)
    {
        // If item is a special localized one ... convert and pack it ...
        if (value.getValueTypeName() == "com.sun.star.uno.XInterface")
        {
            if (auto xSetAccess = value.query<XNameContainer>())
            {
                // list of all locales for localized entry
                Sequence<OUString> locales = xSetAccess->getElementNames();
                // localized values of a configuration entry packed for return
                Sequence<PropertyValue> lProperties(locales.getLength());

                std::transform(
                    locales.begin(), locales.end(), lProperties.getArray(),
                    [&xSetAccess](const OUString& s)
                    { return comphelper::makePropertyValue(s, xSetAccess->getByName(s)); });

                return Any(lProperties);
            }
        }
        // ... or copy normal items to return lists directly.
        return value;
    });
}

static void impl_unpackLocalizedProperties(    const   Sequence< OUString >&   lInNames    ,
                                               const   Sequence< Any >&        lInValues   ,
                                                       Sequence< OUString >&   lOutNames   ,
                                                       Sequence< Any >&        lOutValues)
{
    // This method should be called for special AllLocales ConfigItem-mode only!

    sal_Int32                   nSourceSize;         // marks end of loop over input lists
    sal_Int32                   nDestinationCounter; // actual position in output lists
    sal_Int32                   nPropertiesSize;     // marks end of inner loop
    OUString                    sNodeName;           // base name of node ( e.g. "UIName/" ) ... expand to locale ( e.g. "UIName/de" )
    Sequence< PropertyValue >   lProperties;         // localized values of a configuration entry gotten from lInValues-Any

    // Optimise follow algorithm ... A LITTLE BIT :-)
    // There exist two different possibilities:
    //  i ) There exist no localized entries ...                        =>  size of lOutNames/lOutValues will be the same like lInNames/lInValues!
    //  ii) There exist some (mostly one or two) localized entries ...  =>  size of lOutNames/lOutValues will be some bytes greater than lInNames/lInValues.
    //  =>  I think we should make it fast for i). ii) is a special case and mustn't be SOOOO... fast.
    //      We should reserve same space for output list like input ones first.
    //      Follow algorithm looks for these borders and change it for ii) only!
    //      It will be faster then a "realloc()" call in every loop ...
    nSourceSize = lInNames.getLength();

    lOutNames.realloc   ( nSourceSize );
    auto plOutNames = lOutNames.getArray();
    lOutValues.realloc  ( nSourceSize );
    auto plOutValues = lOutValues.getArray();

    // Algorithm:
    // Copy all names and values from const to return lists.
    // Look for special localized entries ... You can detect it as Sequence< PropertyValue > packed into an Any.
    // Split it ... insert PropertyValue.Name to lOutNames and PropertyValue.Value to lOutValues.

    nDestinationCounter = 0;
    for( sal_Int32 nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter )
    {
        // If item a special localized one ... split it and insert his parts to output lists ...
        if( lInValues[nSourceCounter].getValueType() == cppu::UnoType<Sequence<PropertyValue>>::get() )
        {
            lInValues[nSourceCounter] >>= lProperties;
            nPropertiesSize = lProperties.getLength();

            sNodeName = lInNames[nSourceCounter] + "/";

            if( (nDestinationCounter+nPropertiesSize) > lOutNames.getLength() )
            {
                lOutNames.realloc   ( nDestinationCounter+nPropertiesSize );
                plOutNames = lOutNames.getArray();
                lOutValues.realloc  ( nDestinationCounter+nPropertiesSize );
                plOutValues = lOutValues.getArray();
            }

            for (const auto& rProperty : lProperties)
            {
                plOutNames [nDestinationCounter] = sNodeName + rProperty.Name;
                plOutValues[nDestinationCounter] = rProperty.Value;
                ++nDestinationCounter;
            }
        }
        // ... or copy normal items to return lists directly.
        else
        {
            if( (nDestinationCounter+1) > lOutNames.getLength() )
            {
                lOutNames.realloc   ( nDestinationCounter+1 );
                plOutNames = lOutNames.getArray();
                lOutValues.realloc  ( nDestinationCounter+1 );
                plOutValues = lOutValues.getArray();
            }

            plOutNames [nDestinationCounter] = lInNames [nSourceCounter];
            plOutValues[nDestinationCounter] = lInValues[nSourceCounter];
            ++nDestinationCounter;
        }
    }
}

Sequence< sal_Bool > ConfigItem::GetReadOnlyStates(const css::uno::Sequence< OUString >&&nbsp;rNames)
{
    sal_Int32 i;

    // size of return list is fix!
    // Every item must match to length of incoming name list.
    sal_Int32 nCount = rNames.getLength();
    Sequence< sal_Bool > lStates(nCount);
    sal_Bool* plStates = lStates.getArray();

    // We must be sure to return a valid information every time!
    // Set default to non readonly... similar to the configuration handling of this property.
    std::fill_n(plStates, lStates.getLength(), false);

    // no access - no information...
    Reference< XHierarchicalNameAccess > xHierarchyAccess = GetTree();
    if (!xHierarchyAccess.is())
        return lStates;

    for (i=0; i<nCount; ++i)
    {
        try
        {
            const OUString& sName = rNames[i];
            OUString sPath;
            OUString sProperty;

            (void)::utl::splitLastFromConfigurationPath(sName,sPath,sProperty);
            if (sPath.isEmpty() && sProperty.isEmpty())
            {
                OSL_FAIL("ConfigItem::IsReadonly() split failed");
                continue;
            }

            Reference< XInterface >       xNode;
            Reference< XPropertySet >     xSet;
            Reference< XPropertySetInfo > xInfo;
            if (!sPath.isEmpty())
            {
                Any aNode = xHierarchyAccess->getByHierarchicalName(sPath);
                if (!(aNode >>= xNode) || !xNode.is())
                {
                    OSL_FAIL("ConfigItem::IsReadonly() no set available");
                    continue;
                }
            }
            else
            {
                xNode = xHierarchyAccess;
            }

            xSet.set(xNode, UNO_QUERY);
            if (xSet.is())
            {
                xInfo = xSet->getPropertySetInfo();
                OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly() getPropertySetInfo failed ...");
            }
            else
            {
                xInfo.set(xNode, UNO_QUERY);
                OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly() UNO_QUERY failed ...");
            }

            if (!xInfo.is())
            {
                OSL_FAIL("ConfigItem::IsReadonly() no prop info available");
                continue;
            }

            Property aProp = xInfo->getPropertyByName(sProperty);
            plStates[i] = (aProp.Attributes & PropertyAttribute::READONLY) == PropertyAttribute::READONLY;
        }
        catch (const Exception&)
        {
        }
    }

    return lStates;
}

Sequence< Any > ConfigItem::GetProperties(const Sequence< OUString >& rNames)
{
    Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
    if(xHierarchyAccess.is())
        return GetProperties(xHierarchyAccess, rNames,
                    (m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales);
    return Sequence< Any >(rNames.getLength());
}

Sequence< Any > ConfigItem::GetProperties(
        css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess,
        const Sequence< OUString >& rNames,
        bool bAllLocales)
{
    Sequence< Any > aRet(rNames.getLength());
    const OUString* pNames = rNames.getConstArray();
    Any* pRet = aRet.getArray();
    for(int i = 0; i < rNames.getLength(); i++)
    {
        try
        {
            pRet[i] = xHierarchyAccess->getByHierarchicalName(pNames[i]);
        }
        catch (const Exception&)
        {
            TOOLS_WARN_EXCEPTION(
                "unotools.config",
                "ignoring XHierarchicalNameAccess " << pNames[i]);
        }
    }

    // In special mode "ALL_LOCALES" we must convert localized values to Sequence< PropertyValue >.
    if(bAllLocales)
    {
        Sequence< Any > lValues;
        impl_packLocalizedProperties( rNames, aRet, lValues );
        aRet = std::move(lValues);
    }
    return aRet;
}

bool ConfigItem::PutProperties( const Sequence< OUString >& rNames,
                                                const Sequence< Any>& rValues)
{
    ValueCounter_Impl aCounter(m_nInValueChange);
    Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
    Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY);
    bool bRet = xHierarchyAccess.is() && xTopNodeReplace.is();
    if(bRet)
    {
        Sequence< OUString >    lNames;
        Sequence< Any >         lValues;
        const OUString*         pNames  = nullptr;
        const Any*              pValues = nullptr;
        sal_Int32               nNameCount;
        if(( m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales )
        {
            // If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue >
            // as value of a localized configuration entry!
            // How we can do that?
            // We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"!
            impl_unpackLocalizedProperties( rNames, rValues, lNames, lValues );
            pNames      = lNames.getConstArray  ();
            pValues     = lValues.getConstArray ();
            nNameCount  = lNames.getLength      ();
        }
        else
        {
            // This is the normal mode ...
            // Use given input lists directly.
            pNames      = rNames.getConstArray  ();
            pValues     = rValues.getConstArray ();
            nNameCount  = rNames.getLength      ();
        }
        for(int i = 0; i < nNameCount; i++)
        {
            try
            {
                OUString sNode, sProperty;
                if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty))
                {
                    Any aNode = xHierarchyAccess->getByHierarchicalName(sNode);

                    Reference<XNameAccess> xNodeAcc;
                    aNode >>= xNodeAcc;
                    Reference<XNameReplace>   xNodeReplace(xNodeAcc, UNO_QUERY);
                    Reference<XNameContainer> xNodeCont   (xNodeAcc, UNO_QUERY);

                    bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty));
                    if (bExist && xNodeReplace.is())
                        xNodeReplace->replaceByName(sProperty, pValues[i]);
                    else
                        if (!bExist && xNodeCont.is())
                            xNodeCont->insertByName(sProperty, pValues[i]);
                        else
                            bRet = false;
                }
                else //direct value
                {
                    xTopNodeReplace->replaceByName(sProperty, pValues[i]);
                }
            }
            catch (css::uno::Exception &)
            {
                TOOLS_WARN_EXCEPTION("unotools.config""Exception from PutProperties");
            }
        }
        try
        {
            Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
            xBatch->commitChanges();
        }
        catch (css::uno::Exception &)
        {
            TOOLS_WARN_EXCEPTION("unotools.config""Exception from commitChanges");
        }
    }

    return bRet;
}

bool ConfigItem::PutProperties(
        css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess,
        const Sequence< OUString >& rNames,
        const Sequence< Any>& rValues,
        bool bAllLocales)
{
    Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY);
    bool bRet = xTopNodeReplace.is();
    if(bRet)
    {
        Sequence< OUString >    lNames;
        Sequence< Any >         lValues;
        const OUString*         pNames  = nullptr;
        const Any*              pValues = nullptr;
        sal_Int32               nNameCount;
        if(bAllLocales)
        {
            // If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue >
            // as value of a localized configuration entry!
            // How we can do that?
            // We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"!
            impl_unpackLocalizedProperties( rNames, rValues, lNames, lValues );
            pNames      = lNames.getConstArray  ();
            pValues     = lValues.getConstArray ();
            nNameCount  = lNames.getLength      ();
        }
        else
        {
            // This is the normal mode ...
            // Use given input lists directly.
            pNames      = rNames.getConstArray  ();
            pValues     = rValues.getConstArray ();
            nNameCount  = rNames.getLength      ();
        }
        for(int i = 0; i < nNameCount; i++)
        {
            try
            {
                OUString sNode, sProperty;
                if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty))
                {
                    Any aNode = xHierarchyAccess->getByHierarchicalName(sNode);

                    Reference<XNameAccess> xNodeAcc;
                    aNode >>= xNodeAcc;
                    Reference<XNameReplace>   xNodeReplace(xNodeAcc, UNO_QUERY);
                    Reference<XNameContainer> xNodeCont   (xNodeAcc, UNO_QUERY);

                    bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty));
                    if (bExist && xNodeReplace.is())
                        xNodeReplace->replaceByName(sProperty, pValues[i]);
                    else
                        if (!bExist && xNodeCont.is())
                            xNodeCont->insertByName(sProperty, pValues[i]);
                        else
                            bRet = false;
                }
                else //direct value
                {
                    xTopNodeReplace->replaceByName(sProperty, pValues[i]);
                }
            }
            catch (css::uno::Exception &)
            {
                TOOLS_WARN_EXCEPTION("unotools.config""Exception from PutProperties");
            }
        }
        try
        {
            Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
            xBatch->commitChanges();
        }
        catch (css::uno::Exception &)
        {
            TOOLS_WARN_EXCEPTION("unotools.config""Exception from commitChanges");
        }
    }

    return bRet;
}

void ConfigItem::DisableNotification()
{
    OSL_ENSURE( xChangeLstnr.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" );
    RemoveChangesListener();
}

bool ConfigItem::EnableNotification(const Sequence< OUString >& rNames,
                                    bool bEnableInternalNotification )
{
    OSL_ENSURE(!(m_nMode & ConfigItemMode::ReleaseTree), "notification in ConfigItemMode::ReleaseTree mode not possible");
    m_bEnableInternalNotification = bEnableInternalNotification;
    Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
    Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY);
    if(!xChgNot.is())
        return false;

    OSL_ENSURE(!xChangeLstnr.is(), "EnableNotification already called");
    if(xChangeLstnr.is())
        xChgNot->removeChangesListener( xChangeLstnr );
    bool bRet = true;

    try
    {
        xChangeLstnr = new ConfigChangeListener_Impl(*this, rNames);
        xChgNot->addChangesListener( xChangeLstnr );
    }
    catch (const RuntimeException&)
    {
        bRet = false;
    }
    return bRet;
}

void ConfigItem::RemoveChangesListener()
{
    Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
    if(!xHierarchyAccess.is())
        return;

    Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY);
    if(xChgNot.is() && xChangeLstnr.is())
    {
        try
        {
            xChgNot->removeChangesListener( xChangeLstnr );
            xChangeLstnr = nullptr;
        }
        catch (const Exception&)
        {
        }
    }
}

static void lcl_normalizeLocalNames(Sequence< OUString >& _rNames, ConfigNameFormat _eFormat, Reference<XInterface> const& _xParentNode)
{
    switch (_eFormat)
    {
    case ConfigNameFormat::LocalNode:
        // unaltered - this is our input format
        break;

    case ConfigNameFormat::LocalPath:
        {
            Reference<XTemplateContainer> xTypeContainer(_xParentNode, UNO_QUERY);
            if (xTypeContainer.is())
            {
                OUString sTypeName = xTypeContainer->getElementTemplateName();
                sTypeName = sTypeName.copy(sTypeName.lastIndexOf('/')+1);

                std::transform(std::cbegin(_rNames), std::cend(_rNames), _rNames.getArray(),
                    [&sTypeName](const OUString& rName) -> OUString { return wrapConfigurationElementName(rName,sTypeName); });
            }
            else
            {
                Reference<XServiceInfo> xSVI(_xParentNode, UNO_QUERY);
                if (xSVI.is() && xSVI->supportsService(u"com.sun.star.configuration.SetAccess"_ustr))
                {
                    std::transform(std::cbegin(_rNames), std::cend(_rNames), _rNames.getArray(),
                        [](const OUString& rName) -> OUString { return wrapConfigurationElementName(rName); });
                }
            }
        }
        break;

    }
}

Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode)
{
    ConfigNameFormat const eDefaultFormat = ConfigNameFormat::LocalNode; // CONFIG_NAME_DEFAULT;

    return GetNodeNames(rNode, eDefaultFormat);
}

Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode, ConfigNameFormat eFormat)
{
    Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
    if(xHierarchyAccess.is())
        return GetNodeNames(xHierarchyAccess, rNode, eFormat);
    return Sequence< OUString >();
}

Sequence< OUString > ConfigItem::GetNodeNames(
    css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess,
    const OUString& rNode,
    ConfigNameFormat eFormat)
{
    Sequence< OUString > aRet;
    try
    {
        Reference<XNameAccess> xCont;
        if(!rNode.isEmpty())
        {
            Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
            aNode >>= xCont;
        }
        else
            xCont.set(xHierarchyAccess, UNO_QUERY);
        if(xCont.is())
        {
            aRet = xCont->getElementNames();
            lcl_normalizeLocalNames(aRet,eFormat,xCont);
        }

    }
    catch (css::uno::Exception &)
    {
        TOOLS_WARN_EXCEPTION("unotools.config""Exception from GetNodeNames");
    }
    return aRet;
}

bool ConfigItem::ClearNodeSet(const OUString& rNode)
{
    ValueCounter_Impl aCounter(m_nInValueChange);
    bool bRet = false;
    Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
    if(xHierarchyAccess.is())
        bRet = ClearNodeSet(xHierarchyAccess, rNode);
    return bRet;
}

bool ConfigItem::ClearNodeSet(
    css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess,
    const OUString& rNode)
{
    bool bRet = false;
    try
    {
        Reference<XNameContainer> xCont;
        if(!rNode.isEmpty())
        {
            Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
            aNode >>= xCont;
        }
        else
            xCont.set(xHierarchyAccess, UNO_QUERY);
        if(!xCont.is())
            return false;
        const Sequence< OUString > aNames = xCont->getElementNames();
        Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
        for(const OUString& rName : aNames)
        {
            try
            {
                xCont->removeByName(rName);
            }
            catch (css::uno::Exception &)
            {
                TOOLS_WARN_EXCEPTION("unotools.config""Exception from removeByName");
            }
        }
        xBatch->commitChanges();
        bRet = true;
    }
    catch (css::uno::Exception &)
    {
        TOOLS_WARN_EXCEPTION("unotools.config""Exception from ClearNodeSet");
    }
    return bRet;
}

bool ConfigItem::ClearNodeElements(const OUString& rNode, Sequence< OUString > const &&nbsp;rElements)
{
    ValueCounter_Impl aCounter(m_nInValueChange);
    bool bRet = false;
    Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
    if(xHierarchyAccess.is())
    {
        try
        {
            Reference<XNameContainer> xCont;
            if(!rNode.isEmpty())
            {
                Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
                aNode >>= xCont;
            }
            else
                xCont.set(xHierarchyAccess, UNO_QUERY);
            if(!xCont.is())
                return false;
            try
            {
                for(const OUString& rElement : rElements)
                {
                    xCont->removeByName(rElement);
                }
                Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
                xBatch->commitChanges();
            }
            catch (css::uno::Exception &)
            {
                TOOLS_WARN_EXCEPTION("unotools.config""Exception from commitChanges()");
            }
            bRet = true;
        }
        catch (css::uno::Exception &)
        {
            TOOLS_WARN_EXCEPTION("unotools.config""Exception from GetNodeNames()");
        }
    }
    return bRet;
}

static OUString lcl_extractSetPropertyName( const OUString& rInPath, std::u16string_view rPrefix )
{
    OUString const sSubPath = dropPrefixFromConfigurationPath( rInPath, rPrefix);
    return extractFirstFromConfigurationPath( sSubPath );
}

static
Sequence< OUString > lcl_extractSetPropertyNames( const Sequence< PropertyValue >& rValues, std::u16string_view rPrefix )
{
    Sequence< OUString > aSubNodeNames(rValues.getLength());
    OUString* pSubNodeNames = aSubNodeNames.getArray();

    OUString sLastSubNode;
    sal_Int32 nSubIndex = 0;

    for(const PropertyValue& rProperty : rValues)
    {
        OUString const sSubPath = dropPrefixFromConfigurationPath( rProperty.Name, rPrefix);
        OUString const sSubNode = extractFirstFromConfigurationPath( sSubPath );

        if(sLastSubNode != sSubNode)
        {
            pSubNodeNames[nSubIndex++] = sSubNode;
        }

        sLastSubNode = sSubNode;
    }
    aSubNodeNames.realloc(nSubIndex);

    return aSubNodeNames;
}

// Add or change properties
bool ConfigItem::SetSetProperties(
    const OUString& rNode, const Sequence< PropertyValue >& rValues)
{
    ValueCounter_Impl aCounter(m_nInValueChange);
    Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
    if(!xHierarchyAccess.is())
        return true;
    return SetSetProperties(xHierarchyAccess, rNode, rValues);
}

// Add or change properties
bool ConfigItem::SetSetProperties(
    css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess,
    const OUString& rNode, const Sequence< PropertyValue >& rValues)
{
    bool bRet = true;
    Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
    try
    {
        Reference<XNameContainer> xCont;
        if(!rNode.isEmpty())
        {
            Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
            aNode >>= xCont;
        }
        else
            xCont.set(xHierarchyAccess, UNO_QUERY);
        if(!xCont.is())
            return false;

        Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);

        if(xFac.is())
        {
            const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);

            for(const auto& rSubNodeName : aSubNodeNames)
            {
                if(!xCont->hasByName(rSubNodeName))
                {
                    Reference<XInterface> xInst = xFac->createInstance();
                    Any aVal; aVal <<= xInst;
                    xCont->insertByName(rSubNodeName, aVal);
                }
                //set values
            }
            try
            {
                xBatch->commitChanges();
            }
            catch (css::uno::Exception &)
            {
                TOOLS_WARN_EXCEPTION("unotools.config""Exception from commitChanges()");
            }

            const PropertyValue* pProperties = rValues.getConstArray();

            Sequence< OUString > aSetNames(rValues.getLength());
            OUString* pSetNames = aSetNames.getArray();

            Sequence< Any> aSetValues(rValues.getLength());
            Any* pSetValues = aSetValues.getArray();

            bool bEmptyNode = rNode.isEmpty();
            for(sal_Int32 k = 0; k < rValues.getLength(); k++)
            {
                pSetNames[k] =  pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
                pSetValues[k] = pProperties[k].Value;
            }
            bRet = PutProperties(xHierarchyAccess, aSetNames, aSetValues, /*bAllLocales*/false);
        }
        else
        {
            //if no factory is available then the node contains basic data elements
            for(const PropertyValue& rValue : rValues)
            {
                try
                {
                    OUString sSubNode = lcl_extractSetPropertyName( rValue.Name, rNode );

                    if(xCont->hasByName(sSubNode))
                        xCont->replaceByName(sSubNode, rValue.Value);
                    else
                        xCont->insertByName(sSubNode, rValue.Value);

                    OSL_ENSURE( xHierarchyAccess->hasByHierarchicalName(rValue.Name),
                        "Invalid config path" );
                }
                catch (css::uno::Exception &)
                {
                    TOOLS_WARN_EXCEPTION("unotools.config""Exception from insert/replaceByName()");
                }
            }
            xBatch->commitChanges();
        }
    }
    catch (const Exception&)
    {
        TOOLS_WARN_EXCEPTION("unotools.config""Exception from SetSetProperties");
        bRet = false;
    }
    return bRet;
}

bool ConfigItem::ReplaceSetProperties(
    const OUString& rNode, const Sequence< PropertyValue >& rValues)
{
    ValueCounter_Impl aCounter(m_nInValueChange);
    bool bRet = true;
    Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
    if(xHierarchyAccess.is())
        bRet = ReplaceSetProperties(xHierarchyAccess, rNode, rValues,
                    ( m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales);
    return bRet;
}

bool ConfigItem::ReplaceSetProperties(
    css::uno::Reference<css::container::XHierarchicalNameAccess> const & xHierarchyAccess,
    const OUString& rNode,
    const Sequence< PropertyValue >& rValues,
    bool bAllLocales)
{
    bool bRet = true;
    Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
    try
    {
        Reference<XNameContainer> xCont;
        if(!rNode.isEmpty())
        {
            Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
            aNode >>= xCont;
        }
        else
            xCont.set(xHierarchyAccess, UNO_QUERY);
        if(!xCont.is())
            return false;

        // JB: Change: now the same name handling for sets of simple values
        const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);

        Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
        const bool isSimpleValueSet = !xFac.is();

        //remove unknown members first
        {
            const Sequence<OUString> aContainerSubNodes = xCont->getElementNames();

            for(const OUString& rContainerSubNode : aContainerSubNodes)
            {
                bool bFound = comphelper::findValue(aSubNodeNames, rContainerSubNode) != -1;
                if(!bFound)
                    try
                    {
                        xCont->removeByName(rContainerSubNode);
                    }
                    catch (const Exception&)
                    {
                        if (isSimpleValueSet)
                        {
                            try
                            {
                                // #i37322#: fallback action: replace with <void/>
                                xCont->replaceByName(rContainerSubNode, Any());
                                // fallback successful: continue looping
                                continue;
                            }
                            catch (Exception &)
                            {} // propagate original exception, if fallback fails
                        }
                        throw;
                    }
            }
            try { xBatch->commitChanges(); }
            catch (css::uno::Exception &)
            {
                TOOLS_WARN_EXCEPTION("unotools.config""Exception from commitChanges");
            }
        }

        if(xFac.is()) // !isSimpleValueSet
        {
            for(const OUString& rSubNodeName : aSubNodeNames)
            {
                if(!xCont->hasByName(rSubNodeName))
                {
                    //create if not available
                    Reference<XInterface> xInst = xFac->createInstance();
                    Any aVal; aVal <<= xInst;
                    xCont->insertByName(rSubNodeName, aVal);
                }
            }
            try { xBatch->commitChanges(); }
            catch (css::uno::Exception &)
            {
                TOOLS_WARN_EXCEPTION("unotools.config""Exception from commitChanges");
            }

            const PropertyValue* pProperties = rValues.getConstArray();

            Sequence< OUString > aSetNames(rValues.getLength());
            OUString* pSetNames = aSetNames.getArray();

            Sequence< Any> aSetValues(rValues.getLength());
            Any* pSetValues = aSetValues.getArray();

            bool bEmptyNode = rNode.isEmpty();
            for(sal_Int32 k = 0; k < rValues.getLength(); k++)
            {
                pSetNames[k] =  pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
                pSetValues[k] = pProperties[k].Value;
            }
            bRet = PutProperties(xHierarchyAccess, aSetNames, aSetValues, bAllLocales);
        }
        else
        {
            //if no factory is available then the node contains basic data elements
            for(const PropertyValue& rValue : rValues)
            {
                try
                {
                    OUString sSubNode = lcl_extractSetPropertyName( rValue.Name, rNode );

                    if(xCont->hasByName(sSubNode))
                        xCont->replaceByName(sSubNode, rValue.Value);
                    else
                        xCont->insertByName(sSubNode, rValue.Value);
                }
                catch (css::uno::Exception &)
                {
                    TOOLS_WARN_EXCEPTION("unotools.config""Exception from insert/replaceByName");
                }
            }
            xBatch->commitChanges();
        }
    }
    catch (const Exception& )
    {
        TOOLS_WARN_EXCEPTION("unotools.config""Exception from ReplaceSetProperties");
        bRet = false;
    }
    return bRet;
}

bool ConfigItem::AddNode(const OUString& rNode, const OUString& rNewNode)
{
    ValueCounter_Impl aCounter(m_nInValueChange);
    bool bRet = true;
    Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
    if(xHierarchyAccess.is())
    {
        Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
        try
        {
            Reference<XNameContainer> xCont;
            if(!rNode.isEmpty())
            {
                Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
                aNode >>= xCont;
            }
            else
                xCont.set(xHierarchyAccess, UNO_QUERY);
            if(!xCont.is())
                return false;

            Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);

            if(xFac.is())
            {
                if(!xCont->hasByName(rNewNode))
                {
                    Reference<XInterface> xInst = xFac->createInstance();
                    Any aVal; aVal <<= xInst;
                    xCont->insertByName(rNewNode, aVal);
                }
                try
                {
                    xBatch->commitChanges();
                }
                catch (css::uno::Exception &)
                {
                    TOOLS_WARN_EXCEPTION("unotools.config""Exception from commitChanges");
                }
            }
            else
            {
                //if no factory is available then the node contains basic data elements
                try
                {
                    if(!xCont->hasByName(rNewNode))
                        xCont->insertByName(rNewNode, Any());
                }
                catch (css::uno::Exception &)
                {
                    TOOLS_WARN_EXCEPTION("unotools.config""Exception from AddNode");
                }
            }
            xBatch->commitChanges();
        }
        catch (const Exception&)
        {
            DBG_UNHANDLED_EXCEPTION("unotools.config");
            bRet = false;
        }
    }
    return bRet;
}


void    ConfigItem::SetModified()
{
    m_bIsModified = true;
}

void    ConfigItem::ClearModified()
{
    m_bIsModified = false;
}

Reference< XHierarchicalNameAccess> ConfigItem::GetTree()
{
    Reference< XHierarchicalNameAccess> xRet;
    if (comphelper::IsFuzzing())
        return xRet;
    if(!m_xHierarchyAccess.is())
        xRet = ConfigManager::acquireTree(*this);
    else
        xRet = m_xHierarchyAccess;
    return xRet;
}

void ConfigItem::Commit()
{
    ImplCommit();
    ClearModified();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=82 H=98 G=90

¤ Dauer der Verarbeitung: 0.15 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.