diff options
-rw-r--r-- | include/oox/drawingml/shape.hxx | 16 | ||||
-rw-r--r-- | oox/source/drawingml/shape.cxx | 19 | ||||
-rw-r--r-- | oox/source/shape/WpsContext.cxx | 35 | ||||
-rw-r--r-- | oox/source/token/tokens.txt | 1 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/LinkedTextBoxes.docx | bin | 0 -> 63185 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport.cxx | 10 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxsdrexport.cxx | 75 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 103 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.hxx | 2 | ||||
-rw-r--r-- | writerfilter/source/ooxml/OOXMLFastContextHandler.cxx | 3 |
10 files changed, 250 insertions, 14 deletions
diff --git a/include/oox/drawingml/shape.hxx b/include/oox/drawingml/shape.hxx index a7232fa6870f..926f223ecd08 100644 --- a/include/oox/drawingml/shape.hxx +++ b/include/oox/drawingml/shape.hxx @@ -63,6 +63,15 @@ struct ChartShapeInfo explicit ChartShapeInfo( bool bEmbedShapes ) : mbEmbedShapes( bEmbedShapes ) {} }; +/// Attributes for a linked textbox. +struct LinkedTxbxAttr +{ + sal_Int32 id; + sal_Int32 seq; + LinkedTxbxAttr(): id(0),seq(0){}; + ~LinkedTxbxAttr(){}; +}; + class OOX_DLLPUBLIC Shape : public boost::enable_shared_from_this< Shape > { @@ -176,6 +185,11 @@ public: void setDiagramDoms(const com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& rDiagramDoms) { maDiagramDoms = rDiagramDoms; } com::sun::star::uno::Sequence< com::sun::star::uno::Sequence< com::sun::star::uno::Any > >resolveRelationshipsOfTypeFromOfficeDoc( core::XmlFilterBase& rFilter, const OUString& sFragment, const OUString& sType ); + void setLinkedTxbxAttributes(const LinkedTxbxAttr& rhs){ maLinkedTxbxAttr = rhs; }; + void setTxbxHasLinkedTxtBox( const bool rhs){ mbHasLinkedTxbx = rhs; }; + const LinkedTxbxAttr& getLinkedTxbxAttributes() { return maLinkedTxbxAttr; }; + bool isLinkedTxbx() { return mbHasLinkedTxbx; }; + protected: ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > @@ -279,6 +293,8 @@ private: // to propagate it when applying reference shape bool mbLockedCanvas; ///< Is this shape part of a locked canvas? bool mbWps; ///< Is this a wps shape? + LinkedTxbxAttr maLinkedTxbxAttr; + bool mbHasLinkedTxbx; // this text box has linked text box ? com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> maDiagramDoms; }; diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index f7150db048d1..1d0d4525801f 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -139,6 +139,8 @@ Shape::Shape( const ShapePtr& pSourceShape ) , mbHiddenMasterShape( pSourceShape->mbHiddenMasterShape ) , mbLockedCanvas( pSourceShape->mbLockedCanvas ) , mbWps( pSourceShape->mbWps ) +, maLinkedTxbxAttr() +, mbHasLinkedTxbx(false) , maDiagramDoms( pSourceShape->maDiagramDoms ) {} @@ -677,6 +679,23 @@ Reference< XShape > Shape::createAndInsert( aGrabBag[length].Value = uno::makeAny(mpCustomShapePropertiesPtr->getShapePresetTypeName()); propertySet->setPropertyValue("FrameInteropGrabBag",uno::makeAny(aGrabBag)); } + //If the text box has links then save the link information so that + //it can be accessed in DomainMapper_Impl.cxx while chaining the text frames. + if (this->isLinkedTxbx()) + { + uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> aGrabBag; + propertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag; + sal_Int32 length = aGrabBag.getLength(); + aGrabBag.realloc( length + 3 ); + aGrabBag[length].Name = "TxbxHasLink"; + aGrabBag[length].Value = uno::makeAny(this->isLinkedTxbx()); + aGrabBag[length + 1 ].Name = "Txbx-Id"; + aGrabBag[length + 1 ].Value = uno::makeAny(this->getLinkedTxbxAttributes().id); + aGrabBag[length + 2 ].Name = "Txbx-Seq"; + aGrabBag[length + 2 ].Value = uno::makeAny(this->getLinkedTxbxAttributes().seq); + propertySet->setPropertyValue("FrameInteropGrabBag",uno::makeAny(aGrabBag)); + } // TextFrames have BackColor, not FillColor if (aShapeProps.hasProperty(PROP_FillColor)) diff --git a/oox/source/shape/WpsContext.cxx b/oox/source/shape/WpsContext.cxx index c30992d316ac..57237095c5e6 100644 --- a/oox/source/shape/WpsContext.cxx +++ b/oox/source/shape/WpsContext.cxx @@ -109,9 +109,42 @@ oox::core::ContextHandlerRef WpsContext::onCreateContext(sal_Int32 nElementToken } break; case XML_txbx: + { mpShape->getCustomShapeProperties()->setShapeTypeOverride(true); mpShape->setServiceName("com.sun.star.text.TextFrame"); - break; + //in case if the textbox is linked, save the attributes + //for further processing. + if (rAttribs.hasAttribute(XML_id)) + { + OptValue<OUString> id = rAttribs.getString(XML_id); + if (id.has()) + { + oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr ; + linkedTxtBoxAttr.id = id.get().toInt32(); + mpShape->setTxbxHasLinkedTxtBox(true); + mpShape->setLinkedTxbxAttributes(linkedTxtBoxAttr); + } + } + } + break; + case XML_linkedTxbx: + { + //in case if the textbox is linked, save the attributes + //for further processing. + mpShape->getCustomShapeProperties()->setShapeTypeOverride(true); + mpShape->setServiceName("com.sun.star.text.TextFrame"); + OptValue<OUString> id = rAttribs.getString(XML_id); + OptValue<OUString> seq = rAttribs.getString(XML_seq); + if (id.has() && seq.has()) + { + oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr ; + linkedTxtBoxAttr.id = id.get().toInt32(); + linkedTxtBoxAttr.seq = seq.get().toInt32(); + mpShape->setTxbxHasLinkedTxtBox(true); + mpShape->setLinkedTxbxAttributes(linkedTxtBoxAttr); + } + } + break; default: SAL_WARN("oox", "WpsContext::createFastChildContext: unhandled element: " << getBaseToken(nElementToken)); break; diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt index e2740015a9b6..bab7cf1dc859 100644 --- a/oox/source/token/tokens.txt +++ b/oox/source/token/tokens.txt @@ -3074,6 +3074,7 @@ lines linesAndChars linestyle link +linkedTxbx linkStyles linkTarget linkToQuery diff --git a/sw/qa/extras/ooxmlexport/data/LinkedTextBoxes.docx b/sw/qa/extras/ooxmlexport/data/LinkedTextBoxes.docx Binary files differnew file mode 100644 index 000000000000..1c953c272848 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/LinkedTextBoxes.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx index a7ad9b7ef41b..00122ea7b3be 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx @@ -3087,6 +3087,16 @@ DECLARE_OOXMLEXPORT_TEST(testAuthorPropertySdt, "author-property.docx") // "xmlns:ns0='http://purl.org/dc/elements/1.1/' xmlns:ns1='http://schemas.openxmlformats.org/package/2006/metadata/core-properties'"); } +DECLARE_OOXMLEXPORT_TEST(testFDO77122, "LinkedTextBoxes.docx") +{ + xmlDocPtr pXmlDoc = parseExport("word/document.xml"); + if (!pXmlDoc) + return; + //ensure that the text box links are preserved. + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r[2]/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/a:graphic/a:graphicData[1]/wps:wsp[1]/wps:txbx[1]", "id", "1"); + assertXPath(pXmlDoc, "/w:document[1]/w:body[1]/w:p[1]/w:r[3]/mc:AlternateContent[1]/mc:Choice[1]/w:drawing[1]/wp:anchor[1]/a:graphic[1]/a:graphicData[1]/wps:wsp[1]/wps:linkedTxbx[1]", "id", "1"); +} + DECLARE_OOXMLEXPORT_TEST(testFDO76586, "fdo76586.docx") { /* diff --git a/sw/source/filter/ww8/docxsdrexport.cxx b/sw/source/filter/ww8/docxsdrexport.cxx index a2cb1092da11..da3c9e92769d 100644 --- a/sw/source/filter/ww8/docxsdrexport.cxx +++ b/sw/source/filter/ww8/docxsdrexport.cxx @@ -148,6 +148,8 @@ struct DocxSdrExport::Impl sax_fastparser::FastAttributeList* m_pBodyPrAttrList; sax_fastparser::FastAttributeList* m_pDashLineStyleAttr; bool m_bIsInDMLTextFrame; + sal_Int32 m_nId ; + sal_Int32 m_nSeq ; Impl(DocxSdrExport& rSdrExport, DocxExport& rExport, sax_fastparser::FSHelperPtr pSerializer, oox::drawingml::DrawingML* pDrawingML) : m_rSdrExport(rSdrExport), @@ -165,7 +167,9 @@ struct DocxSdrExport::Impl m_pFlyWrapAttrList(0), m_pBodyPrAttrList(0), m_pDashLineStyleAttr(0), - m_bIsInDMLTextFrame(false) + m_bIsInDMLTextFrame(false), + m_nId(0), + m_nSeq(0) { } @@ -1176,17 +1180,68 @@ void DocxSdrExport::writeDMLTextFrame(sw::Frame* pParentFrame, int nAnchorId) pFS->endElementNS(XML_wps, XML_spPr); m_pImpl->m_rExport.mpParentFrame = NULL; - pFS->startElementNS(XML_wps, XML_txbx, FSEND); - pFS->startElementNS(XML_w, XML_txbxContent, FSEND); + 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 sChainPrevName; + OUString sChainNextName; - m_pImpl->m_bFrameBtLr = checkFrameBtlr(m_pImpl->m_rExport.pDoc->GetNodes()[nStt], 0); - m_pImpl->m_bFlyFrameGraphic = true; - m_pImpl->m_rExport.WriteText(); - m_pImpl->m_bFlyFrameGraphic = false; - m_pImpl->m_bFrameBtLr = false; + xPropertySet->getPropertyValue("ChainPrevName") >>= sChainPrevName ; + xPropertySet->getPropertyValue("ChainNextName") >>= sChainNextName ; - pFS->endElementNS(XML_w, XML_txbxContent); - pFS->endElementNS(XML_wps, XML_txbx); + if (!sChainPrevName.isEmpty()) + { + /* 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()) + { + /* 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), + FSEND); + isTxbxLinked = true ; + } + } + + if (!skipTxBxContent) + { + if (!isTxbxLinked) + pFS->startElementNS(XML_wps, XML_txbx, FSEND);//text box is not linked, therefore no id. + + pFS->startElementNS(XML_w, XML_txbxContent, FSEND); + + m_pImpl->m_bFrameBtLr = checkFrameBtlr(m_pImpl->m_rExport.pDoc->GetNodes()[nStt], 0); + m_pImpl->m_bFlyFrameGraphic = true; + m_pImpl->m_rExport.WriteText(); + m_pImpl->m_bFlyFrameGraphic = false; + m_pImpl->m_bFrameBtLr = false; + + pFS->endElementNS(XML_w, XML_txbxContent); + pFS->endElementNS(XML_wps, XML_txbx); + } sax_fastparser::XFastAttributeListRef xBodyPrAttrList(m_pImpl->m_pBodyPrAttrList); m_pImpl->m_pBodyPrAttrList = NULL; pFS->startElementNS(XML_wps, XML_bodyPr, xBodyPrAttrList); diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 88bcabddb47a..434e9b082ab6 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -59,7 +59,7 @@ #include <com/sun/star/text/ControlCharacter.hpp> #include <com/sun/star/text/XTextColumns.hpp> #include <oox/mathml/import.hxx> - #include <GraphicHelpers.hxx> +#include <GraphicHelpers.hxx> #ifdef DEBUG_DOMAINMAPPER #include <resourcemodel/QNameToString.hxx> @@ -195,7 +195,8 @@ DomainMapper_Impl::DomainMapper_Impl( m_bHasFtnSep(false), m_bIgnoreNextPara(false), m_bIgnoreNextTab(false), - m_bFrameBtLr(false) + m_bFrameBtLr(false), + m_vTextFramesForChaining() { appendTableManager( ); @@ -221,6 +222,7 @@ DomainMapper_Impl::DomainMapper_Impl( DomainMapper_Impl::~DomainMapper_Impl() { + ChainTextFrames(); RemoveLastParagraph( ); getTableManager( ).endLevel(); popTableManager( ); @@ -1775,6 +1777,15 @@ void DomainMapper_Impl::PushShapeContext( const uno::Reference< drawing::XShape } if(checkBtLrStatus && checkZOredrStatus) break; + + if ( aGrabBag[i].Name == "TxbxHasLink" ) + { + //Chaining of textboxes will happen in ~DomainMapper_Impl + //i.e when all the textboxes are read and all its attributes + //have been set ( basically the Name/LinkedDisplayName ) + //which is set in Graphic Import. + m_vTextFramesForChaining.push_back(xShape); + } } uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY_THROW); @@ -2219,7 +2230,95 @@ void DomainMapper_Impl::SetNumberFormat( const OUString& rCommand, } } +static uno::Any lcl_getGrabBagValue( const uno::Sequence<beans::PropertyValue>& grabBag, OUString name ) +{ + for (int i = 0; i < grabBag.getLength(); ++i) + { + if (grabBag[i].Name == name ) + return grabBag[i].Value ; + } + return uno::Any(); +} + +//Link the text frames. +void DomainMapper_Impl::ChainTextFrames() +{ + if( 0 == m_vTextFramesForChaining.size() ) + return ; + + try + { + bool bIsTxbxChained = false ; + 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 + OUString sChainNextName("ChainNextName"); + OUString sChainPrevName("ChainPrevName"); + + for( std::vector<uno::Reference< drawing::XShape > >::iterator outer_itr = m_vTextFramesForChaining.begin(); + outer_itr != m_vTextFramesForChaining.end(); ) + { + bIsTxbxChained = false ; + uno::Reference<text::XTextContent> xTextContent1(*outer_itr, uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertySet> xPropertySet1(xTextContent1, uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> aGrabBag1; + xPropertySet1->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag1; + xPropertySet1->getPropertyValue("LinkDisplayName") >>= sName1; + + 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<uno::Reference< drawing::XShape > >::iterator inner_itr = ( outer_itr + 1 ); + for( ; inner_itr != m_vTextFramesForChaining.end(); ++inner_itr ) + { + uno::Reference<text::XTextContent> xTextContent2(*inner_itr, uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertySet> xPropertySet2(xTextContent2, uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> aGrabBag2; + xPropertySet2->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag2; + xPropertySet2->getPropertyValue("LinkDisplayName") >>= sName2; + + lcl_getGrabBagValue( aGrabBag2, "Txbx-Id") >>= nTxbxId2; + lcl_getGrabBagValue( aGrabBag2, "Txbx-Seq") >>= nTxbxSeq2; + if ( nTxbxId1 == nTxbxId2 ) + { + //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 ) )) + { + 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( 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 + } + catch (const uno::Exception& rException) + { + SAL_WARN("writerfilter", "failed. message: " << rException.Message); + } +} uno::Reference< beans::XPropertySet > DomainMapper_Impl::FindOrCreateFieldMaster( const sal_Char* pFieldMasterService, const OUString& rFieldMasterName ) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index a28636b3b667..842a13b3bb03 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -449,6 +449,7 @@ public: void StartParaMarkerChange( ); void EndParaMarkerChange( ); + void ChainTextFrames(); void RemoveLastParagraph( ); void SetIsLastParagraphInSection( bool bIsLast ); @@ -777,6 +778,7 @@ public: private: void PushPageHeaderFooter(bool bHeader, SectionPropertyMap::PageType eType); + std::vector<uno::Reference< drawing::XShape > > m_vTextFramesForChaining ; }; } //namespace dmapper } //namespace writerfilter diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx index 4f73da5584c9..a8ecda389d99 100644 --- a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx +++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx @@ -2193,7 +2193,8 @@ OOXMLFastContextHandlerShape::lcl_createFastChildContext // OOXMLFastContextHandlerWrapper::lcl_createFastChildContext(), here we // handle the WPS import of shape text, as there the parent context is a // Shape one, so a different situation. - if (Element == static_cast<sal_Int32>(NS_wps | OOXML_txbx)) + if (Element == static_cast<sal_Int32>(NS_wps | OOXML_txbx) || + Element == static_cast<sal_Int32>(NS_wps | OOXML_linkedTxbx) ) sendShape(Element); return xContextHandler; |