tdf#154449 Add support for hidden named ranges

This patch adds the possibility of having "hidden" named ranges in Calc, in a way similar to what MS Excel has (i.e. they're not visible in the UI and can only be hidden/shown via scripting).

This is done by creating a new HIDDEN flag in com.sun.star.sheet.NamedRangeFlag.

Hence thia patch makes it so that named ranges can be made hidden/visible via scripting. For instance, consider a Calc document with a named range "NamedRange1". The following scripts hides "NamedRange1" from the UI (i.e. it's no longer visible in the Manage Names dialog):

Sub SetHidden
  Dim eFlags : eFlags = com.sun.star.sheet.NamedRangeFlag
  aNamedRange = ThisComponent.NamedRanges.getByName("NamedRange1")
  nType = aNamedRange.getType() Or eFlags.HIDDEN
  aNamedRange.setType(nType)
End Sub

To make the named range visible again:

Sub RemoveHidden
  Dim eFlags : eFlags = com.sun.star.sheet.NamedRangeFlag
  aNamedRange = ThisComponent.NamedRanges.getByName("NamedRange1")
  nType = aNamedRange.getType()
  nType = nType - (aNamedRange.getType() And eFlags.HIDDEN)
  aNamedRange.setType(nType)
End Sub

This patch also implements ODS and OOX import/export, as well as QA tests.

Change-Id: I10efe46938fe772b87dc17fc597cb83648b5efb2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155599
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/offapi/com/sun/star/sheet/NamedRangeFlag.idl b/offapi/com/sun/star/sheet/NamedRangeFlag.idl
index 3c42431..5addc08 100644
--- a/offapi/com/sun/star/sheet/NamedRangeFlag.idl
+++ b/offapi/com/sun/star/sheet/NamedRangeFlag.idl
@@ -45,6 +45,13 @@ published constants NamedRangeFlag
     */
    const long ROW_HEADER = 8;


    /** The range is hidden from the user interface

        @since LibreOffice 24.2
     */
    const long HIDDEN = 16;

};


diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx
index 31bdd1f..881a2e8 100644
--- a/sc/inc/rangenam.hxx
+++ b/sc/inc/rangenam.hxx
@@ -55,7 +55,8 @@ public:
        RowHeader  = 0x0010,
        AbsArea    = 0x0020,
        RefArea    = 0x0040,
        AbsPos     = 0x0080
        AbsPos     = 0x0080,
        Hidden     = 0x0100
    };

    enum class IsNameValidType
@@ -124,7 +125,7 @@ public:
    void            AddType( Type nType );
    Type            GetType() const                 { return eType; }
    bool            HasType( Type nType ) const;
    sal_uInt32      GetUnoType() const;
    SC_DLLPUBLIC sal_uInt32 GetUnoType() const;
    SC_DLLPUBLIC OUString GetSymbol( const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
    SC_DLLPUBLIC OUString GetSymbol( const ScAddress& rPos, const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
    void            UpdateSymbol( OUStringBuffer& rBuffer, const ScAddress& );
@@ -166,7 +167,7 @@ public:
};
namespace o3tl
{
    template<> struct typed_flags<ScRangeData::Type> : is_typed_flags<ScRangeData::Type, 0xff> {};
    template<> struct typed_flags<ScRangeData::Type> : is_typed_flags<ScRangeData::Type, 0x1ff> {};
}


diff --git a/sc/qa/unit/data/ods/named-ranges-hidden.ods b/sc/qa/unit/data/ods/named-ranges-hidden.ods
new file mode 100644
index 0000000..ff68f54
--- /dev/null
+++ b/sc/qa/unit/data/ods/named-ranges-hidden.ods
Binary files differ
diff --git a/sc/qa/unit/data/xlsx/named-ranges-hidden.xlsx b/sc/qa/unit/data/xlsx/named-ranges-hidden.xlsx
new file mode 100644
index 0000000..bfb3659
--- /dev/null
+++ b/sc/qa/unit/data/xlsx/named-ranges-hidden.xlsx
Binary files differ
diff --git a/sc/qa/unit/subsequent_filters_test.cxx b/sc/qa/unit/subsequent_filters_test.cxx
index d02ebc0..1956367 100644
--- a/sc/qa/unit/subsequent_filters_test.cxx
+++ b/sc/qa/unit/subsequent_filters_test.cxx
@@ -26,6 +26,7 @@
#include <postit.hxx>
#include <undomanager.hxx>

#include <com/sun/star/sheet/NamedRangeFlag.hdl>
#include "helper/qahelper.hxx"
#include "helper/shared_test_impl.hxx"

@@ -640,6 +641,69 @@ CPPUNIT_TEST_FIXTURE(ScFiltersTest, testRangeNameODS)
    testFile(aCSVPath, *pDoc, 1);
}

CPPUNIT_TEST_FIXTURE(ScFiltersTest, testHiddenRangeNameODS)
{
    createScDoc("ods/named-ranges-hidden.ods");
    ScDocument* pDoc = getScDoc();

    // This named range is set to "hidden"
    ScRangeData* pRangeData1 = pDoc->GetRangeName()->findByUpperName(OUString("NAMEDRANGE1"));
    CPPUNIT_ASSERT(pRangeData1);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(sheet::NamedRangeFlag::HIDDEN),
                         pRangeData1->GetUnoType() & sheet::NamedRangeFlag::HIDDEN);
    // This named range is visible
    ScRangeData* pRangeData2 = pDoc->GetRangeName()->findByUpperName(OUString("NAMEDRANGE2"));
    CPPUNIT_ASSERT(pRangeData2);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0),
                         pRangeData2->GetUnoType() & sheet::NamedRangeFlag::HIDDEN);

    // Set NamedRange2 to hidden
    pRangeData2->AddType(ScRangeData::Type::Hidden);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(sheet::NamedRangeFlag::HIDDEN),
                         pRangeData2->GetUnoType() & sheet::NamedRangeFlag::HIDDEN);

    // Check if both named ranges are hidden after saving and reloading
    saveAndReload("calc8");
    pDoc = getScDoc();
    pRangeData1 = pDoc->GetRangeName()->findByUpperName(OUString("NAMEDRANGE1"));
    CPPUNIT_ASSERT(pRangeData1);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(sheet::NamedRangeFlag::HIDDEN),
                         pRangeData1->GetUnoType() & sheet::NamedRangeFlag::HIDDEN);
    pRangeData2 = pDoc->GetRangeName()->findByUpperName(OUString("NAMEDRANGE2"));
    CPPUNIT_ASSERT(pRangeData2);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(sheet::NamedRangeFlag::HIDDEN),
                         pRangeData2->GetUnoType() & sheet::NamedRangeFlag::HIDDEN);
}

CPPUNIT_TEST_FIXTURE(ScFiltersTest, testHiddenRangeNameXLSX)
{
    createScDoc("xlsx/named-ranges-hidden.xlsx");
    ScDocument* pDoc = getScDoc();

    // This named range is set to "hidden"
    ScRangeData* pRangeData1 = pDoc->GetRangeName()->findByUpperName(OUString("NAMEDRANGE1"));
    CPPUNIT_ASSERT(pRangeData1);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(sheet::NamedRangeFlag::HIDDEN),
                         pRangeData1->GetUnoType() & sheet::NamedRangeFlag::HIDDEN);
    // This named range is visible
    ScRangeData* pRangeData2 = pDoc->GetRangeName()->findByUpperName(OUString("NAMEDRANGE2"));
    CPPUNIT_ASSERT(pRangeData2);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0),
                         pRangeData2->GetUnoType() & sheet::NamedRangeFlag::HIDDEN);

    // Save as ODS and test if the named ranges are still with the correct hidden flag
    saveAndReload("calc8");
    pDoc = getScDoc();
    pRangeData1 = pDoc->GetRangeName()->findByUpperName(OUString("NAMEDRANGE1"));
    CPPUNIT_ASSERT(pRangeData1);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(sheet::NamedRangeFlag::HIDDEN),
                         pRangeData1->GetUnoType() & sheet::NamedRangeFlag::HIDDEN);
    pRangeData2 = pDoc->GetRangeName()->findByUpperName(OUString("NAMEDRANGE2"));
    CPPUNIT_ASSERT(pRangeData2);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0),
                         pRangeData2->GetUnoType() & sheet::NamedRangeFlag::HIDDEN);
}

CPPUNIT_TEST_FIXTURE(ScFiltersTest, testHyperlinksXLSX)
{
    createScDoc("xlsx/hyperlinks.xlsx");
diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx
index b5578ca..051b0a5 100644
--- a/sc/source/core/tool/rangenam.cxx
+++ b/sc/source/core/tool/rangenam.cxx
@@ -529,6 +529,7 @@ sal_uInt32 ScRangeData::GetUnoType() const
    if ( HasType(Type::PrintArea) ) nUnoType |= css::sheet::NamedRangeFlag::PRINT_AREA;
    if ( HasType(Type::ColHeader) ) nUnoType |= css::sheet::NamedRangeFlag::COLUMN_HEADER;
    if ( HasType(Type::RowHeader) ) nUnoType |= css::sheet::NamedRangeFlag::ROW_HEADER;
    if ( HasType(Type::Hidden) )    nUnoType |= css::sheet::NamedRangeFlag::HIDDEN;
    return nUnoType;
}

diff --git a/sc/source/filter/excel/xename.cxx b/sc/source/filter/excel/xename.cxx
index 5ce4a2f..bdb23c6c 100644
--- a/sc/source/filter/excel/xename.cxx
+++ b/sc/source/filter/excel/xename.cxx
@@ -35,8 +35,10 @@
#include <formula/grammar.hxx>
#include <oox/export/utils.hxx>
#include <oox/token/tokens.hxx>
#include <com/sun/star/sheet/NamedRangeFlag.hdl>

using namespace ::oox;
using namespace ::com::sun::star;

// *** Helper classes ***

@@ -630,6 +632,10 @@ sal_uInt16 XclExpNameManagerImpl::CreateName( SCTAB nTab, const ScRangeData& rRa
    NamedExpMap::key_type key(nTab, rRangeData.GetName());
    maNamedExpMap[key] = nNameIdx;

    // Check if it is a hidden named range
    if ((rRangeData.GetUnoType() & sheet::NamedRangeFlag::HIDDEN) == sheet::NamedRangeFlag::HIDDEN)
        xName->SetHidden(true);

    /*  Create the definition formula.
        This may cause recursive creation of other defined names. */
    if( const ScTokenArray* pScTokArr = const_cast< ScRangeData& >( rRangeData ).GetCode() )
diff --git a/sc/source/filter/inc/workbookhelper.hxx b/sc/source/filter/inc/workbookhelper.hxx
index 8e2aa22..fd6343a 100644
--- a/sc/source/filter/inc/workbookhelper.hxx
+++ b/sc/source/filter/inc/workbookhelper.hxx
@@ -219,7 +219,7 @@ public:
    RangeDataRet createNamedRangeObject(
                            OUString& orName,
                            sal_Int32 nIndex,
                            sal_Int32 nNameFlags, bool bHidden ) const;
                            sal_Int32 nNameFlags ) const;

    /** Creates and returns a defined name on-the-fly in the sheet.
        The name will not be buffered in the global defined names buffer.
@@ -227,7 +227,7 @@ public:
    RangeDataRet createLocalNamedRangeObject(
                            OUString& orName,
                            sal_Int32 nIndex,
                            sal_Int32 nNameFlags, sal_Int32 nTab, bool bHidden ) const;
                            sal_Int32 nNameFlags, sal_Int32 nTab ) const;

    /** Creates and returns a database range on-the-fly in the Calc document.
        The range will not be buffered in the global table buffer.
diff --git a/sc/source/filter/oox/defnamesbuffer.cxx b/sc/source/filter/oox/defnamesbuffer.cxx
index e79b562..7b64ec6 100644
--- a/sc/source/filter/oox/defnamesbuffer.cxx
+++ b/sc/source/filter/oox/defnamesbuffer.cxx
@@ -223,20 +223,30 @@ void DefinedName::createNameObject( sal_Int32 nIndex )

    // special flags for this name
    sal_Int32 nNameFlags = 0;
    using namespace ::com::sun::star::sheet::NamedRangeFlag;
    using namespace ::com::sun::star::sheet;
    if( !isGlobalName() ) switch( mcBuiltinId )
    {
        case BIFF_DEFNAME_CRITERIA:
        case BIFF_DEFNAME_FILTERDATABASE: nNameFlags = FILTER_CRITERIA;               break;
        case BIFF_DEFNAME_PRINTAREA:      nNameFlags = PRINT_AREA;                    break;
        case BIFF_DEFNAME_PRINTTITLES:    nNameFlags = COLUMN_HEADER | ROW_HEADER;    break;
        case BIFF_DEFNAME_FILTERDATABASE:
            nNameFlags = NamedRangeFlag::FILTER_CRITERIA;
            break;
        case BIFF_DEFNAME_PRINTAREA:
            nNameFlags = NamedRangeFlag::PRINT_AREA;
            break;
        case BIFF_DEFNAME_PRINTTITLES:
            nNameFlags = NamedRangeFlag::COLUMN_HEADER | NamedRangeFlag::ROW_HEADER;
            break;
    }

    // Set the appropriate flag if it is a hidden named range
    if (maModel.mbHidden)
        nNameFlags |= NamedRangeFlag::HIDDEN;

    // create the name and insert it into the document, maCalcName will be changed to the resulting name
    if (maModel.mnSheet >= 0)
        maScRangeData = createLocalNamedRangeObject(maCalcName, nIndex, nNameFlags, maModel.mnSheet, maModel.mbHidden);
        maScRangeData = createLocalNamedRangeObject(maCalcName, nIndex, nNameFlags, maModel.mnSheet);
    else
        maScRangeData = createNamedRangeObject( maCalcName, nIndex, nNameFlags, maModel.mbHidden);
        maScRangeData = createNamedRangeObject( maCalcName, nIndex, nNameFlags);
    mnTokenIndex = nIndex;
}

diff --git a/sc/source/filter/oox/workbookhelper.cxx b/sc/source/filter/oox/workbookhelper.cxx
index eaeca2d..91166cb 100644
--- a/sc/source/filter/oox/workbookhelper.cxx
+++ b/sc/source/filter/oox/workbookhelper.cxx
@@ -155,9 +155,9 @@ public:
    /** Returns the specified cell or page style from the Calc document. */
    Reference< XStyle > getStyleObject( const OUString& rStyleName, bool bPageStyle ) const;
    /** Creates and returns a defined name on-the-fly in the Calc document. */
    WorkbookHelper::RangeDataRet createNamedRangeObject(OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags, bool bHidden);
    WorkbookHelper::RangeDataRet createNamedRangeObject(OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags);
    /** Creates and returns a defined name on the-fly in the correct Calc sheet. */
    WorkbookHelper::RangeDataRet createLocalNamedRangeObject(OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab, bool bHidden);
    WorkbookHelper::RangeDataRet createLocalNamedRangeObject(OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab);
    /** Creates and returns a database range on-the-fly in the Calc document. */
    Reference< XDatabaseRange > createDatabaseRangeObject( OUString& orName, const ScRange& rRangeAddr );
    /** Creates and returns an unnamed database range on-the-fly in the Calc document. */
@@ -367,7 +367,7 @@ Reference< XStyle > WorkbookGlobals::getStyleObject( const OUString& rStyleName,

namespace {

WorkbookHelper::RangeDataRet lcl_addNewByName(ScDocument& rDoc, ScRangeName* pNames, const OUString& rName, sal_Int16 nIndex, sal_Int32 nUnoType, bool bHidden)
WorkbookHelper::RangeDataRet lcl_addNewByName(ScDocument& rDoc, ScRangeName* pNames, const OUString& rName, sal_Int16 nIndex, sal_Int32 nUnoType)
{
    bool bDone = false;
    ScRangeData::Type nNewType = ScRangeData::Type::Name;
@@ -375,13 +375,15 @@ WorkbookHelper::RangeDataRet lcl_addNewByName(ScDocument& rDoc, ScRangeName* pNa
    if ( nUnoType & NamedRangeFlag::PRINT_AREA )         nNewType |= ScRangeData::Type::PrintArea;
    if ( nUnoType & NamedRangeFlag::COLUMN_HEADER )      nNewType |= ScRangeData::Type::ColHeader;
    if ( nUnoType & NamedRangeFlag::ROW_HEADER )         nNewType |= ScRangeData::Type::RowHeader;
    if ( nUnoType & NamedRangeFlag::HIDDEN )             nNewType |= ScRangeData::Type::Hidden;
    ScTokenArray aTokenArray(rDoc);
    ScRangeData* pNew = new ScRangeData(rDoc, rName, aTokenArray, ScAddress(), nNewType);
    pNew->GuessPosition();
    if ( nIndex )
        pNew->SetIndex( nIndex );
    // create but not insert hidden FILTER_CRITERIA named ranges to ScRangeName
    if ( bHidden && nNewType == ScRangeData::Type::Criteria )
    if (((nUnoType & NamedRangeFlag::HIDDEN) == NamedRangeFlag::HIDDEN)
        && ((nUnoType & NamedRangeFlag::FILTER_CRITERIA) == NamedRangeFlag::FILTER_CRITERIA))
    {
        return WorkbookHelper::RangeDataRet(pNew, true);
    }
@@ -408,7 +410,7 @@ OUString findUnusedName( const ScRangeName* pRangeName, const OUString& rSuggest
}

WorkbookHelper::RangeDataRet WorkbookGlobals::createNamedRangeObject(
    OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags, bool bHidden)
    OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags)
{
    // create the name and insert it into the Calc document
    WorkbookHelper::RangeDataRet aScRangeData(nullptr, false);
@@ -419,13 +421,13 @@ WorkbookHelper::RangeDataRet WorkbookGlobals::createNamedRangeObject(
        // find an unused name
        orName = findUnusedName( pNames, orName );
        // create the named range
        aScRangeData = lcl_addNewByName(rDoc, pNames, orName, nIndex, nNameFlags, bHidden);
        aScRangeData = lcl_addNewByName(rDoc, pNames, orName, nIndex, nNameFlags);
    }
    return aScRangeData;
}

WorkbookHelper::RangeDataRet WorkbookGlobals::createLocalNamedRangeObject(
    OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab, bool bHidden)
    OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab)
{
    // create the name and insert it into the Calc document
    WorkbookHelper::RangeDataRet aScRangeData(nullptr, false);
@@ -438,7 +440,7 @@ WorkbookHelper::RangeDataRet WorkbookGlobals::createLocalNamedRangeObject(
        // find an unused name
        orName = findUnusedName( pNames, orName );
        // create the named range
        aScRangeData = lcl_addNewByName(rDoc, pNames, orName, nIndex, nNameFlags, bHidden);
        aScRangeData = lcl_addNewByName(rDoc, pNames, orName, nIndex, nNameFlags);
    }
    return aScRangeData;
}
@@ -896,14 +898,14 @@ Reference< XStyle > WorkbookHelper::getStyleObject( const OUString& rStyleName, 
    return mrBookGlob.getStyleObject( rStyleName, bPageStyle );
}

WorkbookHelper::RangeDataRet WorkbookHelper::createNamedRangeObject(OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags, bool bHidden) const
WorkbookHelper::RangeDataRet WorkbookHelper::createNamedRangeObject(OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags) const
{
    return mrBookGlob.createNamedRangeObject(orName, nIndex, nNameFlags, bHidden);
    return mrBookGlob.createNamedRangeObject(orName, nIndex, nNameFlags);
}

WorkbookHelper::RangeDataRet WorkbookHelper::createLocalNamedRangeObject(OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab, bool bHidden) const
WorkbookHelper::RangeDataRet WorkbookHelper::createLocalNamedRangeObject(OUString& orName, sal_Int32 nIndex, sal_Int32 nNameFlags, sal_Int32 nTab) const
{
    return mrBookGlob.createLocalNamedRangeObject(orName, nIndex, nNameFlags, nTab, bHidden);
    return mrBookGlob.createLocalNamedRangeObject(orName, nIndex, nNameFlags, nTab);
}

Reference< XDatabaseRange > WorkbookHelper::createDatabaseRangeObject( OUString& orName, const ScRange& rRangeAddr ) const
diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx
index 65a9425..2ac992a 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -4549,6 +4549,12 @@ void ScXMLExport::WriteNamedRange(ScRangeName* pRangeName)
                    sBufferRangeType.append(" ");
                sBufferRangeType.append(GetXMLToken(XML_PRINT_RANGE));
            }
            if ((nRangeType & sheet::NamedRangeFlag::HIDDEN) == sheet::NamedRangeFlag::HIDDEN)
            {
                if (!sBufferRangeType.isEmpty())
                    sBufferRangeType.append(" ");
                sBufferRangeType.append(GetXMLToken(XML_HIDDEN));
            }
            OUString sRangeType = sBufferRangeType.makeStringAndClear();
            if (!sRangeType.isEmpty())
                AddAttribute(XML_NAMESPACE_TABLE, XML_RANGE_USABLE_AS, sRangeType);
diff --git a/sc/source/filter/xml/xmlimprt.cxx b/sc/source/filter/xml/xmlimprt.cxx
index 3aa681b..78473c7 100644
--- a/sc/source/filter/xml/xmlimprt.cxx
+++ b/sc/source/filter/xml/xmlimprt.cxx
@@ -106,6 +106,7 @@ constexpr OUStringLiteral SC_CURRENCYSYMBOL = u"CurrencySymbol";
constexpr OUStringLiteral SC_REPEAT_ROW = u"repeat-row";
constexpr OUStringLiteral SC_FILTER = u"filter";
constexpr OUStringLiteral SC_PRINT_RANGE = u"print-range";
constexpr OUStringLiteral SC_HIDDEN = u"hidden";

using namespace com::sun::star;
using namespace ::xmloff::token;
@@ -1202,6 +1203,8 @@ sal_Int32 ScXMLImport::GetRangeType(std::u16string_view sRangeType)
                nRangeType |= sheet::NamedRangeFlag::FILTER_CRITERIA;
            else if (sTemp == SC_PRINT_RANGE)
                nRangeType |= sheet::NamedRangeFlag::PRINT_AREA;
            else if (sTemp == SC_HIDDEN)
                nRangeType |= sheet::NamedRangeFlag::HIDDEN;
        }
        else if (i < sRangeType.size())
            sBuffer.append(sRangeType[i]);
@@ -1275,6 +1278,7 @@ public:
        if ( nUnoType & sheet::NamedRangeFlag::PRINT_AREA )         nNewType |= ScRangeData::Type::PrintArea;
        if ( nUnoType & sheet::NamedRangeFlag::COLUMN_HEADER )      nNewType |= ScRangeData::Type::ColHeader;
        if ( nUnoType & sheet::NamedRangeFlag::ROW_HEADER )         nNewType |= ScRangeData::Type::RowHeader;
        if ( nUnoType & sheet::NamedRangeFlag::HIDDEN )             nNewType |= ScRangeData::Type::Hidden;

        // Insert a new name.
        ScAddress aPos;
diff --git a/sc/source/ui/namedlg/namemgrtable.cxx b/sc/source/ui/namedlg/namemgrtable.cxx
index fbf6b64..c2dbc19 100644
--- a/sc/source/ui/namedlg/namemgrtable.cxx
+++ b/sc/source/ui/namedlg/namemgrtable.cxx
@@ -152,7 +152,9 @@ void ScRangeManagerTable::Init()
            aLine.aScope = itr.first;
        for (const auto& rEntry : rLocalRangeName)
        {
            if (!rEntry.second->HasType(ScRangeData::Type::Database))
            // Database and hidden named ranges are not shown in the Manage Names dialog
            if (!rEntry.second->HasType(ScRangeData::Type::Database)
                && !rEntry.second->HasType(ScRangeData::Type::Hidden))
            {
                aLine.aName = rEntry.second->GetName();
                addEntry(aLine, false);
diff --git a/sc/source/ui/unoobj/nameuno.cxx b/sc/source/ui/unoobj/nameuno.cxx
index 84283b1..6e02ab7 100644
--- a/sc/source/ui/unoobj/nameuno.cxx
+++ b/sc/source/ui/unoobj/nameuno.cxx
@@ -75,10 +75,11 @@ SC_SIMPLE_SERVICE_INFO( ScLabelRangeObj, "ScLabelRangeObj", "com.sun.star.sheet.
SC_SIMPLE_SERVICE_INFO( ScLabelRangesObj, "ScLabelRangesObj", "com.sun.star.sheet.LabelRanges" )
SC_SIMPLE_SERVICE_INFO( ScNamedRangesObj, "ScNamedRangesObj", "com.sun.star.sheet.NamedRanges" )

// Database named ranges are not considered by getCount, hasByName, removeByName and getElementNames
// Note that hidden named ranges are considered by these methods
static bool lcl_UserVisibleName(const ScRangeData& rData)
{
    //! as method to ScRangeData

    return !rData.HasType(ScRangeData::Type::Database);
}

@@ -293,6 +294,7 @@ sal_Int32 SAL_CALL ScNamedRangeObj::getType()
        if ( pData->HasType(ScRangeData::Type::PrintArea) ) nType |= sheet::NamedRangeFlag::PRINT_AREA;
        if ( pData->HasType(ScRangeData::Type::ColHeader) ) nType |= sheet::NamedRangeFlag::COLUMN_HEADER;
        if ( pData->HasType(ScRangeData::Type::RowHeader) ) nType |= sheet::NamedRangeFlag::ROW_HEADER;
        if ( pData->HasType(ScRangeData::Type::Hidden) )    nType |= sheet::NamedRangeFlag::HIDDEN;
    }
    return nType;
}
@@ -305,6 +307,7 @@ void SAL_CALL ScNamedRangeObj::setType( sal_Int32 nUnoType )
    if ( nUnoType & sheet::NamedRangeFlag::PRINT_AREA )         nNewType |= ScRangeData::Type::PrintArea;
    if ( nUnoType & sheet::NamedRangeFlag::COLUMN_HEADER )      nNewType |= ScRangeData::Type::ColHeader;
    if ( nUnoType & sheet::NamedRangeFlag::ROW_HEADER )         nNewType |= ScRangeData::Type::RowHeader;
    if ( nUnoType & sheet::NamedRangeFlag::HIDDEN )             nNewType |= ScRangeData::Type::Hidden;

    // GRAM_API for API compatibility.
    Modify_Impl( nullptr, nullptr, nullptr, nullptr, &nNewType,formula::FormulaGrammar::GRAM_API );
@@ -458,6 +461,7 @@ void SAL_CALL ScNamedRangesObj::addNewByName( const OUString& aName,
    if ( nUnoType & sheet::NamedRangeFlag::PRINT_AREA )         nNewType |= ScRangeData::Type::PrintArea;
    if ( nUnoType & sheet::NamedRangeFlag::COLUMN_HEADER )      nNewType |= ScRangeData::Type::ColHeader;
    if ( nUnoType & sheet::NamedRangeFlag::ROW_HEADER )         nNewType |= ScRangeData::Type::RowHeader;
    if ( nUnoType & sheet::NamedRangeFlag::HIDDEN )             nNewType |= ScRangeData::Type::Hidden;

    bool bDone = false;
    if (pDocShell)
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
index 0f71070..6b52ab7 100644
--- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
@@ -2061,6 +2061,40 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
      </rng:element>
    </rng:define>

    <!-- Adds hidden option to named ranges -->
    <rng:define name="table-named-range-attlist">
    <rng:attribute name="table:name">
      <rng:ref name="string"/>
    </rng:attribute>
    <rng:attribute name="table:cell-range-address">
      <rng:ref name="cellRangeAddress"/>
    </rng:attribute>
    <rng:optional>
      <rng:attribute name="table:base-cell-address">
        <rng:ref name="cellAddress"/>
      </rng:attribute>
    </rng:optional>
    <rng:optional>
      <rng:attribute name="table:range-usable-as">
        <rng:choice>
          <rng:value>none</rng:value>
          <rng:list>
            <rng:oneOrMore>
              <rng:choice>
                <rng:value>print-range</rng:value>
                <rng:value>filter</rng:value>
                <rng:value>repeat-row</rng:value>
                <rng:value>repeat-column</rng:value>
                <!-- The option "hidden" is the new value for "range-usable-as" -->
                <rng:value>hidden</rng:value>
              </rng:choice>
            </rng:oneOrMore>
          </rng:list>
        </rng:choice>
      </rng:attribute>
    </rng:optional>
  </rng:define>

   </rng:include>

    <!-- TODO no proposal -->