[Libreoffice-commits] core.git: Branch 'libreoffice-5-0' - sw/source

Justin Luth justin_luth at sil.org
Tue Jul 7 00:17:46 PDT 2015


 sw/source/filter/ww8/docxexport.cxx    |    8 ++
 sw/source/filter/ww8/docxsdrexport.cxx |   91 ++++++++++++++++++++++-----------
 sw/source/filter/ww8/wrtw8nds.cxx      |   63 ++++++++++++++++++++++
 sw/source/filter/ww8/wrtww8.cxx        |    3 +
 sw/source/filter/ww8/wrtww8.hxx        |   12 ++++
 5 files changed, 149 insertions(+), 28 deletions(-)

New commits:
commit 2a51dd6aca55a92d8751b67cdf7a5a6ab8c38237
Author: Justin Luth <justin_luth at sil.org>
Date:   Fri Jul 3 20:45:16 2015 +0300

    tdf#87348 enable docx exporting linked textboxes that LO can import
    
    Change-Id: I1f663e1a463919fc0662c94e03b801c7c58f1f5d
    Reviewed-on: https://gerrit.libreoffice.org/16745
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index 855be57..58d9d0b 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -453,6 +453,7 @@ void DocxExport::ExportDocument_Impl()
 
     WriteEmbeddings();
 
+    m_aLinkedTextboxesHelper.clear();   //final cleanup
     delete m_pStyles, m_pStyles = NULL;
     delete m_pSections, m_pSections = NULL;
 }
@@ -1314,6 +1315,10 @@ void DocxExport::WriteMainText()
     // setup the namespaces
     m_pDocumentFS->startElementNS( XML_w, XML_document, MainXmlNamespaces());
 
+    // reset the incrementing linked-textboxes chain ID before re-saving.
+    m_nLinkedTextboxesChainId=0;
+    m_aLinkedTextboxesHelper.clear();
+
     // Write background page color
     if (boost::optional<SvxBrushItem> oBrush = getBackground())
     {
@@ -1331,6 +1336,9 @@ void DocxExport::WriteMainText()
     // the text
     WriteText();
 
+    // clear linked textboxes since old ones can't be linked to frames in a different section (correct?)
+    m_aLinkedTextboxesHelper.clear();
+
     // the last section info
     m_pAttrOutput->EndParaSdtBlock();
     const WW8_SepInfo *pSectionInfo = m_pSections? m_pSections->CurrentSectionInfo(): NULL;
diff --git a/sw/source/filter/ww8/docxsdrexport.cxx b/sw/source/filter/ww8/docxsdrexport.cxx
index 13c7bd0..c6207a5 100644
--- a/sw/source/filter/ww8/docxsdrexport.cxx
+++ b/sw/source/filter/ww8/docxsdrexport.cxx
@@ -144,8 +144,6 @@ struct DocxSdrExport::Impl
     sax_fastparser::FastAttributeList* m_pFlyWrapAttrList;
     sax_fastparser::FastAttributeList* m_pBodyPrAttrList;
     std::unique_ptr<sax_fastparser::FastAttributeList> m_pDashLineStyleAttr;
-    sal_Int32 m_nId ;
-    sal_Int32 m_nSeq ;
     bool m_bDMLAndVMLDrawingOpen;
     /// List of TextBoxes in this document: they are exported as part of their shape, never alone.
     std::set<const SwFrameFormat*> m_aTextBoxes;
@@ -167,8 +165,6 @@ struct DocxSdrExport::Impl
           m_bFlyFrameGraphic(false),
           m_pFlyWrapAttrList(0),
           m_pBodyPrAttrList(0),
-          m_nId(0),
-          m_nSeq(0),
           m_bDMLAndVMLDrawingOpen(false),
           m_aTextBoxes(SwTextBoxHelper::findTextBoxes(m_rExport.m_pDoc)),
           m_nDMLandVMLTextFrameRotation(0)
@@ -1476,48 +1472,87 @@ void DocxSdrExport::writeDMLTextFrame(sw::Frame* pParentFrame, int nAnchorId, bo
         pFS->endElementNS(XML_wps, XML_spPr);
     }
 
+    //first, loop through ALL of the chained textboxes to identify a unique ID for each chain, and sequence number for each textbox in that chain.
+    std::map<OUString, MSWordExportBase::LinkedTextboxInfo>::iterator linkedTextboxesIter;
+    if( !m_pImpl->m_rExport.m_bLinkedTextboxesHelperInitialized )
+    {
+        sal_Int32 nSeq=0;
+        linkedTextboxesIter = m_pImpl->m_rExport.m_aLinkedTextboxesHelper.begin();
+        while ( linkedTextboxesIter != m_pImpl->m_rExport.m_aLinkedTextboxesHelper.end() )
+        {
+            //find the start of a textbox chain: has no PREVIOUS link, but does have NEXT link
+            if ( linkedTextboxesIter->second.sPrevChain.isEmpty() && !linkedTextboxesIter->second.sNextChain.isEmpty() )
+            {
+                //assign this chain a unique ID and start a new sequence
+                nSeq = 0;
+                linkedTextboxesIter->second.nId = ++m_pImpl->m_rExport.m_nLinkedTextboxesChainId;
+                linkedTextboxesIter->second.nSeq = nSeq;
+
+                OUString sCheckForBrokenChains = linkedTextboxesIter->first;
+
+                //follow the chain and assign the same id, and incremental sequence numbers.
+                std::map<OUString, MSWordExportBase::LinkedTextboxInfo>::iterator  followChainIter;
+                followChainIter = m_pImpl->m_rExport.m_aLinkedTextboxesHelper.find(linkedTextboxesIter->second.sNextChain);
+                while ( followChainIter != m_pImpl->m_rExport.m_aLinkedTextboxesHelper.end() )
+                {
+                    //verify that the NEXT textbox also points to me as the PREVIOUS.
+                    // A broken link indicates a leftover remnant that can be ignored.
+                    if( followChainIter->second.sPrevChain != sCheckForBrokenChains )
+                        break;
+
+                    followChainIter->second.nId = m_pImpl->m_rExport.m_nLinkedTextboxesChainId;
+                    followChainIter->second.nSeq = ++nSeq;
+
+                    //empty next chain indicates the end of the linked chain.
+                    if ( followChainIter->second.sNextChain.isEmpty() )
+                        break;
+
+                    sCheckForBrokenChains = followChainIter->first;
+                    followChainIter = m_pImpl->m_rExport.m_aLinkedTextboxesHelper.find(followChainIter->second.sNextChain);
+                }
+            }
+            ++linkedTextboxesIter;
+        }
+        m_pImpl->m_rExport.m_bLinkedTextboxesHelperInitialized = true;
+    }
+
     m_pImpl->m_rExport.m_pParentFrame = NULL;
     bool skipTxBxContent = false ;
     bool isTxbxLinked = false ;
 
-    /* Check if the text box is linked and then decides whether
-       to write the tag txbx or linkedTxbx
-    */
-    if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("ChainPrevName") &&
-            xPropSetInfo->hasPropertyByName("ChainNextName"))
+    OUString sLinkChainName;
+    if ( xPropSetInfo.is() )
     {
-        OUString sChainPrevName;
-        OUString sChainNextName;
-
-        xPropertySet->getPropertyValue("ChainPrevName") >>= sChainPrevName ;
-        xPropertySet->getPropertyValue("ChainNextName") >>= sChainNextName ;
+        if ( xPropSetInfo->hasPropertyByName("LinkDisplayName") )
+            xPropertySet->getPropertyValue("LinkDisplayName") >>= sLinkChainName;
+        else if ( xPropSetInfo->hasPropertyByName("ChainName") )
+            xPropertySet->getPropertyValue("ChainName") >>= sLinkChainName;
+    }
 
-        if (!sChainPrevName.isEmpty())
+    // second, check if THIS textbox is linked and then decide whether to write the tag txbx or linkedTxbx
+    linkedTextboxesIter = m_pImpl->m_rExport.m_aLinkedTextboxesHelper.find(sLinkChainName);
+    if ( linkedTextboxesIter != m_pImpl->m_rExport.m_aLinkedTextboxesHelper.end() )
+    {
+        if( (linkedTextboxesIter->second.nId !=0) && (linkedTextboxesIter->second.nSeq != 0) )
         {
+            //not the first in the chain, so write the tag as linkedTxbx
+            pFS->singleElementNS(XML_wps, XML_linkedTxbx,
+                                 XML_id,  I32S(linkedTextboxesIter->second.nId),
+                                 XML_seq, I32S(linkedTextboxesIter->second.nSeq),
+                                 FSEND);
             /* no text content should be added to this tag,
                since the textbox is linked, the entire content
                is written in txbx block
             */
-            ++m_pImpl->m_nSeq ;
-            pFS->singleElementNS(XML_wps, XML_linkedTxbx,
-                                 XML_id,  I32S(m_pImpl->m_nId),
-                                 XML_seq, I32S(m_pImpl->m_nSeq),
-                                 FSEND);
             skipTxBxContent = true ;
-
-            //Text box chaining for a group of textboxes ends here,
-            //therefore reset the seq.
-            if (sChainNextName.isEmpty())
-                m_pImpl->m_nSeq = 0 ;
         }
-        else if (sChainPrevName.isEmpty() && !sChainNextName.isEmpty())
+        else if( (linkedTextboxesIter->second.nId != 0) && (linkedTextboxesIter->second.nSeq == 0) )
         {
             /* this is the first textbox in the chaining, we add the text content
                to this block*/
-            ++m_pImpl->m_nId ;
             //since the text box is linked, it needs an id.
             pFS->startElementNS(XML_wps, XML_txbx,
-                                XML_id, I32S(m_pImpl->m_nId),
+                                XML_id,  I32S(linkedTextboxesIter->second.nId),
                                 FSEND);
             isTxbxLinked = true ;
         }
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index a3779e4..ac7d9c3 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -562,6 +562,69 @@ bool SwWW8AttrIter::IsAnchorLinkedToThisNode( sal_uLong nNodePos )
 
 FlyProcessingState SwWW8AttrIter::OutFlys(sal_Int32 nSwPos)
 {
+    // collection point to first gather info about all of the potentially linked textboxes: to be analyzed later.
+    OUString sLinkChainName;
+    sw::FrameIter linkedTextboxesIter = maFlyIter;
+    while ( linkedTextboxesIter != maFlyFrms.end() )
+    {
+        uno::Reference< drawing::XShape > xShape;
+        sw::Frame xFrame = *linkedTextboxesIter;
+        const SdrObject* pSdrObj = xFrame.GetFrameFormat().FindRealSdrObject();
+        if( pSdrObj )
+            xShape = uno::Reference< drawing::XShape >(const_cast<SdrObject*>(pSdrObj)->getUnoShape(), uno::UNO_QUERY);
+        uno::Reference< beans::XPropertySet > xPropertySet(xShape, uno::UNO_QUERY);
+        uno::Reference< beans::XPropertySetInfo > xPropertySetInfo;
+        if( xPropertySet.is() )
+            xPropertySetInfo = xPropertySet->getPropertySetInfo();
+        if( xPropertySetInfo.is() )
+        {
+            MSWordExportBase::LinkedTextboxInfo aLinkedTextboxInfo = MSWordExportBase::LinkedTextboxInfo();
+
+            if( xPropertySetInfo->hasPropertyByName("LinkDisplayName") )
+                xPropertySet->getPropertyValue("LinkDisplayName") >>= sLinkChainName;
+            else if( xPropertySetInfo->hasPropertyByName("ChainName") )
+                xPropertySet->getPropertyValue("ChainName") >>= sLinkChainName;
+
+            if( xPropertySetInfo->hasPropertyByName("ChainNextName") )
+                xPropertySet->getPropertyValue("ChainNextName") >>= aLinkedTextboxInfo.sNextChain;
+            if( xPropertySetInfo->hasPropertyByName("ChainPrevName") )
+                xPropertySet->getPropertyValue("ChainPrevName") >>= aLinkedTextboxInfo.sPrevChain;
+
+            //collect a list of linked textboxes: those with a NEXT or PREVIOUS link
+            if( !aLinkedTextboxInfo.sNextChain.isEmpty() || !aLinkedTextboxInfo.sPrevChain.isEmpty() )
+            {
+                assert( !sLinkChainName.isEmpty() );
+
+                //there are many discarded duplicates in documents - no duplicates allowed in the list, so try to find the real one.
+                //if this LinkDisplayName/ChainName already exists on a different shape...
+                //  the earlier processed duplicates are thrown out unless this one can be proved as bad. (last processed duplicate usually is stored)
+                std::map<OUString,MSWordExportBase::LinkedTextboxInfo>::iterator linkFinder;
+                linkFinder = m_rExport.m_aLinkedTextboxesHelper.find(sLinkChainName);
+                if( linkFinder != m_rExport.m_aLinkedTextboxesHelper.end() )
+                {
+                    //If my NEXT/PREV targets have already been discovered, but don't match me, then assume I'm an abandoned remnant
+                    //    (this logic fails if both me and one of my links are duplicated, and the remnants were added first.)
+                    linkFinder = m_rExport.m_aLinkedTextboxesHelper.find(aLinkedTextboxInfo.sNextChain);
+                    if( (linkFinder != m_rExport.m_aLinkedTextboxesHelper.end()) && (linkFinder->second.sPrevChain != sLinkChainName) )
+                    {
+                        ++linkedTextboxesIter;
+                        break;
+                    }
+
+                    linkFinder = m_rExport.m_aLinkedTextboxesHelper.find(aLinkedTextboxInfo.sPrevChain);
+                    if( (linkFinder != m_rExport.m_aLinkedTextboxesHelper.end()) && (linkFinder->second.sNextChain != sLinkChainName) )
+                    {
+                        ++linkedTextboxesIter;
+                        break;
+                    }
+                }
+                m_rExport.m_bLinkedTextboxesHelperInitialized = false;
+                m_rExport.m_aLinkedTextboxesHelper[sLinkChainName] = aLinkedTextboxInfo;
+            }
+        }
+        ++linkedTextboxesIter;
+    }
+
     /*
      #i2916#
      May have an anchored graphic to be placed, loop through sorted array
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index 01a95cf..bbf819a 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -1728,6 +1728,9 @@ void MSWordExportBase::WriteSpecialText( sal_uLong nStart, sal_uLong nEnd, sal_u
                                     // bOutKF was setted / stored in WriteKF1
     SetCurPam(nStart, nEnd);
 
+    // clear linked textboxes since old ones can't be linked to frames in this section
+    m_aLinkedTextboxesHelper.clear();
+
     WriteText();
 
     m_bOutPageDescs = bOldPageDescs;
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 957ab28..d2cb89d 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -497,6 +497,18 @@ public:
     WW8_WrPlcAnnotations* m_pAtn;
     WW8_WrPlcTextBoxes *m_pTextBxs, *m_pHFTextBxs;
 
+    struct LinkedTextboxInfo        //help analyze textbox flow links
+    {
+        sal_Int32 nId;
+        sal_Int32 nSeq;
+        OUString sNextChain;
+        OUString sPrevChain;
+        LinkedTextboxInfo(): nId(0), nSeq(0) {}
+    };
+    std::map<OUString,LinkedTextboxInfo> m_aLinkedTextboxesHelper;
+    bool m_bLinkedTextboxesHelperInitialized = false;
+    sal_Int32 m_nLinkedTextboxesChainId=0;
+
     const sw::Frame *m_pParentFrame; // If set we are exporting content inside
                                     // a frame, e.g. a graphic node
 


More information about the Libreoffice-commits mailing list