summaryrefslogtreecommitdiff
path: root/sw/source/filter/ww8/docxattributeoutput.cxx
diff options
context:
space:
mode:
authorTamás Zolnai <tamas.zolnai@collabora.com>2017-11-04 16:26:23 +0100
committerTamás Zolnai <tamas.zolnai@collabora.com>2017-11-04 19:11:00 +0100
commit98bc7215935f1eb2e0dc6f1db826d8e729430c13 (patch)
tree677dc15a3800537b25738b35f0dac82a54e5bc9e /sw/source/filter/ww8/docxattributeoutput.cxx
parentffb5ad4681f7f68b3b50dc4d94ea7ea8127da5e0 (diff)
tdf#42346: DOCX export of cross-references to objects
* Objects means tables, images, text frames and shapes * Implementation ** MSO uses simple bookmark references as cross-references to objects ** So generate bookmarks in export time if a caption is referenced ** In some cases we also need to split some of the runs ** Implemented all types of cross-references, except the chapter reference Change-Id: I3b17753123d94a04e4f28783ad5663831e7c6c84 Reviewed-on: https://gerrit.libreoffice.org/44294 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tamás Zolnai <tamas.zolnai@collabora.com>
Diffstat (limited to 'sw/source/filter/ww8/docxattributeoutput.cxx')
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx216
1 files changed, 215 insertions, 1 deletions
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 57e182dc34ac..4bf1b1c3dc27 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -125,6 +125,8 @@
#include <IDocumentSettingAccess.hxx>
#include <IDocumentStylePoolAccess.hxx>
#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <reffld.hxx>
#include <osl/file.hxx>
#include <vcl/embeddedfontshelper.hxx>
@@ -594,6 +596,10 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
if( !m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen() )
m_bParagraphOpened = false;
+ // Clear gererated bookmarks
+ m_aBookmarksWithPosStart.clear();
+ m_aBookmarksWithPosEnd.clear();
+
}
void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken,
@@ -1278,6 +1284,8 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos)
m_endPageRef = true;
}
+ DoWriteBookmarkStartIfExist(nPos);
+
m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
if(GetExport().m_bTabInTOC && m_pHyperlinkAttrList.is())
{
@@ -1377,6 +1385,8 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos)
}
m_nFieldsInHyperlink = 0;
}
+
+ DoWriteBookmarkEndIfExist(nPos);
}
void DocxAttributeOutput::DoWriteBookmarkTagStart(const OUString & bookmarkName)
@@ -1404,6 +1414,34 @@ void DocxAttributeOutput::DoWriteBookmarkTagEnd(const OUString & bookmarkName)
}
}
+void DocxAttributeOutput::DoWriteBookmarkStartIfExist(sal_Int32 nPos)
+{
+ auto aRange = m_aBookmarksWithPosStart.equal_range(nPos);
+ for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
+ {
+ DoWriteBookmarkTagStart(aIter->second);
+ m_rOpenedBookmarksIds[aIter->second] = m_nNextBookmarkId;
+ m_sLastOpenedBookmark = OUStringToOString(BookmarkToWord(aIter->second), RTL_TEXTENCODING_UTF8).getStr();
+ m_nNextBookmarkId++;
+ }
+}
+
+void DocxAttributeOutput::DoWriteBookmarkEndIfExist(sal_Int32 nPos)
+{
+ auto aRange = m_aBookmarksWithPosEnd.equal_range(nPos);
+ for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
+ {
+ // Get the id of the bookmark
+ auto pPos = m_rOpenedBookmarksIds.find(aIter->second);
+ if (pPos != m_rOpenedBookmarksIds.end())
+ {
+ // Output the bookmark
+ DoWriteBookmarkTagEnd(aIter->second);
+ m_rOpenedBookmarksIds.erase(aIter->second);
+ }
+ }
+}
+
/// Write the start bookmarks
void DocxAttributeOutput::DoWriteBookmarksStart()
{
@@ -1662,7 +1700,7 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
else
{
// Write the field start
- if ( rInfos.pField && rInfos.pField->GetSubType() & FIXEDFLD )
+ if ( rInfos.pField && (rInfos.pField->Which() == SwFieldIds::DateTime) && rInfos.pField->GetSubType() & FIXEDFLD )
{
m_pSerializer->startElementNS( XML_w, XML_fldChar,
FSNS( XML_w, XML_fldCharType ), "begin",
@@ -7143,6 +7181,176 @@ bool DocxAttributeOutput::PlaceholderField( const SwField* pField )
return false; // do not expand
}
+void DocxAttributeOutput::GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter)
+{
+ if (const SwpHints* pTextAttrs = rNode.GetpSwpHints())
+ {
+ for( size_t i = 0; i < pTextAttrs->Count(); ++i )
+ {
+ const SwTextAttr* pHt = pTextAttrs->Get(i);
+ if (pHt->GetAttr().Which() == RES_TXTATR_FIELD)
+ {
+ const SwFormatField& rField = static_cast<const SwFormatField&>(pHt->GetAttr());
+ const SwField* pField = rField.GetField();
+ // Need to have bookmarks only for sequence fields
+ if (pField && pField->GetTyp()->Which() == SwFieldIds::SetExp && pField->GetSubType() == nsSwGetSetExpType::GSE_SEQ)
+ {
+ const sal_uInt16 nSeqFieldNumber = static_cast<const SwSetExpField*>(pField)->GetSeqNumber();
+ const OUString sObjectName = static_cast<const SwSetExpFieldType*>(pField->GetTyp())->GetName();
+ const SwFieldTypes* pFieldTypes = m_rExport.m_pDoc->getIDocumentFieldsAccess().GetFieldTypes();
+ bool bHaveFullBkm = false;
+ bool bHaveLabelAndNumberBkm = false;
+ bool bHaveCaptionOnlyBkm = false;
+ bool bHaveNumberOnlyBkm = false;
+ bool bRunSplittedAtSep = false;
+ for( auto pFieldType : *pFieldTypes )
+ {
+ if( SwFieldIds::GetRef == pFieldType->Which() )
+ {
+ SwIterator<SwFormatField,SwFieldType> aIter( *pFieldType );
+ for( SwFormatField* pFormatField = aIter.First(); pFormatField; pFormatField = aIter.Next() )
+ {
+ SwGetRefField* pRefField = static_cast<SwGetRefField*>(pFormatField->GetField());
+ // If we have a reference to the current sequence field
+ if(pRefField->GetSeqNo() == nSeqFieldNumber && pRefField->GetSetRefName() == sObjectName)
+ {
+ // Need to create a seperate run for separator character
+ SwWW8AttrIter aLocalAttrIter( m_rExport, rNode );
+ const OUString aText = rNode.GetText();
+ const sal_Int32 nCategoryStart = aText.indexOf(pRefField->GetSetRefName());
+ const sal_Int32 nPosBeforeSeparator = std::max(nCategoryStart, pHt->GetStart());
+ bool bCategoryFirst = nCategoryStart < pHt->GetStart();
+ sal_Int32 nSeparatorPos = 0;
+ if (bCategoryFirst)
+ {
+ nSeparatorPos = aLocalAttrIter.WhereNext();
+ while (nSeparatorPos <= nPosBeforeSeparator)
+ {
+ aLocalAttrIter.NextPos();
+ nSeparatorPos = aLocalAttrIter.WhereNext();
+ }
+ }
+ else
+ {
+ nSeparatorPos = nCategoryStart + pRefField->GetSetRefName().getLength();
+ }
+ sal_Int32 nRefTextPos = 0;
+ if(nSeparatorPos < aText.getLength())
+ {
+ nRefTextPos = SwGetExpField::GetReferenceTextPos(pHt->GetFormatField(), *m_rExport.m_pDoc, nSeparatorPos);
+ if(nRefTextPos != nSeparatorPos)
+ {
+ if(!bRunSplittedAtSep)
+ {
+ if(!bCategoryFirst)
+ rAttrIter.SplitRun(nSeparatorPos);
+ rAttrIter.SplitRun(nRefTextPos);
+ bRunSplittedAtSep = true;
+ }
+ if(!bCategoryFirst)
+ aLocalAttrIter.SplitRun(nSeparatorPos);
+ aLocalAttrIter.SplitRun(nRefTextPos);
+ }
+ else if (bCategoryFirst)
+ {
+ if(!bRunSplittedAtSep)
+ {
+ rAttrIter.SplitRun(nSeparatorPos);
+ bRunSplittedAtSep = true;
+ }
+ aLocalAttrIter.SplitRun(nSeparatorPos);
+ }
+ }
+ // Generate bookmarks on the right position
+ OUString sName("Ref_" + pRefField->GetSetRefName());
+ sName += OUString::number(pRefField->GetSeqNo());
+ switch (pRefField->GetFormat())
+ {
+ case REF_PAGE:
+ case REF_PAGE_PGDESC:
+ case REF_CONTENT:
+ case REF_UPDOWN:
+ sName += "_full";
+ if(!bHaveFullBkm)
+ {
+ sal_Int32 nLastAttrStart = 0;
+ sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
+ while (nActAttr < rNode.GetText().getLength())
+ {
+ nLastAttrStart = nActAttr;
+ aLocalAttrIter.NextPos();
+ nActAttr = aLocalAttrIter.WhereNext();
+ }
+ WriteBookmarks_Impl( sName, std::min(nCategoryStart, pHt->GetStart()), nLastAttrStart );
+ bHaveFullBkm = true;
+ }
+ break;
+ case REF_ONLYNUMBER:
+ {
+ sName += "_label_and_number";
+ if(!bHaveLabelAndNumberBkm)
+ {
+ if(bCategoryFirst)
+ WriteBookmarks_Impl( sName, std::min(nCategoryStart, pHt->GetStart()), std::max(nCategoryStart, pHt->GetStart()) );
+ else
+ {
+ // Find the last run which contains category text
+ SwWW8AttrIter aLocalAttrIter2( m_rExport, rNode );
+ sal_Int32 nCatLastRun = 0;
+ sal_Int32 nNextAttr = aLocalAttrIter2.WhereNext();
+ while (nNextAttr < nSeparatorPos)
+ {
+ nCatLastRun = nNextAttr;
+ aLocalAttrIter2.NextPos();
+ nNextAttr = aLocalAttrIter2.WhereNext();
+ }
+ WriteBookmarks_Impl( sName, pHt->GetStart(), nCatLastRun );
+ }
+ bHaveLabelAndNumberBkm = true;
+ }
+ break;
+ }
+ case REF_ONLYCAPTION:
+ {
+ sName += "_caption_only";
+ if(!bHaveCaptionOnlyBkm)
+ {
+ // Find last run
+ sal_Int32 nLastAttrStart = 0;
+ sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
+ while (nActAttr < rNode.GetText().getLength())
+ {
+ nLastAttrStart = nActAttr;
+ aLocalAttrIter.NextPos();
+ nActAttr = aLocalAttrIter.WhereNext();
+ }
+ WriteBookmarks_Impl( sName, nRefTextPos, nLastAttrStart );
+ bHaveCaptionOnlyBkm = true;
+ }
+ break;
+ }
+ case REF_ONLYSEQNO:
+ {
+ sName += "_number_only";
+ if(!bHaveNumberOnlyBkm)
+ {
+ WriteBookmarks_Impl( sName, pHt->GetStart(), pHt->GetStart() );
+ bHaveNumberOnlyBkm = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
+ }
+ }
+ }
+ }
+}
+
void DocxAttributeOutput::WritePendingPlaceholder()
{
if( pendingPlaceholder == nullptr )
@@ -7248,6 +7456,12 @@ void DocxAttributeOutput::WriteBookmarks_Impl( std::vector< OUString >& rStarts,
rEnds.clear();
}
+void DocxAttributeOutput::WriteBookmarks_Impl( const OUString& rName, sal_Int32 nWithStartPos, sal_Int32 nWithEndPos )
+{
+ m_aBookmarksWithPosStart.insert(std::pair<sal_Int32, OUString>(nWithStartPos, rName));
+ m_aBookmarksWithPosEnd.insert(std::pair<sal_Int32, OUString>(nWithEndPos, rName));
+}
+
void DocxAttributeOutput::WriteAnnotationMarks_Impl( std::vector< OUString >& rStarts,
std::vector< OUString >& rEnds )
{