/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "rtfexport.hxx"
#include "rtfexportfilter.hxx"
#include "rtfsdrexport.hxx"
#include "rtfattributeoutput.hxx"
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <docsh.hxx>
#include <viewsh.hxx>
#include <viewopt.hxx>
#include <fmtpdsc.hxx>
#include <ftninfo.hxx>
#include <fmthdft.hxx>
#include <editeng/colritem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/paperinf.hxx>
#include <editeng/brushitem.hxx>
#include <editeng/protitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/shaditem.hxx>
#include <lineinfo.hxx>
#include <swmodule.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentStylePoolAccess.hxx>
#include <comphelper/string.hxx>
#include <svtools/rtfkeywd.hxx>
#include <filter/msfilter/rtfutil.hxx>
#include <unotools/docinfohelper.hxx>
#include <rtl/tencinfo.h>
#include <sal/log.hxx>
#if OSL_DEBUG_LEVEL > 1
#include <iostream>
#endif
#include <svx/xflclit.hxx>
#include <editeng/hyphenzoneitem.hxx>
#include <fmtmeta.hxx>
#include <o3tl/make_unique.hxx>
#include <IDocumentSettingAccess.hxx>
#include <fmtfsize.hxx>
#include <ndtxt.hxx>
#include <numrule.hxx>
#include <frmatr.hxx>
#include <swtable.hxx>
#include <IMark.hxx>
using namespace ::com::sun::star;
// the default text encoding for the export, if it doesn't fit unicode will
// be used
#define DEF_ENCODING RTL_TEXTENCODING_ASCII_US
AttributeOutputBase& RtfExport::AttrOutput() const { return *m_pAttrOutput; }
MSWordSections& RtfExport::Sections() const { return *m_pSections; }
RtfSdrExport& RtfExport::SdrExporter() const { return *m_pSdrExport; }
bool RtfExport::CollapseScriptsforWordOk(sal_uInt16 nScript, sal_uInt16 nWhich)
{
// FIXME is this actually true for rtf? - this is copied from DOCX
if (nScript == i18n::ScriptType::ASIAN)
{
// for asian in ww8, there is only one fontsize
// and one fontstyle (posture/weight)
switch (nWhich)
{
case RES_CHRATR_FONTSIZE:
case RES_CHRATR_POSTURE:
case RES_CHRATR_WEIGHT:
return false;
default:
break;
}
}
else if (nScript != i18n::ScriptType::COMPLEX)
{
// for western in ww8, there is only one fontsize
// and one fontstyle (posture/weight)
switch (nWhich)
{
case RES_CHRATR_CJK_FONTSIZE:
case RES_CHRATR_CJK_POSTURE:
case RES_CHRATR_CJK_WEIGHT:
return false;
default:
break;
}
}
return true;
}
void RtfExport::AppendBookmarks(const SwTextNode& rNode, sal_Int32 nCurrentPos, sal_Int32 nLen)
{
std::vector<OUString> aStarts;
std::vector<OUString> aEnds;
IMarkVector aMarks;
if (GetBookmarks(rNode, nCurrentPos, nCurrentPos + nLen, aMarks))
{
for (const auto& pMark : aMarks)
{
const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
if (nStart == nCurrentPos)
aStarts.push_back(pMark->GetName());
if (nEnd == nCurrentPos)
aEnds.push_back(pMark->GetName());
}
}
m_pAttrOutput->WriteBookmarks_Impl(aStarts, aEnds);
}
void RtfExport::AppendBookmark(const OUString& rName)
{
std::vector<OUString> aStarts;
std::vector<OUString> aEnds;
aStarts.push_back(rName);
aEnds.push_back(rName);
m_pAttrOutput->WriteBookmarks_Impl(aStarts, aEnds);
}
void RtfExport::AppendAnnotationMarks(const SwTextNode& rNode, sal_Int32 nCurrentPos,
sal_Int32 nLen)
{
std::vector<OUString> aStarts;
std::vector<OUString> aEnds;
IMarkVector aMarks;
if (GetAnnotationMarks(rNode, nCurrentPos, nCurrentPos + nLen, aMarks))
{
for (const auto& pMark : aMarks)
{
const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
if (nStart == nCurrentPos)
aStarts.push_back(pMark->GetName());
if (nEnd == nCurrentPos)
aEnds.push_back(pMark->GetName());
}
}
m_pAttrOutput->WriteAnnotationMarks_Impl(aStarts, aEnds);
}
//For i120928,to export graphic of bullet for RTF filter
void RtfExport::ExportGrfBullet(const SwTextNode& /*rNd*/)
{
// Noop, would be too late, see WriteNumbering() instead.
}
void RtfExport::WriteChar(sal_Unicode /*c*/) { /* WriteChar() has nothing to do for rtf. */}
static bool IsExportNumRule(const SwNumRule& rRule)
{
sal_uInt8 nEnd = MAXLEVEL;
while (nEnd-- && !rRule.GetNumFormat(nEnd))
;
++nEnd;
sal_uInt8 nLvl;
for (nLvl = 0; nLvl < nEnd; ++nLvl)
{
const SwNumFormat* pNFormat = &rRule.Get(nLvl);
if (SVX_NUM_NUMBER_NONE != pNFormat->GetNumberingType() || !pNFormat->GetPrefix().isEmpty()
|| (!pNFormat->GetSuffix().isEmpty() && pNFormat->GetSuffix() != "."))
break;
}
return nLvl != nEnd;
}
void RtfExport::BuildNumbering()
{
const SwNumRuleTable& rListTable = m_pDoc->GetNumRuleTable();
SwNumRule* pOutlineRule = m_pDoc->GetOutlineNumRule();
if (IsExportNumRule(*pOutlineRule))
GetId(*pOutlineRule);
for (auto n = rListTable.size(); n;)
{
SwNumRule* pRule = rListTable[--n];
if (!SwDoc::IsUsed(*pRule))
continue;
if (IsExportNumRule(*pRule))
GetId(*pRule);
}
}
void RtfExport::WriteNumbering()
{
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start");
if (!m_pUsedNumTable)
return; // no numbering is used
Strm()
.WriteChar('{')
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE)
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LISTTABLE);
CollectGrfsOfBullets();
if (!m_vecBulletPic.empty())
Strm()
.WriteChar('{')
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE)
.WriteCharPtr(LO_STRING_SVTOOLS_RTF_LISTPICTURE);
BulletDefinitions();
if (!m_vecBulletPic.empty())
Strm().WriteChar('}');
AbstractNumberingDefinitions();
Strm().WriteChar('}');
Strm().WriteChar('{').WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LISTOVERRIDETABLE);
NumberingDefinitions();
Strm().WriteChar('}');
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end");
}
void RtfExport::WriteRevTab()
{
int nRevAuthors = m_pDoc->getIDocumentRedlineAccess().GetRedlineTable().size();
if (nRevAuthors < 1)
return;
// RTF always seems to use Unknown as the default first entry
GetRedline(OUString("Unknown"));
for (SwRangeRedline* pRedl : m_pDoc->getIDocumentRedlineAccess().GetRedlineTable())
{
GetRedline(SW_MOD()->GetRedlineAuthor(pRedl->GetAuthor()));
}
// Now write the table
Strm()
.WriteChar('{')
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE)
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_REVTBL)
.WriteChar(' ');
for (std::size_t i = 0; i < m_aRedlineTable.size(); ++i)
{
const OUString* pAuthor = GetRedline(i);
Strm().WriteChar('{');
if (pAuthor)
Strm().WriteCharPtr(
msfilter::rtfutil::OutString(*pAuthor, m_eDefaultEncoding).getStr());
Strm().WriteCharPtr(";}");
}
Strm().WriteChar('}').WriteCharPtr(SAL_NEWLINE_STRING);
}
void RtfExport::WriteHeadersFooters(sal_uInt8 nHeadFootFlags, const SwFrameFormat& rFormat,
const SwFrameFormat& rLeftFormat,
const SwFrameFormat& rFirstPageFormat, sal_uInt8 /*nBreakCode*/)
{
// headers
if (nHeadFootFlags & nsHdFtFlags::WW8_HEADER_EVEN)
WriteHeaderFooter(rLeftFormat, true, OOO_STRING_SVTOOLS_RTF_HEADERL);
if (nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD)
WriteHeaderFooter(rFormat, true, OOO_STRING_SVTOOLS_RTF_HEADER);
if (nHeadFootFlags & nsHdFtFlags::WW8_HEADER_FIRST)
WriteHeaderFooter(rFirstPageFormat, true, OOO_STRING_SVTOOLS_RTF_HEADERF, true);
// footers
if (nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_EVEN)
WriteHeaderFooter(rLeftFormat, false, OOO_STRING_SVTOOLS_RTF_FOOTERL);
if (nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD)
WriteHeaderFooter(rFormat, false, OOO_STRING_SVTOOLS_RTF_FOOTER);
if (nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_FIRST)
WriteHeaderFooter(rFirstPageFormat, false, OOO_STRING_SVTOOLS_RTF_FOOTERF, true);
}
void RtfExport::OutputField(const SwField* pField, ww::eField eFieldType, const OUString& rFieldCmd,
FieldFlags nMode)
{
m_pAttrOutput->WriteField_Impl(pField, eFieldType, rFieldCmd, nMode);
}
void RtfExport::WriteFormData(const ::sw::mark::IFieldmark& /*rFieldmark*/)
{
SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
}
void RtfExport::WriteHyperlinkData(const ::sw::mark::IFieldmark& /*rFieldmark*/)
{
SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
}
void RtfExport::DoComboBox(const OUString& /*rName*/, const OUString& /*rHelp*/,
const OUString& /*rToolTip*/, const OUString& /*rSelected*/,
uno::Sequence<OUString>& /*rListItems*/)
{
// this is handled in RtfAttributeOutput::OutputFlyFrame_Impl
}
void RtfExport::DoFormText(const SwInputField* pField)
{
OUString sResult = pField->ExpandField(true);
const OUString& rHelp = pField->GetHelp();
OUString sName = pField->GetPar2();
const OUString& rStatus = pField->GetToolTip();
m_pAttrOutput->RunText().append("{" OOO_STRING_SVTOOLS_RTF_FIELD
"{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FLDINST
"{ FORMTEXT }");
m_pAttrOutput->RunText().append(
"{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FORMFIELD
" {" OOO_STRING_SVTOOLS_RTF_FFTYPE "0");
if (!rHelp.isEmpty())
m_pAttrOutput->RunText().append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP);
if (!rStatus.isEmpty())
m_pAttrOutput->RunText().append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT);
m_pAttrOutput->RunText().append(OOO_STRING_SVTOOLS_RTF_FFTYPETXT "0");
if (!sName.isEmpty())
m_pAttrOutput->RunText()
.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFNAME " ")
.append(msfilter::rtfutil::OutString(sName, m_eDefaultEncoding))
.append("}");
if (!rHelp.isEmpty())
m_pAttrOutput->RunText()
.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFHELPTEXT " ")
.append(msfilter::rtfutil::OutString(rHelp, m_eDefaultEncoding))
.append("}");
m_pAttrOutput->RunText()
.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFDEFTEXT " ")
.append(msfilter::rtfutil::OutString(sResult, m_eDefaultEncoding))
.append("}");
if (!rStatus.isEmpty())
m_pAttrOutput->RunText()
.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFSTATTEXT " ")
.append(msfilter::rtfutil::OutString(rStatus, m_eDefaultEncoding))
.append("}");
m_pAttrOutput->RunText().append("}}}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
m_pAttrOutput->RunText()
.append(msfilter::rtfutil::OutString(sResult, m_eDefaultEncoding))
.append("}}");
}
sal_uLong RtfExport::ReplaceCr(sal_uInt8 /*nChar*/)
{
// Completely unused for Rtf export... only here for code sharing
// purpose with binary export
return 0;
}
void RtfExport::WriteFonts()
{
Strm()
.WriteCharPtr(SAL_NEWLINE_STRING)
.WriteChar('{')
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FONTTBL);
m_aFontHelper.WriteFontTable(*m_pAttrOutput);
Strm().WriteChar('}');
}
void RtfExport::WriteStyles()
{
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start");
m_pStyles->OutputStylesTable();
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end");
}
void RtfExport::WriteFootnoteSettings()
{
const SwPageFootnoteInfo& rFootnoteInfo = m_pDoc->GetPageDesc(0).GetFootnoteInfo();
// Request a separator only in case the width is larger than zero.
bool bSeparator = double(rFootnoteInfo.GetWidth()) > 0;
Strm()
.WriteChar('{')
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE)
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FTNSEP);
if (bSeparator)
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_CHFTNSEP);
Strm().WriteChar('}');
}
void RtfExport::WriteMainText()
{
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start");
if (boost::optional<SvxBrushItem> oBrush = getBackground())
{
Strm().WriteCharPtr(LO_STRING_SVTOOLS_RTF_VIEWBKSP).WriteChar('1');
Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_BACKGROUND);
Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_SHP);
Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SHPINST);
std::vector<std::pair<OString, OString>> aProperties;
aProperties.push_back(std::make_pair<OString, OString>("shapeType", "1"));
aProperties.push_back(std::make_pair<OString, OString>(
"fillColor", OString::number(wwUtility::RGBToBGR(oBrush->GetColor()))));
for (std::pair<OString, OString>& rPair : aProperties)
{
Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_SP "{");
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SN " ");
Strm().WriteCharPtr(rPair.first.getStr());
Strm().WriteCharPtr("}{" OOO_STRING_SVTOOLS_RTF_SV " ");
Strm().WriteCharPtr(rPair.second.getStr());
Strm().WriteCharPtr("}}");
}
Strm().WriteChar('}'); // shpinst
Strm().WriteChar('}'); // shp
Strm().WriteChar('}'); // background
}
SwTableNode* pTableNode = m_pCurPam->GetNode().FindTableNode();
if (m_pWriter && m_pWriter->m_bWriteOnlyFirstTable && pTableNode != nullptr)
{
m_pCurPam->GetPoint()->nNode = *pTableNode;
m_pCurPam->GetMark()->nNode = *(pTableNode->EndOfSectionNode());
}
else
{
m_pCurPam->GetPoint()->nNode
= m_pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex();
}
WriteText();
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end");
}
void RtfExport::WriteInfo()
{
OString aGenerator
= OUStringToOString(utl::DocInfoHelper::GetGeneratorString(), RTL_TEXTENCODING_UTF8);
Strm()
.WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_IGNORE LO_STRING_SVTOOLS_RTF_GENERATOR " ")
.WriteCharPtr(aGenerator.getStr())
.WriteChar('}');
Strm().WriteChar('{').WriteCharPtr(OOO_STRING_SVTOOLS_RTF_INFO);
SwDocShell* pDocShell(m_pDoc->GetDocShell());
uno::Reference<document::XDocumentProperties> xDocProps;
if (pDocShell)
{
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(pDocShell->GetModel(),
uno::UNO_QUERY);
xDocProps.set(xDPS->getDocumentProperties());
}
if (xDocProps.is())
{
// Handle user-defined properties.
uno::Reference<beans::XPropertyContainer> xUserDefinedProperties
= xDocProps->getUserDefinedProperties();
if (xUserDefinedProperties.is())
{
uno::Reference<beans::XPropertySet> xPropertySet(xUserDefinedProperties,
uno::UNO_QUERY);
uno::Reference<beans::XPropertySetInfo> xPropertySetInfo
= xPropertySet->getPropertySetInfo();
// Do we have explicit markup in RTF for this property name?
if (xPropertySetInfo->hasPropertyByName("Company"))
{
OUString aValue;
xPropertySet->getPropertyValue("Company") >>= aValue;
OutUnicode(OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_COMPANY, aValue);
}
}
OutUnicode(OOO_STRING_SVTOOLS_RTF_TITLE, xDocProps->getTitle(), true);
OutUnicode(OOO_STRING_SVTOOLS_RTF_SUBJECT, xDocProps->getSubject());
OutUnicode(OOO_STRING_SVTOOLS_RTF_KEYWORDS,
::comphelper::string::convertCommaSeparated(xDocProps->getKeywords()));
OutUnicode(OOO_STRING_SVTOOLS_RTF_DOCCOMM, xDocProps->getDescription());
OutUnicode(OOO_STRING_SVTOOLS_RTF_AUTHOR, xDocProps->getAuthor());
OutDateTime(OOO_STRING_SVTOOLS_RTF_CREATIM, xDocProps->getCreationDate());
OutUnicode(OOO_STRING_SVTOOLS_RTF_AUTHOR, xDocProps->getModifiedBy());
OutDateTime(OOO_STRING_SVTOOLS_RTF_REVTIM, xDocProps->getModificationDate());
OutDateTime(OOO_STRING_SVTOOLS_RTF_PRINTIM, xDocProps->getPrintDate());
}
Strm().WriteChar('}');
}
void RtfExport::WriteUserPropType(int nType)
{
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PROPTYPE);
OutULong(nType);
}
void RtfExport::WriteUserPropValue(const OUString& rValue)
{
Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_STATICVAL " ");
Strm().WriteCharPtr(msfilter::rtfutil::OutString(rValue, m_eDefaultEncoding).getStr());
Strm().WriteChar('}');
}
void RtfExport::WriteUserProps()
{
Strm().WriteChar('{').WriteCharPtr(
OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_USERPROPS);
SwDocShell* pDocShell(m_pDoc->GetDocShell());
uno::Reference<document::XDocumentProperties> xDocProps;
if (pDocShell)
{
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(pDocShell->GetModel(),
uno::UNO_QUERY);
xDocProps.set(xDPS->getDocumentProperties());
}
else
{
// Clipboard document, read metadata from the meta field manager.
sw::MetaFieldManager& rManager = m_pDoc->GetMetaFieldManager();
xDocProps.set(rManager.getDocumentProperties());
}
if (xDocProps.is())
{
// Handle user-defined properties.
uno::Reference<beans::XPropertyContainer> xUserDefinedProperties
= xDocProps->getUserDefinedProperties();
if (xUserDefinedProperties.is())
{
uno::Reference<beans::XPropertySet> xPropertySet(xUserDefinedProperties,
uno::UNO_QUERY);
uno::Sequence<beans::Property> aProperties
= xPropertySet->getPropertySetInfo()->getProperties();
for (const beans::Property& rProperty : aProperties)
{
if (rProperty.Name.startsWith("Company"))
// We have explicit markup in RTF for this property.
continue;
// Property name.
Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_PROPNAME " ");
Strm().WriteCharPtr(
msfilter::rtfutil::OutString(rProperty.Name, m_eDefaultEncoding).getStr());
Strm().WriteChar('}');
// Property value.
OUString aValue;
double fValue;
bool bValue;
util::DateTime aDate;
uno::Any aAny = xPropertySet->getPropertyValue(rProperty.Name);
if (aAny >>= bValue)
{
WriteUserPropType(11);
WriteUserPropValue(OUString::number(static_cast<int>(bValue)));
}
else if (aAny >>= aValue)
{
WriteUserPropType(30);
WriteUserPropValue(aValue);
}
else if (aAny >>= fValue)
{
aValue = OUString::number(fValue);
if (aValue.indexOf('.') == -1)
{
// Integer.
WriteUserPropType(3);
WriteUserPropValue(aValue);
}
else
{
// Real number.
WriteUserPropType(5);
WriteUserPropValue(aValue);
}
}
else if (aAny >>= aDate)
{
WriteUserPropType(64);
// Format is 'YYYY. MM. DD.'.
aValue += OUString::number(aDate.Year);
aValue += ". ";
if (aDate.Month < 10)
aValue += "0";
aValue += OUString::number(aDate.Month);
aValue += ". ";
if (aDate.Day < 10)
aValue += "0";
aValue += OUString::number(aDate.Day);
aValue += ".";
WriteUserPropValue(aValue);
}
}
}
}
Strm().WriteChar('}');
}
void RtfExport::WritePageDescTable()
{
// Write page descriptions (page styles)
std::size_t nSize = m_pDoc->GetPageDescCnt();
if (!nSize)
return;
Strm().WriteCharPtr(SAL_NEWLINE_STRING);
m_bOutPageDescs = true;
Strm()
.WriteChar('{')
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE)
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PGDSCTBL);
for (std::size_t n = 0; n < nSize; ++n)
{
const SwPageDesc& rPageDesc = m_pDoc->GetPageDesc(n);
Strm()
.WriteCharPtr(SAL_NEWLINE_STRING)
.WriteChar('{')
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PGDSC);
OutULong(n).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PGDSCUSE);
OutULong(static_cast<sal_uLong>(rPageDesc.ReadUseOn()));
OutPageDescription(rPageDesc, false);
// search for the next page description
std::size_t i = nSize;
while (i)
if (rPageDesc.GetFollow() == &m_pDoc->GetPageDesc(--i))
break;
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PGDSCNXT);
OutULong(i).WriteChar(' ');
Strm()
.WriteCharPtr(
msfilter::rtfutil::OutString(rPageDesc.GetName(), m_eDefaultEncoding).getStr())
.WriteCharPtr(";}");
}
Strm().WriteChar('}').WriteCharPtr(SAL_NEWLINE_STRING);
m_bOutPageDescs = false;
// reset table infos, otherwise the depth of the cells will be incorrect,
// in case the page style (header or footer) had tables
m_pTableInfo = std::make_shared<ww8::WW8TableInfo>();
}
ErrCode RtfExport::ExportDocument_Impl()
{
// Make the header
Strm()
.WriteChar('{')
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_RTF)
.WriteChar('1')
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSI);
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_DEFF);
OutULong(m_aFontHelper.GetId(m_pDoc->GetAttrPool().GetDefaultItem(RES_CHRATR_FONT)));
// If this not exist, MS don't understand our ansi characters (0x80-0xff).
Strm().WriteCharPtr("\\adeflang1025");
// Font table
WriteFonts();
m_pStyles = new MSWordStyles(*this);
// Color and stylesheet table
WriteStyles();
// List table
BuildNumbering();
WriteNumbering();
WriteRevTab();
WriteInfo();
WriteUserProps();
// Default TabSize
Strm()
.WriteCharPtr(m_pAttrOutput->m_aTabStop.makeStringAndClear().getStr())
.WriteCharPtr(SAL_NEWLINE_STRING);
// Automatic hyphenation: it's a global setting in Word, it's a paragraph setting in Writer.
// Use the setting from the default style.
SwTextFormatColl* pTextFormatColl = m_pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(
RES_POOLCOLL_STANDARD, /*bRegardLanguage=*/false);
const SfxPoolItem* pItem;
if (pTextFormatColl
&& pTextFormatColl->GetItemState(RES_PARATR_HYPHENZONE, false, &pItem) == SfxItemState::SET)
{
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_HYPHAUTO);
OutULong(int(static_cast<const SvxHyphenZoneItem*>(pItem)->IsHyphen()));
}
// Zoom
SwViewShell* pViewShell(m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell());
if (pViewShell && pViewShell->GetViewOptions()->GetZoomType() == SvxZoomType::PERCENT)
{
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_VIEWSCALE);
OutULong(pViewShell->GetViewOptions()->GetZoom());
}
// Record changes?
if (RedlineFlags::On & m_nOrigRedlineFlags)
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_REVISIONS);
// Mirror margins?
if ((UseOnPage::Mirror & m_pDoc->GetPageDesc(0).ReadUseOn()) == UseOnPage::Mirror)
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MARGMIRROR);
// Init sections
m_pSections = new MSWordSections(*this);
// Page description
WritePageDescTable();
// Enable form protection by default if needed, as there is no switch to
// enable it on a per-section basis. OTOH don't always enable it as it
// breaks moving of drawings - so write it only in case there is really a
// protected section in the document.
{
const SfxItemPool& rPool = m_pDoc->GetAttrPool();
sal_uInt32 const nMaxItem = rPool.GetItemCount2(RES_PROTECT);
for (sal_uInt32 n = 0; n < nMaxItem; ++n)
{
auto pProtect = rPool.GetItem2(RES_PROTECT, n);
if (pProtect && pProtect->IsContentProtected())
{
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FORMPROT);
break;
}
}
}
// enable form field shading
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FORMSHADE);
// size and empty margins of the page
if (m_pDoc->GetPageDescCnt())
{
// Seeking the first SwFormatPageDesc. If no set, the default is valid
const SwFormatPageDesc* pSttPgDsc = nullptr;
{
const SwNode& rSttNd
= *m_pDoc->GetNodes()[m_pDoc->GetNodes().GetEndOfExtras().GetIndex() + 2];
const SfxItemSet* pSet = nullptr;
if (rSttNd.IsContentNode())
pSet = &rSttNd.GetContentNode()->GetSwAttrSet();
else if (rSttNd.IsTableNode())
pSet = &rSttNd.GetTableNode()->GetTable().GetFrameFormat()->GetAttrSet();
else if (rSttNd.IsSectionNode())
pSet = &rSttNd.GetSectionNode()->GetSection().GetFormat()->GetAttrSet();
if (pSet)
{
std::size_t nPosInDoc;
pSttPgDsc = &pSet->Get(RES_PAGEDESC);
if (!pSttPgDsc->GetPageDesc())
pSttPgDsc = nullptr;
else if (m_pDoc->FindPageDesc(pSttPgDsc->GetPageDesc()->GetName(), &nPosInDoc))
{
Strm()
.WriteChar('{')
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE)
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PGDSCNO);
OutULong(nPosInDoc).WriteChar('}');
}
}
}
const SwPageDesc& rPageDesc
= pSttPgDsc ? *pSttPgDsc->GetPageDesc() : m_pDoc->GetPageDesc(0);
const SwFrameFormat& rFormatPage = rPageDesc.GetMaster();
{
if (rPageDesc.GetLandscape())
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LANDSCAPE);
const SwFormatFrameSize& rSz = rFormatPage.GetFrameSize();
// Clipboard document is always created without a printer, then
// the size will be always LONG_MAX! Solution then is to use A4
if (LONG_MAX == rSz.GetHeight() || LONG_MAX == rSz.GetWidth())
{
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PAPERH);
Size a4 = SvxPaperInfo::GetPaperSize(PAPER_A4);
OutULong(a4.Height()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PAPERW);
OutULong(a4.Width());
}
else
{
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PAPERH);
OutULong(rSz.GetHeight()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PAPERW);
OutULong(rSz.GetWidth());
}
}
{
const SvxLRSpaceItem& rLR = rFormatPage.GetLRSpace();
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MARGL);
OutLong(rLR.GetLeft()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MARGR);
OutLong(rLR.GetRight());
}
{
const SvxULSpaceItem& rUL = rFormatPage.GetULSpace();
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MARGT);
OutLong(rUL.GetUpper()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MARGB);
OutLong(rUL.GetLower());
}
Strm()
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SECTD)
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SBKNONE);
// All sections are unlocked by default
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SECTUNLOCKED);
OutLong(1);
OutPageDescription(rPageDesc, true); // Changed bCheckForFirstPage to true so headers
// following title page are correctly added - i13107
if (pSttPgDsc)
{
m_pCurrentPageDesc = &rPageDesc;
}
}
// line numbering
const SwLineNumberInfo& rLnNumInfo = m_pDoc->GetLineNumberInfo();
if (rLnNumInfo.IsPaintLineNumbers())
AttrOutput().SectionLineNumbering(0, rLnNumInfo);
{
// write the footnotes and endnotes-out Info
const SwFootnoteInfo& rFootnoteInfo = m_pDoc->GetFootnoteInfo();
const char* pOut = FTNPOS_CHAPTER == rFootnoteInfo.ePos ? OOO_STRING_SVTOOLS_RTF_ENDDOC
: OOO_STRING_SVTOOLS_RTF_FTNBJ;
Strm().WriteCharPtr(pOut).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FTNSTART);
OutLong(rFootnoteInfo.nFootnoteOffset + 1);
switch (rFootnoteInfo.eNum)
{
case FTNNUM_PAGE:
pOut = OOO_STRING_SVTOOLS_RTF_FTNRSTPG;
break;
case FTNNUM_DOC:
pOut = OOO_STRING_SVTOOLS_RTF_FTNRSTCONT;
break;
default:
pOut = OOO_STRING_SVTOOLS_RTF_FTNRESTART;
break;
}
Strm().WriteCharPtr(pOut);
switch (rFootnoteInfo.aFormat.GetNumberingType())
{
case SVX_NUM_CHARS_LOWER_LETTER:
case SVX_NUM_CHARS_LOWER_LETTER_N:
pOut = OOO_STRING_SVTOOLS_RTF_FTNNALC;
break;
case SVX_NUM_CHARS_UPPER_LETTER:
case SVX_NUM_CHARS_UPPER_LETTER_N:
pOut = OOO_STRING_SVTOOLS_RTF_FTNNAUC;
break;
case SVX_NUM_ROMAN_LOWER:
pOut = OOO_STRING_SVTOOLS_RTF_FTNNRLC;
break;
case SVX_NUM_ROMAN_UPPER:
pOut = OOO_STRING_SVTOOLS_RTF_FTNNRUC;
break;
case SVX_NUM_CHAR_SPECIAL:
pOut = OOO_STRING_SVTOOLS_RTF_FTNNCHI;
break;
default:
pOut = OOO_STRING_SVTOOLS_RTF_FTNNAR;
break;
}
Strm().WriteCharPtr(pOut);
const SwEndNoteInfo& rEndNoteInfo = m_pDoc->GetEndNoteInfo();
Strm()
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_AENDDOC)
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_AFTNRSTCONT)
.WriteCharPtr(OOO_STRING_SVTOOLS_RTF_AFTNSTART);
OutLong(rEndNoteInfo.nFootnoteOffset + 1);
switch (rEndNoteInfo.aFormat.GetNumberingType())
{
case SVX_NUM_CHARS_LOWER_LETTER:
case SVX_NUM_CHARS_LOWER_LETTER_N:
pOut = OOO_STRING_SVTOOLS_RTF_AFTNNALC;
break;
case SVX_NUM_CHARS_UPPER_LETTER:
case SVX_NUM_CHARS_UPPER_LETTER_N:
pOut = OOO_STRING_SVTOOLS_RTF_AFTNNAUC;
break;
case SVX_NUM_ROMAN_LOWER:
pOut = OOO_STRING_SVTOOLS_RTF_AFTNNRLC;
break;
case SVX_NUM_ROMAN_UPPER:
pOut = OOO_STRING_SVTOOLS_RTF_AFTNNRUC;
break;
case SVX_NUM_CHAR_SPECIAL:
pOut = OOO_STRING_SVTOOLS_RTF_AFTNNCHI;
break;
default:
pOut = OOO_STRING_SVTOOLS_RTF_AFTNNAR;
break;
}
Strm().WriteCharPtr(pOut);
}
if (!m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PARA_SPACE_MAX))
// RTF default is true, so write compat flag if this should be false.
Strm().WriteCharPtr(LO_STRING_SVTOOLS_RTF_HTMAUTSP);
Strm().WriteCharPtr(SAL_NEWLINE_STRING);
WriteFootnoteSettings();
WriteMainText();
Strm().WriteChar('}');
return ERRCODE_NONE;
}
void RtfExport::PrepareNewPageDesc(const SfxItemSet* pSet, const SwNode& rNd,
const SwFormatPageDesc* pNewPgDescFormat,
const SwPageDesc* pNewPgDesc)
{
const SwSectionFormat* pFormat = GetSectionFormat(rNd);
const sal_uLong nLnNm = GetSectionLineNo(pSet, rNd);
OSL_ENSURE(pNewPgDescFormat || pNewPgDesc, "Neither page desc format nor page desc provided.");
if (pNewPgDescFormat)
m_pSections->AppendSection(*pNewPgDescFormat, rNd, pFormat, nLnNm);
else if (pNewPgDesc)
m_pSections->AppendSection(pNewPgDesc, rNd, pFormat, nLnNm);
// Don't insert a page break, when we're changing page style just because the next page has to be a different one.
if (!m_pAttrOutput->m_pPrevPageDesc
|| m_pAttrOutput->m_pPrevPageDesc->GetFollow() != pNewPgDesc)
AttrOutput().SectionBreak(msword::PageBreak, m_pSections->CurrentSectionInfo());
}
bool RtfExport::DisallowInheritingOutlineNumbering(const SwFormat& rFormat)
{
bool bRet(false);
if (SfxItemState::SET != rFormat.GetItemState(RES_PARATR_NUMRULE, false))
{
if (const SwFormat* pParent = rFormat.DerivedFrom())
{
if (static_cast<const SwTextFormatColl*>(pParent)
->IsAssignedToListLevelOfOutlineStyle())
{
// Level 9 disables the outline
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LEVEL).WriteInt32(9);
bRet = true;
}
}
}
return bRet;
}
void RtfExport::OutputEndNode(const SwEndNode& rEndNode)
{
if (TXT_MAINTEXT == m_nTextTyp && rEndNode.StartOfSectionNode()->IsTableNode())
// End node of a table: see if a section break should be written after the table.
AttrOutput().SectionBreaks(rEndNode);
}
void RtfExport::OutputGrfNode(const SwGrfNode& /*rGrfNode*/)
{
/* noop, see RtfAttributeOutput::FlyFrameGraphic */
}
void RtfExport::OutputOLENode(const SwOLENode& /*rOLENode*/)
{
/* noop, see RtfAttributeOutput::FlyFrameOLE */
}
void RtfExport::OutputLinkedOLE(const OUString& /*rLinked*/) {}
void RtfExport::OutputTextNode(SwTextNode& rNode)
{
m_nCurrentNodeIndex = rNode.GetIndex();
if (!m_bOutOutlineOnly || rNode.IsOutline())
MSWordExportBase::OutputTextNode(rNode);
m_nCurrentNodeIndex = 0;
}
void RtfExport::AppendSection(const SwPageDesc* pPageDesc, const SwSectionFormat* pFormat,
sal_uLong nLnNum)
{
m_pSections->AppendSection(pPageDesc, pFormat, nLnNum);
AttrOutput().SectionBreak(msword::PageBreak, m_pSections->CurrentSectionInfo());
}
RtfExport::RtfExport(RtfExportFilter* pFilter, SwDoc* pDocument, SwPaM* pCurrentPam,
SwPaM* pOriginalPam, Writer* pWriter, bool bOutOutlineOnly)
: MSWordExportBase(pDocument, pCurrentPam, pOriginalPam)
, m_pFilter(pFilter)
, m_pWriter(pWriter)
, m_pSections(nullptr)
, m_bOutOutlineOnly(bOutOutlineOnly)
, m_eDefaultEncoding(
rtl_getTextEncodingFromWindowsCharset(sw::ms::rtl_TextEncodingToWinCharset(DEF_ENCODING)))
, m_eCurrentEncoding(m_eDefaultEncoding)
, m_bRTFFlySyntax(false)
, m_nCurrentNodeIndex(0)
{
m_bExportModeRTF = true;
// the attribute output for the document
m_pAttrOutput = o3tl::make_unique<RtfAttributeOutput>(*this);
// that just causes problems for RTF
m_bSubstituteBullets = false;
// needed to have a complete font table
m_aFontHelper.bLoadAllFonts = true;
// the related SdrExport
m_pSdrExport = o3tl::make_unique<RtfSdrExport>(*this);
if (!m_pWriter)
m_pWriter = &m_pFilter->m_aWriter;
}
RtfExport::~RtfExport() = default;
SvStream& RtfExport::Strm()
{
if (m_pStream)
return *m_pStream;
return m_pWriter->Strm();
}
void RtfExport::setStream() { m_pStream = o3tl::make_unique<SvMemoryStream>(); }
OString RtfExport::getStream()
{
OString aRet;
if (m_pStream)
aRet = OString(static_cast<const sal_Char*>(m_pStream->GetData()), m_pStream->Tell());
return aRet;
}
void RtfExport::resetStream() { m_pStream.reset(); }
SvStream& RtfExport::OutULong(sal_uLong nVal) { return Writer::OutULong(Strm(), nVal); }
SvStream& RtfExport::OutLong(long nVal) { return Writer::OutLong(Strm(), nVal); }
void RtfExport::OutUnicode(const sal_Char* pToken, const OUString& rContent, bool bUpr)
{
if (!rContent.isEmpty())
{
if (!bUpr)
{
Strm().WriteChar('{').WriteCharPtr(pToken).WriteChar(' ');
Strm().WriteCharPtr(
msfilter::rtfutil::OutString(rContent, m_eCurrentEncoding).getStr());
Strm().WriteChar('}');
}
else
Strm().WriteCharPtr(
msfilter::rtfutil::OutStringUpr(pToken, rContent, m_eCurrentEncoding).getStr());
}
}
void RtfExport::OutDateTime(const sal_Char* pStr, const util::DateTime& rDT)
{
Strm().WriteChar('{').WriteCharPtr(pStr).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_YR);
OutULong(rDT.Year).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MO);
OutULong(rDT.Month).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_DY);
OutULong(rDT.Day).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_HR);
OutULong(rDT.Hours).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MIN);
OutULong(rDT.Minutes).WriteChar('}');
}
sal_uInt16 RtfExport::GetColor(const Color& rColor) const
{
for (const auto& rEntry : m_aColTable)
if (rEntry.second == rColor)
{
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " returning " << rEntry.first << " ("
<< rColor.GetRed() << "," << rColor.GetGreen() << ","
<< rColor.GetBlue() << ")");
return rEntry.first;
}
OSL_FAIL("No such Color in m_aColTable!");
return 0;
}
void RtfExport::InsColor(const Color& rCol)
{
sal_uInt16 n;
bool bAutoColorInTable = false;
for (const auto& rEntry : m_aColTable)
{
if (rEntry.second == rCol)
return; // Already in the table
if (rEntry.second == COL_AUTO)
bAutoColorInTable = true;
}
if (rCol == COL_AUTO)
// COL_AUTO gets value 0
n = 0;
else
{
// other colors get values >0
n = m_aColTable.size();
if (!bAutoColorInTable)
// reserve value "0" for COL_AUTO (if COL_AUTO wasn't inserted until now)
n++;
}
m_aColTable.insert(std::pair<sal_uInt16, Color>(n, rCol));
}
void RtfExport::InsColorLine(const SvxBoxItem& rBox)
{
const editeng::SvxBorderLine* pLine = nullptr;
if (rBox.GetTop())
InsColor((pLine = rBox.GetTop())->GetColor());
if (rBox.GetBottom() && pLine != rBox.GetBottom())
InsColor((pLine = rBox.GetBottom())->GetColor());
if (rBox.GetLeft() && pLine != rBox.GetLeft())
InsColor((pLine = rBox.GetLeft())->GetColor());
if (rBox.GetRight() && pLine != rBox.GetRight())
InsColor(rBox.GetRight()->GetColor());
}
void RtfExport::OutColorTable()
{
// Build the table from rPool since the colors provided to
// RtfAttributeOutput callbacks are too late.
sal_uInt32 nMaxItem;
const SfxItemPool& rPool = m_pDoc->GetAttrPool();
// MSO Word uses a default color table with 16 colors (which is used e.g. for highlighting)
InsColor(COL_BLACK);
InsColor(COL_LIGHTBLUE);
InsColor(COL_LIGHTCYAN);
InsColor(COL_LIGHTGREEN);
InsColor(COL_LIGHTMAGENTA);
InsColor(COL_LIGHTRED);
InsColor(COL_YELLOW);
InsColor(COL_WHITE);
InsColor(COL_BLUE);
InsColor(COL_CYAN);
InsColor(COL_GREEN);
InsColor(COL_MAGENTA);
InsColor(COL_RED);
InsColor(COL_BROWN);
InsColor(COL_GRAY);
InsColor(COL_LIGHTGRAY);
// char color
{
auto pCol = GetDfltAttr(RES_CHRATR_COLOR);
InsColor(pCol->GetValue());
if ((pCol = rPool.GetPoolDefaultItem(RES_CHRATR_COLOR)))
InsColor(pCol->GetValue());
nMaxItem = rPool.GetItemCount2(RES_CHRATR_COLOR);
for (sal_uInt32 n = 0; n < nMaxItem; ++n)
{
if ((pCol = rPool.GetItem2(RES_CHRATR_COLOR, n)))
InsColor(pCol->GetValue());
}
auto pUnder = GetDfltAttr(RES_CHRATR_UNDERLINE);
InsColor(pUnder->GetColor());
nMaxItem = rPool.GetItemCount2(RES_CHRATR_UNDERLINE);
for (sal_uInt32 n = 0; n < nMaxItem; ++n)
{
if ((pUnder = rPool.GetItem2(RES_CHRATR_UNDERLINE, n)))
InsColor(pUnder->GetColor());
}
auto pOver = GetDfltAttr(RES_CHRATR_OVERLINE);
InsColor(pOver->GetColor());
nMaxItem = rPool.GetItemCount2(RES_CHRATR_OVERLINE);
for (sal_uInt32 n = 0; n < nMaxItem; ++n)
{
if ((pOver = rPool.GetItem2(RES_CHRATR_OVERLINE, n)))
InsColor(pOver->GetColor());
}
}
// background color
static const sal_uInt16 aBrushIds[] = { RES_BACKGROUND, RES_CHRATR_BACKGROUND, 0 };
for (const sal_uInt16* pIds = aBrushIds; *pIds; ++pIds)
{
auto pBackground = static_cast<const SvxBrushItem*>(GetDfltAttr(*pIds));
InsColor(pBackground->GetColor());
if ((pBackground = static_cast<const SvxBrushItem*>(rPool.GetPoolDefaultItem(*pIds))))
{
InsColor(pBackground->GetColor());
}
nMaxItem = rPool.GetItemCount2(*pIds);
for (sal_uInt32 n = 0; n < nMaxItem; ++n)
{
if ((pBackground = static_cast<const SvxBrushItem*>(rPool.GetItem2(*pIds, n))))
{
InsColor(pBackground->GetColor());
}
}
}
// shadow color
{
auto pShadow = GetDfltAttr(RES_SHADOW);
InsColor(pShadow->GetColor());
if (nullptr != (pShadow = rPool.GetPoolDefaultItem(RES_SHADOW)))
{
InsColor(pShadow->GetColor());
}
nMaxItem = rPool.GetItemCount2(RES_SHADOW);
for (sal_uInt32 n = 0; n < nMaxItem; ++n)
{
if (nullptr != (pShadow = rPool.GetItem2(RES_SHADOW, n)))
{
InsColor(pShadow->GetColor());
}
}
}
// frame border color
{
const SvxBoxItem* pBox;
if (nullptr != (pBox = rPool.GetPoolDefaultItem(RES_BOX)))
InsColorLine(*pBox);
nMaxItem = rPool.GetItemCount2(RES_BOX);
for (sal_uInt32 n = 0; n < nMaxItem; ++n)
{
if (nullptr != (pBox = rPool.GetItem2(RES_BOX, n)))
InsColorLine(*pBox);
}
}
{
const SvxBoxItem* pCharBox;
if ((pCharBox = rPool.GetPoolDefaultItem(RES_CHRATR_BOX)))
InsColorLine(*pCharBox);
nMaxItem = rPool.GetItemCount2(RES_CHRATR_BOX);
for (sal_uInt32 n = 0; n < nMaxItem; ++n)
{
if ((pCharBox = rPool.GetItem2(RES_CHRATR_BOX, n)))
InsColorLine(*pCharBox);
}
}
// TextFrame or paragraph background solid fill.
nMaxItem = rPool.GetItemCount2(XATTR_FILLCOLOR);
for (sal_uInt32 i = 0; i < nMaxItem; ++i)
{
if (auto pItem = rPool.GetItem2(XATTR_FILLCOLOR, i))
InsColor(pItem->GetColorValue());
}
for (std::size_t n = 0; n < m_aColTable.size(); ++n)
{
const Color& rCol = m_aColTable[n];
if (n || COL_AUTO != rCol)
{
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_RED);
OutULong(rCol.GetRed()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_GREEN);
OutULong(rCol.GetGreen()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_BLUE);
OutULong(rCol.GetBlue());
}
Strm().WriteChar(';');
}
}
void RtfExport::InsStyle(sal_uInt16 nId, const OString& rStyle)
{
m_aStyTable.insert(std::pair<sal_uInt16, OString>(nId, rStyle));
}
OString* RtfExport::GetStyle(sal_uInt16 nId)
{
auto it = m_aStyTable.find(nId);
if (it != m_aStyTable.end())
return &it->second;
return nullptr;
}
sal_uInt16 RtfExport::GetRedline(const OUString& rAuthor)
{
auto it = m_aRedlineTable.find(rAuthor);
if (it != m_aRedlineTable.end())
return it->second;
const sal_uInt16 nId = m_aRedlineTable.size();
m_aRedlineTable.insert(std::pair<OUString, sal_uInt16>(rAuthor, nId));
return nId;
}
const OUString* RtfExport::GetRedline(sal_uInt16 nId)
{
for (const auto& rEntry : m_aRedlineTable)
if (rEntry.second == nId)
return &rEntry.first;
return nullptr;
}
void RtfExport::OutPageDescription(const SwPageDesc& rPgDsc, bool bCheckForFirstPage)
{
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start");
const SwPageDesc* pSave = m_pCurrentPageDesc;
m_pCurrentPageDesc = &rPgDsc;
if (bCheckForFirstPage && m_pCurrentPageDesc->GetFollow()
&& m_pCurrentPageDesc->GetFollow() != m_pCurrentPageDesc)
m_pCurrentPageDesc = m_pCurrentPageDesc->GetFollow();
if (m_pCurrentPageDesc->GetLandscape())
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LNDSCPSXN);
const SwFormat* pFormat = &m_pCurrentPageDesc->GetMaster(); //GetLeft();
m_bOutPageDescs = true;
if (m_pCurrentPageDesc != &rPgDsc)
m_pFirstPageItemSet = &rPgDsc.GetMaster().GetAttrSet();
OutputFormat(*pFormat, true, false);
m_pFirstPageItemSet = nullptr;
m_bOutPageDescs = false;
// normal header / footer (without a style)
const SfxPoolItem* pItem;
if (m_pCurrentPageDesc->GetLeft().GetAttrSet().GetItemState(RES_HEADER, false, &pItem)
== SfxItemState::SET)
WriteHeaderFooter(*pItem, true);
if (m_pCurrentPageDesc->GetLeft().GetAttrSet().GetItemState(RES_FOOTER, false, &pItem)
== SfxItemState::SET)
WriteHeaderFooter(*pItem, false);
// title page
if (m_pCurrentPageDesc != &rPgDsc)
{
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_TITLEPG);
m_pCurrentPageDesc = &rPgDsc;
if (m_pCurrentPageDesc->GetMaster().GetAttrSet().GetItemState(RES_HEADER, false, &pItem)
== SfxItemState::SET)
WriteHeaderFooter(*pItem, true);
if (m_pCurrentPageDesc->GetMaster().GetAttrSet().GetItemState(RES_FOOTER, false, &pItem)
== SfxItemState::SET)
WriteHeaderFooter(*pItem, false);
}
// numbering type
AttrOutput().SectionPageNumbering(m_pCurrentPageDesc->GetNumType().GetNumberingType(),
boost::none);
m_pCurrentPageDesc = pSave;
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end");
}
void RtfExport::WriteHeaderFooter(const SfxPoolItem& rItem, bool bHeader)
{
if (bHeader)
{
const auto& rHeader = static_cast<const SwFormatHeader&>(rItem);
if (!rHeader.IsActive())
return;
}
else
{
const auto& rFooter = static_cast<const SwFormatFooter&>(rItem);
if (!rFooter.IsActive())
return;
}
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start");
const sal_Char* pStr
= (bHeader ? OOO_STRING_SVTOOLS_RTF_HEADER : OOO_STRING_SVTOOLS_RTF_FOOTER);
/* is this a title page? */
if (m_pCurrentPageDesc->GetFollow() && m_pCurrentPageDesc->GetFollow() != m_pCurrentPageDesc)
{
Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_TITLEPG);
pStr = (bHeader ? OOO_STRING_SVTOOLS_RTF_HEADERF : OOO_STRING_SVTOOLS_RTF_FOOTERF);
}
Strm().WriteChar('{').WriteCharPtr(pStr);
WriteHeaderFooterText(m_pCurrentPageDesc->GetMaster(), bHeader);
Strm().WriteChar('}');
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end");
}
void RtfExport::WriteHeaderFooter(const SwFrameFormat& rFormat, bool bHeader, const sal_Char* pStr,
bool bTitlepg)
{
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start");
m_pAttrOutput->WriteHeaderFooter_Impl(rFormat, bHeader, pStr, bTitlepg);
SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end");
}
/// Glue class to call RtfExport as an internal filter, needed by copy&paste support.
class SwRTFWriter : public Writer
{
private:
bool m_bOutOutlineOnly;
public:
SwRTFWriter(const OUString& rFilterName, const OUString& rBaseURL);
ErrCode WriteStream() override;
};
SwRTFWriter::SwRTFWriter(const OUString& rFilterName, const OUString& rBaseURL)
{
SetBaseURL(rBaseURL);
// export outline nodes, only (send outline to clipboard/presentation)
m_bOutOutlineOnly = rFilterName.startsWith("O");
}
ErrCode SwRTFWriter::WriteStream()
{
SwPaM aPam(*m_pCurrentPam->End(), *m_pCurrentPam->Start());
RtfExport aExport(nullptr, m_pDoc, &aPam, m_pCurrentPam, this, m_bOutOutlineOnly);
aExport.ExportDocument(true);
return ERRCODE_NONE;
}
extern "C" SAL_DLLPUBLIC_EXPORT void ExportRTF(const OUString& rFltName, const OUString& rBaseURL,
WriterRef& xRet)
{
xRet = new SwRTFWriter(rFltName, rBaseURL);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.
↑ V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.