summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorumeshkadam <umesh.kadam@synerzip.com>2014-04-18 13:12:53 +0530
committerMiklos Vajna <vmiklos@collabora.co.uk>2014-04-22 12:09:40 +0200
commit255194801e9eb8e3aaede56837450af35f8313e0 (patch)
treeaa423243a383fc9236c0229ef87d468ac98dddf2
parentf12237c4c6239428b00dd4885a25bbc3b4f14368 (diff)
fod#77122 DOCX filter: link between textboxes is not being preserved
Added support for linked textboxes for docx interoperability. Reviewed on: https://gerrit.libreoffice.org/9092 Change-Id: I7db4f5a1783afff53c64908d182788b262f5e863
-rw-r--r--include/oox/drawingml/shape.hxx16
-rw-r--r--oox/source/drawingml/shape.cxx19
-rw-r--r--oox/source/shape/WpsContext.cxx35
-rw-r--r--oox/source/token/tokens.txt1
-rw-r--r--sw/qa/extras/ooxmlexport/data/LinkedTextBoxes.docxbin0 -> 63185 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport.cxx10
-rw-r--r--sw/source/filter/ww8/docxsdrexport.cxx75
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx103
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.hxx2
-rw-r--r--writerfilter/source/ooxml/OOXMLFastContextHandler.cxx3
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
new file mode 100644
index 000000000000..1c953c272848
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/LinkedTextBoxes.docx
Binary files differ
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;