From 976add10b35e482251ed4c75957baeb6811e6e2c Mon Sep 17 00:00:00 2001 From: Justin Luth Date: Thu, 18 Jun 2015 09:40:29 +0300 Subject: tdf#87348 allow non-sequentially processed textboxes to be linked The existing code design ONLY allowed textboxes to be linked if they were basically processed sequentially or reverse sequentially. It appears that the processing is actually based on the order that the textboxes were created, which is usually sequential but not necessarily. Change-Id: Ieb7b37d4cbd4b3a5b5d474803abccfa198a5864b Reviewed-on: https://gerrit.libreoffice.org/16353 Tested-by: Jenkins Reviewed-by: Justin Luth Reviewed-by: Miklos Vajna --- writerfilter/source/dmapper/DomainMapper_Impl.cxx | 114 +++++++++------------- 1 file changed, 48 insertions(+), 66 deletions(-) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index ff6ce1d8b3bf..38a4c075b116 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -2449,91 +2449,73 @@ static uno::Any lcl_getGrabBagValue( const uno::Sequence& //Link the text frames. void DomainMapper_Impl::ChainTextFrames() { - if( 0 == m_vTextFramesForChaining.size() ) + //can't link textboxes if there are not even two of them... + if( 2 > m_vTextFramesForChaining.size() ) return ; + struct TextFramesForChaining { + css::uno::Reference< css::drawing::XShape > xShape; + sal_Int32 nId; + sal_Int32 nSeq; + TextFramesForChaining(): xShape(0), nId(0), nSeq(0) {} + } ; + typedef std::map ChainMap; + try { - sal_Int32 nTxbxId1 = 0 ; //holds id for the shape in outer loop - sal_Int32 nTxbxId2 = 0 ; //holds id for the shape in inner loop - sal_Int32 nTxbxSeq1 = 0 ; //holds seq number for the shape in outer loop - sal_Int32 nTxbxSeq2 = 0 ; //holds seq number for the shape in inner loop - OUString sName1 ; //holds the text box Name for the shape in outer loop - OUString sName2 ; //holds the text box Name for the shape in outer loop + ChainMap aTextFramesForChainingHelper; OUString sChainNextName("ChainNextName"); - OUString sChainPrevName("ChainPrevName"); - for( std::vector >::iterator outer_itr = m_vTextFramesForChaining.begin(); - outer_itr != m_vTextFramesForChaining.end(); ) + //learn about ALL of the textboxes and their chaining values first - because frames are processed in no specific order. + std::vector >::iterator iter; + for( iter = m_vTextFramesForChaining.begin(); iter != m_vTextFramesForChaining.end(); ++iter ) { - bool bIsTxbxChained = false ; - uno::Reference xTextContent1(*outer_itr, uno::UNO_QUERY_THROW); - uno::Reference xPropertySet1(xTextContent1, uno::UNO_QUERY); - uno::Sequence aGrabBag1; - uno::Reference xServiceInfo1(xPropertySet1, uno::UNO_QUERY); - if (xServiceInfo1->supportsService("com.sun.star.text.TextFrame")) + uno::Reference xTextContent(*iter, uno::UNO_QUERY_THROW); + uno::Reference xPropertySet(xTextContent, uno::UNO_QUERY); + uno::Sequence aGrabBag; + uno::Reference xServiceInfo(xPropertySet, uno::UNO_QUERY); + + TextFramesForChaining aChainStruct = TextFramesForChaining(); + OUString sShapeName; + + if ( xServiceInfo->supportsService("com.sun.star.text.TextFrame") ) { - xPropertySet1->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag1; - xPropertySet1->getPropertyValue("LinkDisplayName") >>= sName1; + xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag; + xPropertySet->getPropertyValue("LinkDisplayName") >>= sShapeName; } else { - xPropertySet1->getPropertyValue("InteropGrabBag") >>= aGrabBag1; - xPropertySet1->getPropertyValue("ChainName") >>= sName1; + xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag; + xPropertySet->getPropertyValue("ChainName") >>= sShapeName; } - lcl_getGrabBagValue( aGrabBag1, "Txbx-Id") >>= nTxbxId1; - lcl_getGrabBagValue( aGrabBag1, "Txbx-Seq") >>= nTxbxSeq1; - - //Check which text box in the document links/(is a link) to this one. - std::vector >::iterator inner_itr = ( outer_itr + 1 ); - for( ; inner_itr != m_vTextFramesForChaining.end(); ++inner_itr ) - { - uno::Reference xTextContent2(*inner_itr, uno::UNO_QUERY_THROW); - uno::Reference xPropertySet2(xTextContent2, uno::UNO_QUERY); - uno::Sequence aGrabBag2; - uno::Reference xServiceInfo2(xPropertySet1, uno::UNO_QUERY); - if (xServiceInfo2->supportsService("com.sun.star.text.TextFrame")) - { - xPropertySet2->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag2; - xPropertySet2->getPropertyValue("LinkDisplayName") >>= sName2; - } - else - { - xPropertySet2->getPropertyValue("InteropGrabBag") >>= aGrabBag2; - xPropertySet2->getPropertyValue("ChainName") >>= sName2; - } + lcl_getGrabBagValue( aGrabBag, "Txbx-Id") >>= aChainStruct.nId; + lcl_getGrabBagValue( aGrabBag, "Txbx-Seq") >>= aChainStruct.nSeq; + aChainStruct.xShape = *iter; + aTextFramesForChainingHelper[sShapeName] = aChainStruct; + } - lcl_getGrabBagValue( aGrabBag2, "Txbx-Id") >>= nTxbxId2; - lcl_getGrabBagValue( aGrabBag2, "Txbx-Seq") >>= nTxbxSeq2; + //TODO: Perhaps allow reverse sequences when mso-layout-flow-alt = "bottom-to-top" + const sal_Int32 nDirection = 1; - if ( nTxbxId1 == nTxbxId2 ) + //Finally - go through and attach the chains based on matching ID and incremented sequence number (dml-style). + for (ChainMap::iterator outer_iter= aTextFramesForChainingHelper.begin(); outer_iter != aTextFramesForChainingHelper.end(); ++outer_iter) + { + for (ChainMap::iterator inner_iter=aTextFramesForChainingHelper.begin(); inner_iter != aTextFramesForChainingHelper.end(); ++inner_iter) { - //who connects whom ?? - if ( nTxbxSeq1 == ( nTxbxSeq2 + 1 ) ) - { - xPropertySet2->setPropertyValue(sChainNextName, uno::makeAny(sName1)); - xPropertySet1->setPropertyValue(sChainPrevName, uno::makeAny(sName2)); - bIsTxbxChained = true ; - break ; //there cannot be more than one previous/next frames - } - else if ( nTxbxSeq2 == ( nTxbxSeq1 + 1 ) ) + if ( inner_iter->second.nId == outer_iter->second.nId ) { - xPropertySet1->setPropertyValue(sChainNextName, uno::makeAny(sName2)); - xPropertySet2->setPropertyValue(sChainPrevName, uno::makeAny(sName1)); - bIsTxbxChained = true ; - break ; //there cannot be more than one previous/next frames + if ( inner_iter->second.nSeq == ( outer_iter->second.nSeq + nDirection ) ) + { + uno::Reference xTextContent(outer_iter->second.xShape, uno::UNO_QUERY_THROW); + uno::Reference xPropertySet(xTextContent, uno::UNO_QUERY); + + //The reverse chaining happens automatically, so only one direction needs to be set + xPropertySet->setPropertyValue(sChainNextName, uno::makeAny(inner_iter->first)); + break ; //there cannot be more than one next frame + } } } - } - if( bIsTxbxChained ) - { - //This txt box is no longer needed for chaining since - //there cannot be more than one previous/next frames - outer_itr = m_vTextFramesForChaining.erase(outer_itr); - } - else - ++outer_itr ; } m_vTextFramesForChaining.clear(); //clear the vector } -- cgit v1.2.3