sw/qa/extras/ooxmlexport/ooxmlexport13.cxx        |    4 
 sw/source/core/doc/doclay.cxx                     |   11 +
 sw/source/core/doc/textboxhelper.cxx              |    3 
 sw/source/core/unocore/unotext.cxx                |   21 ++-
 sw/source/filter/xml/xmlexp.hxx                   |    5 
 sw/source/filter/xml/xmlfmte.cxx                  |   12 +
 sw/source/filter/xml/xmliteme.cxx                 |    2 
 sw/source/filter/xml/xmltble.cxx                  |  149 +++++++++++-----------
 sw/source/filter/xml/xmltexte.hxx                 |   12 +
 writerfilter/source/dmapper/DomainMapper_Impl.cxx |   49 +++----
 writerfilter/source/dmapper/GraphicImport.cxx     |   11 -
 11 files changed, 161 insertions(+), 118 deletions(-)

New commits:
commit d83a82d872417a0c50d38c54f95af512136f6d94
Author:     Vasily Melenchuk <vasily.melenc...@cib.de>
AuthorDate: Mon Dec 27 13:54:23 2021 +0300
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Thu Aug 4 13:04:11 2022 +0200

    tdf#143703 sw: always assign name for fly section
    
    Previously generated name was assigned only if not in doc
    reading mode. But there is no guarantee that it will be assigned
    later. Better to insert any name in SwDoc::MakeFlySection_() and
    later it can be overwritten, but fly will definitely have
    any unique name.
    
    * Some test failed because GraphicImport_Impl::applyName() overwrote the
      name with a different generated one.
    
    * This breaks chaining of VML shapes, see test testTDF87348.
    
      The code introduced in commit 091fe76b6329b4bb974987554369cbfadd8f2401
      in DomainMapper_Impl::ChainTextFrames() breaks if the text frame
      already has a name; it's a bit confusing which names there come from
      the file and which come from the API, and it also mixes 2 different
      cases of VML chaining and DrawingML chaining that look like they
      should be using different data.
    
    * This also breaks moving flys anchored at-char in flys into them in
      SwXText::convertToTextFrame(), see ooxmlexport13 testFlyInFly.
    
      This kind of worked by accident before: the fly is copied and then the
      original deleted, keeping the same name (with help of
      SwDoc::mbCopyIsMove); with no name it would compare the SdrObject
      pointer, which is different for the new copy, now the name is the
      same.
    
      Fix this by only moving flys anchored at the edge of the selection
      back inoto the body; it turns out that Word actually supports at-char
      anchors in text frames, but only if it's a VML shape or Compatibility
      Mode or whatever; i wasn't able to do it in a document created from
      scratch.
    
      This is a bit tricky to ignore the nodes added for floating tables as
      seen in ooxmlexport10 testFloatingTablesAnchor.
    
    * Another change is required in SwDoc::SetFlyName() because of
      testTdf127732, as it would rename a frame named "Frame1" to "Frame2"
      when called to rename it to "Frame1".
    
    * Some tests failed because after MakeFlySection_() assigns a name it is
      immediately unconditionally overwritten; replace that with asserts
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127556
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 4d6243693c228703394c00164276f8326447beb9)
    
    Change-Id: I46752a4413ba3a9e981eccd1e153b3aaf8053781
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137766
    Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
index 8f457f89bc16..62ad331a8c64 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
@@ -44,11 +44,11 @@ DECLARE_SW_EXPORT_TEST(testFlyInFly, "ooo39250-1-min.rtf", 
nullptr, Test)
     // check that anchor of text frame is in other text frame
     uno::Reference<text::XTextContent> const xAnchored(getShape(3), 
uno::UNO_QUERY);
     CPPUNIT_ASSERT(xAnchored.is());
-    CPPUNIT_ASSERT_EQUAL(OUString(""), 
uno::Reference<container::XNamed>(xAnchored, uno::UNO_QUERY_THROW)->getName());
+    CPPUNIT_ASSERT_EQUAL(OUString("Frame1")/*generated name*/, 
uno::Reference<container::XNamed>(xAnchored, uno::UNO_QUERY_THROW)->getName());
     uno::Reference<text::XText> const 
xAnchorText(xAnchored->getAnchor()->getText());
     uno::Reference<text::XTextFrame> const xAnchorFrame(xAnchorText, 
uno::UNO_QUERY);
     CPPUNIT_ASSERT(xAnchorFrame.is());
-    CPPUNIT_ASSERT_EQUAL(OUString("Frame2"), 
uno::Reference<container::XNamed>(xAnchorFrame, 
uno::UNO_QUERY_THROW)->getName());
+    CPPUNIT_ASSERT_EQUAL(OUString("Frame3"), 
uno::Reference<container::XNamed>(xAnchorFrame, 
uno::UNO_QUERY_THROW)->getName());
 }
 
 DECLARE_OOXMLEXPORT_TEST(testTdf125778_lostPageBreakTOX, 
"tdf125778_lostPageBreakTOX.docx")
diff --git a/sw/source/core/doc/doclay.cxx b/sw/source/core/doc/doclay.cxx
index ec4861fe39b2..5b3dc0ef3687 100644
--- a/sw/source/core/doc/doclay.cxx
+++ b/sw/source/core/doc/doclay.cxx
@@ -157,13 +157,12 @@ SwFlyFrameFormat* SwDoc::MakeFlySection_( const 
SwPosition& rAnchPos,
         pFrameFormat = getIDocumentStylePoolAccess().GetFrameFormatFromPool( 
RES_POOLFRM_FRAME );
 
     OUString sName;
-    if( !mbInReading )
-        switch( rNode.GetNodeType() )
-        {
+    switch( rNode.GetNodeType() )
+    {
         case SwNodeType::Grf:        sName = GetUniqueGrfName();     break;
         case SwNodeType::Ole:        sName = GetUniqueOLEName();     break;
         default:                sName = GetUniqueFrameName();   break;
-        }
+    }
     SwFlyFrameFormat* pFormat = MakeFlyFrameFormat( sName, pFrameFormat );
 
     // Create content and connect to the format.
@@ -1408,6 +1407,10 @@ const SwFlyFrameFormat* SwDoc::FindFlyByName( const 
OUString& rName, SwNodeType
 
 void SwDoc::SetFlyName( SwFlyFrameFormat& rFormat, const OUString& rName )
 {
+    if (rFormat.GetName() == rName)
+    {
+        return;
+    }
     OUString sName( rName );
     if( sName.isEmpty() || FindFlyByName( sName ) )
     {
diff --git a/sw/source/core/doc/textboxhelper.cxx 
b/sw/source/core/doc/textboxhelper.cxx
index ea57aa58319d..40d1bb607c1e 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -90,7 +90,8 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape)
     xPropertySet->setPropertyValue(UNO_NAME_SURROUND, 
uno::makeAny(text::WrapTextMode_THROUGH));
 
     uno::Reference<container::XNamed> xNamed(xTextFrame, uno::UNO_QUERY);
-    xNamed->setName(pShape->GetDoc()->GetUniqueFrameName());
+    assert(!xNamed->getName().isEmpty());
+    (void)xNamed;
 
     // Link its text range to the original shape.
     uno::Reference<text::XTextRange> xTextBox(xTextFrame, 
uno::UNO_QUERY_THROW);
diff --git a/sw/source/core/unocore/unotext.cxx 
b/sw/source/core/unocore/unotext.cxx
index 3887a11191d7..a4dfe5422af1 100644
--- a/sw/source/core/unocore/unotext.cxx
+++ b/sw/source/core/unocore/unotext.cxx
@@ -1566,6 +1566,8 @@ SwXText::convertToTextFrame(
     }
     bool bParaAfterInserted = false;
     bool bParaBeforeInserted = false;
+    ::std::optional<SwPaM> oAnchorCheckPam;
+    oAnchorCheckPam.emplace(*pStartPam->Start(), *pEndPam->End());
     if (
         pStartStartNode && pEndStartNode &&
         (pStartStartNode != pEndStartNode || pStartStartNode != GetStartNode())
@@ -1646,6 +1648,7 @@ SwXText::convertToTextFrame(
         bParaAfterInserted = 
GetDoc()->getIDocumentContentOperations().AppendTextNode( aEnd );
         pEndPam->DeleteMark();
         *pEndPam->GetPoint() = aEnd;
+        *oAnchorCheckPam->End() = aEnd;
     }
     pStartPam->SetMark();
     *pStartPam->End() = *pEndPam->End();
@@ -1660,10 +1663,17 @@ SwXText::convertToTextFrame(
     {
         const SwFrameFormat* pFrameFormat = 
(*m_pImpl->m_pDoc->GetSpzFrameFormats())[i];
         const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
-        if ( !isGraphicNode(pFrameFormat) &&
-                (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId() || 
RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()) &&
-                pStartPam->Start()->nNode.GetIndex() <= 
rAnchor.GetContentAnchor()->nNode.GetIndex() &&
-                pStartPam->End()->nNode.GetIndex() >= 
rAnchor.GetContentAnchor()->nNode.GetIndex())
+        // note: Word can do at-char anchors in text frames - sometimes!
+        // see testFlyInFly for why this checks only the edges of the 
selection,
+        // and testFloatingTablesAnchor for why it excludes pre/post table
+        // added nodes
+        if (!isGraphicNode(pFrameFormat)
+            && (   (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()
+                    && (    oAnchorCheckPam->Start()->nNode.GetIndex() == 
rAnchor.GetContentAnchor()->nNode.GetIndex()
+                        ||  oAnchorCheckPam->End()->nNode.GetIndex() == 
rAnchor.GetContentAnchor()->nNode.GetIndex()))
+                || (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()
+                    && (    *oAnchorCheckPam->Start() == 
*rAnchor.GetContentAnchor()
+                        ||  *oAnchorCheckPam->End() == 
*rAnchor.GetContentAnchor()))))
         {
             if (pFrameFormat->GetName().isEmpty())
             {
@@ -1675,6 +1685,7 @@ SwXText::convertToTextFrame(
             }
         }
     }
+    oAnchorCheckPam.reset(); // clear SwIndex before deleting nodes
 
     const uno::Reference<text::XTextFrame> xNewFrame(
             SwXTextFrame::CreateXTextFrame(*m_pImpl->m_pDoc, nullptr));
@@ -1692,7 +1703,7 @@ SwXText::convertToTextFrame(
                 new SwXTextRange(*pStartPam, this);
             assert(rNewFrame.IsDescriptor());
             rNewFrame.attachToRange(xInsertTextRange, pStartPam.get());
-            rNewFrame.setName(m_pImpl->m_pDoc->GetUniqueFrameName());
+            assert(!rNewFrame.getName().isEmpty());
         }
 
         SwTextNode *const pTextNode(pStartPam->GetNode().GetTextNode());
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 329999ca18ce..0aec8482e121 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -3309,14 +3309,15 @@ void DomainMapper_Impl::ChainTextFrames()
         sal_Int32 nId;
         sal_Int32 nSeq;
         OUString s_mso_next_textbox;
-        bool bShapeNameSet;
-        TextFramesForChaining(): nId(0), nSeq(0), bShapeNameSet(false) {}
+        OUString shapeName;
+        TextFramesForChaining() : nId(0), nSeq(0) {}
     } ;
     typedef std::map <OUString, TextFramesForChaining> ChainMap;
 
     try
     {
         ChainMap aTextFramesForChainingHelper;
+        ::std::vector<TextFramesForChaining> chainingWPS;
         OUString sChainNextName("ChainNextName");
 
         //learn about ALL of the textboxes and their chaining values first - 
because frames are processed in no specific order.
@@ -3354,19 +3355,22 @@ void DomainMapper_Impl::ChainTextFrames()
 
             //Sometimes the shape names have not been imported.  If not, we 
may have a fallback name.
             //Set name later, only if required for linking.
-            if( sShapeName.isEmpty() )
-                aChainStruct.bShapeNameSet = false;
-            else
-            {
-                aChainStruct.bShapeNameSet = true;
-                sLinkChainName = sShapeName;
-            }
+            aChainStruct.shapeName = sShapeName;
 
-            if( !sLinkChainName.isEmpty() )
+            if (!sLinkChainName.isEmpty())
             {
                 aChainStruct.xShape = rTextFrame;
                 aTextFramesForChainingHelper[sLinkChainName] = aChainStruct;
             }
+            if (aChainStruct.s_mso_next_textbox.isEmpty())
+            {   // no VML chaining => try to chain DrawingML via IDs
+                aChainStruct.xShape = rTextFrame;
+                if (!sLinkChainName.isEmpty())
+                {   // for member of group shapes, TestTdf73499
+                    aChainStruct.shapeName = sLinkChainName;
+                }
+                chainingWPS.emplace_back(aChainStruct);
+            }
         }
 
         //if mso-next-textbox tags are provided, create those vml-style links 
first. Afterwards we will make dml-style id/seq links.
@@ -3381,22 +3385,22 @@ void DomainMapper_Impl::ChainTextFrames()
                 if( nextFinder != aTextFramesForChainingHelper.end() )
                 {
                     //if the frames have no name yet, then set them.  
LinkDisplayName / ChainName are read-only.
-                    if( !msoItem.second.bShapeNameSet )
+                    if (msoItem.second.shapeName.isEmpty())
                     {
                         uno::Reference< container::XNamed > xNamed( 
msoItem.second.xShape, uno::UNO_QUERY );
                         if ( xNamed.is() )
                         {
                             xNamed->setName( msoItem.first );
-                            msoItem.second.bShapeNameSet = true;
+                            msoItem.second.shapeName = msoItem.first;
                         }
                     }
-                    if( !nextFinder->second.bShapeNameSet )
+                    if (nextFinder->second.shapeName.isEmpty())
                     {
                         uno::Reference< container::XNamed > xNamed( 
nextFinder->second.xShape, uno::UNO_QUERY );
                         if ( xNamed.is() )
                         {
                             xNamed->setName( nextFinder->first );
-                            nextFinder->second.bShapeNameSet = true;
+                            nextFinder->second.shapeName = msoItem.first;
                         }
                     }
 
@@ -3404,7 +3408,7 @@ void DomainMapper_Impl::ChainTextFrames()
                     uno::Reference<beans::XPropertySet> 
xPropertySet(xTextContent, uno::UNO_QUERY);
 
                     //The reverse chaining happens automatically, so only one 
direction needs to be set
-                    xPropertySet->setPropertyValue(sChainNextName, 
uno::makeAny(nextFinder->first));
+                    xPropertySet->setPropertyValue(sChainNextName, 
uno::makeAny(nextFinder->second.shapeName));
 
                     //the last item in an mso-next-textbox chain is 
indistinguishable from id/seq items.  Now that it is handled, remove it.
                     if( nextFinder->second.s_mso_next_textbox.isEmpty() )
@@ -3417,26 +3421,23 @@ void DomainMapper_Impl::ChainTextFrames()
         const sal_Int32 nDirection = 1;
 
         //Finally - go through and attach the chains based on matching ID and 
incremented sequence number (dml-style).
-        for (const auto& rOuter : aTextFramesForChainingHelper)
+        for (const auto& rOuter : chainingWPS)
         {
-            if( rOuter.second.s_mso_next_textbox.isEmpty() )  //non-empty ones 
already handled earlier - so skipping them now.
-            {
-                for (const auto& rInner : aTextFramesForChainingHelper)
+                for (const auto& rInner : chainingWPS)
                 {
-                    if ( rInner.second.nId == rOuter.second.nId )
+                    if (rInner.nId == rOuter.nId)
                     {
-                        if ( rInner.second.nSeq == ( rOuter.second.nSeq + 
nDirection ) )
+                        if (rInner.nSeq == (rOuter.nSeq + nDirection))
                         {
-                            uno::Reference<text::XTextContent>  
xTextContent(rOuter.second.xShape, uno::UNO_QUERY_THROW);
+                            uno::Reference<text::XTextContent> const 
xTextContent(rOuter.xShape, uno::UNO_QUERY_THROW);
                             uno::Reference<beans::XPropertySet> 
xPropertySet(xTextContent, uno::UNO_QUERY);
 
                             //The reverse chaining happens automatically, so 
only one direction needs to be set
-                            xPropertySet->setPropertyValue(sChainNextName, 
uno::makeAny(rInner.first));
+                            xPropertySet->setPropertyValue(sChainNextName, 
uno::makeAny(rInner.shapeName));
                             break ; //there cannot be more than one next frame
                         }
                     }
                 }
-            }
         }
         m_vTextFramesForChaining.clear(); //clear the vector
     }
diff --git a/writerfilter/source/dmapper/GraphicImport.cxx 
b/writerfilter/source/dmapper/GraphicImport.cxx
index b69f4565fb13..ea369ae858fc 100644
--- a/writerfilter/source/dmapper/GraphicImport.cxx
+++ b/writerfilter/source/dmapper/GraphicImport.cxx
@@ -367,11 +367,12 @@ public:
     {
         try
         {
-            // Ask the graphic naming helper to find out the name for this
-            // object: It's around till the end of the import, so it remembers
-            // what's the first free name.
-            uno::Reference< container::XNamed > xNamed( 
xGraphicObjectProperties, uno::UNO_QUERY_THROW );
-            
xNamed->setName(rDomainMapper.GetGraphicNamingHelper().NameGraphic(sName));
+            if (!sName.isEmpty())
+            {
+                uno::Reference<container::XNamed> const 
xNamed(xGraphicObjectProperties, uno::UNO_QUERY_THROW);
+                xNamed->setName(sName);
+            }
+            // else: name is automatically generated by 
SwDoc::MakeFlySection_()
 
             if ( sHyperlinkURL.getLength() > 0 )
                 xGraphicObjectProperties->setPropertyValue(getPropertyName( 
PROP_HYPER_LINK_U_R_L ),
commit e4181b920d6916933f9b546a875677d0f5388e1e
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Jul 29 17:00:14 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Thu Aug 4 13:04:10 2022 +0200

    tdf#145226 sw: ODF export: fix table-row/table-cell styles
    
    The SwFrameFormat for table lines and table boxes gets an auto-generated
    name in SwDoc::MakeTableBoxFormat()/MakeTableLineFormat().
    
    The problem is that xmltble.cxx assumes that these SwFrameFormats never
    have a name, and sets names on them temporarily during
    exportTextAutoStyles(), then later reads them when exporting the
    table-rows and table-cells, then eventually resets them all to an empty
    name.
    
    One issue is that it assumes that a non-empty SwFrameFormat name
    indicates a style has been exported, but that isn't always the case, and
    the name may still be an auto-generated one.
    
    Another issue is that overwriting the names interferes with the use of
    the names in Undo operations.
    
    So store the name for the ODF styles in members of the filter classes
    instead of the core model.
    
    (regression from commit 083fe09958658de8c3da87a28e0f8ff7b3b8a5e9)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127548
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 5a9fe1d80ea977c439dd10ee2056abe6b0cb4d07)
    
    tdf#145226 sw: ODF export: fix table-row/table-cell style display-name
    Missed this attribute in commit 5a9fe1d80ea977c439dd10ee2056abe6b0cb4d07
    
    Change-Id: I9b17962decbf9f8ecd2a91551230cf0f012e7a9d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137765
    Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/sw/source/filter/xml/xmlexp.hxx b/sw/source/filter/xml/xmlexp.hxx
index 22e6a42368a7..a5abc5baf15f 100644
--- a/sw/source/filter/xml/xmlexp.hxx
+++ b/sw/source/filter/xml/xmlexp.hxx
@@ -23,6 +23,8 @@
 #include <xmloff/xmlexp.hxx>
 #include "xmlitmap.hxx"
 #include <xmloff/xmltoken.hxx>
+
+#include <optional>
 #include <vector>
 
 class SwDoc;
@@ -73,7 +75,8 @@ class SwXMLExport : public SvXMLExport
                                  SwXMLTableInfo_Impl& rTableInfo,
                                  bool bTop=false );
 
-    void ExportFormat( const SwFormat& rFormat,  enum 
::xmloff::token::XMLTokenEnum eClass );
+    void ExportFormat(const SwFormat& rFormat, enum 
::xmloff::token::XMLTokenEnum eClass,
+            ::std::optional<OUString> const oStyleName);
     void ExportTableFormat( const SwFrameFormat& rFormat, sal_uInt32 nAbsWidth 
);
 
     void ExportTableColumnStyle( const SwXMLTableColumn_Impl& rCol );
diff --git a/sw/source/filter/xml/xmlfmte.cxx b/sw/source/filter/xml/xmlfmte.cxx
index 209cdd5a3904..b7aa337eede3 100644
--- a/sw/source/filter/xml/xmlfmte.cxx
+++ b/sw/source/filter/xml/xmlfmte.cxx
@@ -46,7 +46,8 @@ using namespace ::com::sun::star::drawing;
 using namespace ::com::sun::star::lang;
 using namespace ::xmloff::token;
 
-void SwXMLExport::ExportFormat( const SwFormat& rFormat, enum XMLTokenEnum 
eFamily )
+void SwXMLExport::ExportFormat(const SwFormat& rFormat, enum XMLTokenEnum 
eFamily,
+        ::std::optional<OUString> const oStyleName)
 {
     // <style:style ...>
     CheckAttrList();
@@ -57,11 +58,14 @@ void SwXMLExport::ExportFormat( const SwFormat& rFormat, 
enum XMLTokenEnum eFami
         return;
     OSL_ENSURE( eFamily != XML_TOKEN_INVALID, "family must be specified" );
     // style:name="..."
+    assert(oStyleName || (eFamily != XML_TABLE_ROW && eFamily != 
XML_TABLE_CELL));
     bool bEncoded = false;
-    AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, EncodeStyleName(
-                    rFormat.GetName(), &bEncoded ) );
+    OUString const name(oStyleName ? *oStyleName : rFormat.GetName());
+    AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, EncodeStyleName(name, 
&bEncoded));
     if( bEncoded )
-        AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, rFormat.GetName() 
);
+    {
+        AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, name);
+    }
 
     if( eFamily != XML_TOKEN_INVALID )
         AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, eFamily );
diff --git a/sw/source/filter/xml/xmliteme.cxx 
b/sw/source/filter/xml/xmliteme.cxx
index b307a5c10872..8972bd14a51e 100644
--- a/sw/source/filter/xml/xmliteme.cxx
+++ b/sw/source/filter/xml/xmliteme.cxx
@@ -219,7 +219,7 @@ void SwXMLExport::ExportTableFormat( const SwFrameFormat& 
rFormat, sal_uInt32 nA
 {
     static_cast<SwXMLTableItemMapper_Impl *>(m_pTableItemMapper.get())
         ->SetAbsWidth( nAbsWidth );
-    ExportFormat( rFormat, XML_TABLE );
+    ExportFormat(rFormat, XML_TABLE, {});
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmltble.cxx b/sw/source/filter/xml/xmltble.cxx
index 6a4fa1c9902b..d840509ecdc0 100644
--- a/sw/source/filter/xml/xmltble.cxx
+++ b/sw/source/filter/xml/xmltble.cxx
@@ -179,13 +179,18 @@ class SwXMLTableFrameFormatsSort_Impl
 {
 private:
     SwXMLFrameFormats_Impl aFormatList;
+    SwXMLTextParagraphExport::FormatMap & m_rFormatMap;
+
 public:
-    bool AddRow( SwFrameFormat& rFrameFormat, const OUString& rNamePrefix, 
sal_uInt32 nLine );
-    bool AddCell( SwFrameFormat& rFrameFormat, const OUString& rNamePrefix,
+    SwXMLTableFrameFormatsSort_Impl(SwXMLTextParagraphExport::FormatMap & 
rFormatMap)
+        : m_rFormatMap(rFormatMap)
+    {}
+    ::std::optional<OUString> AddRow(SwFrameFormat& rFrameFormat, const 
OUString& rNamePrefix, sal_uInt32 nLine );
+    ::std::optional<OUString> AddCell(SwFrameFormat& rFrameFormat, const 
OUString& rNamePrefix,
                   sal_uInt32 nCol, sal_uInt32 nRow, bool bTop );
 };
 
-bool SwXMLTableFrameFormatsSort_Impl::AddRow( SwFrameFormat& rFrameFormat,
+::std::optional<OUString> 
SwXMLTableFrameFormatsSort_Impl::AddRow(SwFrameFormat& rFrameFormat,
                                          const OUString& rNamePrefix,
                                             sal_uInt32 nLine )
 {
@@ -206,10 +211,12 @@ bool SwXMLTableFrameFormatsSort_Impl::AddRow( 
SwFrameFormat& rFrameFormat,
 
     // empty styles have not to be exported
     if( !pFrameSize && !pBrush && !pRowSplit )
-        return false;
+    {
+        m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>()); // 
empty just to enable assert
+        return {};
+    }
 
     // order is: -/brush, size/-, size/brush
-    bool bInsert = true;
     SwXMLFrameFormats_Impl::iterator i;
     for( i = aFormatList.begin(); i < aFormatList.end(); ++i )
     {
@@ -272,19 +279,19 @@ bool SwXMLTableFrameFormatsSort_Impl::AddRow( 
SwFrameFormat& rFrameFormat,
             continue;
 
         // found!
-        rFrameFormat.SetName( pTestFormat->GetName() );
-        bInsert = false;
-        break;
+        auto const oName(m_rFormatMap.find(pTestFormat)->second);
+        assert(oName);
+        m_rFormatMap.emplace(&rFrameFormat, oName);
+        return {};
     }
 
-    if( bInsert )
     {
-        rFrameFormat.SetName( rNamePrefix + "." + OUString::number(nLine+1) );
+        OUString const name(rNamePrefix + "." + OUString::number(nLine+1));
+        m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>(name));
         if ( i != aFormatList.end() ) ++i;
         aFormatList.insert( i, &rFrameFormat );
+        return ::std::optional<OUString>(name);
     }
-
-    return bInsert;
 }
 
 static OUString lcl_xmltble_appendBoxPrefix(const OUString& rNamePrefix,
@@ -301,7 +308,7 @@ static OUString lcl_xmltble_appendBoxPrefix(const OUString& 
rNamePrefix,
         + "." + OUString::number(nRow + 1);
 }
 
-bool SwXMLTableFrameFormatsSort_Impl::AddCell( SwFrameFormat& rFrameFormat,
+::std::optional<OUString> 
SwXMLTableFrameFormatsSort_Impl::AddCell(SwFrameFormat& rFrameFormat,
                                          const OUString& rNamePrefix,
                                             sal_uInt32 nCol, sal_uInt32 nRow, 
bool bTop )
 {
@@ -336,7 +343,10 @@ bool SwXMLTableFrameFormatsSort_Impl::AddCell( 
SwFrameFormat& rFrameFormat,
 
     // empty styles have not to be exported
     if( !pVertOrient && !pBrush && !pBox && !pNumFormat && !pFrameDir && 
!pAttCnt )
-        return false;
+    {
+        m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>()); // 
empty just to enable assert
+        return {};
+    }
 
     // order is: -/-/-/num,
     //           -/-/box/-, -/-/box/num,
@@ -344,7 +354,6 @@ bool SwXMLTableFrameFormatsSort_Impl::AddCell( 
SwFrameFormat& rFrameFormat,
     //           vert/-/-/-, vert/-/-/num, vert/-/box/-, ver/-/box/num,
     //           vert/brush/-/-, vert/brush/-/num, vert/brush/box/-,
     //           vert/brush/box/num
-    bool bInsert = true;
     SwXMLFrameFormats_Impl::iterator i;
     for( i = aFormatList.begin(); i < aFormatList.end(); ++i )
     {
@@ -462,19 +471,19 @@ bool SwXMLTableFrameFormatsSort_Impl::AddCell( 
SwFrameFormat& rFrameFormat,
             continue;
 
         // found!
-        rFrameFormat.SetName( pTestFormat->GetName() );
-        bInsert = false;
-        break;
+        auto const oName(m_rFormatMap.find(pTestFormat)->second);
+        assert(oName);
+        m_rFormatMap.emplace(&rFrameFormat, oName);
+        return {};
     }
 
-    if( bInsert )
     {
-        rFrameFormat.SetName( lcl_xmltble_appendBoxPrefix( rNamePrefix, nCol, 
nRow, bTop ) );
+        OUString const name(lcl_xmltble_appendBoxPrefix(rNamePrefix, nCol, 
nRow, bTop));
+        m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>(name));
         if ( i != aFormatList.end() ) ++i;
         aFormatList.insert( i, &rFrameFormat );
+        return ::std::optional<OUString>(name);
     }
-
-    return bInsert;
 }
 
 class SwXMLTableInfo_Impl
@@ -483,10 +492,21 @@ class SwXMLTableInfo_Impl
     Reference<XTextSection> m_xBaseSection;
     bool m_bBaseSectionValid;
     sal_uInt32 const m_nPrefix;
+    SwXMLTextParagraphExport::FormatMap const& m_rLineFormats;
+    SwXMLTextParagraphExport::FormatMap const& m_rBoxFormats;
 
 public:
 
-    inline SwXMLTableInfo_Impl( const SwTable *pTable, sal_uInt16 nPrefix );
+    inline SwXMLTableInfo_Impl( const SwTable *pTable, sal_uInt16 nPrefix,
+            SwXMLTextParagraphExport::FormatMap const& rLineFormats,
+            SwXMLTextParagraphExport::FormatMap const& rBoxFormats)
+        : m_pTable(pTable)
+        , m_bBaseSectionValid(false)
+        , m_nPrefix(nPrefix)
+        , m_rLineFormats(rLineFormats)
+        , m_rBoxFormats(rBoxFormats)
+    {
+    }
 
     const SwTable *GetTable() const { return m_pTable; }
     const SwFrameFormat *GetTableFormat() const { return 
m_pTable->GetFrameFormat(); }
@@ -496,15 +516,10 @@ public:
     inline void SetBaseSection( const Reference < XTextSection >& rBase );
     /// The namespace (table or loext) that should be used for the elements.
     sal_uInt16 GetPrefix() const { return m_nPrefix; }
+    SwXMLTextParagraphExport::FormatMap const& GetLineFormats() const { return 
m_rLineFormats; }
+    SwXMLTextParagraphExport::FormatMap const& GetBoxFormats() const { return 
m_rBoxFormats; }
 };
 
-inline SwXMLTableInfo_Impl::SwXMLTableInfo_Impl(const SwTable *pTable, 
sal_uInt16 nPrefix) :
-    m_pTable(pTable),
-    m_bBaseSectionValid(false),
-    m_nPrefix(nPrefix)
-{
-}
-
 inline void SwXMLTableInfo_Impl::SetBaseSection(
         const Reference < XTextSection >& rBaseSection )
 {
@@ -638,8 +653,10 @@ void SwXMLExport::ExportTableLinesAutoStyles( const 
SwTableLines& rLines,
         SwTableLine *pLine = rLines[nLine];
 
         SwFrameFormat *pFrameFormat = pLine->GetFrameFormat();
-        if( rExpRows.AddRow( *pFrameFormat, rNamePrefix, nLine ) )
-            ExportFormat( *pFrameFormat, XML_TABLE_ROW );
+        if (auto oNew = rExpRows.AddRow(*pFrameFormat, rNamePrefix, nLine))
+        {
+            ExportFormat(*pFrameFormat, XML_TABLE_ROW, oNew);
+        }
 
         const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
         const size_t nBoxes = rBoxes.size();
@@ -666,9 +683,11 @@ void SwXMLExport::ExportTableLinesAutoStyles( const 
SwTableLines& rLines,
             if( pBoxSttNd )
             {
                 SwFrameFormat *pFrameFormat2 = pBox->GetFrameFormat();
-                if( rExpCells.AddCell( *pFrameFormat2, rNamePrefix, nOldCol, 
nLine,
+                if (auto oNew = rExpCells.AddCell(*pFrameFormat2, rNamePrefix, 
nOldCol, nLine,
                                        bTop) )
-                    ExportFormat( *pFrameFormat2, XML_TABLE_CELL );
+                {
+                    ExportFormat(*pFrameFormat2, XML_TABLE_CELL, oNew);
+                }
 
                 Reference < XCell > xCell = SwXCell::CreateXCell(
                                                 const_cast<SwFrameFormat 
*>(rTableInfo.GetTableFormat()),
@@ -714,8 +733,13 @@ void SwXMLExport::ExportTableLinesAutoStyles( const 
SwTableLines& rLines,
     }
 }
 
-void SwXMLExport::ExportTableAutoStyles( const SwTableNode& rTableNd )
+void SwXMLExport::ExportTableAutoStyles(const SwTableNode& rTableNd)
 {
+    auto & rFormats(static_cast<SwXMLTextParagraphExport 
*>(GetTextParagraphExport().get())->GetTableFormats());
+    auto const it(rFormats.find(&rTableNd));
+    assert(it != rFormats.end());
+    SwXMLTextParagraphExport::FormatMap & rRowFormats(it->second.first);
+    SwXMLTextParagraphExport::FormatMap & rBoxFormats(it->second.second);
     const SwTable& rTable = rTableNd.GetTable();
     const SwFrameFormat *pTableFormat = rTable.GetFrameFormat();
 
@@ -743,9 +767,9 @@ void SwXMLExport::ExportTableAutoStyles( const SwTableNode& 
rTableNd )
     ExportTableFormat( *pTableFormat, nAbsWidth );
 
     SwXMLTableColumnsSortByWidth_Impl aExpCols;
-    SwXMLTableFrameFormatsSort_Impl aExpRows;
-    SwXMLTableFrameFormatsSort_Impl aExpCells;
-    SwXMLTableInfo_Impl aTableInfo( &rTable, XML_NAMESPACE_TABLE );
+    SwXMLTableFrameFormatsSort_Impl aExpRows(rRowFormats);
+    SwXMLTableFrameFormatsSort_Impl aExpCells(rBoxFormats);
+    SwXMLTableInfo_Impl aTableInfo(&rTable, XML_NAMESPACE_TABLE, rRowFormats, 
rBoxFormats);
     ExportTableLinesAutoStyles( rTable.GetTabLines(), nAbsWidth, nBaseWidth,
                                 pTableFormat->GetName(), aExpCols, aExpRows, 
aExpCells,
                                 aTableInfo, true);
@@ -763,10 +787,12 @@ void SwXMLExport::ExportTableBox( const SwTableBox& rBox,
         const SwFrameFormat *pFrameFormat = rBox.GetFrameFormat();
         if( pFrameFormat )
         {
-            const OUString& sName = pFrameFormat->GetName();
-            if( !sName.isEmpty() )
+            auto const it(rTableInfo.GetBoxFormats().find(pFrameFormat));
+            assert(it != rTableInfo.GetBoxFormats().end());
+            if (it->second)
             {
-                AddAttribute( XML_NAMESPACE_TABLE, XML_STYLE_NAME, 
EncodeStyleName(sName) );
+                assert(!it->second->isEmpty());
+                AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, 
EncodeStyleName(*it->second));
             }
         }
     }
@@ -896,10 +922,12 @@ void SwXMLExport::ExportTableLine( const SwTableLine& 
rLine,
     const SwFrameFormat *pFrameFormat = rLine.GetFrameFormat();
     if( pFrameFormat )
     {
-        const OUString& sName = pFrameFormat->GetName();
-        if( !sName.isEmpty() )
+        auto const it(rTableInfo.GetLineFormats().find(pFrameFormat));
+        assert(it != rTableInfo.GetLineFormats().end());
+        if (it->second)
         {
-            AddAttribute( XML_NAMESPACE_TABLE, XML_STYLE_NAME, 
EncodeStyleName(sName) );
+            assert(!it->second->isEmpty());
+            AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, 
EncodeStyleName(*it->second));
         }
     }
 
@@ -1051,29 +1079,6 @@ void SwXMLExport::ExportTableLines( const SwTableLines& 
rLines,
     delete pLines;
 }
 
-static void lcl_xmltble_ClearName_Line( SwTableLine* pLine );
-
-static void lcl_xmltble_ClearName_Box( SwTableBox* pBox )
-{
-    if( !pBox->GetSttNd() )
-    {
-        for( SwTableLine* pLine : pBox->GetTabLines() )
-            lcl_xmltble_ClearName_Line( pLine );
-    }
-    else
-    {
-        SwFrameFormat *pFrameFormat = pBox->GetFrameFormat();
-        if( pFrameFormat && !pFrameFormat->GetName().isEmpty() )
-            pFrameFormat->SetName( OUString() );
-    }
-}
-
-void lcl_xmltble_ClearName_Line( SwTableLine* pLine )
-{
-    for( SwTableBox* pBox : pLine->GetTabBoxes() )
-        lcl_xmltble_ClearName_Box( pBox );
-}
-
 void SwXMLExport::ExportTable( const SwTableNode& rTableNd )
 {
     const SwTable& rTable = rTableNd.GetTable();
@@ -1132,15 +1137,16 @@ void SwXMLExport::ExportTable( const SwTableNode& 
rTableNd )
                                        XML_DDE_SOURCE, true, false);
         }
 
-        SwXMLTableInfo_Impl aTableInfo( &rTable, nPrefix );
+        auto const& rFormats(static_cast<SwXMLTextParagraphExport 
const*>(GetTextParagraphExport().get())->GetTableFormats());
+        auto const it(rFormats.find(&rTableNd));
+        assert(it != rFormats.end());
+        SwXMLTableInfo_Impl aTableInfo(&rTable, nPrefix, it->second.first, 
it->second.second);
         ExportTableLines( rTable.GetTabLines(), aTableInfo, 
rTable.GetRowsToRepeat() );
-
-        for( SwTableLine *pLine : const_cast<SwTable &>(rTable).GetTabLines() )
-            lcl_xmltble_ClearName_Line( pLine );
     }
 }
 
 void SwXMLTextParagraphExport::exportTableAutoStyles() {
+    // note: maTableNodes is used here only to keep the iteration order as 
before
     for (const auto* pTableNode : maTableNodes)
     {
         
static_cast<SwXMLExport&>(GetExport()).ExportTableAutoStyles(*pTableNode);
@@ -1187,6 +1193,7 @@ void SwXMLTextParagraphExport::exportTable(
                     && (bExportStyles || 
!pFormat->GetDoc()->IsInHeaderFooter(aIdx)))
                 {
                     maTableNodes.push_back(pTableNd);
+                    m_TableFormats.emplace(pTableNd, 
::std::make_pair(SwXMLTextParagraphExport::FormatMap(), 
SwXMLTextParagraphExport::FormatMap()));
                     // Collect all tables inside cells of this table, too
                     const auto aCellNames = pXTable->getCellNames();
                     for (const OUString& rCellName : aCellNames)
diff --git a/sw/source/filter/xml/xmltexte.hxx 
b/sw/source/filter/xml/xmltexte.hxx
index 4432e4ce0166..78e0271384c3 100644
--- a/sw/source/filter/xml/xmltexte.hxx
+++ b/sw/source/filter/xml/xmltexte.hxx
@@ -23,6 +23,9 @@
 #include <xmloff/txtparae.hxx>
 #include <tools/globname.hxx>
 
+#include <optional>
+#include <unordered_map>
+
 #define XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE "vnd.sun.star.GraphicObject:"
 
 class SwXMLExport;
@@ -41,6 +44,10 @@ class SwXMLTextParagraphExport : public 
XMLTextParagraphExport
 
     // Collected autostyles for use in exportTextAutoStyles
     std::vector<const SwTableNode*> maTableNodes;
+public:
+    typedef ::std::unordered_map<SwFrameFormat const*, 
::std::optional<OUString>> FormatMap;
+private:
+    ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, 
FormatMap>> m_TableFormats;
 
     static SwNoTextNode *GetNoTextNode(
         const css::uno::Reference < css::beans::XPropertySet >& rPropSet );
@@ -63,6 +70,11 @@ public:
         SwXMLExport& rExp,
          SvXMLAutoStylePoolP& rAutoStylePool );
     virtual ~SwXMLTextParagraphExport() override;
+
+    ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, 
FormatMap>> const&
+        GetTableFormats() const { return m_TableFormats; }
+    ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, 
FormatMap>> &
+        GetTableFormats()       { return m_TableFormats; }
 };
 
 #endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLTEXTE_HXX

Reply via email to