offapi/com/sun/star/text/ContentControl.idl                      |    6 ++
 oox/source/token/tokens.txt                                      |    1 
 schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng      |    5 +
 sw/inc/formatcontentcontrol.hxx                                  |    7 ++
 sw/inc/unoprnms.hxx                                              |    1 
 sw/qa/core/unocore/unocore.cxx                                   |    2 
 sw/qa/extras/ooxmlexport/ooxmlexport17.cxx                       |    2 
 sw/source/core/txtnode/attrcontentcontrol.cxx                    |    2 
 sw/source/core/unocore/unocontentcontrol.cxx                     |   29 
++++++++++
 sw/source/core/unocore/unomap1.cxx                               |    1 
 sw/source/filter/ww8/docxattributeoutput.cxx                     |   16 +++++
 sw/source/filter/ww8/docxattributeoutput.hxx                     |    2 
 writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx               |    4 +
 writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx |binary
 writerfilter/source/dmapper/DomainMapper.cxx                     |   15 +++++
 writerfilter/source/dmapper/DomainMapper_Impl.cxx                |    5 +
 writerfilter/source/dmapper/SdtHelper.cxx                        |    5 +
 writerfilter/source/dmapper/SdtHelper.hxx                        |    6 ++
 writerfilter/source/ooxml/model.xml                              |    4 +
 xmloff/qa/unit/data/content-control-alias.fodt                   |    2 
 xmloff/qa/unit/text.cxx                                          |    5 +
 xmloff/source/text/txtparae.cxx                                  |    8 ++
 xmloff/source/text/xmlcontentcontrolcontext.cxx                  |   14 ++++
 xmloff/source/text/xmlcontentcontrolcontext.hxx                  |    1 
 24 files changed, 142 insertions(+), 1 deletion(-)

New commits:
commit 908d058c67c4efb3dc142ea8d6ad59badf01c9c6
Author:     Justin Luth <justin.l...@collabora.com>
AuthorDate: Fri Dec 2 10:48:46 2022 -0500
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Dec 14 07:14:59 2022 +0000

    tdf#151548 sw content controls: preserve tabIndex
    
    This has to be vital to keyboard navigation.
    Certainly it is good to have it imported
    before we start to consider tab-movements
    for form controls.
    
    All tabIndex 1's are processed (in placement order)
    and then the 2's etc. 0's are to be done last.
    
    XML_TAB_INDEX already existed in include/xmloff/xmltoken.hxx
    and "tab-index" already exists in xmloff/source/token/tokens.txt
    
    make CppunitTest_writerfilter_dmapper CPPUNIT_TEST_NAME=testSdtRunRichText
    make CppunitTest_sw_ooxmlexport17 
CPPUNIT_TEST_NAME=testDateContentControlExport
    make CppunitTest_sw_core_unocore CPPUNIT_TEST_NAME=testContentControlDate
    make CppunitTest_xmloff_text CPPUNIT_TEST_NAME=testAliasContentControlExport
    make CppunitTest_xmloff_text CPPUNIT_TEST_NAME=testAliasContentControlImport
    
    No existing unit test found containing blockSDT with tabIndex.
    
    Change-Id: I8a958844e6192b079a2b22a62dedfd8739021f4a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143603
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <jl...@mail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/offapi/com/sun/star/text/ContentControl.idl 
b/offapi/com/sun/star/text/ContentControl.idl
index 59894741de2b..ce741d9b2926 100644
--- a/offapi/com/sun/star/text/ContentControl.idl
+++ b/offapi/com/sun/star/text/ContentControl.idl
@@ -128,6 +128,12 @@ service ContentControl
     */
     [optional, property] long Id;
 
+    /** Describes the order in which keyboard navigation moves between controls
+
+        @since LibreOffice 7.6
+    */
+    [optional, property] unsigned long TabIndex;
+
     /** Describes whether the control itself and/or its data can be modified 
or deleted by the user.
 
         @since LibreOffice 7.6
diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt
index 8ed5687983b6..b66321243320 100644
--- a/oox/source/token/tokens.txt
+++ b/oox/source/token/tokens.txt
@@ -5123,6 +5123,7 @@ tOff
 tR
 tab
 tabColor
+tabIndex
 tabLst
 tabRatio
 tabSelected
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng 
b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
index 613ded76689c..ea1083bb1fbc 100644
--- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
@@ -3008,6 +3008,11 @@ 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
           <rng:ref name="string"/>
         </rng:attribute>
       </rng:optional>
+      <rng:optional>
+        <rng:attribute name="loext:tab-index">
+          <rng:ref name="nonNegativeInteger"/>
+        </rng:attribute>
+      </rng:optional>
       <rng:optional>
         <rng:attribute name="loext:lock">
           <rng:ref name="string"/>
diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx
index e561fa6e23fb..77e6addbca09 100644
--- a/sw/inc/formatcontentcontrol.hxx
+++ b/sw/inc/formatcontentcontrol.hxx
@@ -179,6 +179,9 @@ class SW_DLLPUBLIC SwContentControl : public 
sw::BroadcastingModify
     /// The id: just remembered.
     sal_Int32 m_nId = 0;
 
+    /// The tabIndex: just remembered.
+    sal_uInt32 m_nTabIndex = 0;
+
     /// The control and content locks: mostly just remembered.
     OUString m_aLock;
 
@@ -362,6 +365,10 @@ public:
 
     sal_Int32 GetId() const { return m_nId; }
 
+    void SetTabIndex(sal_uInt32 nTabIndex) { m_nTabIndex = nTabIndex; }
+
+    sal_uInt32 GetTabIndex() const { return m_nTabIndex; }
+
     // At the design level, define how the control should be locked. No effect 
at implementation lvl
     void SetLock(bool bLockContent, bool bLockControl);
     void SetLock(const OUString& rLock) { m_aLock = rLock; }
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 2e7158fac97e..ff1cc28303be 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -917,6 +917,7 @@ inline constexpr OUStringLiteral UNO_NAME_COLOR = u"Color";
 inline constexpr OUStringLiteral UNO_NAME_ALIAS = u"Alias";
 inline constexpr OUStringLiteral UNO_NAME_TAG = u"Tag";
 inline constexpr OUStringLiteral UNO_NAME_ID = u"Id";
+inline constexpr OUStringLiteral UNO_NAME_TAB_INDEX = u"TabIndex";
 inline constexpr OUStringLiteral UNO_NAME_LOCK = u"Lock";
 inline constexpr OUStringLiteral UNO_NAME_DATE_STRING = u"DateString";
 #endif
diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx
index 985353db3e80..98d8092a7a9d 100644
--- a/sw/qa/core/unocore/unocore.cxx
+++ b/sw/qa/core/unocore/unocore.cxx
@@ -633,6 +633,7 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, 
testContentControlDate)
     xContentControlProps->setPropertyValue("Color", 
uno::Any(OUString("008000")));
     xContentControlProps->setPropertyValue("Alias", 
uno::Any(OUString("myalias")));
     xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("mytag")));
+    xContentControlProps->setPropertyValue("TabIndex", 
uno::Any(sal_uInt32(1)));
     xContentControlProps->setPropertyValue("Lock", 
uno::Any(OUString("sdtContentLocked")));
     xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
 
@@ -659,6 +660,7 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, 
testContentControlDate)
     CPPUNIT_ASSERT_EQUAL(OUString("008000"), pContentControl->GetColor());
     CPPUNIT_ASSERT_EQUAL(OUString("myalias"), pContentControl->GetAlias());
     CPPUNIT_ASSERT_EQUAL(OUString("mytag"), pContentControl->GetTag());
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(1), 
pContentControl->GetTabIndex());
     CPPUNIT_ASSERT_EQUAL(OUString("sdtContentLocked"), 
pContentControl->GetLock());
 }
 
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
index 7a9a14c1cb1a..1ddaeeeb8a8a 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
@@ -423,6 +423,7 @@ CPPUNIT_TEST_FIXTURE(Test, testDateContentControlExport)
     xContentControlProps->setPropertyValue("Color", 
uno::Any(OUString("008000")));
     xContentControlProps->setPropertyValue("Alias", 
uno::Any(OUString("myalias")));
     xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("mytag")));
+    xContentControlProps->setPropertyValue("TabIndex", 
uno::Any(sal_uInt32(2)));
     xContentControlProps->setPropertyValue("Lock", 
uno::Any(OUString("sdtLocked")));
 
     xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
@@ -447,6 +448,7 @@ CPPUNIT_TEST_FIXTURE(Test, testDateContentControlExport)
     assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w15:color", "val", "008000");
     assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:alias", "val", "myalias");
     assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:tag", "val", "mytag");
+    assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:tabIndex", "val", "2");
     assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:lock", "val", "sdtLocked");
 }
 
diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx 
b/sw/source/core/txtnode/attrcontentcontrol.cxx
index ffbe23589f99..d5e104f7790b 100644
--- a/sw/source/core/txtnode/attrcontentcontrol.cxx
+++ b/sw/source/core/txtnode/attrcontentcontrol.cxx
@@ -562,6 +562,8 @@ void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) 
const
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("tag"), 
BAD_CAST(m_aTag.toUtf8().getStr()));
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("id"),
                                       
BAD_CAST(OString::number(m_nId).getStr()));
+    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("tab-index"),
+                                      
BAD_CAST(OString::number(m_nTabIndex).getStr()));
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("lock"),
                                       BAD_CAST(m_aLock.toUtf8().getStr()));
 
diff --git a/sw/source/core/unocore/unocontentcontrol.cxx 
b/sw/source/core/unocore/unocontentcontrol.cxx
index 8b6c4e798f2c..5cce5c804c49 100644
--- a/sw/source/core/unocore/unocontentcontrol.cxx
+++ b/sw/source/core/unocore/unocontentcontrol.cxx
@@ -179,6 +179,7 @@ public:
     OUString m_aAlias;
     OUString m_aTag;
     sal_Int32 m_nId;
+    sal_uInt32 m_nTabIndex;
     OUString m_aLock;
 
     Impl(SwXContentControl& rThis, SwDoc& rDoc, SwContentControl* 
pContentControl,
@@ -198,6 +199,7 @@ public:
         , m_bComboBox(false)
         , m_bDropDown(false)
         , m_nId(0)
+        , m_nTabIndex(0)
     {
         if (m_pContentControl)
         {
@@ -494,6 +496,7 @@ void SwXContentControl::AttachImpl(const 
uno::Reference<text::XTextRange>& xText
     pContentControl->SetAlias(m_pImpl->m_aAlias);
     pContentControl->SetTag(m_pImpl->m_aTag);
     pContentControl->SetId(m_pImpl->m_nId);
+    pContentControl->SetTabIndex(m_pImpl->m_nTabIndex);
     pContentControl->SetLock(m_pImpl->m_aLock);
 
     SwFormatContentControl aContentControl(pContentControl, nWhich);
@@ -985,6 +988,21 @@ void SAL_CALL SwXContentControl::setPropertyValue(const 
OUString& rPropertyName,
             }
         }
     }
+    else if (rPropertyName == UNO_NAME_TAB_INDEX)
+    {
+        sal_uInt32 nValue = 0;
+        if (rValue >>= nValue)
+        {
+            if (m_pImpl->m_bIsDescriptor)
+            {
+                m_pImpl->m_nTabIndex = nValue;
+            }
+            else
+            {
+                m_pImpl->m_pContentControl->SetTabIndex(nValue);
+            }
+        }
+    }
     else if (rPropertyName == UNO_NAME_LOCK)
     {
         OUString aValue;
@@ -1262,6 +1280,17 @@ uno::Any SAL_CALL 
SwXContentControl::getPropertyValue(const OUString& rPropertyN
             aRet <<= m_pImpl->m_pContentControl->GetId();
         }
     }
+    else if (rPropertyName == UNO_NAME_TAB_INDEX)
+    {
+        if (m_pImpl->m_bIsDescriptor)
+        {
+            aRet <<= m_pImpl->m_nTabIndex;
+        }
+        else
+        {
+            aRet <<= m_pImpl->m_pContentControl->GetTabIndex();
+        }
+    }
     else if (rPropertyName == UNO_NAME_LOCK)
     {
         if (m_pImpl->m_bIsDescriptor)
diff --git a/sw/source/core/unocore/unomap1.cxx 
b/sw/source/core/unocore/unomap1.cxx
index 437f293a9f78..fef42a508942 100644
--- a/sw/source/core/unocore/unomap1.cxx
+++ b/sw/source/core/unocore/unomap1.cxx
@@ -1013,6 +1013,7 @@ o3tl::span<const SfxItemPropertyMapEntry> 
SwUnoPropertyMapProvider::GetContentCo
         { UNO_NAME_ALIAS, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 
},
         { UNO_NAME_TAG, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
         { UNO_NAME_ID, 0, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0 },
+        { UNO_NAME_TAB_INDEX, 0, cppu::UnoType<sal_uInt32>::get(), 
PROPERTY_NONE, 0 },
         { UNO_NAME_LOCK, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
         { UNO_NAME_DATE_STRING, 0, cppu::UnoType<OUString>::get(), 
PropertyAttribute::READONLY, 0 },
     };
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 11bf0e1f9b82..03bdb9e361ba 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -624,6 +624,7 @@ void SdtBlockHelper::DeleteAndResetTheLists()
     if (!m_aColor.isEmpty())
         m_aColor.clear();
     m_bShowingPlaceHolder = false;
+    m_nTabIndex = 0;
     m_bHasId = false;
 }
 
@@ -727,6 +728,10 @@ void SdtBlockHelper::WriteExtraParams(const 
::sax_fastparser::FSHelperPtr& pSeri
     if (!m_aTag.isEmpty())
         pSerializer->singleElementNS(XML_w, XML_tag, FSNS(XML_w, XML_val), 
m_aTag);
 
+    if (m_nTabIndex)
+        pSerializer->singleElementNS(XML_w, XML_tabIndex, FSNS(XML_w, XML_val),
+                                     OString::number(m_nTabIndex));
+
     if (!m_aLock.isEmpty())
         pSerializer->singleElementNS(XML_w, XML_lock, FSNS(XML_w, XML_val), 
m_aLock);
 }
@@ -843,6 +848,11 @@ void SdtBlockHelper::GetSdtParamsFromGrabBag(const 
uno::Sequence<beans::Property
             if (!(aPropertyValue.Value >>= m_aTag))
                 SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected 
sdt tag value");
         }
+        else if (aPropertyValue.Name == "ooxml:CT_SdtPr_tabIndex" && 
!m_nTabIndex)
+        {
+            if (!(aPropertyValue.Value >>= m_nTabIndex))
+                SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected 
sdt tabIndex value");
+        }
         else if (aPropertyValue.Name == "ooxml:CT_SdtPr_lock" && 
m_aLock.isEmpty())
         {
             if (!(aPropertyValue.Value >>= m_aLock))
@@ -2408,6 +2418,12 @@ void DocxAttributeOutput::WriteContentControlStart()
                                        
OString::number(m_pContentControl->GetId()));
     }
 
+    if (m_pContentControl->GetTabIndex())
+    {
+        m_pSerializer->singleElementNS(XML_w, XML_tabIndex, FSNS(XML_w, 
XML_val),
+                                       
OString::number(m_pContentControl->GetTabIndex()));
+    }
+
     if (!m_pContentControl->GetLock().isEmpty())
     {
         m_pSerializer->singleElementNS(XML_w, XML_lock, FSNS(XML_w, XML_val),
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx 
b/sw/source/filter/ww8/docxattributeoutput.hxx
index 055d277c7827..c4be90cd5140 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -131,6 +131,7 @@ public:
         : m_bHasId(false)
         , m_bStartedSdt(false)
         , m_bShowingPlaceHolder(false)
+        , m_nTabIndex(0)
         , m_nSdtPrToken(0)
     {}
 
@@ -145,6 +146,7 @@ public:
     bool m_bShowingPlaceHolder;
     OUString m_aAlias;
     OUString m_aTag;
+    sal_Int32 m_nTabIndex;
     OUString m_aLock;
     sal_Int32 m_nSdtPrToken;
 
diff --git a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx 
b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
index 8f9ea8ca5ddb..7b27ff66d08c 100644
--- a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
@@ -71,6 +71,10 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtRunRichText)
     xContentControlProps->getPropertyValue("Tag") >>= aTag;
     // This was empty.
     CPPUNIT_ASSERT_EQUAL(OUString("mytag"), aTag);
+    sal_uInt32 nTabIndex = 0;
+    xContentControlProps->getPropertyValue("TabIndex") >>= nTabIndex;
+    // This was 0
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(5), nTabIndex);
     OUString aLock;
     xContentControlProps->getPropertyValue("Lock") >>= aLock;
     // This was empty.
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx 
b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx
index aabc745bcf0e..ca980abb0356 100644
Binary files a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx 
and b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx differ
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx 
b/writerfilter/source/dmapper/DomainMapper.cxx
index a0b06009b6c6..c77c9f2a0a93 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -2848,6 +2848,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
     case NS_ooxml::LN_CT_SdtPr_showingPlcHdr:
     case NS_ooxml::LN_CT_SdtPr_color:
     case NS_ooxml::LN_CT_SdtPr_tag:
+    case NS_ooxml::LN_CT_SdtPr_tabIndex:
     case NS_ooxml::LN_CT_SdtPr_lock:
     {
         if (!m_pImpl->GetSdtStarts().empty())
@@ -2886,6 +2887,12 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
                 break;
             }
 
+            if (nSprmId == NS_ooxml::LN_CT_SdtPr_tabIndex)
+            {
+                m_pImpl->m_pSdtHelper->SetTabIndex(nIntValue);
+                break;
+            }
+
             if (nSprmId == NS_ooxml::LN_CT_SdtPr_lock)
             {
                 m_pImpl->m_pSdtHelper->SetLock(sStringValue);
@@ -2939,6 +2946,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
             case NS_ooxml::LN_CT_SdtPr_id:          sName = 
"ooxml:CT_SdtPr_id"; break;
             case NS_ooxml::LN_CT_SdtPr_alias:       sName = 
"ooxml:CT_SdtPr_alias"; break;
             case NS_ooxml::LN_CT_SdtPr_tag:         sName = 
"ooxml:CT_SdtPr_tag"; break;
+            case NS_ooxml::LN_CT_SdtPr_tabIndex:    sName = 
"ooxml:CT_SdtPr_tabIndex"; break;
             case NS_ooxml::LN_CT_SdtPr_lock:        sName = 
"ooxml:CT_SdtPr_lock"; break;
             case NS_ooxml::LN_CT_SdtPlaceholder_docPart: sName = 
"ooxml:CT_SdtPlaceholder_docPart"; break;
             case NS_ooxml::LN_CT_SdtPr_showingPlcHdr: sName = 
"ooxml:CT_SdtPr_showingPlcHdr"; break;
@@ -2977,6 +2985,13 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
             aValue.Value <<= bool(nIntValue);
             m_pImpl->m_pSdtHelper->appendToInteropGrabBag(aValue);
         }
+        else if (nSprmId == NS_ooxml::LN_CT_SdtPr_tabIndex)
+        {
+            beans::PropertyValue aValue;
+            aValue.Name = sName;
+            aValue.Value <<= nIntValue;
+            m_pImpl->m_pSdtHelper->appendToInteropGrabBag(aValue);
+        }
         else
             m_pImpl->m_pSdtHelper->appendToInteropGrabBag(getInteropGrabBag());
         
m_pImpl->m_pSdtHelper->setOutsideAParagraph(m_pImpl->IsOutsideAParagraph());
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 3f3906570c61..0cc56b14d4f2 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -957,6 +957,11 @@ void DomainMapper_Impl::PopSdt()
         xContentControlProps->setPropertyValue("Id", 
uno::Any(m_pSdtHelper->GetId()));
     }
 
+    if (m_pSdtHelper->GetTabIndex())
+    {
+        xContentControlProps->setPropertyValue("TabIndex", 
uno::Any(m_pSdtHelper->GetTabIndex()));
+    }
+
     if (!m_pSdtHelper->GetLock().isEmpty())
     {
         xContentControlProps->setPropertyValue("Lock", 
uno::Any(m_pSdtHelper->GetLock()));
diff --git a/writerfilter/source/dmapper/SdtHelper.cxx 
b/writerfilter/source/dmapper/SdtHelper.cxx
index 81b03df774cd..2eece1c06df6 100644
--- a/writerfilter/source/dmapper/SdtHelper.cxx
+++ b/writerfilter/source/dmapper/SdtHelper.cxx
@@ -521,6 +521,7 @@ void SdtHelper::clear()
     m_aAlias.clear();
     m_aTag.clear();
     m_nId = 0;
+    m_nTabIndex = 0;
     m_aLock.clear();
 }
 
@@ -547,6 +548,10 @@ void SdtHelper::SetId(sal_Int32 nId) { m_nId = nId; }
 
 sal_Int32 SdtHelper::GetId() const { return m_nId; }
 
+void SdtHelper::SetTabIndex(sal_uInt32 nTabIndex) { m_nTabIndex = nTabIndex; }
+
+sal_uInt32 SdtHelper::GetTabIndex() const { return m_nTabIndex; }
+
 void SdtHelper::SetLock(const OUString& rLock) { m_aLock = rLock; }
 
 const OUString& SdtHelper::GetLock() const { return m_aLock; }
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx 
b/writerfilter/source/dmapper/SdtHelper.hxx
index dbe0b2659e7a..35bedde509c0 100644
--- a/writerfilter/source/dmapper/SdtHelper.hxx
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -135,6 +135,9 @@ class SdtHelper final : public virtual SvRefBase
     /// <w:sdtPr>'s <w:id w:val="...">.
     sal_Int32 m_nId = 0;
 
+    /// <w:sdtPr>'s <w:tabIndex w:val="...">.
+    sal_uInt32 m_nTabIndex = 0;
+
     /// <w:sdtPr>'s <w:lock w:val="...">.
     OUString m_aLock;
 
@@ -226,6 +229,9 @@ public:
     void SetId(sal_Int32 nId);
     sal_Int32 GetId() const;
 
+    void SetTabIndex(sal_uInt32 nTabIndex);
+    sal_uInt32 GetTabIndex() const;
+
     void SetLock(const OUString& rLock);
     const OUString& GetLock() const;
 
diff --git a/writerfilter/source/ooxml/model.xml 
b/writerfilter/source/ooxml/model.xml
index 4f2446aa5272..11a434d3d7ee 100644
--- a/writerfilter/source/ooxml/model.xml
+++ b/writerfilter/source/ooxml/model.xml
@@ -13998,6 +13998,9 @@
           <element name="id">
             <ref name="CT_DecimalNumber"/>
           </element>
+          <element name="tabIndex">
+            <ref name="CT_DecimalNumber"/>
+          </element>
           <element name="tag">
             <ref name="CT_String"/>
           </element>
@@ -18298,6 +18301,7 @@
       <element name="dataBinding" tokenid="ooxml:CT_SdtPr_dataBinding"/>
       <element name="temporary" tokenid="ooxml:CT_SdtPr_temporary"/>
       <element name="id" tokenid="ooxml:CT_SdtPr_id"/>
+      <element name="tabIndex" tokenid="ooxml:CT_SdtPr_tabIndex"/>
       <element name="tag" tokenid="ooxml:CT_SdtPr_tag"/>
       <element name="equation" tokenid="ooxml:CT_SdtPr_equation"/>
       <element name="comboBox" tokenid="ooxml:CT_SdtPr_comboBox"/>
diff --git a/xmloff/qa/unit/data/content-control-alias.fodt 
b/xmloff/qa/unit/data/content-control-alias.fodt
index 8f541bef42cc..48fdc7b9436c 100644
--- a/xmloff/qa/unit/data/content-control-alias.fodt
+++ b/xmloff/qa/unit/data/content-control-alias.fodt
@@ -2,7 +2,7 @@
 <office:document xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
   <office:body>
     <office:text>
-      <text:p><loext:content-control loext:alias="my alias" loext:tag="my tag" 
loext:lock="sdtContentLocked">test</loext:content-control></text:p>
+      <text:p><loext:content-control loext:alias="my alias" loext:tag="my tag" 
loext:tab-index="4" 
loext:lock="sdtContentLocked">test</loext:content-control></text:p>
     </office:text>
   </office:body>
 </office:document>
diff --git a/xmloff/qa/unit/text.cxx b/xmloff/qa/unit/text.cxx
index 2187e3d2a89d..250c9d945028 100644
--- a/xmloff/qa/unit/text.cxx
+++ b/xmloff/qa/unit/text.cxx
@@ -781,6 +781,7 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, 
testAliasContentControlExport)
     uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, 
uno::UNO_QUERY);
     xContentControlProps->setPropertyValue("Alias", uno::Any(OUString("my 
alias")));
     xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("my 
tag")));
+    xContentControlProps->setPropertyValue("TabIndex", 
uno::Any(sal_uInt32(3)));
     xContentControlProps->setPropertyValue("Lock", 
uno::Any(OUString("unlocked")));
     xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
 
@@ -795,6 +796,7 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, 
testAliasContentControlExport)
     // i.e. alias was lost on export.
     assertXPath(pXmlDoc, "//loext:content-control", "alias", "my alias");
     assertXPath(pXmlDoc, "//loext:content-control", "tag", "my tag");
+    assertXPath(pXmlDoc, "//loext:content-control", "tab-index", "3");
     assertXPath(pXmlDoc, "//loext:content-control", "lock", "unlocked");
 }
 
@@ -855,6 +857,9 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, 
testAliasContentControlImport)
     OUString aTag;
     xContentControlProps->getPropertyValue("Tag") >>= aTag;
     CPPUNIT_ASSERT_EQUAL(OUString("my tag"), aTag);
+    sal_uInt32 nTabIndex;
+    xContentControlProps->getPropertyValue("TabIndex") >>= nTabIndex;
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(4), nTabIndex);
     OUString aLock;
     xContentControlProps->getPropertyValue("Lock") >>= aLock;
     CPPUNIT_ASSERT_EQUAL(OUString("sdtContentLocked"), aLock);
diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx
index b2117dfdc726..4ee5f3fd8a90 100644
--- a/xmloff/source/text/txtparae.cxx
+++ b/xmloff/source/text/txtparae.cxx
@@ -4067,6 +4067,14 @@ void XMLTextParagraphExport::ExportContentControl(
             GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_TAG, aTag);
         }
 
+        sal_uInt32 nTabIndex;
+        xPropertySet->getPropertyValue("TabIndex") >>= nTabIndex;
+        if (nTabIndex)
+        {
+            GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_TAB_INDEX,
+                                     OUString::number(nTabIndex));
+        }
+
         OUString aLock;
         xPropertySet->getPropertyValue("Lock") >>= aLock;
         if (!aLock.isEmpty())
diff --git a/xmloff/source/text/xmlcontentcontrolcontext.cxx 
b/xmloff/source/text/xmlcontentcontrolcontext.cxx
index 83c1621b057e..caf1af04b8d7 100644
--- a/xmloff/source/text/xmlcontentcontrolcontext.cxx
+++ b/xmloff/source/text/xmlcontentcontrolcontext.cxx
@@ -49,6 +49,7 @@ void XMLContentControlContext::startFastElement(
     for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList))
     {
         bool bTmp = false;
+        sal_Int32 nTmp = 0;
 
         switch (rIter.getToken())
         {
@@ -151,6 +152,14 @@ void XMLContentControlContext::startFastElement(
                 m_aTag = rIter.toString();
                 break;
             }
+            case XML_ELEMENT(LO_EXT, XML_TAB_INDEX):
+            {
+                if (sax::Converter::convertNumber(nTmp, rIter.toView()))
+                {
+                    m_nTabIndex = nTmp;
+                }
+                break;
+            }
             case XML_ELEMENT(LO_EXT, XML_LOCK):
             {
                 m_aLock = rIter.toString();
@@ -267,6 +276,11 @@ void XMLContentControlContext::endFastElement(sal_Int32)
         xPropertySet->setPropertyValue("Tag", uno::Any(m_aTag));
     }
 
+    if (m_nTabIndex)
+    {
+        xPropertySet->setPropertyValue("TabIndex", uno::Any(m_nTabIndex));
+    }
+
     if (!m_aLock.isEmpty())
     {
         xPropertySet->setPropertyValue("Lock", uno::Any(m_aLock));
diff --git a/xmloff/source/text/xmlcontentcontrolcontext.hxx 
b/xmloff/source/text/xmlcontentcontrolcontext.hxx
index f0b1eea0b010..44abe71d6a08 100644
--- a/xmloff/source/text/xmlcontentcontrolcontext.hxx
+++ b/xmloff/source/text/xmlcontentcontrolcontext.hxx
@@ -53,6 +53,7 @@ class XMLContentControlContext : public SvXMLImportContext
     bool m_bDropDown = false;
     OUString m_aAlias;
     OUString m_aTag;
+    sal_uInt32 m_nTabIndex = 0;
     OUString m_aLock;
 
 public:

Reply via email to